Merge lp:~raoul-snyman/openlp/custom-shortcuts-2.4 into lp:openlp/2.4

Proposed by Raoul Snyman
Status: Merged
Merged at revision: 2681
Proposed branch: lp:~raoul-snyman/openlp/custom-shortcuts-2.4
Merge into: lp:openlp/2.4
Diff against target: 284 lines (+130/-77)
3 files modified
CHANGELOG.rst (+5/-4)
openlp/core/ui/shortcutlistform.py (+86/-73)
tests/interfaces/openlp_core_ui/test_shortcutlistform.py (+39/-0)
To merge this branch: bzr merge lp:~raoul-snyman/openlp/custom-shortcuts-2.4
Reviewer Review Type Date Requested Status
Tim Bentley Approve
Review via email: mp+321347@code.launchpad.net

Commit message

Disable the shortcut controls when an action has not been selected

To post a comment you must log in.
Revision history for this message
Tim Bentley (trb143) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'CHANGELOG.rst'
--- CHANGELOG.rst 2017-03-27 23:25:12 +0000
+++ CHANGELOG.rst 2017-03-29 18:46:40 +0000
@@ -1,11 +1,12 @@
1OpenLP 2.4.61OpenLP 2.4.6
2============2============
33
4* Fixed a bug where the author type upgrade was being ignore because it was looking at the wrong table4* Fix a bug where the author type upgrade was being ignore because it was looking at the wrong table
5* Fixed a bug where the songs_songbooks table was not being created because the if expression was the wrong way round5* Fix a bug where the songs_songbooks table was not being created because the if expression was the wrong way round
6* Changed the songs_songbooks migration SQL slightly to take into account a bug that has (hopefully) been fixed6* Change the songs_songbooks migration SQL slightly to take into account a bug that has (hopefully) been fixed
7* Sometimes the timer goes off as OpenLP is shutting down, and the application has already been deleted (reported via support system)7* Sometimes the timer goes off as OpenLP is shutting down, and the application has already been deleted (reported via support system)
8* Fix opening the data folder (KDE thought the old way was an SMB share)8* Fix opening the data folder (KDE thought the old way was an SMB share)
9* Fix a problem with the new QMediaPlayer not controlling the playlist anymore9* Fix a problem with the new QMediaPlayer not controlling the playlist anymore
10* Added importing of author types to the OpenLP 2 song importer10* Add importing of author types to the OpenLP 2 song importer
11* Fix a problem with loading Qt's translation files, bug #167616311* Fix a problem with loading Qt's translation files, bug #1676163
12* Disable the controls in the shortcut dialog unless a shortcut is actually selected
1213
=== modified file 'openlp/core/ui/shortcutlistform.py'
--- openlp/core/ui/shortcutlistform.py 2016-12-31 11:05:48 +0000
+++ openlp/core/ui/shortcutlistform.py 2017-03-29 18:46:40 +0000
@@ -49,6 +49,8 @@
49 self.changed_actions = {}49 self.changed_actions = {}
50 self.action_list = ActionList.get_instance()50 self.action_list = ActionList.get_instance()
51 self.dialog_was_shown = False51 self.dialog_was_shown = False
52 self.default_radio_button.setEnabled(False)
53 self.custom_radio_button.setEnabled(False)
52 self.primary_push_button.toggled.connect(self.on_primary_push_button_clicked)54 self.primary_push_button.toggled.connect(self.on_primary_push_button_clicked)
53 self.alternate_push_button.toggled.connect(self.on_alternate_push_button_clicked)55 self.alternate_push_button.toggled.connect(self.on_alternate_push_button_clicked)
54 self.tree_widget.currentItemChanged.connect(self.on_current_item_changed)56 self.tree_widget.currentItemChanged.connect(self.on_current_item_changed)
@@ -110,8 +112,89 @@
110 self.reload_shortcut_list()112 self.reload_shortcut_list()
111 self._adjust_button(self.primary_push_button, False, False, '')113 self._adjust_button(self.primary_push_button, False, False, '')
112 self._adjust_button(self.alternate_push_button, False, False, '')114 self._adjust_button(self.alternate_push_button, False, False, '')
115 self._set_controls_enabled(False)
113 return QtWidgets.QDialog.exec(self)116 return QtWidgets.QDialog.exec(self)
114117
118 def _validiate_shortcut(self, changing_action, key_sequence):
119 """
120 Checks if the given ``changing_action `` can use the given ``key_sequence``. Returns ``True`` if the
121 ``key_sequence`` can be used by the action, otherwise displays a dialog and returns ``False``.
122
123 :param changing_action: The action which wants to use the ``key_sequence``.
124 :param key_sequence: The key sequence which the action want so use.
125 """
126 is_valid = True
127 for category in self.action_list.categories:
128 for action in category.actions:
129 shortcuts = self._action_shortcuts(action)
130 if key_sequence not in shortcuts:
131 continue
132 if action is changing_action:
133 if self.primary_push_button.isChecked() and shortcuts.index(key_sequence) == 0:
134 continue
135 if self.alternate_push_button.isChecked() and shortcuts.index(key_sequence) == 1:
136 continue
137 # Have the same parent, thus they cannot have the same shortcut.
138 if action.parent() is changing_action.parent():
139 is_valid = False
140 # The new shortcut is already assigned, but if both shortcuts are only valid in a different widget the
141 # new shortcut is valid, because they will not interfere.
142 if action.shortcutContext() in [QtCore.Qt.WindowShortcut, QtCore.Qt.ApplicationShortcut]:
143 is_valid = False
144 if changing_action.shortcutContext() in [QtCore.Qt.WindowShortcut, QtCore.Qt.ApplicationShortcut]:
145 is_valid = False
146 if not is_valid:
147 self.main_window.warning_message(translate('OpenLP.ShortcutListDialog', 'Duplicate Shortcut'),
148 translate('OpenLP.ShortcutListDialog',
149 'The shortcut "%s" is already assigned to another action, please'
150 ' use a different shortcut.') %
151 self.get_shortcut_string(key_sequence, for_display=True))
152 self.dialog_was_shown = True
153 return is_valid
154
155 def _action_shortcuts(self, action):
156 """
157 This returns the shortcuts for the given ``action``, which also includes those shortcuts which are not saved
158 yet but already assigned (as changes are applied when closing the dialog).
159 """
160 if action in self.changed_actions:
161 return self.changed_actions[action]
162 return action.shortcuts()
163
164 def _current_item_action(self, item=None):
165 """
166 Returns the action of the given ``item``. If no item is given, we return the action of the current item of
167 the ``tree_widget``.
168 """
169 if item is None:
170 item = self.tree_widget.currentItem()
171 if item is None:
172 return
173 return item.data(0, QtCore.Qt.UserRole)
174
175 def _adjust_button(self, button, checked=None, enabled=None, text=None):
176 """
177 Can be called to adjust more properties of the given ``button`` at once.
178 """
179 # Set the text before checking the button, because this emits a signal.
180 if text is not None:
181 button.setText(text)
182 if checked is not None:
183 button.setChecked(checked)
184 if enabled is not None:
185 button.setEnabled(enabled)
186
187 def _set_controls_enabled(self, is_enabled=False):
188 """
189 Enable or disable the shortcut controls
190 """
191 self.default_radio_button.setEnabled(is_enabled)
192 self.custom_radio_button.setEnabled(is_enabled)
193 self.primary_push_button.setEnabled(is_enabled)
194 self.alternate_push_button.setEnabled(is_enabled)
195 self.clear_primary_button.setEnabled(is_enabled)
196 self.clear_alternate_button.setEnabled(is_enabled)
197
115 def reload_shortcut_list(self):198 def reload_shortcut_list(self):
116 """199 """
117 Reload the ``tree_widget`` list to add new and remove old actions.200 Reload the ``tree_widget`` list to add new and remove old actions.
@@ -229,8 +312,7 @@
229 A item has been pressed. We adjust the button's text to the action's shortcut which is encapsulate in the item.312 A item has been pressed. We adjust the button's text to the action's shortcut which is encapsulate in the item.
230 """313 """
231 action = self._current_item_action(item)314 action = self._current_item_action(item)
232 self.primary_push_button.setEnabled(action is not None)315 self._set_controls_enabled(action is not None)
233 self.alternate_push_button.setEnabled(action is not None)
234 primary_text = ''316 primary_text = ''
235 alternate_text = ''317 alternate_text = ''
236 primary_label_text = ''318 primary_label_text = ''
@@ -244,7 +326,7 @@
244 if len(action.default_shortcuts) == 2:326 if len(action.default_shortcuts) == 2:
245 alternate_label_text = self.get_shortcut_string(action.default_shortcuts[1], for_display=True)327 alternate_label_text = self.get_shortcut_string(action.default_shortcuts[1], for_display=True)
246 shortcuts = self._action_shortcuts(action)328 shortcuts = self._action_shortcuts(action)
247 # We do not want to loose pending changes, that is why we have to keep the text when, this function has not329 # We do not want to loose pending changes, that is why we have to keep the text when this function has not
248 # been triggered by a signal.330 # been triggered by a signal.
249 if item is None:331 if item is None:
250 primary_text = self.primary_push_button.text()332 primary_text = self.primary_push_button.text()
@@ -254,7 +336,7 @@
254 elif len(shortcuts) == 2:336 elif len(shortcuts) == 2:
255 primary_text = self.get_shortcut_string(shortcuts[0], for_display=True)337 primary_text = self.get_shortcut_string(shortcuts[0], for_display=True)
256 alternate_text = self.get_shortcut_string(shortcuts[1], for_display=True)338 alternate_text = self.get_shortcut_string(shortcuts[1], for_display=True)
257 # When we are capturing a new shortcut, we do not want, the buttons to display the current shortcut.339 # When we are capturing a new shortcut, we do not want the buttons to display the current shortcut.
258 if self.primary_push_button.isChecked():340 if self.primary_push_button.isChecked():
259 primary_text = ''341 primary_text = ''
260 if self.alternate_push_button.isChecked():342 if self.alternate_push_button.isChecked():
@@ -396,75 +478,6 @@
396 self.refresh_shortcut_list()478 self.refresh_shortcut_list()
397 self.on_current_item_changed(self.tree_widget.currentItem())479 self.on_current_item_changed(self.tree_widget.currentItem())
398480
399 def _validiate_shortcut(self, changing_action, key_sequence):
400 """
401 Checks if the given ``changing_action `` can use the given ``key_sequence``. Returns ``True`` if the
402 ``key_sequence`` can be used by the action, otherwise displays a dialog and returns ``False``.
403
404 :param changing_action: The action which wants to use the ``key_sequence``.
405 :param key_sequence: The key sequence which the action want so use.
406 """
407 is_valid = True
408 for category in self.action_list.categories:
409 for action in category.actions:
410 shortcuts = self._action_shortcuts(action)
411 if key_sequence not in shortcuts:
412 continue
413 if action is changing_action:
414 if self.primary_push_button.isChecked() and shortcuts.index(key_sequence) == 0:
415 continue
416 if self.alternate_push_button.isChecked() and shortcuts.index(key_sequence) == 1:
417 continue
418 # Have the same parent, thus they cannot have the same shortcut.
419 if action.parent() is changing_action.parent():
420 is_valid = False
421 # The new shortcut is already assigned, but if both shortcuts are only valid in a different widget the
422 # new shortcut is valid, because they will not interfere.
423 if action.shortcutContext() in [QtCore.Qt.WindowShortcut, QtCore.Qt.ApplicationShortcut]:
424 is_valid = False
425 if changing_action.shortcutContext() in [QtCore.Qt.WindowShortcut, QtCore.Qt.ApplicationShortcut]:
426 is_valid = False
427 if not is_valid:
428 self.main_window.warning_message(translate('OpenLP.ShortcutListDialog', 'Duplicate Shortcut'),
429 translate('OpenLP.ShortcutListDialog',
430 'The shortcut "%s" is already assigned to another action, please'
431 ' use a different shortcut.') %
432 self.get_shortcut_string(key_sequence, for_display=True))
433 self.dialog_was_shown = True
434 return is_valid
435
436 def _action_shortcuts(self, action):
437 """
438 This returns the shortcuts for the given ``action``, which also includes those shortcuts which are not saved
439 yet but already assigned (as changes are applied when closing the dialog).
440 """
441 if action in self.changed_actions:
442 return self.changed_actions[action]
443 return action.shortcuts()
444
445 def _current_item_action(self, item=None):
446 """
447 Returns the action of the given ``item``. If no item is given, we return the action of the current item of
448 the ``tree_widget``.
449 """
450 if item is None:
451 item = self.tree_widget.currentItem()
452 if item is None:
453 return
454 return item.data(0, QtCore.Qt.UserRole)
455
456 def _adjust_button(self, button, checked=None, enabled=None, text=None):
457 """
458 Can be called to adjust more properties of the given ``button`` at once.
459 """
460 # Set the text before checking the button, because this emits a signal.
461 if text is not None:
462 button.setText(text)
463 if checked is not None:
464 button.setChecked(checked)
465 if enabled is not None:
466 button.setEnabled(enabled)
467
468 @staticmethod481 @staticmethod
469 def get_shortcut_string(shortcut, for_display=False):482 def get_shortcut_string(shortcut, for_display=False):
470 if for_display:483 if for_display:
471484
=== modified file 'tests/interfaces/openlp_core_ui/test_shortcutlistform.py'
--- tests/interfaces/openlp_core_ui/test_shortcutlistform.py 2016-12-31 11:05:48 +0000
+++ tests/interfaces/openlp_core_ui/test_shortcutlistform.py 2017-03-29 18:46:40 +0000
@@ -52,6 +52,24 @@
52 del self.form52 del self.form
53 del self.main_window53 del self.main_window
5454
55 def test_set_controls_enabled(self):
56 """
57 Test that the _set_controls_enabled() method works correctly
58 """
59 # GIVEN: A shortcut form, and a value to set the controls
60 is_enabled = True
61
62 # WHEN: _set_controls_enabled() is called
63 self.form._set_controls_enabled(is_enabled)
64
65 # THEN: The controls should be enabled
66 assert self.form.default_radio_button.isEnabled() is True
67 assert self.form.custom_radio_button.isEnabled() is True
68 assert self.form.primary_push_button.isEnabled() is True
69 assert self.form.alternate_push_button.isEnabled() is True
70 assert self.form.clear_primary_button.isEnabled() is True
71 assert self.form.clear_alternate_button.isEnabled() is True
72
55 def adjust_button_test(self):73 def adjust_button_test(self):
56 """74 """
57 Test the _adjust_button() method75 Test the _adjust_button() method
@@ -71,6 +89,27 @@
71 mocked_check_method.assert_called_once_with(True)89 mocked_check_method.assert_called_once_with(True)
72 self.assertEqual(button.isEnabled(), enabled, 'The button should be disabled.')90 self.assertEqual(button.isEnabled(), enabled, 'The button should be disabled.')
7391
92 @patch('openlp.core.ui.shortcutlistform.QtWidgets.QDialog.exec')
93 def test_exec(self, mocked_exec):
94 """
95 Test the exec method
96 """
97 # GIVEN: A form and a mocked out base exec method
98 mocked_exec.return_value = True
99
100 # WHEN: exec is called
101 result = self.form.exec()
102
103 # THEN: The result should be True and the controls should be disabled
104 assert self.form.default_radio_button.isEnabled() is False
105 assert self.form.custom_radio_button.isEnabled() is False
106 assert self.form.primary_push_button.isEnabled() is False
107 assert self.form.alternate_push_button.isEnabled() is False
108 assert self.form.clear_primary_button.isEnabled() is False
109 assert self.form.clear_alternate_button.isEnabled() is False
110 mocked_exec.assert_called_once_with(self.form)
111 assert result is True
112
74 def space_key_press_event_test(self):113 def space_key_press_event_test(self):
75 """114 """
76 Test the keyPressEvent when the spacebar was pressed115 Test the keyPressEvent when the spacebar was pressed

Subscribers

People subscribed via source and target branches

to all changes: