mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Add framework to allow user interface action plugins to specify what location they can be added to/cannot be removed from
This commit is contained in:
parent
dcde8a7e59
commit
a97cffc1e9
@ -60,6 +60,17 @@ class InterfaceAction(QObject):
|
||||
#: shortcut must be a translated string if not None
|
||||
action_spec = ('text', 'icon', None, None)
|
||||
|
||||
#: Set of locations to which this action must not be added.
|
||||
#: See :attr:`all_locations` for a list of possible locations
|
||||
dont_add_to = frozenset([])
|
||||
|
||||
#: Set of locations from which this action must not be removed.
|
||||
#: See :attr:`all_locations` for a list of possible locations
|
||||
dont_remove_from = frozenset([])
|
||||
|
||||
all_locations = frozenset(['toolbar', 'toolbar-device', 'context-menu',
|
||||
'context-menu-device'])
|
||||
|
||||
def __init__(self, parent, site_customization):
|
||||
QObject.__init__(self, parent)
|
||||
self.setObjectName(self.name)
|
||||
|
@ -22,7 +22,9 @@ from calibre.gui2.actions import InterfaceAction
|
||||
class AddAction(InterfaceAction):
|
||||
|
||||
name = 'Add Books'
|
||||
action_spec = (_('Add books'), 'add_book.svg', None, _('A'))
|
||||
action_spec = (_('Add books'), 'add_book.svg',
|
||||
_('Add books to the calibre library/device from files on your computer')
|
||||
, _('A'))
|
||||
|
||||
def genesis(self):
|
||||
self._add_filesystem_book = self.Dispatcher(self.__add_filesystem_book)
|
||||
|
@ -10,7 +10,9 @@ from calibre.gui2.actions import InterfaceAction
|
||||
class AddToLibraryAction(InterfaceAction):
|
||||
|
||||
name = 'Add To Library'
|
||||
action_spec = (_('Add books to library'), 'add_book.svg', None, None)
|
||||
action_spec = (_('Add books to library'), 'add_book.svg',
|
||||
_('Add books to your calibre library from the connected device'), None)
|
||||
dont_add_to = frozenset(['toolbar', 'context-menu'])
|
||||
|
||||
def location_selected(self, loc):
|
||||
enabled = loc != 'library'
|
||||
|
@ -18,6 +18,7 @@ class GenerateCatalogAction(InterfaceAction):
|
||||
|
||||
name = 'Generate Catalog'
|
||||
action_spec = (_('Create catalog of books in your calibre library'), None, None, None)
|
||||
dont_add_to = frozenset(['toolbar-device', 'context-menu-device'])
|
||||
|
||||
def generate_catalog(self):
|
||||
rows = self.gui.library_view.selectionModel().selectedRows()
|
||||
|
@ -72,6 +72,7 @@ class ChooseLibraryAction(InterfaceAction):
|
||||
name = 'Choose Library'
|
||||
action_spec = (_('%d books'), 'lt.png',
|
||||
_('Choose calibre library to work with'), None)
|
||||
dont_add_to = frozenset(['toolbar-device', 'context-menu-device'])
|
||||
|
||||
def genesis(self):
|
||||
self.count_changed(0)
|
||||
|
@ -20,6 +20,7 @@ class ConvertAction(InterfaceAction):
|
||||
|
||||
name = 'Convert Books'
|
||||
action_spec = (_('Convert books'), 'convert.svg', None, _('C'))
|
||||
dont_add_to = frozenset(['toolbar-device', 'context-menu-device'])
|
||||
|
||||
def genesis(self):
|
||||
cm = QMenu()
|
||||
|
@ -63,6 +63,7 @@ class CopyToLibraryAction(InterfaceAction):
|
||||
action_spec = (_('Copy to library'), 'lt.png',
|
||||
_('Copy selected books to the specified library'), None)
|
||||
popup_type = QToolButton.InstantPopup
|
||||
dont_add_to = frozenset(['toolbar-device', 'context-menu-device'])
|
||||
|
||||
def genesis(self):
|
||||
self.menu = QMenu(self.gui)
|
||||
|
@ -19,6 +19,7 @@ class ShareConnMenu(QMenu): # {{{
|
||||
connect_to_itunes = pyqtSignal()
|
||||
config_email = pyqtSignal()
|
||||
toggle_server = pyqtSignal()
|
||||
dont_add_to = frozenset(['toolbar-device', 'context-menu-device'])
|
||||
|
||||
def __init__(self, parent=None):
|
||||
QMenu.__init__(self, parent)
|
||||
@ -95,6 +96,8 @@ class SendToDeviceAction(InterfaceAction):
|
||||
|
||||
name = 'Send To Device'
|
||||
action_spec = (_('Send to device'), 'sync.svg', None, _('D'))
|
||||
dont_remove_from = frozenset(['toolbar-device'])
|
||||
dont_add_to = frozenset(['toolbar', 'context-menu'])
|
||||
|
||||
def genesis(self):
|
||||
self.qaction.triggered.connect(self.do_sync)
|
||||
|
@ -10,7 +10,9 @@ from calibre.gui2.actions import InterfaceAction
|
||||
class EditCollectionsAction(InterfaceAction):
|
||||
|
||||
name = 'Edit Collections'
|
||||
action_spec = (_('Manage collections'), None, None, None)
|
||||
action_spec = (_('Manage collections'), None,
|
||||
_('Manage the collections on this device'), None)
|
||||
dont_add_to = frozenset(['toolbar', 'context-menu'])
|
||||
|
||||
def location_selected(self, loc):
|
||||
enabled = loc != 'library'
|
||||
|
@ -13,6 +13,7 @@ class OpenFolderAction(InterfaceAction):
|
||||
name = 'Open Folder'
|
||||
action_spec = (_('Open containing folder'), 'document_open.svg', None,
|
||||
_('O'))
|
||||
dont_add_to = frozenset(['toolbar-device', 'context-menu-device'])
|
||||
|
||||
def genesis(self):
|
||||
self.qaction.triggered.connect(self.gui.iactions['View'].view_folder)
|
||||
|
@ -15,6 +15,7 @@ class PreferencesAction(InterfaceAction):
|
||||
|
||||
name = 'Preferences'
|
||||
action_spec = (_('Preferences'), 'config.svg', None, _('Ctrl+P'))
|
||||
dont_remove_from = frozenset(['toolbar'])
|
||||
|
||||
def genesis(self):
|
||||
pm = QMenu()
|
||||
|
@ -15,6 +15,7 @@ class ShowBookDetailsAction(InterfaceAction):
|
||||
name = 'Show Book Details'
|
||||
action_spec = (_('Show book details'), 'dialog_information.svg', None,
|
||||
_('I'))
|
||||
dont_add_to = frozenset(['toolbar-device', 'context-menu-device'])
|
||||
|
||||
def genesis(self):
|
||||
self.qaction.triggered.connect(self.show_book_info)
|
||||
|
@ -13,7 +13,7 @@ from PyQt4.Qt import QWidget, QAbstractListModel, Qt, QIcon, \
|
||||
from calibre.gui2.dialogs.config.toolbar_ui import Ui_Form
|
||||
from calibre.gui2.layout import TOOLBAR_NO_DEVICE, TOOLBAR_DEVICE
|
||||
from calibre.gui2.init import LIBRARY_CONTEXT_MENU, DEVICE_CONTEXT_MENU
|
||||
from calibre.gui2 import gprefs, NONE
|
||||
from calibre.gui2 import gprefs, NONE, warning_dialog
|
||||
|
||||
DEFAULTS = {
|
||||
'toolbar': TOOLBAR_NO_DEVICE,
|
||||
@ -27,17 +27,15 @@ UNREMOVABLE = {
|
||||
'toolbar-device': ['Send To Device', 'Location Manager'],
|
||||
}
|
||||
|
||||
UNADDABLE = {
|
||||
'toolbar': ['Location Manager'],
|
||||
'context-menu': ['Location Manager'],
|
||||
'context-menu-device': ['Location Manager'],
|
||||
}
|
||||
|
||||
class FakeAction(object):
|
||||
|
||||
def __init__(self, name, icon, tooltip=None):
|
||||
def __init__(self, name, icon, tooltip=None,
|
||||
dont_add_to=frozenset([]), dont_remove_from=frozenset([])):
|
||||
self.name = name
|
||||
self.action_spec = (name, icon, tooltip, None)
|
||||
self.dont_remove_from = dont_remove_from
|
||||
self.dont_add_to = dont_add_to
|
||||
|
||||
class BaseModel(QAbstractListModel):
|
||||
|
||||
@ -45,7 +43,9 @@ class BaseModel(QAbstractListModel):
|
||||
if name == 'Donate':
|
||||
return FakeAction(name, 'donate.svg')
|
||||
if name == 'Location Manager':
|
||||
return FakeAction(name, None)
|
||||
return FakeAction(name, None,
|
||||
_('Switch between library and device views'),
|
||||
dont_remove_from=set(['toolbar-device']))
|
||||
if name is None:
|
||||
return FakeAction('--- '+_('Separator')+' ---', None)
|
||||
return gui.iactions[name]
|
||||
@ -90,15 +90,17 @@ class AllModel(BaseModel):
|
||||
all = list(gui.iactions.keys()) + ['Donate']
|
||||
all = [x for x in all if x not in current] + [None]
|
||||
all = [self.name_to_action(x, gui) for x in all]
|
||||
all = [x for x in all if key not in x.dont_add_to]
|
||||
all.sort()
|
||||
self.gui = gui
|
||||
|
||||
self._data = all
|
||||
|
||||
def add(self, names):
|
||||
actions = []
|
||||
for name in actions:
|
||||
for name in names:
|
||||
if name is None or name.startswith('---'): continue
|
||||
actions.append(self.name_to_action(name))
|
||||
actions.append(self.name_to_action(name, self.gui))
|
||||
self._data.extend(actions)
|
||||
self._data.sort()
|
||||
self.reset()
|
||||
@ -126,6 +128,7 @@ class CurrentModel(BaseModel):
|
||||
current = gprefs.get('action-layout-'+key, DEFAULTS[key])
|
||||
self._data = [self.name_to_action(x, gui) for x in current]
|
||||
self.key = key
|
||||
self.gui = gui
|
||||
|
||||
def move(self, idx, delta):
|
||||
row = idx.row()
|
||||
@ -145,11 +148,12 @@ class CurrentModel(BaseModel):
|
||||
def add(self, names):
|
||||
actions = []
|
||||
reject = set([])
|
||||
for name in actions:
|
||||
if name in UNADDABLE[self.key]:
|
||||
reject.add(name)
|
||||
continue
|
||||
actions.append(self.name_to_action(name))
|
||||
for name in names:
|
||||
ac = self.name_to_action(name, self.gui)
|
||||
if self.key in ac.dont_add_to:
|
||||
reject.add(ac)
|
||||
else:
|
||||
actions.append(ac)
|
||||
|
||||
self._data.extend(actions)
|
||||
self.reset()
|
||||
@ -157,19 +161,20 @@ class CurrentModel(BaseModel):
|
||||
|
||||
def remove(self, indices):
|
||||
rows = [i.row() for i in indices]
|
||||
r = UNREMOVABLE[self.key]
|
||||
remove, removed = set([]), set([])
|
||||
remove, rejected = set([]), set([])
|
||||
for row in rows:
|
||||
ac = self._data[row]
|
||||
if ac.name in r: continue
|
||||
if self.key in ac.dont_remove_from:
|
||||
rejected.add(ac)
|
||||
continue
|
||||
remove.add(row)
|
||||
removed.add(ac.name)
|
||||
ndata = []
|
||||
for i, ac in enumerate(self._data):
|
||||
if i not in remove:
|
||||
ndata.append(ac)
|
||||
self._data = ndata
|
||||
self.reset()
|
||||
return rejected
|
||||
|
||||
|
||||
class ToolbarLayout(QWidget, Ui_Form):
|
||||
@ -212,15 +217,33 @@ class ToolbarLayout(QWidget, Ui_Form):
|
||||
names = self.all_actions.model().names(x)
|
||||
if names:
|
||||
not_added = self.current_actions.model().add(names)
|
||||
added = set(names) - not_added
|
||||
ns = set([x.name for x in not_added])
|
||||
added = set(names) - ns
|
||||
self.all_actions.model().remove(x, added)
|
||||
if not_added:
|
||||
warning_dialog(self, _('Cannot add'),
|
||||
_('Cannot add the actions %s to this location') %
|
||||
','.join([a.action_spec[0] for a in not_added]),
|
||||
show=True)
|
||||
if added:
|
||||
ca = self.current_actions
|
||||
idx = ca.model().index(ca.model().rowCount(None)-1)
|
||||
ca.scrollTo(idx)
|
||||
|
||||
def remove_action(self, *args):
|
||||
x = self.current_actions.selectionModel().selectedIndexes()
|
||||
names = self.current_actions.model().names(x)
|
||||
if names:
|
||||
self.current_actions.model().remove(x)
|
||||
self.all_actions.model().add(names)
|
||||
not_removed = self.current_actions.model().remove(x)
|
||||
ns = set([x.name for x in not_removed])
|
||||
removed = set(names) - ns
|
||||
self.all_actions.model().add(removed)
|
||||
if not_removed:
|
||||
warning_dialog(self, _('Cannot remove'),
|
||||
_('Cannot remove the actions %s from this location') %
|
||||
','.join([a.action_spec[0] for a in not_removed]),
|
||||
show=True)
|
||||
|
||||
|
||||
def move(self, delta, *args):
|
||||
ci = self.current_actions.currentIndex()
|
||||
|
@ -112,6 +112,6 @@ class cmd_commit(_cmd_commit):
|
||||
server = xmlrpclib.ServerProxy(url)
|
||||
server.ticket.update(int(bug), msg,
|
||||
{'status':'closed', 'resolution':'fixed'},
|
||||
notify=True)
|
||||
True)
|
||||
|
||||
bzrlib.commands.register_command(cmd_commit)
|
||||
|
Loading…
x
Reference in New Issue
Block a user