mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Edit metadata dialog: Add special author edit
Edit metadata dialog: Facilitate editing the authors for books that have a large number of authors, by using a dedicated "Edit authors" tool, which you can launch by right clicking the authors in the edit metadata dialog and selecting "Edit authors". Fixes #1255288 [[Enhancement] Display authors in editable popup window](https://bugs.launchpad.net/calibre/+bug/1255288)
This commit is contained in:
parent
7f4cce12f4
commit
0199955e0e
198
src/calibre/gui2/dialogs/authors_edit.py
Normal file
198
src/calibre/gui2/dialogs/authors_edit.py
Normal file
@ -0,0 +1,198 @@
|
||||
#!/usr/bin/env python
|
||||
# vim:fileencoding=utf-8
|
||||
from __future__ import (unicode_literals, division, absolute_import,
|
||||
print_function)
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from PyQt4.Qt import (
|
||||
QDialog, QGridLayout, QDialogButtonBox, QListWidget, QApplication, Qt,
|
||||
pyqtSignal, QSize, QPushButton, QIcon, QStyledItemDelegate, QLabel)
|
||||
|
||||
from calibre.utils.config_base import tweaks
|
||||
from calibre.gui2 import gprefs
|
||||
from calibre.gui2.complete2 import EditWithComplete
|
||||
from calibre.ebooks.metadata import string_to_authors
|
||||
|
||||
class ItemDelegate(QStyledItemDelegate):
|
||||
|
||||
edited = pyqtSignal(object)
|
||||
|
||||
def __init__(self, all_authors, parent):
|
||||
QStyledItemDelegate.__init__(self, parent)
|
||||
self.all_authors = all_authors
|
||||
|
||||
def sizeHint(self, *args):
|
||||
return QStyledItemDelegate.sizeHint(self, *args) + QSize(0, 15)
|
||||
|
||||
def setEditorData(self, editor, index):
|
||||
name = unicode(index.data(Qt.DisplayRole).toString())
|
||||
editor.setText(name)
|
||||
editor.lineEdit().selectAll()
|
||||
|
||||
def setModelData(self, editor, model, index):
|
||||
authors = string_to_authors(unicode(editor.text()))
|
||||
model.setData(index, authors[0])
|
||||
self.edited.emit(index.row())
|
||||
|
||||
def createEditor(self, parent, option, index):
|
||||
self.ed = EditWithComplete(parent)
|
||||
self.ed.setFocusPolicy(Qt.StrongFocus)
|
||||
init_line_edit(self.ed, self.all_authors)
|
||||
return self.ed
|
||||
|
||||
class List(QListWidget):
|
||||
|
||||
def __init__(self, all_authors, parent):
|
||||
QListWidget.__init__(self, parent)
|
||||
self.setDragEnabled(True)
|
||||
self.setSelectionMode(self.ExtendedSelection)
|
||||
self.setDropIndicatorShown(True)
|
||||
self.setDragDropMode(self.InternalMove)
|
||||
self.setAlternatingRowColors(True)
|
||||
self.d = ItemDelegate(all_authors, self)
|
||||
self.d.edited.connect(self.edited, type=Qt.QueuedConnection)
|
||||
self.setItemDelegate(self.d)
|
||||
|
||||
def delete_selected(self):
|
||||
for item in self.selectedItems():
|
||||
self.takeItem(self.row(item))
|
||||
|
||||
def keyPressEvent(self, ev):
|
||||
if ev.key() == Qt.Key_Delete:
|
||||
self.delete_selected()
|
||||
ev.accept()
|
||||
return
|
||||
return QListWidget.keyPressEvent(self, ev)
|
||||
|
||||
def addItem(self, *args):
|
||||
try:
|
||||
return QListWidget.addItem(self, *args)
|
||||
finally:
|
||||
self.mark_as_editable()
|
||||
|
||||
def addItems(self, *args):
|
||||
try:
|
||||
return QListWidget.addItems(self, *args)
|
||||
finally:
|
||||
self.mark_as_editable()
|
||||
|
||||
def mark_as_editable(self):
|
||||
for i in xrange(self.count()):
|
||||
item = self.item(i)
|
||||
item.setFlags(item.flags() | Qt.ItemIsEditable)
|
||||
|
||||
def edited(self, i):
|
||||
item = self.item(i)
|
||||
q = unicode(item.text())
|
||||
remove = []
|
||||
for j in xrange(self.count()):
|
||||
if i != j and unicode(self.item(j).text()) == q:
|
||||
remove.append(j)
|
||||
for x in sorted(remove, reverse=True):
|
||||
self.takeItem(x)
|
||||
|
||||
class Edit(EditWithComplete):
|
||||
|
||||
returnPressed = pyqtSignal()
|
||||
|
||||
def keyPressEvent(self, ev):
|
||||
if ev.key() in (Qt.Key_Return, Qt.Key_Enter):
|
||||
ev.accept()
|
||||
self.returnPressed.emit()
|
||||
return
|
||||
return EditWithComplete.keyPressEvent(self, ev)
|
||||
|
||||
def init_line_edit(a, all_authors):
|
||||
a.set_separator('&')
|
||||
a.set_space_before_sep(True)
|
||||
a.set_add_separator(tweaks['authors_completer_append_separator'])
|
||||
a.update_items_cache(all_authors)
|
||||
|
||||
class AuthorsEdit(QDialog):
|
||||
|
||||
def __init__(self, all_authors, current_authors, parent=None):
|
||||
QDialog.__init__(self, parent)
|
||||
self.l = l = QGridLayout()
|
||||
self.setLayout(l)
|
||||
self.setWindowTitle(_('Edit authors'))
|
||||
|
||||
self.la = QLabel(_(
|
||||
'Edit the authors for this book. You can drag and drop to re-arrange authors'))
|
||||
self.la.setWordWrap(True)
|
||||
l.addWidget(self.la, 0, 0, 1, 3)
|
||||
|
||||
self.al = al = List(all_authors, self)
|
||||
al.addItems(current_authors)
|
||||
l.addWidget(al, 1, 0, 1, 3)
|
||||
|
||||
self.author = a = Edit(self)
|
||||
init_line_edit(a, all_authors)
|
||||
a.lineEdit().setPlaceholderText(_('Enter an author to add'))
|
||||
a.returnPressed.connect(self.add_author)
|
||||
l.addWidget(a, 2, 0)
|
||||
|
||||
self.ab = b = QPushButton(_('&Add'))
|
||||
b.setIcon(QIcon(I('plus.png')))
|
||||
l.addWidget(b, 2, 1)
|
||||
b.clicked.connect(self.add_author)
|
||||
|
||||
self.db = b = QPushButton(_('&Remove selected'))
|
||||
l.addWidget(b, 2, 2)
|
||||
b.setIcon(QIcon(I('minus.png')))
|
||||
b.clicked.connect(self.al.delete_selected)
|
||||
|
||||
self.bb = bb = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
|
||||
bb.accepted.connect(self.accept)
|
||||
bb.rejected.connect(self.reject)
|
||||
l.addWidget(bb, 3, 0, 1, 3)
|
||||
|
||||
l.setColumnStretch(0, 10)
|
||||
self.resize(self.sizeHint() + QSize(150, 100))
|
||||
geom = gprefs.get('authors-edit-geometry', None)
|
||||
if geom is not None:
|
||||
self.restoreGeometry(geom)
|
||||
self.author.setFocus(Qt.OtherFocusReason)
|
||||
|
||||
def save_geometry(self):
|
||||
gprefs.set('authors-edit-geometry', bytearray(self.saveGeometry()))
|
||||
|
||||
def accept(self):
|
||||
self.save_geometry()
|
||||
return QDialog.accept(self)
|
||||
|
||||
def reject(self):
|
||||
self.save_geometry()
|
||||
return QDialog.reject(self)
|
||||
|
||||
@property
|
||||
def authors(self):
|
||||
ans = []
|
||||
for i in xrange(self.al.count()):
|
||||
ans.append(unicode(self.al.item(i).text()))
|
||||
return ans or [_('Unknown')]
|
||||
|
||||
def add_author(self):
|
||||
text = self.author.text().strip()
|
||||
authors = OrderedDict((icu_lower(x), (i, x)) for i, x in enumerate(self.authors))
|
||||
if text:
|
||||
for author in string_to_authors(text):
|
||||
la = icu_lower(author)
|
||||
if la in authors and authors[la][1] != author:
|
||||
# Case change
|
||||
i = authors[la][0]
|
||||
authors[la] = (i, author)
|
||||
self.al.item(i).setText(author)
|
||||
else:
|
||||
self.al.addItem(author)
|
||||
authors[la] = author
|
||||
self.author.setText('')
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = QApplication([])
|
||||
d = AuthorsEdit(['kovid goyal', 'divok layog', 'other author'], ['kovid goyal', 'other author'])
|
||||
d.exec_()
|
||||
print (d.authors)
|
@ -227,6 +227,21 @@ class AuthorsEdit(EditWithComplete):
|
||||
self.setSizeAdjustPolicy(self.AdjustToMinimumContentsLengthWithIcon)
|
||||
self.manage_authors_signal = manage_authors
|
||||
manage_authors.triggered.connect(self.manage_authors)
|
||||
self.lineEdit().createStandardContextMenu = self.createStandardContextMenu
|
||||
|
||||
def createStandardContextMenu(self):
|
||||
menu = QLineEdit.createStandardContextMenu(self.lineEdit())
|
||||
menu.addSeparator()
|
||||
menu.addAction(_('&Edit authors'), self.edit_authors)
|
||||
return menu
|
||||
|
||||
def edit_authors(self):
|
||||
all_authors = self.lineEdit().all_items
|
||||
current_authors = self.current_val
|
||||
from calibre.gui2.dialogs.authors_edit import AuthorsEdit
|
||||
d = AuthorsEdit(all_authors, current_authors, self)
|
||||
if d.exec_() == d.Accepted:
|
||||
self.current_val = d.authors
|
||||
|
||||
def manage_authors(self):
|
||||
if self.original_val != self.current_val:
|
||||
|
Loading…
x
Reference in New Issue
Block a user