Merge lp:~phill-ridout/openlp/saved_bible_verses into lp:openlp
- saved_bible_verses
- Merge into trunk
Status: | Superseded |
---|---|
Proposed branch: | lp:~phill-ridout/openlp/saved_bible_verses |
Merge into: | lp:openlp |
Diff against target: |
1020 lines (+318/-196) 9 files modified
openlp/core/ui/lib/listwidgetwithdnd.py (+10/-4) openlp/plugins/bibles/lib/__init__.py (+3/-3) openlp/plugins/bibles/lib/db.py (+13/-0) openlp/plugins/bibles/lib/manager.py (+15/-43) openlp/plugins/bibles/lib/mediaitem.py (+178/-63) resources/images/openlp-2.qrc (+2/-4) tests/functional/openlp_core_ui_lib/test_listwidgetwithdnd.py (+33/-31) tests/functional/openlp_plugins/bibles/test_mediaitem.py (+63/-47) tests/interfaces/openlp_plugins/bibles/test_lib_parse_reference.py (+1/-1) |
To merge this branch: | bzr merge lp:~phill-ridout/openlp/saved_bible_verses |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Tim Bentley | Needs Fixing | ||
Review via email: mp+321949@code.launchpad.net |
This proposal supersedes a proposal from 2017-04-03.
This proposal has been superseded by a proposal from 2017-05-07.
Commit message
Description of the change
Adds more flexibility to 'locking' bible verses.
fixes #1625681 "If Bible search results are locked, duplicated results are listed"
lp:~phill-ridout/openlp/saved_bible_verses (revision 2734)
[SUCCESS] https:/
[SUCCESS] https:/
[SUCCESS] https:/
[SUCCESS] https:/
[SUCCESS] https:/
[SUCCESS] https:/
[SUCCESS] https:/
[SUCCESS] https:/
Process finished with exit code 0
Tim Bentley (trb143) wrote : Posted in a previous version of this proposal | # |
Tim Bentley (trb143) wrote : | # |
Traceback (most recent call last):
File "/home/
self.
File "/home/
self.
File "/home/
self.
File "/home/
version = self.plugin.
AttributeError: 'NoneType' object has no attribute 'name'
downloaded and started to no bibles loaded !!!!!!!
Loaded a new bible and started to type. Search as type fired and downloaded the chapter and gave me a message saying search as you type is not available!
Then a traceback
Traceback (most recent call last):
File "/home/
self.
File "/home/
self.
File "/home/
self.
File "/home/
self.
File "/home/
for count, verse in enumerate(
TypeError: 'NoneType' object is not iterable
On the select UI I only have 2 lines of search as the options is large and takes up most the the space.
Unmerged revisions
Preview Diff
1 | === modified file 'openlp/core/ui/lib/listwidgetwithdnd.py' (properties changed: -x to +x) | |||
2 | --- openlp/core/ui/lib/listwidgetwithdnd.py 2017-02-18 07:23:15 +0000 | |||
3 | +++ openlp/core/ui/lib/listwidgetwithdnd.py 2017-05-07 10:12:27 +0000 | |||
4 | @@ -44,7 +44,6 @@ | |||
5 | 44 | self.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) | 44 | self.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) |
6 | 45 | self.setAlternatingRowColors(True) | 45 | self.setAlternatingRowColors(True) |
7 | 46 | self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) | 46 | self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) |
8 | 47 | self.locked = False | ||
9 | 48 | 47 | ||
10 | 49 | def activateDnD(self): | 48 | def activateDnD(self): |
11 | 50 | """ | 49 | """ |
12 | @@ -54,15 +53,13 @@ | |||
13 | 54 | self.setDragDropMode(QtWidgets.QAbstractItemView.DragDrop) | 53 | self.setDragDropMode(QtWidgets.QAbstractItemView.DragDrop) |
14 | 55 | Registry().register_function(('%s_dnd' % self.mime_data_text), self.parent().load_file) | 54 | Registry().register_function(('%s_dnd' % self.mime_data_text), self.parent().load_file) |
15 | 56 | 55 | ||
17 | 57 | def clear(self, search_while_typing=False, override_lock=False): | 56 | def clear(self, search_while_typing=False): |
18 | 58 | """ | 57 | """ |
19 | 59 | Re-implement clear, so that we can customise feedback when using 'Search as you type' | 58 | Re-implement clear, so that we can customise feedback when using 'Search as you type' |
20 | 60 | 59 | ||
21 | 61 | :param search_while_typing: True if we want to display the customised message | 60 | :param search_while_typing: True if we want to display the customised message |
22 | 62 | :return: None | 61 | :return: None |
23 | 63 | """ | 62 | """ |
24 | 64 | if self.locked and not override_lock: | ||
25 | 65 | return | ||
26 | 66 | if search_while_typing: | 63 | if search_while_typing: |
27 | 67 | self.no_results_text = UiStrings().ShortResults | 64 | self.no_results_text = UiStrings().ShortResults |
28 | 68 | else: | 65 | else: |
29 | @@ -128,6 +125,15 @@ | |||
30 | 128 | else: | 125 | else: |
31 | 129 | event.ignore() | 126 | event.ignore() |
32 | 130 | 127 | ||
33 | 128 | def allItems(self): | ||
34 | 129 | """ | ||
35 | 130 | An generator to list all the items in the widget | ||
36 | 131 | |||
37 | 132 | :return: a generator | ||
38 | 133 | """ | ||
39 | 134 | for row in range(self.count()): | ||
40 | 135 | yield self.item(row) | ||
41 | 136 | |||
42 | 131 | def paintEvent(self, event): | 137 | def paintEvent(self, event): |
43 | 132 | """ | 138 | """ |
44 | 133 | Re-implement paintEvent so that we can add 'No Results' text when the listWidget is empty. | 139 | Re-implement paintEvent so that we can add 'No Results' text when the listWidget is empty. |
45 | 134 | 140 | ||
46 | === modified file 'openlp/plugins/bibles/lib/__init__.py' | |||
47 | --- openlp/plugins/bibles/lib/__init__.py 2017-02-18 07:23:15 +0000 | |||
48 | +++ openlp/plugins/bibles/lib/__init__.py 2017-05-07 10:12:27 +0000 | |||
49 | @@ -341,10 +341,10 @@ | |||
50 | 341 | if not book_ref_id: | 341 | if not book_ref_id: |
51 | 342 | book_ref_id = bible.get_book_ref_id_by_localised_name(book, language_selection) | 342 | book_ref_id = bible.get_book_ref_id_by_localised_name(book, language_selection) |
52 | 343 | elif not bible.get_book_by_book_ref_id(book_ref_id): | 343 | elif not bible.get_book_by_book_ref_id(book_ref_id): |
54 | 344 | return False | 344 | return [] |
55 | 345 | # We have not found the book so do not continue | 345 | # We have not found the book so do not continue |
56 | 346 | if not book_ref_id: | 346 | if not book_ref_id: |
58 | 347 | return False | 347 | return [] |
59 | 348 | ranges = match.group('ranges') | 348 | ranges = match.group('ranges') |
60 | 349 | range_list = get_reference_match('range_separator').split(ranges) | 349 | range_list = get_reference_match('range_separator').split(ranges) |
61 | 350 | ref_list = [] | 350 | ref_list = [] |
62 | @@ -403,7 +403,7 @@ | |||
63 | 403 | return ref_list | 403 | return ref_list |
64 | 404 | else: | 404 | else: |
65 | 405 | log.debug('Invalid reference: {text}'.format(text=reference)) | 405 | log.debug('Invalid reference: {text}'.format(text=reference)) |
67 | 406 | return None | 406 | return [] |
68 | 407 | 407 | ||
69 | 408 | 408 | ||
70 | 409 | class SearchResults(object): | 409 | class SearchResults(object): |
71 | 410 | 410 | ||
72 | === modified file 'openlp/plugins/bibles/lib/db.py' | |||
73 | --- openlp/plugins/bibles/lib/db.py 2017-02-18 07:23:15 +0000 | |||
74 | +++ openlp/plugins/bibles/lib/db.py 2017-05-07 10:12:27 +0000 | |||
75 | @@ -158,6 +158,7 @@ | |||
76 | 158 | self.get_name() | 158 | self.get_name() |
77 | 159 | if 'path' in kwargs: | 159 | if 'path' in kwargs: |
78 | 160 | self.path = kwargs['path'] | 160 | self.path = kwargs['path'] |
79 | 161 | self._is_web_bible = None | ||
80 | 161 | 162 | ||
81 | 162 | def get_name(self): | 163 | def get_name(self): |
82 | 163 | """ | 164 | """ |
83 | @@ -426,6 +427,18 @@ | |||
84 | 426 | return 0 | 427 | return 0 |
85 | 427 | return count | 428 | return count |
86 | 428 | 429 | ||
87 | 430 | @property | ||
88 | 431 | def is_web_bible(self): | ||
89 | 432 | """ | ||
90 | 433 | A read only property indicating if the bible is a 'web bible' | ||
91 | 434 | |||
92 | 435 | :return: If the bible is a web bible. | ||
93 | 436 | :rtype: bool | ||
94 | 437 | """ | ||
95 | 438 | if self._is_web_bible is None: | ||
96 | 439 | self._is_web_bible = bool(self.get_object(BibleMeta, 'download_source')) | ||
97 | 440 | return self._is_web_bible | ||
98 | 441 | |||
99 | 429 | def dump_bible(self): | 442 | def dump_bible(self): |
100 | 430 | """ | 443 | """ |
101 | 431 | Utility debugging method to dump the contents of a bible. | 444 | Utility debugging method to dump the contents of a bible. |
102 | 432 | 445 | ||
103 | === modified file 'openlp/plugins/bibles/lib/manager.py' | |||
104 | --- openlp/plugins/bibles/lib/manager.py 2017-02-18 07:23:15 +0000 | |||
105 | +++ openlp/plugins/bibles/lib/manager.py 2017-05-07 10:12:27 +0000 | |||
106 | @@ -142,8 +142,8 @@ | |||
107 | 142 | log.debug('Bible Name: "{name}"'.format(name=name)) | 142 | log.debug('Bible Name: "{name}"'.format(name=name)) |
108 | 143 | self.db_cache[name] = bible | 143 | self.db_cache[name] = bible |
109 | 144 | # Look to see if lazy load bible exists and get create getter. | 144 | # Look to see if lazy load bible exists and get create getter. |
112 | 145 | source = self.db_cache[name].get_object(BibleMeta, 'download_source') | 145 | if self.db_cache[name].is_web_bible: |
113 | 146 | if source: | 146 | source = self.db_cache[name].get_object(BibleMeta, 'download_source') |
114 | 147 | download_name = self.db_cache[name].get_object(BibleMeta, 'download_name').value | 147 | download_name = self.db_cache[name].get_object(BibleMeta, 'download_name').value |
115 | 148 | meta_proxy = self.db_cache[name].get_object(BibleMeta, 'proxy_server') | 148 | meta_proxy = self.db_cache[name].get_object(BibleMeta, 'proxy_server') |
116 | 149 | web_bible = HTTPBible(self.parent, path=self.path, file=filename, download_source=source.value, | 149 | web_bible = HTTPBible(self.parent, path=self.path, file=filename, download_source=source.value, |
117 | @@ -278,7 +278,7 @@ | |||
118 | 278 | :param show_error: | 278 | :param show_error: |
119 | 279 | """ | 279 | """ |
120 | 280 | if not bible or not ref_list: | 280 | if not bible or not ref_list: |
122 | 281 | return None | 281 | return [] |
123 | 282 | return self.db_cache[bible].get_verses(ref_list, show_error) | 282 | return self.db_cache[bible].get_verses(ref_list, show_error) |
124 | 283 | 283 | ||
125 | 284 | def get_language_selection(self, bible): | 284 | def get_language_selection(self, bible): |
126 | @@ -305,11 +305,17 @@ | |||
127 | 305 | """ | 305 | """ |
128 | 306 | Does a verse search for the given bible and text. | 306 | Does a verse search for the given bible and text. |
129 | 307 | 307 | ||
133 | 308 | :param bible: The bible to search in (unicode). | 308 | :param bible: The bible to search |
134 | 309 | :param second_bible: The second bible (unicode). We do not search in this bible. | 309 | :type bible: str |
135 | 310 | :param text: The text to search for (unicode). | 310 | :param text: The text to search for |
136 | 311 | :type text: str | ||
137 | 312 | |||
138 | 313 | :return: The search results if valid, or None if the search is invalid. | ||
139 | 314 | :rtype: None, list | ||
140 | 311 | """ | 315 | """ |
141 | 312 | log.debug('BibleManager.verse_search("{bible}", "{text}")'.format(bible=bible, text=text)) | 316 | log.debug('BibleManager.verse_search("{bible}", "{text}")'.format(bible=bible, text=text)) |
142 | 317 | if not text: | ||
143 | 318 | return None | ||
144 | 313 | # If no bibles are installed, message is given. | 319 | # If no bibles are installed, message is given. |
145 | 314 | if not bible: | 320 | if not bible: |
146 | 315 | self.main_window.information_message( | 321 | self.main_window.information_message( |
147 | @@ -317,8 +323,7 @@ | |||
148 | 317 | UiStrings().BibleNoBibles) | 323 | UiStrings().BibleNoBibles) |
149 | 318 | return None | 324 | return None |
150 | 319 | # Check if the bible or second_bible is a web bible. | 325 | # Check if the bible or second_bible is a web bible. |
153 | 320 | web_bible = self.db_cache[bible].get_object(BibleMeta, 'download_source') | 326 | if self.db_cache[bible].is_web_bible: |
152 | 321 | if web_bible: | ||
154 | 322 | # If either Bible is Web, cursor is reset to normal and message is given. | 327 | # If either Bible is Web, cursor is reset to normal and message is given. |
155 | 323 | self.application.set_normal_cursor() | 328 | self.application.set_normal_cursor() |
156 | 324 | self.main_window.information_message( | 329 | self.main_window.information_message( |
157 | @@ -328,41 +333,8 @@ | |||
158 | 328 | 'This means that the currently selected Bible is a Web Bible.') | 333 | 'This means that the currently selected Bible is a Web Bible.') |
159 | 329 | ) | 334 | ) |
160 | 330 | return None | 335 | return None |
196 | 331 | # Shorter than 3 char searches break OpenLP with very long search times, thus they are blocked. | 336 | # Fetch the results from db. If no results are found, return None, no message is given for this. |
197 | 332 | if len(text) - text.count(' ') < 3: | 337 | if text: |
163 | 333 | return None | ||
164 | 334 | # Fetch the results from db. If no results are found, return None, no message is given for this. | ||
165 | 335 | elif text: | ||
166 | 336 | return self.db_cache[bible].verse_search(text) | ||
167 | 337 | else: | ||
168 | 338 | return None | ||
169 | 339 | |||
170 | 340 | def verse_search_while_typing(self, bible, second_bible, text): | ||
171 | 341 | """ | ||
172 | 342 | Does a verse search for the given bible and text. | ||
173 | 343 | This is used during "Search while typing" | ||
174 | 344 | It's the same thing as the normal text search, but it does not show the web Bible error. | ||
175 | 345 | (It would result in the error popping every time a char is entered or removed) | ||
176 | 346 | It also does not have a minimum text len, this is set in mediaitem.py | ||
177 | 347 | |||
178 | 348 | :param bible: The bible to search in (unicode). | ||
179 | 349 | :param second_bible: The second bible (unicode). We do not search in this bible. | ||
180 | 350 | :param text: The text to search for (unicode). | ||
181 | 351 | """ | ||
182 | 352 | # If no bibles are installed, message is given. | ||
183 | 353 | if not bible: | ||
184 | 354 | return None | ||
185 | 355 | # Check if the bible or second_bible is a web bible. | ||
186 | 356 | web_bible = self.db_cache[bible].get_object(BibleMeta, 'download_source') | ||
187 | 357 | second_web_bible = '' | ||
188 | 358 | if second_bible: | ||
189 | 359 | second_web_bible = self.db_cache[second_bible].get_object(BibleMeta, 'download_source') | ||
190 | 360 | if web_bible or second_web_bible: | ||
191 | 361 | # If either Bible is Web, cursor is reset to normal and search ends w/o any message. | ||
192 | 362 | self.application.set_normal_cursor() | ||
193 | 363 | return None | ||
194 | 364 | # Fetch the results from db. If no results are found, return None, no message is given for this. | ||
195 | 365 | elif text: | ||
198 | 366 | return self.db_cache[bible].verse_search(text) | 338 | return self.db_cache[bible].verse_search(text) |
199 | 367 | else: | 339 | else: |
200 | 368 | return None | 340 | return None |
201 | 369 | 341 | ||
202 | === modified file 'openlp/plugins/bibles/lib/mediaitem.py' (properties changed: -x to +x) | |||
203 | --- openlp/plugins/bibles/lib/mediaitem.py 2017-02-18 20:22:47 +0000 | |||
204 | +++ openlp/plugins/bibles/lib/mediaitem.py 2017-05-07 10:12:27 +0000 | |||
205 | @@ -22,6 +22,7 @@ | |||
206 | 22 | 22 | ||
207 | 23 | import logging | 23 | import logging |
208 | 24 | import re | 24 | import re |
209 | 25 | from enum import Enum, unique | ||
210 | 25 | 26 | ||
211 | 26 | from PyQt5 import QtCore, QtWidgets | 27 | from PyQt5 import QtCore, QtWidgets |
212 | 27 | 28 | ||
213 | @@ -48,15 +49,45 @@ | |||
214 | 48 | 'list': get_reference_separator('sep_l_display')} | 49 | 'list': get_reference_separator('sep_l_display')} |
215 | 49 | 50 | ||
216 | 50 | 51 | ||
218 | 51 | class BibleSearch(object): | 52 | @unique |
219 | 53 | class BibleSearch(Enum): | ||
220 | 52 | """ | 54 | """ |
222 | 53 | Enumeration class for the different search methods for the "Search" tab. | 55 | Enumeration class for the different search types for the "Search" tab. |
223 | 54 | """ | 56 | """ |
224 | 55 | Reference = 1 | 57 | Reference = 1 |
225 | 56 | Text = 2 | 58 | Text = 2 |
226 | 57 | Combined = 3 | 59 | Combined = 3 |
227 | 58 | 60 | ||
228 | 59 | 61 | ||
229 | 62 | @unique | ||
230 | 63 | class ResultsTab(Enum): | ||
231 | 64 | """ | ||
232 | 65 | Enumeration class for the different tabs for the results list. | ||
233 | 66 | """ | ||
234 | 67 | Saved = 0 | ||
235 | 68 | Search = 1 | ||
236 | 69 | |||
237 | 70 | |||
238 | 71 | @unique | ||
239 | 72 | class SearchStatus(Enum): | ||
240 | 73 | """ | ||
241 | 74 | Enumeration class for the different search methods. | ||
242 | 75 | """ | ||
243 | 76 | SearchButton = 0 | ||
244 | 77 | SearchAsYouType = 1 | ||
245 | 78 | NotEnoughText = 2 | ||
246 | 79 | |||
247 | 80 | |||
248 | 81 | @unique | ||
249 | 82 | class SearchTabs(Enum): | ||
250 | 83 | """ | ||
251 | 84 | Enumeration class for the tabs on the media item. | ||
252 | 85 | """ | ||
253 | 86 | Search = 0 | ||
254 | 87 | Select = 1 | ||
255 | 88 | Options = 2 | ||
256 | 89 | |||
257 | 90 | |||
258 | 60 | class BibleMediaItem(MediaManagerItem): | 91 | class BibleMediaItem(MediaManagerItem): |
259 | 61 | """ | 92 | """ |
260 | 62 | This is the custom media manager item for Bibles. | 93 | This is the custom media manager item for Bibles. |
261 | @@ -73,11 +104,13 @@ | |||
262 | 73 | :param kwargs: Keyword arguments to pass to the super method. (dict) | 104 | :param kwargs: Keyword arguments to pass to the super method. (dict) |
263 | 74 | """ | 105 | """ |
264 | 75 | self.clear_icon = build_icon(':/bibles/bibles_search_clear.png') | 106 | self.clear_icon = build_icon(':/bibles/bibles_search_clear.png') |
267 | 76 | self.lock_icon = build_icon(':/bibles/bibles_search_lock.png') | 107 | self.save_results_icon = build_icon(':/bibles/bibles_save_results.png') |
266 | 77 | self.unlock_icon = build_icon(':/bibles/bibles_search_unlock.png') | ||
268 | 78 | self.sort_icon = build_icon(':/bibles/bibles_book_sort.png') | 108 | self.sort_icon = build_icon(':/bibles/bibles_book_sort.png') |
269 | 79 | self.bible = None | 109 | self.bible = None |
270 | 80 | self.second_bible = None | 110 | self.second_bible = None |
271 | 111 | self.saved_results = [] | ||
272 | 112 | self.current_results = [] | ||
273 | 113 | self.search_status = SearchStatus().SearchButton | ||
274 | 81 | # TODO: Make more central and clean up after! | 114 | # TODO: Make more central and clean up after! |
275 | 82 | self.search_timer = QtCore.QTimer() | 115 | self.search_timer = QtCore.QTimer() |
276 | 83 | self.search_timer.setInterval(200) | 116 | self.search_timer.setInterval(200) |
277 | @@ -162,8 +195,10 @@ | |||
278 | 162 | self.select_tab.setVisible(False) | 195 | self.select_tab.setVisible(False) |
279 | 163 | self.page_layout.addWidget(self.select_tab) | 196 | self.page_layout.addWidget(self.select_tab) |
280 | 164 | # General Search Opions | 197 | # General Search Opions |
283 | 165 | self.options_widget = QtWidgets.QGroupBox(translate('BiblesPlugin.MediaItem', 'Options'), self) | 198 | self.options_tab = QtWidgets.QWidget() |
284 | 166 | self.general_bible_layout = QtWidgets.QFormLayout(self.options_widget) | 199 | self.options_tab.setSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) |
285 | 200 | self.search_tab_bar.addTab(translate('BiblesPlugin.MediaItem', 'Options')) | ||
286 | 201 | self.general_bible_layout = QtWidgets.QFormLayout(self.options_tab) | ||
287 | 167 | self.version_combo_box = create_horizontal_adjusting_combo_box(self, 'version_combo_box') | 202 | self.version_combo_box = create_horizontal_adjusting_combo_box(self, 'version_combo_box') |
288 | 168 | self.general_bible_layout.addRow('{version}:'.format(version=UiStrings().Version), self.version_combo_box) | 203 | self.general_bible_layout.addRow('{version}:'.format(version=UiStrings().Version), self.version_combo_box) |
289 | 169 | self.second_combo_box = create_horizontal_adjusting_combo_box(self, 'second_combo_box') | 204 | self.second_combo_box = create_horizontal_adjusting_combo_box(self, 'second_combo_box') |
290 | @@ -171,20 +206,28 @@ | |||
291 | 171 | self.style_combo_box = create_horizontal_adjusting_combo_box(self, 'style_combo_box') | 206 | self.style_combo_box = create_horizontal_adjusting_combo_box(self, 'style_combo_box') |
292 | 172 | self.style_combo_box.addItems(['', '', '']) | 207 | self.style_combo_box.addItems(['', '', '']) |
293 | 173 | self.general_bible_layout.addRow(UiStrings().LayoutStyle, self.style_combo_box) | 208 | self.general_bible_layout.addRow(UiStrings().LayoutStyle, self.style_combo_box) |
295 | 174 | self.search_button_layout = QtWidgets.QHBoxLayout() | 209 | self.options_tab.setVisible(False) |
296 | 210 | self.page_layout.addWidget(self.options_tab) | ||
297 | 211 | # This widget is the easier way to reset the spacing of search_button_layout. (Because page_layout has had its | ||
298 | 212 | # spacing set to 0) | ||
299 | 213 | self.search_button_widget = QtWidgets.QWidget() | ||
300 | 214 | self.search_button_layout = QtWidgets.QHBoxLayout(self.search_button_widget) | ||
301 | 175 | self.search_button_layout.addStretch() | 215 | self.search_button_layout.addStretch() |
302 | 176 | # Note: If we use QPushButton instead of the QToolButton, the icon will be larger than the Lock icon. | 216 | # Note: If we use QPushButton instead of the QToolButton, the icon will be larger than the Lock icon. |
304 | 177 | self.clear_button = QtWidgets.QToolButton(self) | 217 | self.clear_button = QtWidgets.QPushButton() |
305 | 178 | self.clear_button.setIcon(self.clear_icon) | 218 | self.clear_button.setIcon(self.clear_icon) |
309 | 179 | self.lock_button = QtWidgets.QToolButton(self) | 219 | self.save_results_button = QtWidgets.QPushButton() |
310 | 180 | self.lock_button.setIcon(self.unlock_icon) | 220 | self.save_results_button.setIcon(self.save_results_icon) |
308 | 181 | self.lock_button.setCheckable(True) | ||
311 | 182 | self.search_button_layout.addWidget(self.clear_button) | 221 | self.search_button_layout.addWidget(self.clear_button) |
313 | 183 | self.search_button_layout.addWidget(self.lock_button) | 222 | self.search_button_layout.addWidget(self.save_results_button) |
314 | 184 | self.search_button = QtWidgets.QPushButton(self) | 223 | self.search_button = QtWidgets.QPushButton(self) |
315 | 185 | self.search_button_layout.addWidget(self.search_button) | 224 | self.search_button_layout.addWidget(self.search_button) |
318 | 186 | self.general_bible_layout.addRow(self.search_button_layout) | 225 | self.page_layout.addWidget(self.search_button_widget) |
319 | 187 | self.page_layout.addWidget(self.options_widget) | 226 | self.results_view_tab = QtWidgets.QTabBar(self) |
320 | 227 | self.results_view_tab.addTab('') | ||
321 | 228 | self.results_view_tab.addTab('') | ||
322 | 229 | self.results_view_tab.setCurrentIndex(ResultsTab.Search) | ||
323 | 230 | self.page_layout.addWidget(self.results_view_tab) | ||
324 | 188 | 231 | ||
325 | 189 | def setupUi(self): | 232 | def setupUi(self): |
326 | 190 | super().setupUi() | 233 | super().setupUi() |
327 | @@ -211,12 +254,15 @@ | |||
328 | 211 | # Buttons | 254 | # Buttons |
329 | 212 | self.book_order_button.toggled.connect(self.on_book_order_button_toggled) | 255 | self.book_order_button.toggled.connect(self.on_book_order_button_toggled) |
330 | 213 | self.clear_button.clicked.connect(self.on_clear_button_clicked) | 256 | self.clear_button.clicked.connect(self.on_clear_button_clicked) |
332 | 214 | self.lock_button.toggled.connect(self.on_lock_button_toggled) | 257 | self.save_results_button.clicked.connect(self.on_save_results_button_clicked) |
333 | 215 | self.search_button.clicked.connect(self.on_search_button_clicked) | 258 | self.search_button.clicked.connect(self.on_search_button_clicked) |
334 | 216 | # Other stuff | 259 | # Other stuff |
335 | 217 | self.search_edit.returnPressed.connect(self.on_search_button_clicked) | 260 | self.search_edit.returnPressed.connect(self.on_search_button_clicked) |
336 | 218 | self.search_tab_bar.currentChanged.connect(self.on_search_tab_bar_current_changed) | 261 | self.search_tab_bar.currentChanged.connect(self.on_search_tab_bar_current_changed) |
337 | 262 | self.results_view_tab.currentChanged.connect(self.on_results_view_tab_current_changed) | ||
338 | 219 | self.search_edit.textChanged.connect(self.on_search_edit_text_changed) | 263 | self.search_edit.textChanged.connect(self.on_search_edit_text_changed) |
339 | 264 | self.on_results_view_tab_total_update(ResultsTab.Saved) | ||
340 | 265 | self.on_results_view_tab_total_update(ResultsTab.Search) | ||
341 | 220 | 266 | ||
342 | 221 | def retranslateUi(self): | 267 | def retranslateUi(self): |
343 | 222 | log.debug('retranslateUi') | 268 | log.debug('retranslateUi') |
344 | @@ -225,9 +271,9 @@ | |||
345 | 225 | self.style_combo_box.setItemText(LayoutStyle.VersePerSlide, UiStrings().VersePerSlide) | 271 | self.style_combo_box.setItemText(LayoutStyle.VersePerSlide, UiStrings().VersePerSlide) |
346 | 226 | self.style_combo_box.setItemText(LayoutStyle.VersePerLine, UiStrings().VersePerLine) | 272 | self.style_combo_box.setItemText(LayoutStyle.VersePerLine, UiStrings().VersePerLine) |
347 | 227 | self.style_combo_box.setItemText(LayoutStyle.Continuous, UiStrings().Continuous) | 273 | self.style_combo_box.setItemText(LayoutStyle.Continuous, UiStrings().Continuous) |
351 | 228 | self.clear_button.setToolTip(translate('BiblesPlugin.MediaItem', 'Clear the search results.')) | 274 | self.clear_button.setToolTip(translate('BiblesPlugin.MediaItem', 'Clear the results on the current tab.')) |
352 | 229 | self.lock_button.setToolTip( | 275 | self.save_results_button.setToolTip( |
353 | 230 | translate('BiblesPlugin.MediaItem', 'Toggle to keep or clear the previous results.')) | 276 | translate('BiblesPlugin.MediaItem', 'Add the search results to the saved list.')) |
354 | 231 | self.search_button.setText(UiStrings().Search) | 277 | self.search_button.setText(UiStrings().Search) |
355 | 232 | 278 | ||
356 | 233 | def on_focus(self): | 279 | def on_focus(self): |
357 | @@ -241,8 +287,10 @@ | |||
358 | 241 | if self.search_tab.isVisible(): | 287 | if self.search_tab.isVisible(): |
359 | 242 | self.search_edit.setFocus() | 288 | self.search_edit.setFocus() |
360 | 243 | self.search_edit.selectAll() | 289 | self.search_edit.selectAll() |
362 | 244 | else: | 290 | if self.select_tab.isVisible(): |
363 | 245 | self.select_book_combo_box.setFocus() | 291 | self.select_book_combo_box.setFocus() |
364 | 292 | if self.options_tab.isVisible(): | ||
365 | 293 | self.version_combo_box.setFocus() | ||
366 | 246 | 294 | ||
367 | 247 | def config_update(self): | 295 | def config_update(self): |
368 | 248 | """ | 296 | """ |
369 | @@ -415,14 +463,48 @@ | |||
370 | 415 | """ | 463 | """ |
371 | 416 | Show the selected tab and set focus to it | 464 | Show the selected tab and set focus to it |
372 | 417 | 465 | ||
374 | 418 | :param index: The tab selected (int) | 466 | :param index: The tab selected |
375 | 467 | :type index: int | ||
376 | 419 | :return: None | 468 | :return: None |
377 | 420 | """ | 469 | """ |
381 | 421 | search_tab = index == 0 | 470 | if index == SearchTabs.Search or index == SearchTabs.Select: |
382 | 422 | self.search_tab.setVisible(search_tab) | 471 | self.search_button.setEnabled(True) |
383 | 423 | self.select_tab.setVisible(not search_tab) | 472 | else: |
384 | 473 | self.search_button.setEnabled(False) | ||
385 | 474 | self.search_tab.setVisible(index == SearchTabs.Search) | ||
386 | 475 | self.select_tab.setVisible(index == SearchTabs.Select) | ||
387 | 476 | self.options_tab.setVisible(index == SearchTabs.Options) | ||
388 | 424 | self.on_focus() | 477 | self.on_focus() |
389 | 425 | 478 | ||
390 | 479 | def on_results_view_tab_current_changed(self, index): | ||
391 | 480 | """ | ||
392 | 481 | Update list_widget with the contents of the selected list | ||
393 | 482 | |||
394 | 483 | :param index: The index of the tab that has been changed to. (int) | ||
395 | 484 | :return: None | ||
396 | 485 | """ | ||
397 | 486 | if index == ResultsTab.Saved: | ||
398 | 487 | self.add_built_results_to_list_widget(self.saved_results) | ||
399 | 488 | elif index == ResultsTab.Search: | ||
400 | 489 | self.add_built_results_to_list_widget(self.current_results) | ||
401 | 490 | |||
402 | 491 | def on_results_view_tab_total_update(self, index): | ||
403 | 492 | """ | ||
404 | 493 | Update the result total count on the tab with the given index. | ||
405 | 494 | |||
406 | 495 | :param index: Index of the tab to update (int) | ||
407 | 496 | :return: None | ||
408 | 497 | """ | ||
409 | 498 | string = '' | ||
410 | 499 | count = 0 | ||
411 | 500 | if index == ResultsTab.Saved: | ||
412 | 501 | string = translate('BiblesPlugin.MediaItem', 'Saved ({result_count})') | ||
413 | 502 | count = len(self.saved_results) | ||
414 | 503 | elif index == ResultsTab.Search: | ||
415 | 504 | string = translate('BiblesPlugin.MediaItem', 'Results ({result_count})') | ||
416 | 505 | count = len(self.current_results) | ||
417 | 506 | self.results_view_tab.setTabText(index, string.format(result_count=count)) | ||
418 | 507 | |||
419 | 426 | def on_book_order_button_toggled(self, checked): | 508 | def on_book_order_button_toggled(self, checked): |
420 | 427 | """ | 509 | """ |
421 | 428 | Change the sort order of the book names | 510 | Change the sort order of the book names |
422 | @@ -442,22 +524,25 @@ | |||
423 | 442 | 524 | ||
424 | 443 | :return: None | 525 | :return: None |
425 | 444 | """ | 526 | """ |
429 | 445 | self.list_view.clear() | 527 | current_index = self.results_view_tab.currentIndex() |
430 | 446 | self.search_edit.clear() | 528 | for item in self.list_view.selectedItems(): |
431 | 447 | self.on_focus() | 529 | self.list_view.takeItem(self.list_view.row(item)) |
432 | 530 | results = [item.data(QtCore.Qt.UserRole) for item in self.list_view.allItems()] | ||
433 | 531 | if current_index == ResultsTab.Saved: | ||
434 | 532 | self.saved_results = results | ||
435 | 533 | elif current_index == ResultsTab.Search: | ||
436 | 534 | self.current_results = results | ||
437 | 535 | self.on_results_view_tab_total_update(current_index) | ||
438 | 448 | 536 | ||
440 | 449 | def on_lock_button_toggled(self, checked): | 537 | def on_save_results_button_clicked(self): |
441 | 450 | """ | 538 | """ |
443 | 451 | Toggle the lock button, if Search tab is used, set focus to search field. | 539 | Add the selected verses to the saved_results list. |
444 | 452 | 540 | ||
445 | 453 | :param checked: The state of the toggle button. (bool) | ||
446 | 454 | :return: None | 541 | :return: None |
447 | 455 | """ | 542 | """ |
453 | 456 | self.list_view.locked = checked | 543 | for verse in self.list_view.selectedItems(): |
454 | 457 | if checked: | 544 | self.saved_results.append(verse.data(QtCore.Qt.UserRole)) |
455 | 458 | self.sender().setIcon(self.lock_icon) | 545 | self.on_results_view_tab_total_update(ResultsTab.Saved) |
451 | 459 | else: | ||
452 | 460 | self.sender().setIcon(self.unlock_icon) | ||
456 | 461 | 546 | ||
457 | 462 | def on_style_combo_box_index_changed(self, index): | 547 | def on_style_combo_box_index_changed(self, index): |
458 | 463 | """ | 548 | """ |
459 | @@ -490,16 +575,17 @@ | |||
460 | 490 | :return: None | 575 | :return: None |
461 | 491 | """ | 576 | """ |
462 | 492 | new_selection = self.second_combo_box.currentData() | 577 | new_selection = self.second_combo_box.currentData() |
464 | 493 | if self.list_view.count(): | 578 | if self.saved_results: |
465 | 494 | # Exclusive or (^) the new and previous selections to detect if the user has switched between single and | 579 | # Exclusive or (^) the new and previous selections to detect if the user has switched between single and |
466 | 495 | # dual bible mode | 580 | # dual bible mode |
467 | 496 | if (new_selection is None) ^ (self.second_bible is None): | 581 | if (new_selection is None) ^ (self.second_bible is None): |
468 | 497 | if critical_error_message_box( | 582 | if critical_error_message_box( |
469 | 498 | message=translate('BiblesPlugin.MediaItem', | 583 | message=translate('BiblesPlugin.MediaItem', |
470 | 499 | 'OpenLP cannot combine single and dual Bible verse search results. ' | 584 | 'OpenLP cannot combine single and dual Bible verse search results. ' |
472 | 500 | 'Do you want to clear your search results and start a new search?'), | 585 | 'Do you want to clear your saved results?'), |
473 | 501 | parent=self, question=True) == QtWidgets.QMessageBox.Yes: | 586 | parent=self, question=True) == QtWidgets.QMessageBox.Yes: |
475 | 502 | self.list_view.clear(override_lock=True) | 587 | self.saved_results = [] |
476 | 588 | self.on_results_view_tab_total_update(ResultsTab.Saved) | ||
477 | 503 | else: | 589 | else: |
478 | 504 | self.second_combo_box.setCurrentIndex(self.second_combo_box.findData(self.second_bible)) | 590 | self.second_combo_box.setCurrentIndex(self.second_combo_box.findData(self.second_bible)) |
479 | 505 | return | 591 | return |
480 | @@ -525,7 +611,8 @@ | |||
481 | 525 | log.warning('Not enough chapters in %s', book_ref_id) | 611 | log.warning('Not enough chapters in %s', book_ref_id) |
482 | 526 | critical_error_message_box(message=translate('BiblesPlugin.MediaItem', 'Bible not fully loaded.')) | 612 | critical_error_message_box(message=translate('BiblesPlugin.MediaItem', 'Bible not fully loaded.')) |
483 | 527 | else: | 613 | else: |
485 | 528 | self.search_button.setEnabled(True) | 614 | if self.select_tab.isVisible(): |
486 | 615 | self.search_button.setEnabled(True) | ||
487 | 529 | self.adjust_combo_box(1, self.chapter_count, self.from_chapter) | 616 | self.adjust_combo_box(1, self.chapter_count, self.from_chapter) |
488 | 530 | self.adjust_combo_box(1, self.chapter_count, self.to_chapter) | 617 | self.adjust_combo_box(1, self.chapter_count, self.to_chapter) |
489 | 531 | self.adjust_combo_box(1, verse_count, self.from_verse) | 618 | self.adjust_combo_box(1, verse_count, self.from_verse) |
490 | @@ -602,6 +689,8 @@ | |||
491 | 602 | 689 | ||
492 | 603 | :return: None | 690 | :return: None |
493 | 604 | """ | 691 | """ |
494 | 692 | self.search_timer.stop() | ||
495 | 693 | self.search_status = SearchStatus().SearchButton | ||
496 | 605 | if not self.bible: | 694 | if not self.bible: |
497 | 606 | self.main_window.information_message(UiStrings().BibleNoBiblesTitle, UiStrings().BibleNoBibles) | 695 | self.main_window.information_message(UiStrings().BibleNoBiblesTitle, UiStrings().BibleNoBibles) |
498 | 607 | return | 696 | return |
499 | @@ -613,6 +702,7 @@ | |||
500 | 613 | elif self.select_tab.isVisible(): | 702 | elif self.select_tab.isVisible(): |
501 | 614 | self.select_search() | 703 | self.select_search() |
502 | 615 | self.search_button.setEnabled(True) | 704 | self.search_button.setEnabled(True) |
503 | 705 | self.results_view_tab.setCurrentIndex(ResultsTab.Search) | ||
504 | 616 | self.application.set_normal_cursor() | 706 | self.application.set_normal_cursor() |
505 | 617 | 707 | ||
506 | 618 | def select_search(self): | 708 | def select_search(self): |
507 | @@ -636,18 +726,21 @@ | |||
508 | 636 | 726 | ||
509 | 637 | :return: None | 727 | :return: None |
510 | 638 | """ | 728 | """ |
511 | 729 | self.search_results = [] | ||
512 | 639 | verse_refs = self.plugin.manager.parse_ref(self.bible.name, search_text) | 730 | verse_refs = self.plugin.manager.parse_ref(self.bible.name, search_text) |
513 | 640 | self.search_results = self.plugin.manager.get_verses(self.bible.name, verse_refs, True) | 731 | self.search_results = self.plugin.manager.get_verses(self.bible.name, verse_refs, True) |
514 | 641 | if self.second_bible and self.search_results: | 732 | if self.second_bible and self.search_results: |
515 | 642 | self.search_results = self.plugin.manager.get_verses(self.second_bible.name, verse_refs, True) | 733 | self.search_results = self.plugin.manager.get_verses(self.second_bible.name, verse_refs, True) |
516 | 643 | self.display_results() | 734 | self.display_results() |
517 | 644 | 735 | ||
519 | 645 | def on_text_search(self, text, search_while_type=False): | 736 | def on_text_search(self, text): |
520 | 646 | """ | 737 | """ |
521 | 647 | We are doing a 'Text Search'. | 738 | We are doing a 'Text Search'. |
522 | 648 | This search is called on def text_search by 'Search' Text and Combined Searches. | 739 | This search is called on def text_search by 'Search' Text and Combined Searches. |
523 | 649 | """ | 740 | """ |
524 | 650 | self.search_results = self.plugin.manager.verse_search(self.bible.name, text) | 741 | self.search_results = self.plugin.manager.verse_search(self.bible.name, text) |
525 | 742 | if self.search_results is None: | ||
526 | 743 | return | ||
527 | 651 | if self.second_bible and self.search_results: | 744 | if self.second_bible and self.search_results: |
528 | 652 | filtered_search_results = [] | 745 | filtered_search_results = [] |
529 | 653 | not_found_count = 0 | 746 | not_found_count = 0 |
530 | @@ -663,7 +756,7 @@ | |||
531 | 663 | verse=verse.verse, bible_name=self.second_bible.name)) | 756 | verse=verse.verse, bible_name=self.second_bible.name)) |
532 | 664 | not_found_count += 1 | 757 | not_found_count += 1 |
533 | 665 | self.search_results = filtered_search_results | 758 | self.search_results = filtered_search_results |
535 | 666 | if not_found_count != 0 and not search_while_type: | 759 | if not_found_count != 0 and self.search_status == SearchStatus.SearchButton: |
536 | 667 | self.main_window.information_message( | 760 | self.main_window.information_message( |
537 | 668 | translate('BiblesPlugin.MediaItem', 'Verses not found'), | 761 | translate('BiblesPlugin.MediaItem', 'Verses not found'), |
538 | 669 | translate('BiblesPlugin.MediaItem', | 762 | translate('BiblesPlugin.MediaItem', |
539 | @@ -673,22 +766,23 @@ | |||
540 | 673 | ).format(second_name=self.second_bible.name, name=self.bible.name, count=not_found_count)) | 766 | ).format(second_name=self.second_bible.name, name=self.bible.name, count=not_found_count)) |
541 | 674 | self.display_results() | 767 | self.display_results() |
542 | 675 | 768 | ||
544 | 676 | def text_search(self, search_while_type=False): | 769 | def text_search(self): |
545 | 677 | """ | 770 | """ |
546 | 678 | This triggers the proper 'Search' search based on which search type is used. | 771 | This triggers the proper 'Search' search based on which search type is used. |
547 | 679 | "Eg. "Reference Search", "Text Search" or "Combined search". | 772 | "Eg. "Reference Search", "Text Search" or "Combined search". |
548 | 680 | """ | 773 | """ |
549 | 774 | self.search_results = [] | ||
550 | 681 | log.debug('text_search called') | 775 | log.debug('text_search called') |
551 | 682 | text = self.search_edit.text() | 776 | text = self.search_edit.text() |
552 | 683 | if text == '': | 777 | if text == '': |
554 | 684 | self.list_view.clear() | 778 | self.display_results() |
555 | 685 | return | 779 | return |
557 | 686 | self.list_view.clear(search_while_typing=search_while_type) | 780 | self.on_results_view_tab_total_update(ResultsTab.Search) |
558 | 687 | if self.search_edit.current_search_type() == BibleSearch.Reference: | 781 | if self.search_edit.current_search_type() == BibleSearch.Reference: |
559 | 688 | if get_reference_match('full').match(text): | 782 | if get_reference_match('full').match(text): |
560 | 689 | # Valid reference found. Do reference search. | 783 | # Valid reference found. Do reference search. |
561 | 690 | self.text_reference_search(text) | 784 | self.text_reference_search(text) |
563 | 691 | elif not search_while_type: | 785 | elif self.search_status == SearchStatus.SearchButton: |
564 | 692 | self.main_window.information_message( | 786 | self.main_window.information_message( |
565 | 693 | translate('BiblesPlugin.BibleManager', 'Scripture Reference Error'), | 787 | translate('BiblesPlugin.BibleManager', 'Scripture Reference Error'), |
566 | 694 | translate('BiblesPlugin.BibleManager', | 788 | translate('BiblesPlugin.BibleManager', |
567 | @@ -700,10 +794,12 @@ | |||
568 | 700 | self.text_reference_search(text) | 794 | self.text_reference_search(text) |
569 | 701 | else: | 795 | else: |
570 | 702 | # It can only be a 'Combined' search without a valid reference, or a 'Text' search | 796 | # It can only be a 'Combined' search without a valid reference, or a 'Text' search |
575 | 703 | if search_while_type: | 797 | if self.search_status == SearchStatus().SearchAsYouType: |
576 | 704 | if len(text) > 8 and VALID_TEXT_SEARCH.search(text): | 798 | if len(text) <= 8: |
577 | 705 | self.on_text_search(text, True) | 799 | self.search_status = SearchStatus.NotEnoughText |
578 | 706 | elif VALID_TEXT_SEARCH.search(text): | 800 | self.display_results() |
579 | 801 | return | ||
580 | 802 | if VALID_TEXT_SEARCH.search(text): | ||
581 | 707 | self.on_text_search(text) | 803 | self.on_text_search(text) |
582 | 708 | 804 | ||
583 | 709 | def on_search_edit_text_changed(self): | 805 | def on_search_edit_text_changed(self): |
584 | @@ -713,9 +809,12 @@ | |||
585 | 713 | 809 | ||
586 | 714 | :return: None | 810 | :return: None |
587 | 715 | """ | 811 | """ |
591 | 716 | if Settings().value('bibles/is search while typing enabled'): | 812 | if not Settings().value('bibles/is search while typing enabled') or \ |
592 | 717 | if not self.search_timer.isActive(): | 813 | not self.bible or self.bible.is_web_bible or \ |
593 | 718 | self.search_timer.start() | 814 | (self.second_bible and self.bible.is_web_bible): |
594 | 815 | return | ||
595 | 816 | if not self.search_timer.isActive(): | ||
596 | 817 | self.search_timer.start() | ||
597 | 719 | 818 | ||
598 | 720 | def on_search_timer_timeout(self): | 819 | def on_search_timer_timeout(self): |
599 | 721 | """ | 820 | """ |
600 | @@ -724,7 +823,9 @@ | |||
601 | 724 | 823 | ||
602 | 725 | :return: None | 824 | :return: None |
603 | 726 | """ | 825 | """ |
605 | 727 | self.text_search(True) | 826 | self.search_status = SearchStatus().SearchAsYouType |
606 | 827 | self.text_search() | ||
607 | 828 | self.results_view_tab.setCurrentIndex(ResultsTab.Search) | ||
608 | 728 | 829 | ||
609 | 729 | def display_results(self): | 830 | def display_results(self): |
610 | 730 | """ | 831 | """ |
611 | @@ -732,14 +833,16 @@ | |||
612 | 732 | 833 | ||
613 | 733 | :return: None | 834 | :return: None |
614 | 734 | """ | 835 | """ |
621 | 735 | self.list_view.clear() | 836 | self.current_results = self.build_display_results(self.bible, self.second_bible, self.search_results) |
616 | 736 | if self.search_results: | ||
617 | 737 | items = self.build_display_results(self.bible, self.second_bible, self.search_results) | ||
618 | 738 | for item in items: | ||
619 | 739 | self.list_view.addItem(item) | ||
620 | 740 | self.list_view.selectAll() | ||
622 | 741 | self.search_results = [] | 837 | self.search_results = [] |
624 | 742 | self.second_search_results = [] | 838 | self.add_built_results_to_list_widget(self.current_results) |
625 | 839 | |||
626 | 840 | def add_built_results_to_list_widget(self, results): | ||
627 | 841 | self.list_view.clear(self.search_status == SearchStatus.NotEnoughText) | ||
628 | 842 | for item in self.build_list_widget_items(results): | ||
629 | 843 | self.list_view.addItem(item) | ||
630 | 844 | self.list_view.selectAll() | ||
631 | 845 | self.on_results_view_tab_total_update(ResultsTab.Search) | ||
632 | 743 | 846 | ||
633 | 744 | def build_display_results(self, bible, second_bible, search_results): | 847 | def build_display_results(self, bible, second_bible, search_results): |
634 | 745 | """ | 848 | """ |
635 | @@ -789,10 +892,17 @@ | |||
636 | 789 | bible_text = '{book} {chapter:d}{sep}{verse:d} ({version}, {second_version})' | 892 | bible_text = '{book} {chapter:d}{sep}{verse:d} ({version}, {second_version})' |
637 | 790 | else: | 893 | else: |
638 | 791 | bible_text = '{book} {chapter:d}{sep}{verse:d} ({version})' | 894 | bible_text = '{book} {chapter:d}{sep}{verse:d} ({version})' |
640 | 792 | bible_verse = QtWidgets.QListWidgetItem(bible_text.format(sep=verse_separator, **data)) | 895 | data['item_title'] = bible_text.format(sep=verse_separator, **data) |
641 | 896 | items.append(data) | ||
642 | 897 | return items | ||
643 | 898 | |||
644 | 899 | def build_list_widget_items(self, items): | ||
645 | 900 | list_widget_items = [] | ||
646 | 901 | for data in items: | ||
647 | 902 | bible_verse = QtWidgets.QListWidgetItem(data['item_title']) | ||
648 | 793 | bible_verse.setData(QtCore.Qt.UserRole, data) | 903 | bible_verse.setData(QtCore.Qt.UserRole, data) |
651 | 794 | items.append(bible_verse) | 904 | list_widget_items.append(bible_verse) |
652 | 795 | return items | 905 | return list_widget_items |
653 | 796 | 906 | ||
654 | 797 | def generate_slide_data(self, service_item, item=None, xml_version=False, remote=False, | 907 | def generate_slide_data(self, service_item, item=None, xml_version=False, remote=False, |
655 | 798 | context=ServiceItemContext.Service): | 908 | context=ServiceItemContext.Service): |
656 | @@ -897,6 +1007,8 @@ | |||
657 | 897 | """ | 1007 | """ |
658 | 898 | Search for some Bible verses (by reference). | 1008 | Search for some Bible verses (by reference). |
659 | 899 | """ | 1009 | """ |
660 | 1010 | if self.bible is None: | ||
661 | 1011 | return [] | ||
662 | 900 | reference = self.plugin.manager.parse_ref(self.bible.name, string) | 1012 | reference = self.plugin.manager.parse_ref(self.bible.name, string) |
663 | 901 | search_results = self.plugin.manager.get_verses(self.bible.name, reference, showError) | 1013 | search_results = self.plugin.manager.get_verses(self.bible.name, reference, showError) |
664 | 902 | if search_results: | 1014 | if search_results: |
665 | @@ -908,6 +1020,9 @@ | |||
666 | 908 | """ | 1020 | """ |
667 | 909 | Create a media item from an item id. | 1021 | Create a media item from an item id. |
668 | 910 | """ | 1022 | """ |
669 | 1023 | if self.bible is None: | ||
670 | 1024 | return [] | ||
671 | 911 | reference = self.plugin.manager.parse_ref(self.bible.name, item_id) | 1025 | reference = self.plugin.manager.parse_ref(self.bible.name, item_id) |
672 | 912 | search_results = self.plugin.manager.get_verses(self.bible.name, reference, False) | 1026 | search_results = self.plugin.manager.get_verses(self.bible.name, reference, False) |
674 | 913 | return self.build_display_results(self.bible, None, search_results) | 1027 | items = self.build_display_results(self.bible, None, search_results) |
675 | 1028 | return self.build_list_widget_items(items) | ||
676 | 914 | 1029 | ||
677 | === added file 'resources/images/bibles_save_results.png' | |||
678 | 915 | Binary files resources/images/bibles_save_results.png 1970-01-01 00:00:00 +0000 and resources/images/bibles_save_results.png 2017-05-07 10:12:27 +0000 differ | 1030 | Binary files resources/images/bibles_save_results.png 1970-01-01 00:00:00 +0000 and resources/images/bibles_save_results.png 2017-05-07 10:12:27 +0000 differ |
679 | === removed file 'resources/images/bibles_search_lock.png' | |||
680 | 916 | Binary files resources/images/bibles_search_lock.png 2011-05-11 23:59:37 +0000 and resources/images/bibles_search_lock.png 1970-01-01 00:00:00 +0000 differ | 1031 | Binary files resources/images/bibles_search_lock.png 2011-05-11 23:59:37 +0000 and resources/images/bibles_search_lock.png 1970-01-01 00:00:00 +0000 differ |
681 | === removed file 'resources/images/bibles_search_unlock.png' | |||
682 | 917 | Binary files resources/images/bibles_search_unlock.png 2011-05-11 23:59:37 +0000 and resources/images/bibles_search_unlock.png 1970-01-01 00:00:00 +0000 differ | 1032 | Binary files resources/images/bibles_search_unlock.png 2011-05-11 23:59:37 +0000 and resources/images/bibles_search_unlock.png 1970-01-01 00:00:00 +0000 differ |
683 | === removed file 'resources/images/network_ssl.png' | |||
684 | 918 | Binary files resources/images/network_ssl.png 2014-04-14 18:09:47 +0000 and resources/images/network_ssl.png 1970-01-01 00:00:00 +0000 differ | 1033 | Binary files resources/images/network_ssl.png 2014-04-14 18:09:47 +0000 and resources/images/network_ssl.png 1970-01-01 00:00:00 +0000 differ |
685 | === modified file 'resources/images/openlp-2.qrc' | |||
686 | --- resources/images/openlp-2.qrc 2016-12-18 14:11:31 +0000 | |||
687 | +++ resources/images/openlp-2.qrc 2017-05-07 10:12:27 +0000 | |||
688 | @@ -34,8 +34,7 @@ | |||
689 | 34 | <file>bibles_search_text.png</file> | 34 | <file>bibles_search_text.png</file> |
690 | 35 | <file>bibles_search_reference.png</file> | 35 | <file>bibles_search_reference.png</file> |
691 | 36 | <file>bibles_search_clear.png</file> | 36 | <file>bibles_search_clear.png</file> |
694 | 37 | <file>bibles_search_unlock.png</file> | 37 | <file>bibles_save_results.png</file> |
693 | 38 | <file>bibles_search_lock.png</file> | ||
695 | 39 | </qresource> | 38 | </qresource> |
696 | 40 | <qresource prefix="plugins"> | 39 | <qresource prefix="plugins"> |
697 | 41 | <file>plugin_alerts.png</file> | 40 | <file>plugin_alerts.png</file> |
698 | @@ -144,7 +143,6 @@ | |||
699 | 144 | </qresource> | 143 | </qresource> |
700 | 145 | <qresource prefix="remote"> | 144 | <qresource prefix="remote"> |
701 | 146 | <file>network_server.png</file> | 145 | <file>network_server.png</file> |
702 | 147 | <file>network_ssl.png</file> | ||
703 | 148 | <file>network_auth.png</file> | 146 | <file>network_auth.png</file> |
704 | 149 | </qresource> | 147 | </qresource> |
705 | 150 | <qresource prefix="songusage"> | 148 | <qresource prefix="songusage"> |
706 | @@ -188,4 +186,4 @@ | |||
707 | 188 | <file>android_app_qr.png</file> | 186 | <file>android_app_qr.png</file> |
708 | 189 | <file>ios_app_qr.png</file> | 187 | <file>ios_app_qr.png</file> |
709 | 190 | </qresource> | 188 | </qresource> |
710 | 191 | </RCC> | ||
711 | 192 | \ No newline at end of file | 189 | \ No newline at end of file |
712 | 190 | </RCC> | ||
713 | 193 | 191 | ||
714 | === modified file 'tests/functional/openlp_core_ui_lib/test_listwidgetwithdnd.py' (properties changed: -x to +x) | |||
715 | --- tests/functional/openlp_core_ui_lib/test_listwidgetwithdnd.py 2017-02-18 07:23:15 +0000 | |||
716 | +++ tests/functional/openlp_core_ui_lib/test_listwidgetwithdnd.py 2017-05-07 10:12:27 +0000 | |||
717 | @@ -23,6 +23,7 @@ | |||
718 | 23 | This module contains tests for the openlp.core.lib.listwidgetwithdnd module | 23 | This module contains tests for the openlp.core.lib.listwidgetwithdnd module |
719 | 24 | """ | 24 | """ |
720 | 25 | from unittest import TestCase | 25 | from unittest import TestCase |
721 | 26 | from types import GeneratorType | ||
722 | 26 | 27 | ||
723 | 27 | from openlp.core.common.uistrings import UiStrings | 28 | from openlp.core.common.uistrings import UiStrings |
724 | 28 | from openlp.core.ui.lib.listwidgetwithdnd import ListWidgetWithDnD | 29 | from openlp.core.ui.lib.listwidgetwithdnd import ListWidgetWithDnD |
725 | @@ -33,37 +34,6 @@ | |||
726 | 33 | """ | 34 | """ |
727 | 34 | Test the :class:`~openlp.core.lib.listwidgetwithdnd.ListWidgetWithDnD` class | 35 | Test the :class:`~openlp.core.lib.listwidgetwithdnd.ListWidgetWithDnD` class |
728 | 35 | """ | 36 | """ |
729 | 36 | def test_clear_locked(self): | ||
730 | 37 | """ | ||
731 | 38 | Test the clear method the list is 'locked' | ||
732 | 39 | """ | ||
733 | 40 | with patch('openlp.core.ui.lib.listwidgetwithdnd.QtWidgets.QListWidget.clear') as mocked_clear_super_method: | ||
734 | 41 | # GIVEN: An instance of ListWidgetWithDnD | ||
735 | 42 | widget = ListWidgetWithDnD() | ||
736 | 43 | |||
737 | 44 | # WHEN: The list is 'locked' and clear has been called | ||
738 | 45 | widget.locked = True | ||
739 | 46 | widget.clear() | ||
740 | 47 | |||
741 | 48 | # THEN: The super method should not have been called (i.e. The list not cleared) | ||
742 | 49 | self.assertFalse(mocked_clear_super_method.called) | ||
743 | 50 | |||
744 | 51 | def test_clear_overide_locked(self): | ||
745 | 52 | """ | ||
746 | 53 | Test the clear method the list is 'locked', but clear is called with 'override_lock' set to True | ||
747 | 54 | """ | ||
748 | 55 | with patch('openlp.core.ui.lib.listwidgetwithdnd.QtWidgets.QListWidget.clear') as mocked_clear_super_method: | ||
749 | 56 | # GIVEN: An instance of ListWidgetWithDnD | ||
750 | 57 | widget = ListWidgetWithDnD() | ||
751 | 58 | |||
752 | 59 | # WHEN: The list is 'locked' and clear has been called with override_lock se to True | ||
753 | 60 | widget.locked = True | ||
754 | 61 | widget.clear(override_lock=True) | ||
755 | 62 | |||
756 | 63 | # THEN: The super method should have been called (i.e. The list is cleared regardless whether it is locked | ||
757 | 64 | # or not) | ||
758 | 65 | mocked_clear_super_method.assert_called_once_with() | ||
759 | 66 | |||
760 | 67 | def test_clear(self): | 37 | def test_clear(self): |
761 | 68 | """ | 38 | """ |
762 | 69 | Test the clear method when called without any arguments. | 39 | Test the clear method when called without any arguments. |
763 | @@ -90,6 +60,38 @@ | |||
764 | 90 | # THEN: The results text should be the 'short results' text. | 60 | # THEN: The results text should be the 'short results' text. |
765 | 91 | self.assertEqual(widget.no_results_text, UiStrings().ShortResults) | 61 | self.assertEqual(widget.no_results_text, UiStrings().ShortResults) |
766 | 92 | 62 | ||
767 | 63 | def test_all_items_no_list_items(self): | ||
768 | 64 | """ | ||
769 | 65 | Test allItems when there are no items in the list widget | ||
770 | 66 | """ | ||
771 | 67 | # GIVEN: An instance of ListWidgetWithDnD | ||
772 | 68 | widget = ListWidgetWithDnD() | ||
773 | 69 | with patch.object(widget, 'count', return_value=0), \ | ||
774 | 70 | patch.object(widget, 'item', side_effect=lambda x: [][x]): | ||
775 | 71 | |||
776 | 72 | # WHEN: Calling allItems | ||
777 | 73 | result = widget.allItems() | ||
778 | 74 | |||
779 | 75 | # THEN: An instance of a Generator object should be returned. The generator should not yeild any results | ||
780 | 76 | self.assertIsInstance(result, GeneratorType) | ||
781 | 77 | self.assertEqual(list(result), []) | ||
782 | 78 | |||
783 | 79 | def test_all_items_list_items(self): | ||
784 | 80 | """ | ||
785 | 81 | Test allItems when the list widget contains some items. | ||
786 | 82 | """ | ||
787 | 83 | # GIVEN: An instance of ListWidgetWithDnD | ||
788 | 84 | widget = ListWidgetWithDnD() | ||
789 | 85 | with patch.object(widget, 'count', return_value=2), \ | ||
790 | 86 | patch.object(widget, 'item', side_effect=lambda x: [5, 3][x]): | ||
791 | 87 | |||
792 | 88 | # WHEN: Calling allItems | ||
793 | 89 | result = widget.allItems() | ||
794 | 90 | |||
795 | 91 | # THEN: An instance of a Generator object should be returned. The generator should not yeild any results | ||
796 | 92 | self.assertIsInstance(result, GeneratorType) | ||
797 | 93 | self.assertEqual(list(result), [5, 3]) | ||
798 | 94 | |||
799 | 93 | def test_paint_event(self): | 95 | def test_paint_event(self): |
800 | 94 | """ | 96 | """ |
801 | 95 | Test the paintEvent method when the list is not empty | 97 | Test the paintEvent method when the list is not empty |
802 | 96 | 98 | ||
803 | === modified file 'tests/functional/openlp_plugins/bibles/test_mediaitem.py' (properties changed: -x to +x) | |||
804 | --- tests/functional/openlp_plugins/bibles/test_mediaitem.py 2017-02-18 07:23:15 +0000 | |||
805 | +++ tests/functional/openlp_plugins/bibles/test_mediaitem.py 2017-05-07 10:12:27 +0000 | |||
806 | @@ -31,7 +31,8 @@ | |||
807 | 31 | 31 | ||
808 | 32 | from openlp.core.common import Registry | 32 | from openlp.core.common import Registry |
809 | 33 | from openlp.core.lib import MediaManagerItem | 33 | from openlp.core.lib import MediaManagerItem |
811 | 34 | from openlp.plugins.bibles.lib.mediaitem import BibleMediaItem, BibleSearch, get_reference_separators, VALID_TEXT_SEARCH | 34 | from openlp.plugins.bibles.lib.mediaitem import BibleMediaItem, BibleSearch, ResultsTab, SearchStatus, \ |
812 | 35 | get_reference_separators, VALID_TEXT_SEARCH | ||
813 | 35 | 36 | ||
814 | 36 | 37 | ||
815 | 37 | class TestBibleMediaItemModulefunctions(TestCase): | 38 | class TestBibleMediaItemModulefunctions(TestCase): |
816 | @@ -143,6 +144,7 @@ | |||
817 | 143 | self.media_item = BibleMediaItem(None, self.mocked_plugin) | 144 | self.media_item = BibleMediaItem(None, self.mocked_plugin) |
818 | 144 | 145 | ||
819 | 145 | self.media_item.settings_section = 'bibles' | 146 | self.media_item.settings_section = 'bibles' |
820 | 147 | self.media_item.results_view_tab = MagicMock() | ||
821 | 146 | 148 | ||
822 | 147 | self.mocked_book_1 = MagicMock(**{'get_name.return_value': 'Book 1', 'book_reference_id': 1}) | 149 | self.mocked_book_1 = MagicMock(**{'get_name.return_value': 'Book 1', 'book_reference_id': 1}) |
823 | 148 | self.mocked_book_2 = MagicMock(**{'get_name.return_value': 'Book 2', 'book_reference_id': 2}) | 150 | self.mocked_book_2 = MagicMock(**{'get_name.return_value': 'Book 2', 'book_reference_id': 2}) |
824 | @@ -658,56 +660,65 @@ | |||
825 | 658 | # THEN: The select_book_combo_box model sort should have been reset | 660 | # THEN: The select_book_combo_box model sort should have been reset |
826 | 659 | self.media_item.select_book_combo_box.model().sort.assert_called_once_with(-1) | 661 | self.media_item.select_book_combo_box.model().sort.assert_called_once_with(-1) |
827 | 660 | 662 | ||
831 | 661 | def test_on_clear_button_clicked(self): | 663 | def test_on_clear_button_clicked_saved_tab(self): |
832 | 662 | """ | 664 | """ |
833 | 663 | Test on_clear_button_clicked | 665 | Test on_clear_button_clicked when the saved tab is selected |
834 | 666 | """ | ||
835 | 667 | # GIVEN: An instance of :class:`MediaManagerItem` and mocked out saved_tab and select_tab and a mocked out | ||
836 | 668 | # list_view and search_edit | ||
837 | 669 | self.media_item.list_view = MagicMock() | ||
838 | 670 | self.media_item.search_edit = MagicMock() | ||
839 | 671 | self.media_item.results_view_tab = MagicMock(**{'currentIndex.return_value': ResultsTab.Saved}) | ||
840 | 672 | self.media_item.saved_results = ['Some', 'Results'] | ||
841 | 673 | with patch.object(self.media_item, 'on_focus'): | ||
842 | 674 | |||
843 | 675 | # WHEN: Calling on_clear_button_clicked | ||
844 | 676 | self.media_item.on_clear_button_clicked() | ||
845 | 677 | |||
846 | 678 | # THEN: The list_view should be cleared | ||
847 | 679 | self.assertEqual(self.media_item.saved_results, []) | ||
848 | 680 | self.media_item.list_view.clear.assert_called_once_with() | ||
849 | 681 | |||
850 | 682 | def test_on_clear_button_clicked_search_tab(self): | ||
851 | 683 | """ | ||
852 | 684 | Test on_clear_button_clicked when the search tab is selected | ||
853 | 664 | """ | 685 | """ |
854 | 665 | # GIVEN: An instance of :class:`MediaManagerItem` and mocked out search_tab and select_tab and a mocked out | 686 | # GIVEN: An instance of :class:`MediaManagerItem` and mocked out search_tab and select_tab and a mocked out |
855 | 666 | # list_view and search_edit | 687 | # list_view and search_edit |
856 | 667 | self.media_item.list_view = MagicMock() | 688 | self.media_item.list_view = MagicMock() |
857 | 668 | self.media_item.search_edit = MagicMock() | 689 | self.media_item.search_edit = MagicMock() |
858 | 690 | self.media_item.results_view_tab = MagicMock(**{'currentIndex.return_value': ResultsTab.Search}) | ||
859 | 691 | self.media_item.current_results = ['Some', 'Results'] | ||
860 | 669 | with patch.object(self.media_item, 'on_focus'): | 692 | with patch.object(self.media_item, 'on_focus'): |
861 | 670 | 693 | ||
862 | 671 | # WHEN: Calling on_clear_button_clicked | 694 | # WHEN: Calling on_clear_button_clicked |
863 | 672 | self.media_item.on_clear_button_clicked() | 695 | self.media_item.on_clear_button_clicked() |
864 | 673 | 696 | ||
865 | 674 | # THEN: The list_view and the search_edit should be cleared | 697 | # THEN: The list_view and the search_edit should be cleared |
866 | 698 | self.assertEqual(self.media_item.current_results, []) | ||
867 | 675 | self.media_item.list_view.clear.assert_called_once_with() | 699 | self.media_item.list_view.clear.assert_called_once_with() |
868 | 676 | self.media_item.search_edit.clear.assert_called_once_with() | 700 | self.media_item.search_edit.clear.assert_called_once_with() |
869 | 677 | 701 | ||
903 | 678 | def test_on_lock_button_toggled_search_tab_lock_icon(self): | 702 | def test_on_save_results_button_clicked(self): |
904 | 679 | """ | 703 | """ |
905 | 680 | Test that "on_lock_button_toggled" toggles the lock properly. | 704 | Test that "on_save_results_button_clicked" saves the results. |
906 | 681 | """ | 705 | """ |
907 | 682 | # GIVEN: An instance of :class:`MediaManagerItem` a mocked sender and list_view | 706 | # GIVEN: An instance of :class:`MediaManagerItem` and a mocked list_view |
908 | 683 | self.media_item.list_view = MagicMock() | 707 | result_1 = MagicMock(**{'data.return_value': 'R1'}) |
909 | 684 | self.media_item.lock_icon = 'lock icon' | 708 | result_2 = MagicMock(**{'data.return_value': 'R2'}) |
910 | 685 | mocked_sender_instance = MagicMock() | 709 | result_3 = MagicMock(**{'data.return_value': 'R3'}) |
911 | 686 | with patch.object(self.media_item, 'sender', return_value=mocked_sender_instance): | 710 | self.media_item.list_view = MagicMock(**{'selectedItems.return_value': [result_1, result_2, result_3]}) |
912 | 687 | 711 | ||
913 | 688 | # WHEN: When the lock_button is checked | 712 | with patch.object(self.media_item, 'on_results_view_tab_total_update') as \ |
914 | 689 | self.media_item.on_lock_button_toggled(True) | 713 | mocked_on_results_view_tab_total_update: |
915 | 690 | 714 | ||
916 | 691 | # THEN: list_view should be 'locked' and the lock icon set | 715 | # WHEN: When the save_results_button is clicked |
917 | 692 | self.assertTrue(self.media_item.list_view.locked) | 716 | self.media_item.on_save_results_button_clicked() |
918 | 693 | mocked_sender_instance.setIcon.assert_called_once_with('lock icon') | 717 | |
919 | 694 | 718 | # THEN: The selected results in the list_view should be added to the 'saved_results' list. And the saved_tab | |
920 | 695 | def test_on_lock_button_toggled_unlock_icon(self): | 719 | # total should be updated. |
921 | 696 | """ | 720 | self.assertEqual(self.media_item.saved_results, ['R1', 'R2', 'R3']) |
922 | 697 | Test that "on_lock_button_toggled" toggles the lock properly. | 721 | mocked_on_results_view_tab_total_update.assert_called_once_with(ResultsTab.Saved) |
890 | 698 | """ | ||
891 | 699 | # GIVEN: An instance of :class:`MediaManagerItem` a mocked sender and list_view | ||
892 | 700 | self.media_item.list_view = MagicMock() | ||
893 | 701 | self.media_item.unlock_icon = 'unlock icon' | ||
894 | 702 | mocked_sender_instance = MagicMock() | ||
895 | 703 | with patch.object(self.media_item, 'sender', return_value=mocked_sender_instance): | ||
896 | 704 | |||
897 | 705 | # WHEN: When the lock_button is unchecked | ||
898 | 706 | self.media_item.on_lock_button_toggled(False) | ||
899 | 707 | |||
900 | 708 | # THEN: list_view should be 'unlocked' and the unlock icon set | ||
901 | 709 | self.assertFalse(self.media_item.list_view.locked) | ||
902 | 710 | mocked_sender_instance.setIcon.assert_called_once_with('unlock icon') | ||
923 | 711 | 722 | ||
924 | 712 | def test_on_style_combo_box_changed(self): | 723 | def test_on_style_combo_box_changed(self): |
925 | 713 | """ | 724 | """ |
926 | @@ -815,7 +826,9 @@ | |||
927 | 815 | self.media_item.list_view = MagicMock(**{'count.return_value': 5}) | 826 | self.media_item.list_view = MagicMock(**{'count.return_value': 5}) |
928 | 816 | self.media_item.style_combo_box = MagicMock() | 827 | self.media_item.style_combo_box = MagicMock() |
929 | 817 | self.media_item.select_book_combo_box = MagicMock() | 828 | self.media_item.select_book_combo_box = MagicMock() |
930 | 829 | self.media_item.search_results = ['list', 'of', 'results'] | ||
931 | 818 | with patch.object(self.media_item, 'initialise_advanced_bible') as mocked_initialise_advanced_bible, \ | 830 | with patch.object(self.media_item, 'initialise_advanced_bible') as mocked_initialise_advanced_bible, \ |
932 | 831 | patch.object(self.media_item, 'display_results'), \ | ||
933 | 819 | patch('openlp.plugins.bibles.lib.mediaitem.critical_error_message_box', | 832 | patch('openlp.plugins.bibles.lib.mediaitem.critical_error_message_box', |
934 | 820 | return_value=QtWidgets.QMessageBox.Yes) as mocked_critical_error_message_box: | 833 | return_value=QtWidgets.QMessageBox.Yes) as mocked_critical_error_message_box: |
935 | 821 | 834 | ||
936 | @@ -825,9 +838,8 @@ | |||
937 | 825 | self.media_item.second_combo_box = MagicMock(**{'currentData.return_value': self.mocked_bible_1}) | 838 | self.media_item.second_combo_box = MagicMock(**{'currentData.return_value': self.mocked_bible_1}) |
938 | 826 | self.media_item.on_second_combo_box_index_changed(5) | 839 | self.media_item.on_second_combo_box_index_changed(5) |
939 | 827 | 840 | ||
941 | 828 | # THEN: The list_view should be cleared and the selected bible should be set as the current bible | 841 | # THEN: The selected bible should be set as the current bible |
942 | 829 | self.assertTrue(mocked_critical_error_message_box.called) | 842 | self.assertTrue(mocked_critical_error_message_box.called) |
943 | 830 | self.media_item.list_view.clear.assert_called_once_with(override_lock=True) | ||
944 | 831 | self.media_item.style_combo_box.setEnabled.assert_called_once_with(False) | 843 | self.media_item.style_combo_box.setEnabled.assert_called_once_with(False) |
945 | 832 | self.assertTrue(mocked_initialise_advanced_bible.called) | 844 | self.assertTrue(mocked_initialise_advanced_bible.called) |
946 | 833 | self.assertEqual(self.media_item.second_bible, self.mocked_bible_1) | 845 | self.assertEqual(self.media_item.second_bible, self.mocked_bible_1) |
947 | @@ -841,7 +853,9 @@ | |||
948 | 841 | self.media_item.list_view = MagicMock(**{'count.return_value': 5}) | 853 | self.media_item.list_view = MagicMock(**{'count.return_value': 5}) |
949 | 842 | self.media_item.style_combo_box = MagicMock() | 854 | self.media_item.style_combo_box = MagicMock() |
950 | 843 | self.media_item.select_book_combo_box = MagicMock() | 855 | self.media_item.select_book_combo_box = MagicMock() |
951 | 856 | self.media_item.search_results = ['list', 'of', 'results'] | ||
952 | 844 | with patch.object(self.media_item, 'initialise_advanced_bible') as mocked_initialise_advanced_bible, \ | 857 | with patch.object(self.media_item, 'initialise_advanced_bible') as mocked_initialise_advanced_bible, \ |
953 | 858 | patch.object(self.media_item, 'display_results'), \ | ||
954 | 845 | patch('openlp.plugins.bibles.lib.mediaitem.critical_error_message_box', | 859 | patch('openlp.plugins.bibles.lib.mediaitem.critical_error_message_box', |
955 | 846 | return_value=QtWidgets.QMessageBox.Yes) as mocked_critical_error_message_box: | 860 | return_value=QtWidgets.QMessageBox.Yes) as mocked_critical_error_message_box: |
956 | 847 | # WHEN: The previously is a bible new selection is None and the user selects yes | 861 | # WHEN: The previously is a bible new selection is None and the user selects yes |
957 | @@ -850,9 +864,8 @@ | |||
958 | 850 | self.media_item.second_combo_box = MagicMock(**{'currentData.return_value': None}) | 864 | self.media_item.second_combo_box = MagicMock(**{'currentData.return_value': None}) |
959 | 851 | self.media_item.on_second_combo_box_index_changed(0) | 865 | self.media_item.on_second_combo_box_index_changed(0) |
960 | 852 | 866 | ||
962 | 853 | # THEN: The list_view should be cleared and the selected bible should be set as the current bible | 867 | # THEN: The selected bible should be set as the current bible |
963 | 854 | self.assertTrue(mocked_critical_error_message_box.called) | 868 | self.assertTrue(mocked_critical_error_message_box.called) |
964 | 855 | self.media_item.list_view.clear.assert_called_once_with(override_lock=True) | ||
965 | 856 | self.media_item.style_combo_box.setEnabled.assert_called_once_with(True) | 869 | self.media_item.style_combo_box.setEnabled.assert_called_once_with(True) |
966 | 857 | self.assertFalse(mocked_initialise_advanced_bible.called) | 870 | self.assertFalse(mocked_initialise_advanced_bible.called) |
967 | 858 | self.assertEqual(self.media_item.second_bible, None) | 871 | self.assertEqual(self.media_item.second_bible, None) |
968 | @@ -1388,8 +1401,9 @@ | |||
969 | 1388 | # WHEN: Calling on_search_timer_timeout | 1401 | # WHEN: Calling on_search_timer_timeout |
970 | 1389 | self.media_item.on_search_timer_timeout() | 1402 | self.media_item.on_search_timer_timeout() |
971 | 1390 | 1403 | ||
974 | 1391 | # THEN: The text_search method should have been called with True | 1404 | # THEN: The search_status should be set to SearchAsYouType and text_search should have been called |
975 | 1392 | mocked_text_search.assert_called_once_with(True) | 1405 | self.assertEqual(self.media_item.search_status, SearchStatus().SearchAsYouType) |
976 | 1406 | mocked_text_search.assert_called_once_with() | ||
977 | 1393 | 1407 | ||
978 | 1394 | def test_display_results_no_results(self): | 1408 | def test_display_results_no_results(self): |
979 | 1395 | """ | 1409 | """ |
980 | @@ -1407,7 +1421,6 @@ | |||
981 | 1407 | self.media_item.display_results() | 1421 | self.media_item.display_results() |
982 | 1408 | 1422 | ||
983 | 1409 | # THEN: No items should be added to the list | 1423 | # THEN: No items should be added to the list |
984 | 1410 | self.media_item.list_view.clear.assert_called_once_with() | ||
985 | 1411 | self.assertFalse(self.media_item.list_view.addItem.called) | 1424 | self.assertFalse(self.media_item.list_view.addItem.called) |
986 | 1412 | 1425 | ||
987 | 1413 | def test_display_results_results(self): | 1426 | def test_display_results_results(self): |
988 | @@ -1415,7 +1428,10 @@ | |||
989 | 1415 | Test the display_results method when there are items to display | 1428 | Test the display_results method when there are items to display |
990 | 1416 | """ | 1429 | """ |
991 | 1417 | # GIVEN: An instance of BibleMediaItem and a mocked build_display_results which returns a list of results | 1430 | # GIVEN: An instance of BibleMediaItem and a mocked build_display_results which returns a list of results |
993 | 1418 | with patch.object(self.media_item, 'build_display_results', return_value=['list', 'items']): | 1431 | with patch.object(self.media_item, 'build_display_results', return_value=[ |
994 | 1432 | {'item_title': 'Title 1'}, {'item_title': 'Title 2'}]), \ | ||
995 | 1433 | patch.object(self.media_item, 'add_built_results_to_list_widget') as \ | ||
996 | 1434 | mocked_add_built_results_to_list_widget: | ||
997 | 1419 | self.media_item.search_results = ['results'] | 1435 | self.media_item.search_results = ['results'] |
998 | 1420 | self.media_item.list_view = MagicMock() | 1436 | self.media_item.list_view = MagicMock() |
999 | 1421 | 1437 | ||
1000 | @@ -1423,5 +1439,5 @@ | |||
1001 | 1423 | self.media_item.display_results() | 1439 | self.media_item.display_results() |
1002 | 1424 | 1440 | ||
1003 | 1425 | # THEN: addItem should have been with the display items | 1441 | # THEN: addItem should have been with the display items |
1006 | 1426 | self.media_item.list_view.clear.assert_called_once_with() | 1442 | mocked_add_built_results_to_list_widget.assert_called_once_with( |
1007 | 1427 | self.assertEqual(self.media_item.list_view.addItem.call_args_list, [call('list'), call('items')]) | 1443 | [{'item_title': 'Title 1'}, {'item_title': 'Title 2'}]) |
1008 | 1428 | 1444 | ||
1009 | === modified file 'tests/interfaces/openlp_plugins/bibles/test_lib_parse_reference.py' | |||
1010 | --- tests/interfaces/openlp_plugins/bibles/test_lib_parse_reference.py 2016-12-31 11:01:36 +0000 | |||
1011 | +++ tests/interfaces/openlp_plugins/bibles/test_lib_parse_reference.py 2017-05-07 10:12:27 +0000 | |||
1012 | @@ -108,7 +108,7 @@ | |||
1013 | 108 | # WHEN asking to parse the bible reference | 108 | # WHEN asking to parse the bible reference |
1014 | 109 | results = parse_reference('Raoul 1', self.manager.db_cache['tests'], MagicMock()) | 109 | results = parse_reference('Raoul 1', self.manager.db_cache['tests'], MagicMock()) |
1015 | 110 | # THEN a verse array should be returned | 110 | # THEN a verse array should be returned |
1017 | 111 | self.assertEqual(False, results, "The bible Search should return False") | 111 | self.assertEqual([], results, "The bible Search should return an empty list") |
1018 | 112 | 112 | ||
1019 | 113 | def test_parse_reference_five(self): | 113 | def test_parse_reference_five(self): |
1020 | 114 | """ | 114 | """ |
Please can you remove the resource file as this makes it difficult to see the changes.
The resource file can be merged in the next request,