Copy to library: Add a action to show a dialog that allows for easy selection of libraries for copy/move. Useful when there are a large number of libraries to choose from. Fixes #1706198 [[Enhancement] Provide users the ability to remove/hide popup menu option copy to library, leaving only Delete After Copy option visible](https://bugs.launchpad.net/calibre/+bug/1706198)

This commit is contained in:
Kovid Goyal 2017-08-03 11:25:45 +05:30
parent 0f6d873070
commit a74d0546eb
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C

View File

@ -12,8 +12,9 @@ from contextlib import closing
from collections import defaultdict
from PyQt5.Qt import (
QToolButton, QDialog, QGridLayout, QIcon, QLabel, QDialogButtonBox, QApplication,
QFormLayout, QCheckBox, QWidget, QScrollArea, QVBoxLayout, Qt, QListWidgetItem, QListWidget)
QToolButton, QDialog, QGridLayout, QIcon, QLabel, QDialogButtonBox,
QApplication, QLineEdit, QHBoxLayout, QFormLayout, QCheckBox, QWidget,
QScrollArea, QVBoxLayout, Qt, QListWidgetItem, QListWidget, QSize)
from calibre import as_unicode
from calibre.constants import isosx
@ -22,10 +23,10 @@ from calibre.gui2.actions import InterfaceAction
from calibre.gui2 import (error_dialog, Dispatcher, warning_dialog, gprefs,
info_dialog, choose_dir)
from calibre.gui2.dialogs.progress import ProgressDialog
from calibre.gui2.widgets import HistoryLineEdit
from calibre.gui2.widgets2 import Dialog
from calibre.utils.config import prefs, tweaks
from calibre.utils.date import now
from calibre.utils.icu import sort_key
from calibre.utils.icu import sort_key, numeric_sort_key
def ask_about_cc_mismatch(gui, db, newdb, missing_cols, incompatible_cols): # {{{
@ -257,28 +258,52 @@ class Worker(Thread): # {{{
# }}}
class ChooseLibrary(QDialog): # {{{
class ChooseLibrary(Dialog): # {{{
def __init__(self, parent):
super(ChooseLibrary, self).__init__(parent)
d = self
d.l = l = QGridLayout()
d.setLayout(l)
d.setWindowTitle(_('Choose library'))
la = d.la = QLabel(_('Library &path:'))
l.addWidget(la, 0, 0)
le = d.le = HistoryLineEdit(d)
le.initialize('choose_library_for_copy')
l.addWidget(le, 0, 1)
def __init__(self, parent, locations):
self.locations = locations
Dialog.__init__(self, _('Choose library'), 'copy_to_choose_library_dialog', parent)
self.resort()
self.current_changed()
def resort(self):
if self.sort_alphabetically.isChecked():
sorted_locations = sorted(self.locations, key=lambda (name, loc): numeric_sort_key(name))
else:
sorted_locations = self.locations
self.items.clear()
for name, loc in sorted_locations:
i = QListWidgetItem(name, self.items)
i.setData(Qt.UserRole, loc)
self.items.setCurrentRow(0)
def setup_ui(self):
self.l = l = QGridLayout(self)
self.items = i = QListWidget(self)
i.setSelectionMode(i.SingleSelection)
i.currentItemChanged.connect(self.current_changed)
l.addWidget(i)
self.v = v = QVBoxLayout()
l.addLayout(v, 0, 1)
self.sort_alphabetically = sa = QCheckBox(_('&Sort libraries alphabetically'))
v.addWidget(sa)
sa.setChecked(bool(gprefs.get('copy_to_library_choose_library_sort_alphabetically', True)))
sa.stateChanged.connect(self.resort)
sa.stateChanged.connect(lambda: gprefs.set('copy_to_library_choose_library_sort_alphabetically', bool(self.sort_alphabetically.isChecked())))
la = self.la = QLabel(_('Library &path:'))
v.addWidget(la)
le = self.le = QLineEdit(self)
la.setBuddy(le)
b = d.b = QToolButton(d)
b = self.b = QToolButton(self)
b.setIcon(QIcon(I('document_open.png')))
b.setToolTip(_('Browse for library'))
b.clicked.connect(self.browse)
l.addWidget(b, 0, 2)
self.bb = bb = QDialogButtonBox(QDialogButtonBox.Cancel)
bb.accepted.connect(self.accept)
bb.rejected.connect(self.reject)
h = QHBoxLayout()
h.addWidget(le), h.addWidget(b)
v.addLayout(h)
v.addStretch(10)
bb = self.bb
bb.setStandardButtons(QDialogButtonBox.Cancel)
self.delete_after_copy = False
b = bb.addButton(_('&Copy'), bb.AcceptRole)
b.setIcon(QIcon(I('edit-copy.png')))
@ -288,9 +313,16 @@ class ChooseLibrary(QDialog): # {{{
b2.setIcon(QIcon(I('edit-cut.png')))
b2.setToolTip(_('Copy to the specified library and delete from the current library'))
b.setDefault(True)
l.addWidget(bb, 1, 0, 1, 3)
le.setMinimumWidth(350)
self.resize(self.sizeHint())
l.addWidget(bb, 1, 0, 1, 2)
self.items.setFocus(Qt.OtherFocusReason)
def sizeHint(self):
return QSize(800, 550)
def current_changed(self):
i = self.items.currentItem() or self.items.item(0)
loc = i.data(Qt.UserRole)
self.le.setText(loc)
def browse(self):
d = choose_dir(self, 'choose_library_for_copy',
@ -396,8 +428,7 @@ class CopyToLibraryAction(InterfaceAction):
return
db = self.gui.library_view.model().db
locations = list(self.stats.locations(db))
if len(locations) > 50:
self.menu.addAction(_('Choose library by path...'), self.choose_library)
self.menu.addAction(_('Choose library...'), self.choose_library)
self.menu.addSeparator()
for name, loc in locations:
name = name.replace('&', '&&')
@ -407,15 +438,15 @@ class CopyToLibraryAction(InterfaceAction):
partial(self.copy_to_library, loc, delete_after=True))
self.menu.addSeparator()
if len(locations) <= 50:
self.menu.addAction(_('Choose library by path...'), self.choose_library)
self.qaction.setVisible(bool(locations))
if isosx:
# The cloned action has to have its menu updated
self.qaction.changed.emit()
def choose_library(self):
d = ChooseLibrary(self.gui)
db = self.gui.library_view.model().db
locations = list(self.stats.locations(db))
d = ChooseLibrary(self.gui, locations)
if d.exec_() == d.Accepted:
path, delete_after = d.args
if not path: