From fdc7b3610549a6f0c21d85b1142d4b78cbed1109 Mon Sep 17 00:00:00 2001 From: Jim Miller Date: Fri, 16 Oct 2020 15:02:12 -0500 Subject: [PATCH] Add persist_shortcut option for keyboard shortcuts that may be library specific. --- src/calibre/gui2/actions/__init__.py | 14 ++++++--- src/calibre/gui2/keyboard.py | 43 +++++++++++++++++++--------- 2 files changed, 39 insertions(+), 18 deletions(-) diff --git a/src/calibre/gui2/actions/__init__.py b/src/calibre/gui2/actions/__init__.py index eed9a9f566..d1e006fd1c 100644 --- a/src/calibre/gui2/actions/__init__.py +++ b/src/calibre/gui2/actions/__init__.py @@ -154,7 +154,7 @@ class InterfaceAction(QObject): bn = self.interface_action_base_plugin.name return 'Interface Action: %s (%s)'%(bn, self.name) - def create_action(self, spec=None, attr='qaction', shortcut_name=None): + def create_action(self, spec=None, attr='qaction', shortcut_name=None, persist_shortcut=False): if spec is None: spec = self.action_spec text, icon, tooltip, shortcut = spec @@ -191,7 +191,8 @@ class InterfaceAction(QObject): self.gui.keyboard.register_shortcut(self.unique_name + ' - ' + attr, shortcut_name, default_keys=keys, action=shortcut_action, description=desc, - group=self.action_spec[0]) + group=self.action_spec[0], + persist_shortcut=persist_shortcut) except NameConflict as e: try: prints(unicode_type(e)) @@ -216,7 +217,7 @@ class InterfaceAction(QObject): return action def create_menu_action(self, menu, unique_name, text, icon=None, shortcut=None, - description=None, triggered=None, shortcut_name=None): + description=None, triggered=None, shortcut_name=None, persist_shortcut=False): ''' Convenience method to easily add actions to a QMenu. Returns the created QAction. This action has one extra attribute @@ -242,6 +243,10 @@ class InterfaceAction(QObject): :param shortcut_name: The text displayed to the user when customizing the keyboard shortcuts for this action. By default it is set to the value of ``text``. + :param persist_shortcut: Shortcuts for actions that don't + always appear, or are library dependent, may disappear + when other keyboard shortcuts are edited unless + ```persist_shortcut``` is set True. ''' if shortcut_name is None: @@ -265,7 +270,8 @@ class InterfaceAction(QObject): if shortcut is not False: self.gui.keyboard.register_shortcut(unique_name, shortcut_name, default_keys=keys, - action=ac, description=description, group=self.action_spec[0]) + action=ac, description=description, group=self.action_spec[0], + persist_shortcut=persist_shortcut) # In Qt 5 keyboard shortcuts dont work unless the # action is explicitly added to the main window and on OSX and # Unity since the menu might be exported, the shortcuts wont work diff --git a/src/calibre/gui2/keyboard.py b/src/calibre/gui2/keyboard.py index 84f2430837..5b19746fad 100644 --- a/src/calibre/gui2/keyboard.py +++ b/src/calibre/gui2/keyboard.py @@ -105,7 +105,7 @@ class Manager(QObject): # {{{ self.groups = {} def register_shortcut(self, unique_name, name, default_keys=(), - description=None, action=None, group=None): + description=None, action=None, group=None, persist_shortcut=False): ''' Register a shortcut with calibre. calibre will manage the shortcut, automatically resolving conflicts and allowing the user to customize @@ -124,13 +124,18 @@ class Manager(QObject): # {{{ :param group: A string describing what "group" this shortcut belongs to. This is used to organize the list of shortcuts when the user is customizing them. + :persist_shortcut: Shortcuts for actions that don't always + appear, or are library dependent, may disappear when other + keyboard shortcuts are edited unless ```persist_shortcut``` is + set True. ''' if unique_name in self.shortcuts: name = self.shortcuts[unique_name]['name'] raise NameConflict('Shortcut for %r already registered by %s'%( unique_name, name)) shortcut = {'name':name, 'desc':description, 'action': action, - 'default_keys':tuple(default_keys)} + 'default_keys':tuple(default_keys), + 'persist_shortcut':persist_shortcut} self.shortcuts[unique_name] = shortcut group = group if group else _('Miscellaneous') self.groups[group] = self.groups.get(group, []) + [unique_name] @@ -277,24 +282,34 @@ class ConfigModel(SearchQueryParser, QAbstractItemModel): self.index(num-1, 0, group)) def commit(self): - # start with a copy and remove set_to_defaults instead of - # building from empty because shortcuts tied to actions not - # visible in the current library will be erased otherwise. - # Reading List, View Manager and FanFicFare plugins are - # examples where menu actions change by library. - kmap = dict(self.keyboard.config['map']) + kmap = {} + # persist flags not in map for back compat + # not *just* persist flag for forward compat + options_map = {} + options_map.update(self.keyboard.config.get('options_map',{})) + # keep mapped keys that are marked persistent. + for un, keys in iteritems(self.keyboard.config['map']): + if options_map.get(un,{}).get('persist_shortcut',False): + kmap[un] = keys for node in self.all_shortcuts: sc = node.data + un = sc['unique_name'] if sc['set_to_default']: - if sc['unique_name'] in kmap: - del kmap[sc['unique_name']] + if un in kmap: + del kmap[un] + if un in options_map: + del options_map[un] else: + if sc['persist_shortcut']: + options_map[un] = options_map.get(un,{}) + options_map[un]['persist_shortcut'] = sc['persist_shortcut'] keys = [unicode_type(k.toString(k.PortableText)) for k in sc['keys']] - kmap[sc['unique_name']] = keys - # note that something further on appears to depends on - # self.keyboard.config['map'] being a different object now to - # signal to save it. + kmap[un] = keys + # note that JSONConfig further on appears to depends on + # self.keyboard.config['map'] and ['persist_map'] being + # different objects now to signal to save to disk. self.keyboard.config['map'] = kmap + self.keyboard.config['options_map'] = options_map def universal_set(self): ans = set()