From 2587ed01c564a63d8b6d2206bc56da6cd37001de Mon Sep 17 00:00:00 2001 From: Rebecca Breu Date: Sun, 1 Aug 2021 19:10:03 +0200 Subject: [PATCH] Read keyboard shortcuts from file --- CHANGELOG.rst | 2 +- beeref/actions/mixin.py | 10 ++++++---- beeref/config.py | 24 ++++++++++++++++++++++++ tests/actions/test_mixin.py | 35 ++++++++++++++++++++++++++--------- tests/conftest.py | 12 ++++++++++++ tests/test_config.py | 24 ++++++++++++++++++++++++ 6 files changed, 93 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 1fe1685..b5476f0 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,7 +6,7 @@ Note that bee files from version 0.2.0 won't open in BeeRef 0.1.x. Added ----- -* You can now add plain text notes +* You can now add plain text notes and paste text from the clipboard Changed ------- diff --git a/beeref/actions/mixin.py b/beeref/actions/mixin.py index 570ffe0..2a2536a 100644 --- a/beeref/actions/mixin.py +++ b/beeref/actions/mixin.py @@ -22,7 +22,7 @@ from PyQt6 import QtGui, QtWidgets from .actions import actions from .menu_structure import menu_structure, MENU_SEPARATOR -from beeref import config +from beeref.config import KeyboardSettings class ActionsMixin: @@ -73,8 +73,10 @@ class ActionsMixin: def _create_actions(self): for action in actions: qaction = QtGui.QAction(action['text'], self) - if 'shortcuts' in action: - qaction.setShortcuts(action['shortcuts']) + shortcuts = KeyboardSettings().get_shortcuts( + 'Actions', action['id'], action.get('shortcuts')) + if shortcuts: + qaction.setShortcuts(shortcuts) if action.get('checkable', False): self._init_action_checkable(action, qaction) else: @@ -108,7 +110,7 @@ class ActionsMixin: self._recent_files_submenu = menu self._clear_recent_files() - files = config.BeeSettings().get_recent_files(existing_only=True) + files = self.settings.get_recent_files(existing_only=True) items = [] for i, filename in enumerate(files): qaction = QtGui.QAction(os.path.basename(filename), self) diff --git a/beeref/config.py b/beeref/config.py index 00261f0..ca71034 100644 --- a/beeref/config.py +++ b/beeref/config.py @@ -26,6 +26,9 @@ from beeref import constants from beeref.logging import qt_message_handler +logger = logging.getLogger(__name__) + + parser = argparse.ArgumentParser( description=f'{constants.APPNAME_FULL} {constants.VERSION}') parser.add_argument( @@ -138,6 +141,27 @@ class BeeSettings(QtCore.QSettings): return values +class KeyboardSettings(QtCore.QSettings): + + def __init__(self): + settings_format = QtCore.QSettings.Format.IniFormat + filename = os.path.join( + os.path.dirname(BeeSettings().fileName()), + 'KeyboardSettings.ini') + super().__init__(filename, settings_format) + + def set_shortcuts(self, group, key, values): + self.setValue(f'{group}/{key}', ', '.join(values)) + + def get_shortcuts(self, group, key, default=None): + values = self.value(f'{group}/{key}') + if values is not None: + values = list(filter(lambda x: x, values.split(', '))) + logger.debug(f'Found custom shorcuts for {group}/{key}: {values}') + return values + return default or [] + + def logfile_name(): return os.path.join( os.path.dirname(BeeSettings().fileName()), f'{constants.APPNAME}.log') diff --git a/tests/actions/test_mixin.py b/tests/actions/test_mixin.py index 15dc276..e8c521e 100644 --- a/tests/actions/test_mixin.py +++ b/tests/actions/test_mixin.py @@ -49,6 +49,25 @@ def test_create_actions( assert widget.bee_actions['foo'] == qaction +@patch('beeref.actions.mixin.menu_structure') +@patch('beeref.actions.mixin.actions') +def test_create_actions_with_shortcut_from_settings( + actions_mock, menu_mock, qapp, kbsettings): + kbsettings.set_shortcuts('Actions', 'foo', ['Alt+O']) + widget = FooWidget() + actions_mock.__iter__.return_value = [{ + 'id': 'foo', + 'text': '&Foo', + 'shortcuts': ['Ctrl+F'], + 'callback': 'on_foo', + }] + + menu_mock.__iter__.return_value = ['foo'] + widget.build_menu_and_actions() + qaction = widget.actions()[0] + assert qaction.shortcut() == 'Alt+O' + + @patch('PyQt6.QtGui.QAction.triggered') @patch('PyQt6.QtGui.QAction.toggled') @patch('beeref.actions.mixin.menu_structure') @@ -245,14 +264,12 @@ def test_build_menu_and_actions_disables_actiongroups( assert qaction.isEnabled() is False -@patch('beeref.config.BeeSettings.get_recent_files') @patch('PyQt6.QtGui.QAction.triggered') @patch('beeref.actions.mixin.menu_structure') @patch('beeref.actions.mixin.actions') -def test_create_recent_files( - actions_mock, menu_mock, triggered_mock, files_mock, qapp): +def test_create_recent_files(actions_mock, menu_mock, triggered_mock, qapp): widget = FooWidget() - files_mock.return_value = [ + widget.settings.get_recent_files.return_value = [ os.path.abspath(f'{i}.bee') for i in range(15)] menu_mock.__iter__.return_value = [{ 'menu': 'Open &Recent', @@ -279,14 +296,13 @@ def test_create_recent_files( assert widget.bee_actions['recent_files_14'] == qaction15 -@patch('beeref.config.BeeSettings.get_recent_files') @patch('PyQt6.QtGui.QAction.triggered') @patch('beeref.actions.mixin.menu_structure') @patch('beeref.actions.mixin.actions') -def test_update_recent_files( - actions_mock, menu_mock, triggered_mock, files_mock, qapp): +def test_update_recent_files(actions_mock, menu_mock, triggered_mock, qapp): widget = FooWidget() - files_mock.return_value = [os.path.abspath('foo.bee')] + widget.settings.get_recent_files.return_value = [ + os.path.abspath('foo.bee')] menu_mock.__iter__.return_value = [{ 'menu': 'Open &Recent', 'items': '_build_recent_files', @@ -298,7 +314,8 @@ def test_update_recent_files( qaction1 = widget.actions()[0] assert qaction1.text() == 'foo.bee' - files_mock.return_value = [os.path.abspath('bar.bee')] + widget.settings.get_recent_files.return_value = [ + os.path.abspath('bar.bee')] widget.update_menu_and_actions() triggered_mock.connect.assert_called() assert len(widget.actions()) == 1 diff --git a/tests/conftest.py b/tests/conftest.py index 6b814d7..f8aa360 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -39,6 +39,18 @@ def settings(tmpdir): dir_patcher.stop() +@pytest.fixture(autouse=True) +def kbsettings(tmpdir): + from beeref.config import KeyboardSettings + dir_patcher = patch('beeref.config.BeeSettings.get_settings_dir', + return_value=tmpdir.dirname) + dir_patcher.start() + kbsettings = KeyboardSettings() + yield kbsettings + kbsettings.clear() + dir_patcher.stop() + + @pytest.fixture def main_window(qtbot): from beeref.__main__ import BeeRefMainWindow diff --git a/tests/test_config.py b/tests/test_config.py index 7536df9..8dadb6a 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -71,3 +71,27 @@ def test_settings_recent_files_update_respects_max_num(settings): assert len(recent) == 10 assert recent[0] == os.path.abspath('14.bee') assert recent[-1] == os.path.abspath('5.bee') + + +def test_keyboardsettings_set_shortcuts(kbsettings): + kbsettings.set_shortcuts('Actions', 'foo', ['Ctrl+F']) + assert kbsettings.get_shortcuts('Actions', 'foo') == ['Ctrl+F'] + + +def test_keyboardsettings_set_shortcuts_multiple(kbsettings): + kbsettings.set_shortcuts('Actions', 'foo', ['Ctrl+F', 'Alt+O']) + assert kbsettings.get_shortcuts('Actions', 'foo') == ['Ctrl+F', 'Alt+O'] + + +def test_keyboardsettings_get_shortcuts_default(kbsettings): + assert kbsettings.get_shortcuts('Actions', 'bar', ['Ctrl+B']) == ['Ctrl+B'] + + +def test_keyboardsettings_get_shortcuts_defaults_dont_overwrite_empty( + kbsettings): + kbsettings.set_shortcuts('Actions', 'bar', []) + assert kbsettings.get_shortcuts('Actions', 'bar', ['Ctrl+B']) == [] + + +def test_keyboardsettings_get_shortcuts_not_set_no_defaults(kbsettings): + assert kbsettings.get_shortcuts('Actions', 'baz') == []