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