Merge lp:~raoul-snyman/openlp/custom-shortcuts-2.4 into lp:openlp/2.4
- custom-shortcuts-2.4
- Merge into 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 |
Related bugs: |
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
Description of the change
Disable the shortcut controls when an action has not been selected
Add this to your merge proposal:
-------
lp:~raoul-snyman/openlp/custom-shortcuts-2.4 (revision 2681)
[SUCCESS] https:/
[SUCCESS] https:/
[SUCCESS] https:/
[SUCCESS] https:/
[SUCCESS] https:/
[SUCCESS] https:/
[SUCCESS] https:/
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
1 | === modified file 'CHANGELOG.rst' | |||
2 | --- CHANGELOG.rst 2017-03-27 23:25:12 +0000 | |||
3 | +++ CHANGELOG.rst 2017-03-29 18:46:40 +0000 | |||
4 | @@ -1,11 +1,12 @@ | |||
5 | 1 | OpenLP 2.4.6 | 1 | OpenLP 2.4.6 |
6 | 2 | ============ | 2 | ============ |
7 | 3 | 3 | ||
11 | 4 | * Fixed a bug where the author type upgrade was being ignore because it was looking at the wrong table | 4 | * Fix a bug where the author type upgrade was being ignore because it was looking at the wrong table |
12 | 5 | * Fixed a bug where the songs_songbooks table was not being created because the if expression was the wrong way round | 5 | * Fix a bug where the songs_songbooks table was not being created because the if expression was the wrong way round |
13 | 6 | * Changed the songs_songbooks migration SQL slightly to take into account a bug that has (hopefully) been fixed | 6 | * Change the songs_songbooks migration SQL slightly to take into account a bug that has (hopefully) been fixed |
14 | 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) |
15 | 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) |
16 | 9 | * Fix a problem with the new QMediaPlayer not controlling the playlist anymore | 9 | * Fix a problem with the new QMediaPlayer not controlling the playlist anymore |
18 | 10 | * Added importing of author types to the OpenLP 2 song importer | 10 | * Add importing of author types to the OpenLP 2 song importer |
19 | 11 | * Fix a problem with loading Qt's translation files, bug #1676163 | 11 | * Fix a problem with loading Qt's translation files, bug #1676163 |
20 | 12 | * Disable the controls in the shortcut dialog unless a shortcut is actually selected | ||
21 | 12 | 13 | ||
22 | === modified file 'openlp/core/ui/shortcutlistform.py' | |||
23 | --- openlp/core/ui/shortcutlistform.py 2016-12-31 11:05:48 +0000 | |||
24 | +++ openlp/core/ui/shortcutlistform.py 2017-03-29 18:46:40 +0000 | |||
25 | @@ -49,6 +49,8 @@ | |||
26 | 49 | self.changed_actions = {} | 49 | self.changed_actions = {} |
27 | 50 | self.action_list = ActionList.get_instance() | 50 | self.action_list = ActionList.get_instance() |
28 | 51 | self.dialog_was_shown = False | 51 | self.dialog_was_shown = False |
29 | 52 | self.default_radio_button.setEnabled(False) | ||
30 | 53 | self.custom_radio_button.setEnabled(False) | ||
31 | 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) |
32 | 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) |
33 | 54 | self.tree_widget.currentItemChanged.connect(self.on_current_item_changed) | 56 | self.tree_widget.currentItemChanged.connect(self.on_current_item_changed) |
34 | @@ -110,8 +112,89 @@ | |||
35 | 110 | self.reload_shortcut_list() | 112 | self.reload_shortcut_list() |
36 | 111 | self._adjust_button(self.primary_push_button, False, False, '') | 113 | self._adjust_button(self.primary_push_button, False, False, '') |
37 | 112 | self._adjust_button(self.alternate_push_button, False, False, '') | 114 | self._adjust_button(self.alternate_push_button, False, False, '') |
38 | 115 | self._set_controls_enabled(False) | ||
39 | 113 | return QtWidgets.QDialog.exec(self) | 116 | return QtWidgets.QDialog.exec(self) |
40 | 114 | 117 | ||
41 | 118 | def _validiate_shortcut(self, changing_action, key_sequence): | ||
42 | 119 | """ | ||
43 | 120 | Checks if the given ``changing_action `` can use the given ``key_sequence``. Returns ``True`` if the | ||
44 | 121 | ``key_sequence`` can be used by the action, otherwise displays a dialog and returns ``False``. | ||
45 | 122 | |||
46 | 123 | :param changing_action: The action which wants to use the ``key_sequence``. | ||
47 | 124 | :param key_sequence: The key sequence which the action want so use. | ||
48 | 125 | """ | ||
49 | 126 | is_valid = True | ||
50 | 127 | for category in self.action_list.categories: | ||
51 | 128 | for action in category.actions: | ||
52 | 129 | shortcuts = self._action_shortcuts(action) | ||
53 | 130 | if key_sequence not in shortcuts: | ||
54 | 131 | continue | ||
55 | 132 | if action is changing_action: | ||
56 | 133 | if self.primary_push_button.isChecked() and shortcuts.index(key_sequence) == 0: | ||
57 | 134 | continue | ||
58 | 135 | if self.alternate_push_button.isChecked() and shortcuts.index(key_sequence) == 1: | ||
59 | 136 | continue | ||
60 | 137 | # Have the same parent, thus they cannot have the same shortcut. | ||
61 | 138 | if action.parent() is changing_action.parent(): | ||
62 | 139 | is_valid = False | ||
63 | 140 | # The new shortcut is already assigned, but if both shortcuts are only valid in a different widget the | ||
64 | 141 | # new shortcut is valid, because they will not interfere. | ||
65 | 142 | if action.shortcutContext() in [QtCore.Qt.WindowShortcut, QtCore.Qt.ApplicationShortcut]: | ||
66 | 143 | is_valid = False | ||
67 | 144 | if changing_action.shortcutContext() in [QtCore.Qt.WindowShortcut, QtCore.Qt.ApplicationShortcut]: | ||
68 | 145 | is_valid = False | ||
69 | 146 | if not is_valid: | ||
70 | 147 | self.main_window.warning_message(translate('OpenLP.ShortcutListDialog', 'Duplicate Shortcut'), | ||
71 | 148 | translate('OpenLP.ShortcutListDialog', | ||
72 | 149 | 'The shortcut "%s" is already assigned to another action, please' | ||
73 | 150 | ' use a different shortcut.') % | ||
74 | 151 | self.get_shortcut_string(key_sequence, for_display=True)) | ||
75 | 152 | self.dialog_was_shown = True | ||
76 | 153 | return is_valid | ||
77 | 154 | |||
78 | 155 | def _action_shortcuts(self, action): | ||
79 | 156 | """ | ||
80 | 157 | This returns the shortcuts for the given ``action``, which also includes those shortcuts which are not saved | ||
81 | 158 | yet but already assigned (as changes are applied when closing the dialog). | ||
82 | 159 | """ | ||
83 | 160 | if action in self.changed_actions: | ||
84 | 161 | return self.changed_actions[action] | ||
85 | 162 | return action.shortcuts() | ||
86 | 163 | |||
87 | 164 | def _current_item_action(self, item=None): | ||
88 | 165 | """ | ||
89 | 166 | Returns the action of the given ``item``. If no item is given, we return the action of the current item of | ||
90 | 167 | the ``tree_widget``. | ||
91 | 168 | """ | ||
92 | 169 | if item is None: | ||
93 | 170 | item = self.tree_widget.currentItem() | ||
94 | 171 | if item is None: | ||
95 | 172 | return | ||
96 | 173 | return item.data(0, QtCore.Qt.UserRole) | ||
97 | 174 | |||
98 | 175 | def _adjust_button(self, button, checked=None, enabled=None, text=None): | ||
99 | 176 | """ | ||
100 | 177 | Can be called to adjust more properties of the given ``button`` at once. | ||
101 | 178 | """ | ||
102 | 179 | # Set the text before checking the button, because this emits a signal. | ||
103 | 180 | if text is not None: | ||
104 | 181 | button.setText(text) | ||
105 | 182 | if checked is not None: | ||
106 | 183 | button.setChecked(checked) | ||
107 | 184 | if enabled is not None: | ||
108 | 185 | button.setEnabled(enabled) | ||
109 | 186 | |||
110 | 187 | def _set_controls_enabled(self, is_enabled=False): | ||
111 | 188 | """ | ||
112 | 189 | Enable or disable the shortcut controls | ||
113 | 190 | """ | ||
114 | 191 | self.default_radio_button.setEnabled(is_enabled) | ||
115 | 192 | self.custom_radio_button.setEnabled(is_enabled) | ||
116 | 193 | self.primary_push_button.setEnabled(is_enabled) | ||
117 | 194 | self.alternate_push_button.setEnabled(is_enabled) | ||
118 | 195 | self.clear_primary_button.setEnabled(is_enabled) | ||
119 | 196 | self.clear_alternate_button.setEnabled(is_enabled) | ||
120 | 197 | |||
121 | 115 | def reload_shortcut_list(self): | 198 | def reload_shortcut_list(self): |
122 | 116 | """ | 199 | """ |
123 | 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. |
124 | @@ -229,8 +312,7 @@ | |||
125 | 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. |
126 | 230 | """ | 313 | """ |
127 | 231 | action = self._current_item_action(item) | 314 | action = self._current_item_action(item) |
130 | 232 | self.primary_push_button.setEnabled(action is not None) | 315 | self._set_controls_enabled(action is not None) |
129 | 233 | self.alternate_push_button.setEnabled(action is not None) | ||
131 | 234 | primary_text = '' | 316 | primary_text = '' |
132 | 235 | alternate_text = '' | 317 | alternate_text = '' |
133 | 236 | primary_label_text = '' | 318 | primary_label_text = '' |
134 | @@ -244,7 +326,7 @@ | |||
135 | 244 | if len(action.default_shortcuts) == 2: | 326 | if len(action.default_shortcuts) == 2: |
136 | 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) |
137 | 246 | shortcuts = self._action_shortcuts(action) | 328 | shortcuts = self._action_shortcuts(action) |
139 | 247 | # We do not want to loose pending changes, that is why we have to keep the text when, this function has not | 329 | # We do not want to loose pending changes, that is why we have to keep the text when this function has not |
140 | 248 | # been triggered by a signal. | 330 | # been triggered by a signal. |
141 | 249 | if item is None: | 331 | if item is None: |
142 | 250 | primary_text = self.primary_push_button.text() | 332 | primary_text = self.primary_push_button.text() |
143 | @@ -254,7 +336,7 @@ | |||
144 | 254 | elif len(shortcuts) == 2: | 336 | elif len(shortcuts) == 2: |
145 | 255 | primary_text = self.get_shortcut_string(shortcuts[0], for_display=True) | 337 | primary_text = self.get_shortcut_string(shortcuts[0], for_display=True) |
146 | 256 | alternate_text = self.get_shortcut_string(shortcuts[1], for_display=True) | 338 | alternate_text = self.get_shortcut_string(shortcuts[1], for_display=True) |
148 | 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. |
149 | 258 | if self.primary_push_button.isChecked(): | 340 | if self.primary_push_button.isChecked(): |
150 | 259 | primary_text = '' | 341 | primary_text = '' |
151 | 260 | if self.alternate_push_button.isChecked(): | 342 | if self.alternate_push_button.isChecked(): |
152 | @@ -396,75 +478,6 @@ | |||
153 | 396 | self.refresh_shortcut_list() | 478 | self.refresh_shortcut_list() |
154 | 397 | self.on_current_item_changed(self.tree_widget.currentItem()) | 479 | self.on_current_item_changed(self.tree_widget.currentItem()) |
155 | 398 | 480 | ||
156 | 399 | def _validiate_shortcut(self, changing_action, key_sequence): | ||
157 | 400 | """ | ||
158 | 401 | Checks if the given ``changing_action `` can use the given ``key_sequence``. Returns ``True`` if the | ||
159 | 402 | ``key_sequence`` can be used by the action, otherwise displays a dialog and returns ``False``. | ||
160 | 403 | |||
161 | 404 | :param changing_action: The action which wants to use the ``key_sequence``. | ||
162 | 405 | :param key_sequence: The key sequence which the action want so use. | ||
163 | 406 | """ | ||
164 | 407 | is_valid = True | ||
165 | 408 | for category in self.action_list.categories: | ||
166 | 409 | for action in category.actions: | ||
167 | 410 | shortcuts = self._action_shortcuts(action) | ||
168 | 411 | if key_sequence not in shortcuts: | ||
169 | 412 | continue | ||
170 | 413 | if action is changing_action: | ||
171 | 414 | if self.primary_push_button.isChecked() and shortcuts.index(key_sequence) == 0: | ||
172 | 415 | continue | ||
173 | 416 | if self.alternate_push_button.isChecked() and shortcuts.index(key_sequence) == 1: | ||
174 | 417 | continue | ||
175 | 418 | # Have the same parent, thus they cannot have the same shortcut. | ||
176 | 419 | if action.parent() is changing_action.parent(): | ||
177 | 420 | is_valid = False | ||
178 | 421 | # The new shortcut is already assigned, but if both shortcuts are only valid in a different widget the | ||
179 | 422 | # new shortcut is valid, because they will not interfere. | ||
180 | 423 | if action.shortcutContext() in [QtCore.Qt.WindowShortcut, QtCore.Qt.ApplicationShortcut]: | ||
181 | 424 | is_valid = False | ||
182 | 425 | if changing_action.shortcutContext() in [QtCore.Qt.WindowShortcut, QtCore.Qt.ApplicationShortcut]: | ||
183 | 426 | is_valid = False | ||
184 | 427 | if not is_valid: | ||
185 | 428 | self.main_window.warning_message(translate('OpenLP.ShortcutListDialog', 'Duplicate Shortcut'), | ||
186 | 429 | translate('OpenLP.ShortcutListDialog', | ||
187 | 430 | 'The shortcut "%s" is already assigned to another action, please' | ||
188 | 431 | ' use a different shortcut.') % | ||
189 | 432 | self.get_shortcut_string(key_sequence, for_display=True)) | ||
190 | 433 | self.dialog_was_shown = True | ||
191 | 434 | return is_valid | ||
192 | 435 | |||
193 | 436 | def _action_shortcuts(self, action): | ||
194 | 437 | """ | ||
195 | 438 | This returns the shortcuts for the given ``action``, which also includes those shortcuts which are not saved | ||
196 | 439 | yet but already assigned (as changes are applied when closing the dialog). | ||
197 | 440 | """ | ||
198 | 441 | if action in self.changed_actions: | ||
199 | 442 | return self.changed_actions[action] | ||
200 | 443 | return action.shortcuts() | ||
201 | 444 | |||
202 | 445 | def _current_item_action(self, item=None): | ||
203 | 446 | """ | ||
204 | 447 | Returns the action of the given ``item``. If no item is given, we return the action of the current item of | ||
205 | 448 | the ``tree_widget``. | ||
206 | 449 | """ | ||
207 | 450 | if item is None: | ||
208 | 451 | item = self.tree_widget.currentItem() | ||
209 | 452 | if item is None: | ||
210 | 453 | return | ||
211 | 454 | return item.data(0, QtCore.Qt.UserRole) | ||
212 | 455 | |||
213 | 456 | def _adjust_button(self, button, checked=None, enabled=None, text=None): | ||
214 | 457 | """ | ||
215 | 458 | Can be called to adjust more properties of the given ``button`` at once. | ||
216 | 459 | """ | ||
217 | 460 | # Set the text before checking the button, because this emits a signal. | ||
218 | 461 | if text is not None: | ||
219 | 462 | button.setText(text) | ||
220 | 463 | if checked is not None: | ||
221 | 464 | button.setChecked(checked) | ||
222 | 465 | if enabled is not None: | ||
223 | 466 | button.setEnabled(enabled) | ||
224 | 467 | |||
225 | 468 | @staticmethod | 481 | @staticmethod |
226 | 469 | def get_shortcut_string(shortcut, for_display=False): | 482 | def get_shortcut_string(shortcut, for_display=False): |
227 | 470 | if for_display: | 483 | if for_display: |
228 | 471 | 484 | ||
229 | === modified file 'tests/interfaces/openlp_core_ui/test_shortcutlistform.py' | |||
230 | --- tests/interfaces/openlp_core_ui/test_shortcutlistform.py 2016-12-31 11:05:48 +0000 | |||
231 | +++ tests/interfaces/openlp_core_ui/test_shortcutlistform.py 2017-03-29 18:46:40 +0000 | |||
232 | @@ -52,6 +52,24 @@ | |||
233 | 52 | del self.form | 52 | del self.form |
234 | 53 | del self.main_window | 53 | del self.main_window |
235 | 54 | 54 | ||
236 | 55 | def test_set_controls_enabled(self): | ||
237 | 56 | """ | ||
238 | 57 | Test that the _set_controls_enabled() method works correctly | ||
239 | 58 | """ | ||
240 | 59 | # GIVEN: A shortcut form, and a value to set the controls | ||
241 | 60 | is_enabled = True | ||
242 | 61 | |||
243 | 62 | # WHEN: _set_controls_enabled() is called | ||
244 | 63 | self.form._set_controls_enabled(is_enabled) | ||
245 | 64 | |||
246 | 65 | # THEN: The controls should be enabled | ||
247 | 66 | assert self.form.default_radio_button.isEnabled() is True | ||
248 | 67 | assert self.form.custom_radio_button.isEnabled() is True | ||
249 | 68 | assert self.form.primary_push_button.isEnabled() is True | ||
250 | 69 | assert self.form.alternate_push_button.isEnabled() is True | ||
251 | 70 | assert self.form.clear_primary_button.isEnabled() is True | ||
252 | 71 | assert self.form.clear_alternate_button.isEnabled() is True | ||
253 | 72 | |||
254 | 55 | def adjust_button_test(self): | 73 | def adjust_button_test(self): |
255 | 56 | """ | 74 | """ |
256 | 57 | Test the _adjust_button() method | 75 | Test the _adjust_button() method |
257 | @@ -71,6 +89,27 @@ | |||
258 | 71 | mocked_check_method.assert_called_once_with(True) | 89 | mocked_check_method.assert_called_once_with(True) |
259 | 72 | self.assertEqual(button.isEnabled(), enabled, 'The button should be disabled.') | 90 | self.assertEqual(button.isEnabled(), enabled, 'The button should be disabled.') |
260 | 73 | 91 | ||
261 | 92 | @patch('openlp.core.ui.shortcutlistform.QtWidgets.QDialog.exec') | ||
262 | 93 | def test_exec(self, mocked_exec): | ||
263 | 94 | """ | ||
264 | 95 | Test the exec method | ||
265 | 96 | """ | ||
266 | 97 | # GIVEN: A form and a mocked out base exec method | ||
267 | 98 | mocked_exec.return_value = True | ||
268 | 99 | |||
269 | 100 | # WHEN: exec is called | ||
270 | 101 | result = self.form.exec() | ||
271 | 102 | |||
272 | 103 | # THEN: The result should be True and the controls should be disabled | ||
273 | 104 | assert self.form.default_radio_button.isEnabled() is False | ||
274 | 105 | assert self.form.custom_radio_button.isEnabled() is False | ||
275 | 106 | assert self.form.primary_push_button.isEnabled() is False | ||
276 | 107 | assert self.form.alternate_push_button.isEnabled() is False | ||
277 | 108 | assert self.form.clear_primary_button.isEnabled() is False | ||
278 | 109 | assert self.form.clear_alternate_button.isEnabled() is False | ||
279 | 110 | mocked_exec.assert_called_once_with(self.form) | ||
280 | 111 | assert result is True | ||
281 | 112 | |||
282 | 74 | def space_key_press_event_test(self): | 113 | def space_key_press_event_test(self): |
283 | 75 | """ | 114 | """ |
284 | 76 | Test the keyPressEvent when the spacebar was pressed | 115 | Test the keyPressEvent when the spacebar was pressed |