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