Merge lp:~phill-ridout/openlp/ftw-refactors into lp:openlp

Proposed by Phill
Status: Superseded
Proposed branch: lp:~phill-ridout/openlp/ftw-refactors
Merge into: lp:openlp
Diff against target: 1039 lines (+328/-211)
14 files modified
openlp/core/app.py (+1/-1)
openlp/core/common/httputils.py (+16/-8)
openlp/core/display/render.py (+2/-2)
openlp/core/threading.py (+2/-2)
openlp/core/ui/firsttimeform.py (+78/-94)
openlp/core/ui/firsttimewizard.py (+64/-55)
openlp/core/ui/mainwindow.py (+1/-2)
openlp/core/widgets/widgets.py (+28/-0)
openlp/plugins/songs/lib/importers/openlp.py (+1/-1)
openlp/plugins/songs/reporting.py (+0/-7)
tests/functional/openlp_core/common/test_httputils.py (+1/-1)
tests/functional/openlp_core/test_threading.py (+5/-9)
tests/functional/openlp_core/ui/test_firsttimeform.py (+123/-23)
tests/functional/openlp_plugins/songs/test_openlpimporter.py (+6/-6)
To merge this branch: bzr merge lp:~phill-ridout/openlp/ftw-refactors
Reviewer Review Type Date Requested Status
Tim Bentley Approve
Tomas Groth Pending
Review via email: mp+364184@code.launchpad.net

This proposal supersedes a proposal from 2019-03-08.

This proposal has been superseded by a proposal from 2019-03-08.

Commit message

Add proxy settings to ftw. Option to skip sample data

Description of the change

Add option to skip downloading.
Add dialog for proxy settings to FTW
FTW refactors.
General fixes.

To post a comment you must log in.
Revision history for this message
Raoul Snyman (raoul-snyman) wrote : Posted in a previous version of this proposal

Linux tests failed, please see https://ci.openlp.io/job/MP-02-Linux_Tests/89/ for more details

Revision history for this message
Raoul Snyman (raoul-snyman) wrote : Posted in a previous version of this proposal

Linux tests failed, please see https://ci.openlp.io/job/MP-02-Linux_Tests/90/ for more details

Revision history for this message
Raoul Snyman (raoul-snyman) wrote : Posted in a previous version of this proposal

Linux tests passed!

Revision history for this message
Raoul Snyman (raoul-snyman) wrote : Posted in a previous version of this proposal

Linting failed, please see https://ci.openlp.io/job/MP-03-Linting/41/ for more details

Revision history for this message
Tomas Groth (tomasgroth) wrote : Posted in a previous version of this proposal

Some code style needs fixing - see link above

review: Needs Fixing
Revision history for this message
Raoul Snyman (raoul-snyman) wrote : Posted in a previous version of this proposal

Linux tests passed!

Revision history for this message
Raoul Snyman (raoul-snyman) wrote : Posted in a previous version of this proposal

Linting failed, please see https://ci.openlp.io/job/MP-03-Linting/49/ for more details

Revision history for this message
Raoul Snyman (raoul-snyman) wrote :

Linux tests passed!

Revision history for this message
Raoul Snyman (raoul-snyman) wrote :

Linting failed, please see https://ci.openlp.io/job/MP-03-Linting/50/ for more details

2850. By Phill

PEP fixes

Revision history for this message
Tim Bentley (trb143) :
review: Approve
2851. By Phill

mac test fix?

2852. By Phill

Test fixes

2853. By Phill

HEAD

2854. By Phill

Test fix

2855. By Phill

PEP8

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'openlp/core/app.py'
2--- openlp/core/app.py 2019-02-14 15:09:09 +0000
3+++ openlp/core/app.py 2019-03-08 21:25:50 +0000
4@@ -101,7 +101,7 @@
5 ftw.initialize(screens)
6 if ftw.exec() == QtWidgets.QDialog.Accepted:
7 Settings().setValue('core/has run wizard', True)
8- elif ftw.was_cancelled:
9+ else:
10 QtCore.QCoreApplication.exit()
11 sys.exit()
12 # Correct stylesheet bugs
13
14=== modified file 'openlp/core/common/httputils.py'
15--- openlp/core/common/httputils.py 2019-02-21 21:29:00 +0000
16+++ openlp/core/common/httputils.py 2019-03-08 21:25:50 +0000
17@@ -158,16 +158,20 @@
18 return response.text
19
20
21-def get_url_file_size(url):
22+def get_url_file_size(url, proxy=None):
23 """
24 Get the size of a file.
25
26 :param url: The URL of the file we want to download.
27+ :param dict | ProxyMode | None proxy: ProxyMode enum or a dictionary containing the proxy servers, with their types
28+ as the key e.g. {'http': 'http://proxyserver:port', 'https': 'https://proxyserver:port'}
29 """
30 retries = 0
31+ if not isinstance(proxy, dict):
32+ proxy = get_proxy_settings(mode=proxy)
33 while True:
34 try:
35- response = requests.head(url, timeout=float(CONNECTION_TIMEOUT), allow_redirects=True)
36+ response = requests.head(url, proxies=proxy, timeout=float(CONNECTION_TIMEOUT), allow_redirects=True)
37 return int(response.headers['Content-Length'])
38 except OSError:
39 if retries > CONNECTION_RETRIES:
40@@ -178,7 +182,7 @@
41 continue
42
43
44-def download_file(update_object, url, file_path, sha256=None):
45+def download_file(update_object, url, file_path, sha256=None, proxy=None):
46 """"
47 Download a file given a URL. The file is retrieved in chunks, giving the ability to cancel the download at any
48 point. Returns False on download error.
49@@ -187,15 +191,19 @@
50 :param url: URL to download
51 :param file_path: Destination file
52 :param sha256: The check sum value to be checked against the download value
53+ :param dict | ProxyMode | None proxy: ProxyMode enum or a dictionary containing the proxy servers, with their types
54+ as the key e.g. {'http': 'http://proxyserver:port', 'https': 'https://proxyserver:port'}
55 """
56 block_count = 0
57 block_size = 4096
58 retries = 0
59+ if not isinstance(proxy, dict):
60+ proxy = get_proxy_settings(mode=proxy)
61 log.debug('url_get_file: %s', url)
62 while retries < CONNECTION_RETRIES:
63 try:
64 with file_path.open('wb') as saved_file:
65- response = requests.get(url, timeout=float(CONNECTION_TIMEOUT), stream=True)
66+ response = requests.get(url, proxies=proxy, timeout=float(CONNECTION_TIMEOUT), stream=True)
67 if sha256:
68 hasher = hashlib.sha256()
69 # Download until finished or canceled.
70@@ -244,21 +252,21 @@
71 """
72 self._base_url = base_url
73 self._file_name = file_name
74- self._download_cancelled = False
75+ self.was_cancelled = False
76 super().__init__()
77
78 def start(self):
79 """
80 Download the url to the temporary directory
81 """
82- if self._download_cancelled:
83+ if self.was_cancelled:
84 self.quit.emit()
85 return
86 try:
87 dest_path = Path(gettempdir()) / 'openlp' / self._file_name
88 url = '{url}{name}'.format(url=self._base_url, name=self._file_name)
89 is_success = download_file(self, url, dest_path)
90- if is_success and not self._download_cancelled:
91+ if is_success and not self.was_cancelled:
92 self.download_succeeded.emit(dest_path)
93 else:
94 self.download_failed.emit()
95@@ -273,4 +281,4 @@
96 """
97 A slot to allow the download to be cancelled from outside of the thread
98 """
99- self._download_cancelled = True
100+ self.was_cancelled = True
101
102=== modified file 'openlp/core/display/render.py'
103--- openlp/core/display/render.py 2019-02-19 21:38:44 +0000
104+++ openlp/core/display/render.py 2019-03-08 21:25:50 +0000
105@@ -43,8 +43,8 @@
106 log = logging.getLogger(__name__)
107
108 SLIM_CHARS = 'fiíIÍjlĺľrtť.,;/ ()|"\'!:\\'
109-CHORD_LINE_MATCH = re.compile(r'\[(.*?)\]([\u0080-\uFFFF,\w]*)' # noqa
110- '([\u0080-\uFFFF,\w,\s,\.,\,,\!,\?,\;,\:,\|,\",\',\-,\_]*)(\Z)?')
111+CHORD_LINE_MATCH = re.compile(r'\[(.*?)\]([\u0080-\uFFFF,\w]*)'
112+ r'([\u0080-\uFFFF,\w,\s,\.,\,,\!,\?,\;,\:,\|,\",\',\-,\_]*)(\Z)?')
113 CHORD_TEMPLATE = '<span class="chordline">{chord}</span>'
114 FIRST_CHORD_TEMPLATE = '<span class="chordline firstchordline">{chord}</span>'
115 CHORD_LINE_TEMPLATE = '<span class="chord"><span><strong>{chord}</strong></span></span>{tail}{whitespace}{remainder}'
116
117=== modified file 'openlp/core/threading.py'
118--- openlp/core/threading.py 2019-02-14 15:09:09 +0000
119+++ openlp/core/threading.py 2019-03-08 21:25:50 +0000
120@@ -76,11 +76,11 @@
121 Get the worker by the thread name
122
123 :param str thread_name: The name of the thread
124- :returns: The worker for this thread name
125+ :returns: The worker for this thread name, or None
126 """
127 thread_info = Registry().get('application').worker_threads.get(thread_name)
128 if not thread_info:
129- raise KeyError('No thread named "{}" exists'.format(thread_name))
130+ return
131 return thread_info.get('worker')
132
133
134
135=== modified file 'openlp/core/ui/firsttimeform.py'
136--- openlp/core/ui/firsttimeform.py 2019-02-21 21:29:00 +0000
137+++ openlp/core/ui/firsttimeform.py 2019-03-08 21:25:50 +0000
138@@ -32,7 +32,7 @@
139
140 from PyQt5 import QtCore, QtWidgets
141
142-from openlp.core.common import clean_button_text, trace_error_handler
143+from openlp.core.common import trace_error_handler
144 from openlp.core.common.applocation import AppLocation
145 from openlp.core.common.httputils import DownloadWorker, download_file, get_url_file_size, get_web_page
146 from openlp.core.common.i18n import translate
147@@ -46,6 +46,7 @@
148 from openlp.core.threading import get_thread_worker, is_thread_finished, run_thread
149 from openlp.core.ui.firsttimewizard import FirstTimePage, UiFirstTimeWizard
150 from openlp.core.ui.icons import UiIcons
151+from openlp.core.widgets.widgets import ProxyDialog
152
153
154 log = logging.getLogger(__name__)
155@@ -91,7 +92,7 @@
156
157 class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties):
158 """
159- This is the Theme Import Wizard, which allows easy creation and editing of OpenLP themes.
160+ This is the FirstTimeWizard, designed to help new users to get up and running quickly.
161 """
162 log.info('ThemeWizardForm loaded')
163
164@@ -103,6 +104,7 @@
165 self.web_access = True
166 self.web = ''
167 self.setup_ui(self)
168+ self.customButtonClicked.connect(self._on_custom_button_clicked)
169 self.themes_list_widget.itemSelectionChanged.connect(self.on_themes_list_widget_selection_changed)
170 self.themes_deselect_all_button.clicked.connect(self.themes_list_widget.clearSelection)
171 self.themes_select_all_button.clicked.connect(self.themes_list_widget.selectAll)
172@@ -111,13 +113,13 @@
173 """
174 Returns the id of the next FirstTimePage to go to based on enabled plugins
175 """
176- if FirstTimePage.ScreenConfig < self.currentId() < FirstTimePage.Songs and self.songs_check_box.isChecked():
177+ if FirstTimePage.Download < self.currentId() < FirstTimePage.Songs and self.songs_check_box.isChecked():
178 # If the songs plugin is enabled then go to the songs page
179 return FirstTimePage.Songs
180- elif FirstTimePage.ScreenConfig < self.currentId() < FirstTimePage.Bibles and self.bible_check_box.isChecked():
181+ elif FirstTimePage.Download < self.currentId() < FirstTimePage.Bibles and self.bible_check_box.isChecked():
182 # Otherwise, if the Bibles plugin is enabled then go to the Bibles page
183 return FirstTimePage.Bibles
184- elif FirstTimePage.ScreenConfig < self.currentId() < FirstTimePage.Themes:
185+ elif FirstTimePage.Download < self.currentId() < FirstTimePage.Themes:
186 # Otherwise, if the current page is somewhere between the Welcome and the Themes pages, go to the themes
187 return FirstTimePage.Themes
188 else:
189@@ -133,9 +135,7 @@
190 if not self.web_access:
191 return FirstTimePage.NoInternet
192 else:
193- return FirstTimePage.Plugins
194- elif self.currentId() == FirstTimePage.Plugins:
195- return self.get_next_page_id()
196+ return FirstTimePage.Songs
197 elif self.currentId() == FirstTimePage.Progress:
198 return -1
199 elif self.currentId() == FirstTimePage.NoInternet:
200@@ -147,7 +147,7 @@
201 Run the wizard.
202 """
203 self.set_defaults()
204- return QtWidgets.QWizard.exec(self)
205+ return super().exec()
206
207 def initialize(self, screens):
208 """
209@@ -227,17 +227,13 @@
210 """
211 self.restart()
212 self.web = 'https://get.openlp.org/ftw/'
213- self.cancel_button.clicked.connect(self.on_cancel_button_clicked)
214- self.no_internet_finish_button.clicked.connect(self.on_no_internet_finish_button_clicked)
215- self.no_internet_cancel_button.clicked.connect(self.on_no_internet_cancel_button_clicked)
216 self.currentIdChanged.connect(self.on_current_id_changed)
217 Registry().register_function('config_screen_changed', self.screen_selection_widget.load)
218- self.no_internet_finish_button.setVisible(False)
219- self.no_internet_cancel_button.setVisible(False)
220 # Check if this is a re-run of the wizard.
221 self.has_run_wizard = Settings().value('core/has run wizard')
222 create_paths(Path(gettempdir(), 'openlp'))
223 self.theme_combo_box.clear()
224+ self.button(QtWidgets.QWizard.CustomButton1).setVisible(False)
225 if self.has_run_wizard:
226 self.songs_check_box.setChecked(self.plugin_manager.get_plugin_by_name('songs').is_active())
227 self.bible_check_box.setChecked(self.plugin_manager.get_plugin_by_name('bibles').is_active())
228@@ -260,57 +256,85 @@
229 """
230 Detects Page changes and updates as appropriate.
231 """
232- # Keep track of the page we are at. Triggering "Cancel" causes page_id to be a -1.
233+ back_button = self.button(QtWidgets.QWizard.BackButton)
234+ cancel_button = self.button(QtWidgets.QWizard.CancelButton)
235+ internet_settings_button = self.button(QtWidgets.QWizard.CustomButton1)
236+ next_button = self.button(QtWidgets.QWizard.NextButton)
237+ back_button.setVisible(True)
238+ next_button.setVisible(True)
239+ internet_settings_button.setVisible(False)
240 self.application.process_events()
241- if page_id != -1:
242- self.last_id = page_id
243- if page_id == FirstTimePage.Download:
244- self.back_button.setVisible(False)
245- self.next_button.setVisible(False)
246- # Set the no internet page text.
247- if self.has_run_wizard:
248- self.no_internet_label.setText(self.no_internet_text)
249- else:
250- self.no_internet_label.setText(self.no_internet_text + self.cancel_wizard_text)
251+ if page_id == FirstTimePage.SampleOption:
252+ internet_settings_button.setVisible(True)
253+ elif page_id == FirstTimePage.Download:
254+ back_button.setVisible(False)
255+ next_button.setVisible(False)
256 self.application.set_busy_cursor()
257 self._download_index()
258 self.application.set_normal_cursor()
259- self.back_button.setVisible(False)
260- self.next_button.setVisible(True)
261 self.next()
262 elif page_id == FirstTimePage.NoInternet:
263- self.back_button.setVisible(False)
264- self.next_button.setVisible(False)
265- self.cancel_button.setVisible(False)
266- self.no_internet_finish_button.setVisible(True)
267- if self.has_run_wizard:
268- self.no_internet_cancel_button.setVisible(False)
269- else:
270- self.no_internet_cancel_button.setVisible(True)
271- elif page_id == FirstTimePage.Plugins:
272- self.back_button.setVisible(False)
273+ next_button.setVisible(False)
274+ cancel_button.setVisible(False)
275+ internet_settings_button.setVisible(True)
276 elif page_id == FirstTimePage.Progress:
277+ back_button.setVisible(False)
278+ next_button.setVisible(False)
279 self.application.set_busy_cursor()
280 self._pre_wizard()
281 self._perform_wizard()
282 self._post_wizard()
283 self.application.set_normal_cursor()
284
285- def on_cancel_button_clicked(self):
286- """
287- Process the triggering of the cancel button.
288+ def accept(self):
289+ """
290+ Called when the user clicks 'Finish'. Reimplement it to to save the plugin status
291+
292+ :rtype: None
293+ """
294+ self._set_plugin_status(self.songs_check_box, 'songs/status')
295+ self._set_plugin_status(self.bible_check_box, 'bibles/status')
296+ self._set_plugin_status(self.presentation_check_box, 'presentations/status')
297+ self._set_plugin_status(self.image_check_box, 'images/status')
298+ self._set_plugin_status(self.media_check_box, 'media/status')
299+ self._set_plugin_status(self.custom_check_box, 'custom/status')
300+ self._set_plugin_status(self.song_usage_check_box, 'songusage/status')
301+ self._set_plugin_status(self.alert_check_box, 'alerts/status')
302+ self.screen_selection_widget.save()
303+ if self.theme_combo_box.currentIndex() != -1:
304+ Settings().setValue('themes/global theme', self.theme_combo_box.currentText())
305+ super().accept()
306+
307+ def reject(self):
308+ """
309+ Called when the user clicks the cancel button. Reimplement it to clean up the threads.
310+
311+ :rtype: None
312 """
313 self.was_cancelled = True
314- if self.thumbnail_download_threads: # TODO: Use main thread list
315- for thread_name in self.thumbnail_download_threads:
316- worker = get_thread_worker(thread_name)
317- if worker:
318- worker.cancel_download()
319+ for thread_name in self.thumbnail_download_threads:
320+ worker = get_thread_worker(thread_name)
321+ if worker:
322+ worker.cancel_download()
323 # Was the thread created.
324 if self.thumbnail_download_threads:
325 while any([not is_thread_finished(thread_name) for thread_name in self.thumbnail_download_threads]):
326 time.sleep(0.1)
327 self.application.set_normal_cursor()
328+ super().reject()
329+
330+ def _on_custom_button_clicked(self, which):
331+ """
332+ Slot to handle the a click on one of the wizards custom buttons.
333+
334+ :param int QtWidgets.QWizard which: The button pressed
335+ :rtype: None
336+ """
337+ # Internet settings button
338+ if which == QtWidgets.QWizard.CustomButton1:
339+ proxy_dialog = ProxyDialog(self)
340+ proxy_dialog.retranslate_ui()
341+ proxy_dialog.exec()
342
343 def on_themes_list_widget_selection_changed(self):
344 """
345@@ -330,23 +354,6 @@
346 elif not item.isSelected() and cbox_index != -1:
347 self.theme_combo_box.removeItem(cbox_index)
348
349- def on_no_internet_finish_button_clicked(self):
350- """
351- Process the triggering of the "Finish" button on the No Internet page.
352- """
353- self.application.set_busy_cursor()
354- self._perform_wizard()
355- self.application.set_normal_cursor()
356- Settings().setValue('core/has run wizard', True)
357- self.close()
358-
359- def on_no_internet_cancel_button_clicked(self):
360- """
361- Process the triggering of the "Cancel" button on the No Internet page.
362- """
363- self.was_cancelled = True
364- self.close()
365-
366 def update_progress(self, count, block_size):
367 """
368 Calculate and display the download progress. This method is called by download_file().
369@@ -373,7 +380,7 @@
370 Prepare the UI for the process.
371 """
372 self.max_progress = 0
373- self.finish_button.setVisible(False)
374+ self.button(QtWidgets.QWizard.FinishButton).setEnabled(False)
375 self.application.process_events()
376 try:
377 # Loop through the songs list and increase for each selected item
378@@ -432,54 +439,31 @@
379 self.progress_bar.setValue(self.progress_bar.maximum())
380 if self.has_run_wizard:
381 text = translate('OpenLP.FirstTimeWizard',
382- 'Download complete. Click the {button} button to return to OpenLP.'
383- ).format(button=clean_button_text(self.buttonText(QtWidgets.QWizard.FinishButton)))
384- self.progress_label.setText(text)
385+ 'Download complete. Click the \'{finish_button}\' button to return to OpenLP.')
386 else:
387 text = translate('OpenLP.FirstTimeWizard',
388- 'Download complete. Click the {button} button to start OpenLP.'
389- ).format(button=clean_button_text(self.buttonText(QtWidgets.QWizard.FinishButton)))
390- self.progress_label.setText(text)
391+ 'Download complete. Click the \'{finish_button}\' button to start OpenLP.')
392 else:
393 if self.has_run_wizard:
394- text = translate('OpenLP.FirstTimeWizard',
395- 'Click the {button} button to return to OpenLP.'
396- ).format(button=clean_button_text(self.buttonText(QtWidgets.QWizard.FinishButton)))
397- self.progress_label.setText(text)
398+ text = translate('OpenLP.FirstTimeWizard', 'Click the \'{finish_button}\' button to return to OpenLP.')
399 else:
400- text = translate('OpenLP.FirstTimeWizard',
401- 'Click the {button} button to start OpenLP.'
402- ).format(button=clean_button_text(self.buttonText(QtWidgets.QWizard.FinishButton)))
403- self.progress_label.setText(text)
404- self.finish_button.setVisible(True)
405- self.finish_button.setEnabled(True)
406- self.cancel_button.setVisible(False)
407- self.next_button.setVisible(False)
408+ text = translate('OpenLP.FirstTimeWizard', 'Click the \'{finish_button}\' button to start OpenLP.')
409+ self.progress_label.setText(text.format(finish_button=self.finish_button_text))
410+ self.button(QtWidgets.QWizard.FinishButton).setEnabled(True)
411+ self.button(QtWidgets.QWizard.CancelButton).setVisible(False)
412 self.application.process_events()
413
414 def _perform_wizard(self):
415 """
416 Run the tasks in the wizard.
417 """
418- # Set plugin states
419- self._increment_progress_bar(translate('OpenLP.FirstTimeWizard', 'Enabling selected plugins...'))
420- self._set_plugin_status(self.songs_check_box, 'songs/status')
421- self._set_plugin_status(self.bible_check_box, 'bibles/status')
422- self._set_plugin_status(self.presentation_check_box, 'presentations/status')
423- self._set_plugin_status(self.image_check_box, 'images/status')
424- self._set_plugin_status(self.media_check_box, 'media/status')
425- self._set_plugin_status(self.custom_check_box, 'custom/status')
426- self._set_plugin_status(self.song_usage_check_box, 'songusage/status')
427- self._set_plugin_status(self.alert_check_box, 'alerts/status')
428+
429 if self.web_access:
430 if not self._download_selected():
431 critical_error_message_box(translate('OpenLP.FirstTimeWizard', 'Download Error'),
432 translate('OpenLP.FirstTimeWizard', 'There was a connection problem while '
433 'downloading, so further downloads will be skipped. Try to re-run '
434 'the First Time Wizard later.'))
435- self.screen_selection_widget.save()
436- if self.theme_combo_box.currentIndex() != -1:
437- Settings().setValue('themes/global theme', self.theme_combo_box.currentText())
438
439 def _download_selected(self):
440 """
441
442=== modified file 'openlp/core/ui/firsttimewizard.py'
443--- openlp/core/ui/firsttimewizard.py 2019-02-15 22:34:53 +0000
444+++ openlp/core/ui/firsttimewizard.py 2019-03-08 21:25:50 +0000
445@@ -39,14 +39,15 @@
446 An enumeration class with each of the pages of the wizard.
447 """
448 Welcome = 0
449- ScreenConfig = 1
450- Download = 2
451- NoInternet = 3
452- Plugins = 4
453- Songs = 5
454- Bibles = 6
455- Themes = 7
456- Progress = 8
457+ Plugins = 1
458+ ScreenConfig = 2
459+ SampleOption = 3
460+ Download = 4
461+ NoInternet = 5
462+ Songs = 6
463+ Bibles = 7
464+ Themes = 8
465+ Progress = 9
466
467
468 class ThemeListWidget(QtWidgets.QListWidget):
469@@ -97,20 +98,13 @@
470 first_time_wizard.resize(550, 386)
471 first_time_wizard.setModal(True)
472 first_time_wizard.setOptions(QtWidgets.QWizard.IndependentPages | QtWidgets.QWizard.NoBackButtonOnStartPage |
473- QtWidgets.QWizard.NoBackButtonOnLastPage | QtWidgets.QWizard.HaveCustomButton1 |
474- QtWidgets.QWizard.HaveCustomButton2)
475+ QtWidgets.QWizard.NoBackButtonOnLastPage | QtWidgets.QWizard.HaveCustomButton1)
476 if is_macosx(): # pragma: nocover
477 first_time_wizard.setPixmap(QtWidgets.QWizard.BackgroundPixmap,
478 QtGui.QPixmap(':/wizards/openlp-osx-wizard.png'))
479 first_time_wizard.resize(634, 386)
480 else:
481 first_time_wizard.setWizardStyle(QtWidgets.QWizard.ModernStyle)
482- self.finish_button = self.button(QtWidgets.QWizard.FinishButton)
483- self.no_internet_finish_button = self.button(QtWidgets.QWizard.CustomButton1)
484- self.cancel_button = self.button(QtWidgets.QWizard.CancelButton)
485- self.no_internet_cancel_button = self.button(QtWidgets.QWizard.CustomButton2)
486- self.next_button = self.button(QtWidgets.QWizard.NextButton)
487- self.back_button = self.button(QtWidgets.QWizard.BackButton)
488 add_welcome_page(first_time_wizard, ':/wizards/wizard_firsttime.bmp')
489 # The screen config page
490 self.screen_page = QtWidgets.QWizardPage()
491@@ -121,6 +115,18 @@
492 self.screen_selection_widget.load()
493 self.screen_page_layout.addRow(self.screen_selection_widget)
494 first_time_wizard.setPage(FirstTimePage.ScreenConfig, self.screen_page)
495+ # Download Samples page
496+ self.resource_page = QtWidgets.QWizardPage()
497+ self.resource_page.setObjectName('resource_page')
498+ self.resource_page.setFinalPage(True)
499+ self.resource_layout = QtWidgets.QVBoxLayout(self.resource_page)
500+ self.resource_layout.setContentsMargins(50, 20, 50, 20)
501+ self.resource_layout.setObjectName('resource_layout')
502+ self.resource_label = QtWidgets.QLabel(self.resource_page)
503+ self.resource_label.setObjectName('resource_label')
504+ self.resource_label.setWordWrap(True)
505+ self.resource_layout.addWidget(self.resource_label)
506+ first_time_wizard.setPage(FirstTimePage.SampleOption, self.resource_page)
507 # The download page
508 self.download_page = QtWidgets.QWizardPage()
509 self.download_page.setObjectName('download_page')
510@@ -134,6 +140,7 @@
511 # The "you don't have an internet connection" page.
512 self.no_internet_page = QtWidgets.QWizardPage()
513 self.no_internet_page.setObjectName('no_internet_page')
514+ self.no_internet_page.setFinalPage(True)
515 self.no_internet_layout = QtWidgets.QVBoxLayout(self.no_internet_page)
516 self.no_internet_layout.setContentsMargins(50, 30, 50, 40)
517 self.no_internet_layout.setObjectName('no_internet_layout')
518@@ -242,27 +249,32 @@
519 self.progress_bar.setObjectName('progress_bar')
520 self.progress_layout.addWidget(self.progress_bar)
521 first_time_wizard.setPage(FirstTimePage.Progress, self.progress_page)
522- self.retranslate_ui(first_time_wizard)
523+ self.retranslate_ui()
524
525- def retranslate_ui(self, first_time_wizard):
526+ def retranslate_ui(self):
527 """
528 Translate the UI on the fly
529
530 :param first_time_wizard: The wizard form
531 """
532- first_time_wizard.setWindowTitle(translate('OpenLP.FirstTimeWizard', 'First Time Wizard'))
533+ self.finish_button_text = clean_button_text(self.buttonText(QtWidgets.QWizard.FinishButton))
534+ back_button_text = clean_button_text(self.buttonText(QtWidgets.QWizard.BackButton))
535+ next_button_text = clean_button_text(self.buttonText(QtWidgets.QWizard.NextButton))
536+
537+ self.setWindowTitle(translate('OpenLP.FirstTimeWizard', 'First Time Wizard'))
538 text = translate('OpenLP.FirstTimeWizard', 'Welcome to the First Time Wizard')
539- first_time_wizard.title_label.setText('<span style="font-size:14pt; font-weight:600;">{text}'
540- '</span>'.format(text=text))
541- button = clean_button_text(first_time_wizard.buttonText(QtWidgets.QWizard.NextButton))
542- first_time_wizard.information_label.setText(
543+ self.title_label.setText('<span style="font-size:14pt; font-weight:600;">{text}</span>'.format(text=text))
544+ self.information_label.setText(
545 translate('OpenLP.FirstTimeWizard', 'This wizard will help you to configure OpenLP for initial use. '
546- 'Click the {button} button below to start.').format(button=button))
547+ 'Click the \'{next_button}\' button below to start.'
548+ ).format(next_button=next_button_text))
549+ self.setButtonText(
550+ QtWidgets.QWizard.CustomButton1, translate('OpenLP.FirstTimeWizard', 'Internet Settings'))
551 self.download_page.setTitle(translate('OpenLP.FirstTimeWizard', 'Downloading Resource Index'))
552- self.download_page.setSubTitle(translate('OpenLP.FirstTimeWizard', 'Please wait while the resource index is '
553- 'downloaded.'))
554- self.download_label.setText(translate('OpenLP.FirstTimeWizard', 'Please wait while OpenLP downloads the '
555- 'resource index file...'))
556+ self.download_page.setSubTitle(translate('OpenLP.FirstTimeWizard',
557+ 'Please wait while the resource index is downloaded.'))
558+ self.download_label.setText(translate('OpenLP.FirstTimeWizard',
559+ 'Please wait while OpenLP downloads the resource index file...'))
560 self.plugin_page.setTitle(translate('OpenLP.FirstTimeWizard', 'Select parts of the program you wish to use'))
561 self.plugin_page.setSubTitle(translate('OpenLP.FirstTimeWizard',
562 'You can also change these settings after the Wizard.'))
563@@ -270,11 +282,10 @@
564 self.screen_page.setSubTitle(translate('OpenLP.FirstTimeWizard',
565 'Choose the main display screen for OpenLP.'))
566 self.songs_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Songs'))
567- self.custom_check_box.setText(translate('OpenLP.FirstTimeWizard',
568- 'Custom Slides – Easier to manage than songs and they have their own'
569- ' list of slides'))
570- self.bible_check_box.setText(translate('OpenLP.FirstTimeWizard',
571- 'Bibles – Import and show Bibles'))
572+ self.custom_check_box.setText(
573+ translate('OpenLP.FirstTimeWizard',
574+ 'Custom Slides – Easier to manage than songs and they have their own list of slides'))
575+ self.bible_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Bibles – Import and show Bibles'))
576 self.image_check_box.setText(translate('OpenLP.FirstTimeWizard',
577 'Images – Show images or replace background with them'))
578 self.presentation_check_box.setText(translate('OpenLP.FirstTimeWizard',
579@@ -283,22 +294,25 @@
580 self.song_usage_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Song Usage Monitor'))
581 self.alert_check_box.setText(translate('OpenLP.FirstTimeWizard',
582 'Alerts – Display informative messages while showing other slides'))
583+ self.resource_page.setTitle(translate('OpenLP.FirstTimeWizard', 'Resource Data'))
584+ self.resource_page.setSubTitle(translate('OpenLP.FirstTimeWizard', 'Can OpenLP download some resource data?'))
585+ self.resource_label.setText(
586+ translate('OpenLP.FirstTimeWizard',
587+ 'OpenLP has collected some resources that we have permission to distribute.\n\n'
588+ 'If you would like to download some of these resources click the \'{next_button}\' button, '
589+ 'otherwise click the \'{finish_button}\' button.'
590+ ).format(next_button=next_button_text, finish_button=self.finish_button_text))
591 self.no_internet_page.setTitle(translate('OpenLP.FirstTimeWizard', 'No Internet Connection'))
592- self.no_internet_page.setSubTitle(
593- translate('OpenLP.FirstTimeWizard', 'Unable to detect an Internet connection.'))
594- button = clean_button_text(first_time_wizard.buttonText(QtWidgets.QWizard.FinishButton))
595- self.no_internet_text = translate('OpenLP.FirstTimeWizard',
596- 'No Internet connection was found. The First Time Wizard needs an Internet '
597- 'connection in order to be able to download sample songs, Bibles and themes.'
598- ' Click the {button} button now to start OpenLP with initial settings and '
599- 'no sample data.\n\nTo re-run the First Time Wizard and import this sample '
600- 'data at a later time, check your Internet connection and re-run this '
601- 'wizard by selecting "Tools/Re-run First Time Wizard" from OpenLP.'
602- ).format(button=button)
603- button = clean_button_text(first_time_wizard.buttonText(QtWidgets.QWizard.CancelButton))
604- self.cancel_wizard_text = translate('OpenLP.FirstTimeWizard',
605- '\n\nTo cancel the First Time Wizard completely (and not start OpenLP), '
606- 'click the {button} button now.').format(button=button)
607+ self.no_internet_page.setSubTitle(translate('OpenLP.FirstTimeWizard', 'Cannot connect to the internet.'))
608+ self.no_internet_label.setText(
609+ translate('OpenLP.FirstTimeWizard',
610+ 'OpenLP could not connect to the internet to get information about the sample data available.\n\n'
611+ 'Please check your internet connection. If your church uses a proxy server click the '
612+ '\'Internet Settings\' button below and enter the server details there.\n\nClick the '
613+ '\'{back_button}\' button to try again.\n\nIf you click the \'{finish_button}\' '
614+ 'button you can download the data at a later time by selecting \'Re-run First Time Wizard\' '
615+ 'from the \'Tools\' menu in OpenLP.'
616+ ).format(back_button=back_button_text, finish_button=self.finish_button_text))
617 self.songs_page.setTitle(translate('OpenLP.FirstTimeWizard', 'Sample Songs'))
618 self.songs_page.setSubTitle(translate('OpenLP.FirstTimeWizard', 'Select and download public domain songs.'))
619 self.bibles_page.setTitle(translate('OpenLP.FirstTimeWizard', 'Sample Bibles'))
620@@ -310,13 +324,8 @@
621 self.themes_select_all_button.setToolTip(translate('OpenLP.FirstTimeWizard', 'Select all'))
622 self.themes_deselect_all_button.setToolTip(translate('OpenLP.FirstTimeWizard', 'Deselect all'))
623 self.progress_page.setTitle(translate('OpenLP.FirstTimeWizard', 'Downloading and Configuring'))
624- self.progress_page.setSubTitle(translate('OpenLP.FirstTimeWizard', 'Please wait while resources are downloaded '
625- 'and OpenLP is configured.'))
626- self.progress_label.setText(translate('OpenLP.FirstTimeWizard', 'Starting configuration process...'))
627- first_time_wizard.setButtonText(QtWidgets.QWizard.CustomButton1,
628- clean_button_text(first_time_wizard.buttonText(QtWidgets.QWizard.FinishButton)))
629- first_time_wizard.setButtonText(QtWidgets.QWizard.CustomButton2,
630- clean_button_text(first_time_wizard.buttonText(QtWidgets.QWizard.CancelButton)))
631+ self.progress_page.setSubTitle(
632+ translate('OpenLP.FirstTimeWizard', 'Please wait while resources are downloaded and OpenLP is configured.'))
633
634 def on_projectors_check_box_clicked(self):
635 # When clicking projectors_check box, change the visibility setting for Projectors panel.
636
637=== modified file 'openlp/core/ui/mainwindow.py'
638--- openlp/core/ui/mainwindow.py 2019-02-14 15:09:09 +0000
639+++ openlp/core/ui/mainwindow.py 2019-03-08 21:25:50 +0000
640@@ -681,8 +681,7 @@
641 return
642 first_run_wizard = FirstTimeForm(self)
643 first_run_wizard.initialize(ScreenList())
644- first_run_wizard.exec()
645- if first_run_wizard.was_cancelled:
646+ if first_run_wizard.exec() == QtWidgets.QDialog.Rejected:
647 return
648 self.application.set_busy_cursor()
649 self.first_time()
650
651=== modified file 'openlp/core/widgets/widgets.py'
652--- openlp/core/widgets/widgets.py 2019-02-14 15:09:09 +0000
653+++ openlp/core/widgets/widgets.py 2019-03-08 21:25:50 +0000
654@@ -150,6 +150,34 @@
655 settings.setValue('advanced/proxy password', self.password_edit.text())
656
657
658+class ProxyDialog(QtWidgets.QDialog):
659+ """
660+ A basic dialog to show proxy settingd
661+ """
662+ def __init__(self, *args, **kwargs):
663+ super().__init__(*args, **kwargs)
664+ self.layout = QtWidgets.QVBoxLayout(self)
665+ self.proxy_widget = ProxyWidget(self)
666+ self.layout.addWidget(self.proxy_widget)
667+ self.button_box = \
668+ QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel, self)
669+ self.layout.addWidget(self.button_box)
670+ self.button_box.accepted.connect(self.accept)
671+ self.button_box.rejected.connect(self.reject)
672+
673+ def accept(self):
674+ """
675+ Reimplement the the accept slot so that the ProxyWidget settings can be saved.
676+ :rtype: None
677+ """
678+ self.proxy_widget.save()
679+ super().accept()
680+
681+ def retranslate_ui(self):
682+ self.proxy_widget.retranslate_ui()
683+ self.setWindowTitle(translate('OpenLP.ProxyDialog', 'Proxy Server Settings'))
684+
685+
686 class ScreenButton(QtWidgets.QPushButton):
687 """
688 A special button class that holds the screen information about it
689
690=== modified file 'openlp/plugins/songs/lib/importers/openlp.py'
691--- openlp/plugins/songs/lib/importers/openlp.py 2019-02-14 15:09:09 +0000
692+++ openlp/plugins/songs/lib/importers/openlp.py 2019-03-08 21:25:50 +0000
693@@ -106,7 +106,7 @@
694 pass
695
696 # Check the file type
697- if not isinstance(self.import_source, str) or not self.import_source.endswith('.sqlite'):
698+ if self.import_source.suffix != '.sqlite':
699 self.log_error(self.import_source, translate('SongsPlugin.OpenLPSongImport',
700 'Not a valid OpenLP 2 song database.'))
701 return
702
703=== modified file 'openlp/plugins/songs/reporting.py'
704--- openlp/plugins/songs/reporting.py 2019-02-14 15:09:09 +0000
705+++ openlp/plugins/songs/reporting.py 2019-03-08 21:25:50 +0000
706@@ -49,13 +49,6 @@
707 Path(translate('SongPlugin.ReportSongList', 'song_extract.csv')),
708 translate('SongPlugin.ReportSongList', 'CSV format (*.csv)'))
709
710- if report_file_path is None:
711- main_window.error_message(
712- translate('SongPlugin.ReportSongList', 'Output Path Not Selected'),
713- translate('SongPlugin.ReportSongList', 'You have not set a valid output location for your report. \n'
714- 'Please select an existing path on your computer.')
715- )
716- return
717 report_file_path.with_suffix('.csv')
718 Registry().get('application').set_busy_cursor()
719 try:
720
721=== modified file 'run_openlp.py' (properties changed: +x to -x)
722=== modified file 'setup.py' (properties changed: +x to -x)
723=== modified file 'tests/functional/openlp_core/common/test_httputils.py'
724--- tests/functional/openlp_core/common/test_httputils.py 2019-02-14 15:09:09 +0000
725+++ tests/functional/openlp_core/common/test_httputils.py 2019-03-08 21:25:50 +0000
726@@ -224,7 +224,7 @@
727 file_size = get_url_file_size(fake_url)
728
729 # THEN: The correct methods are called with the correct arguments and a web page is returned
730- mocked_requests.head.assert_called_once_with(fake_url, allow_redirects=True, timeout=30.0)
731+ mocked_requests.head.assert_called_once_with(fake_url, allow_redirects=True, proxies=None, timeout=30.0)
732 assert file_size == 100
733
734 @patch('openlp.core.common.httputils.requests')
735
736=== modified file 'tests/functional/openlp_core/test_threading.py'
737--- tests/functional/openlp_core/test_threading.py 2019-02-14 15:09:09 +0000
738+++ tests/functional/openlp_core/test_threading.py 2019-03-08 21:25:50 +0000
739@@ -133,15 +133,11 @@
740 # GIVEN: A mocked thread worker
741 MockRegistry.return_value.get.return_value.worker_threads = {}
742
743- try:
744- # WHEN: get_thread_worker() is called
745- get_thread_worker('test_thread')
746- assert False, 'A KeyError should have been raised'
747- except KeyError:
748- # THEN: The mocked worker is returned
749- pass
750- except Exception:
751- assert False, 'A KeyError should have been raised'
752+ # WHEN: get_thread_worker() is called
753+ result = get_thread_worker('test_thread')
754+
755+ # THEN: None should have been returned
756+ assert result is None
757
758
759 @patch('openlp.core.threading.Registry')
760
761=== modified file 'tests/functional/openlp_core/ui/test_firsttimeform.py'
762--- tests/functional/openlp_core/ui/test_firsttimeform.py 2019-02-16 08:57:11 +0000
763+++ tests/functional/openlp_core/ui/test_firsttimeform.py 2019-03-08 21:25:50 +0000
764@@ -27,6 +27,8 @@
765 from unittest import TestCase
766 from unittest.mock import MagicMock, call, patch, DEFAULT
767
768+from PyQt5 import QtWidgets
769+
770 from openlp.core.common.path import Path
771 from openlp.core.common.registry import Registry
772 from openlp.core.ui.firsttimeform import FirstTimeForm, ThemeListWidgetItem
773@@ -45,6 +47,7 @@
774 """
775 Test the :class:`ThemeListWidgetItem` class
776 """
777+
778 def setUp(self):
779 self.sample_theme_data = {'file_name': 'BlueBurst.otz', 'sha256': 'sha_256_hash',
780 'thumbnail': 'BlueBurst.png', 'title': 'Blue Burst'}
781@@ -59,7 +62,7 @@
782 """
783 Test that the theme data is loaded correctly in to a ThemeListWidgetItem object when instantiated
784 """
785- # GIVEN: A sample theme dictanary object
786+ # GIVEN: A sample theme dictionary object
787 # WHEN: Creating an instance of `ThemeListWidgetItem`
788 instance = ThemeListWidgetItem('url', self.sample_theme_data, MagicMock())
789
790@@ -74,7 +77,7 @@
791 """
792 Test that the `DownloadWorker` worker is set up correctly and that the thread is started.
793 """
794- # GIVEN: A sample theme dictanary object
795+ # GIVEN: A sample theme dictionary object
796 mocked_ftw = MagicMock(spec=FirstTimeForm)
797 mocked_ftw.thumbnail_download_threads = []
798
799@@ -120,10 +123,23 @@
800 # THEN: The screens should be set up, and the default values initialised
801 assert expected_screens == frw.screens, 'The screens should be correct'
802 assert frw.web_access is True, 'The default value of self.web_access should be True'
803- assert frw.was_cancelled is False, 'The default value of self.was_cancelled should be False'
804 assert [] == frw.thumbnail_download_threads, 'The list of threads should be empty'
805 assert frw.has_run_wizard is False, 'has_run_wizard should be False'
806
807+ @patch('openlp.core.ui.firsttimewizard.QtWidgets.QWizard.exec')
808+ def test_exec(self, mocked_qwizard_exec):
809+
810+ # GIVEN: An instance of FirstTimeForm
811+ frw = FirstTimeForm(None)
812+ with patch.object(frw, 'set_defaults') as mocked_set_defaults:
813+
814+ # WHEN: exec is called
815+ frw.exec()
816+
817+ # THEN: The wizard should be reset and the exec methon on the super class should have been called
818+ mocked_set_defaults.assert_called_once()
819+ mocked_qwizard_exec.assert_called_once()
820+
821 def test_set_defaults(self):
822 """
823 Test that the default values are set when set_defaults() is run
824@@ -134,8 +150,6 @@
825 mocked_settings = MagicMock()
826 mocked_settings.value.side_effect = lambda key: {'core/has run wizard': False}[key]
827 with patch.object(frw, 'restart') as mocked_restart, \
828- patch.object(frw, 'cancel_button') as mocked_cancel_button, \
829- patch.object(frw, 'no_internet_finish_button') as mocked_no_internet_finish_btn, \
830 patch.object(frw, 'currentIdChanged') as mocked_currentIdChanged, \
831 patch.object(frw, 'theme_combo_box') as mocked_theme_combo_box, \
832 patch.object(frw, 'songs_check_box') as mocked_songs_check_box, \
833@@ -153,12 +167,8 @@
834 # THEN: The default values should have been set
835 mocked_restart.assert_called_once()
836 assert 'https://get.openlp.org/ftw/' == frw.web, 'The default URL should be set'
837- mocked_cancel_button.clicked.connect.assert_called_once_with(frw.on_cancel_button_clicked)
838- mocked_no_internet_finish_btn.clicked.connect.assert_called_once_with(
839- frw.on_no_internet_finish_button_clicked)
840 mocked_currentIdChanged.connect.assert_called_once_with(frw.on_current_id_changed)
841 mocked_register_function.assert_called_once_with('config_screen_changed', frw.screen_selection_widget.load)
842- mocked_no_internet_finish_btn.setVisible.assert_called_once_with(False)
843 mocked_settings.value.assert_has_calls([call('core/has run wizard')])
844 mocked_gettempdir.assert_called_once()
845 mocked_create_paths.assert_called_once_with(Path('temp', 'openlp'))
846@@ -177,8 +187,6 @@
847 mocked_settings.value.side_effect = \
848 lambda key: {'core/has run wizard': True, 'themes/global theme': 'Default Theme'}[key]
849 with patch.object(frw, 'restart') as mocked_restart, \
850- patch.object(frw, 'cancel_button') as mocked_cancel_button, \
851- patch.object(frw, 'no_internet_finish_button') as mocked_no_internet_finish_btn, \
852 patch.object(frw, 'currentIdChanged') as mocked_currentIdChanged, \
853 patch.object(frw, 'theme_combo_box', **{'findText.return_value': 3}) as mocked_theme_combo_box, \
854 patch.multiple(frw, songs_check_box=DEFAULT, bible_check_box=DEFAULT, presentation_check_box=DEFAULT,
855@@ -200,12 +208,8 @@
856 # THEN: The default values should have been set
857 mocked_restart.assert_called_once()
858 assert 'https://get.openlp.org/ftw/' == frw.web, 'The default URL should be set'
859- mocked_cancel_button.clicked.connect.assert_called_once_with(frw.on_cancel_button_clicked)
860- mocked_no_internet_finish_btn.clicked.connect.assert_called_once_with(
861- frw.on_no_internet_finish_button_clicked)
862 mocked_currentIdChanged.connect.assert_called_once_with(frw.on_current_id_changed)
863 mocked_register_function.assert_called_once_with('config_screen_changed', frw.screen_selection_widget.load)
864- mocked_no_internet_finish_btn.setVisible.assert_called_once_with(False)
865 mocked_settings.value.assert_has_calls([call('core/has run wizard'), call('themes/global theme')])
866 mocked_gettempdir.assert_called_once()
867 mocked_create_paths.assert_called_once_with(Path('temp', 'openlp'))
868@@ -219,12 +223,78 @@
869 mocked_theme_combo_box.findText.assert_called_once_with('Default Theme')
870 mocked_theme_combo_box.setCurrentIndex(3)
871
872+ @patch('openlp.core.ui.firsttimewizard.QtWidgets.QWizard.accept')
873+ @patch('openlp.core.ui.firsttimewizard.Settings')
874+ def test_accept_method(self, mocked_settings, mocked_qwizard_accept):
875+ """
876+ Test the FirstTimeForm.accept method
877+ """
878+ # GIVEN: An instance of FirstTimeForm
879+ frw = FirstTimeForm(None)
880+ with patch.object(frw, '_set_plugin_status') as mocked_set_plugin_status, \
881+ patch.multiple(frw, songs_check_box=DEFAULT, bible_check_box=DEFAULT, presentation_check_box=DEFAULT,
882+ image_check_box=DEFAULT, media_check_box=DEFAULT, custom_check_box=DEFAULT,
883+ song_usage_check_box=DEFAULT, alert_check_box=DEFAULT) as mocked_check_boxes, \
884+ patch.object(frw, 'screen_selection_widget') as mocked_screen_selection_widget:
885+
886+ # WHEN: Calling accept
887+ frw.accept()
888+
889+ # THEN: The selected plugins should be enabled, the screen selection saved and the super method called
890+ mocked_set_plugin_status.assert_has_calls([
891+ call(mocked_check_boxes['songs_check_box'], 'songs/status'),
892+ call(mocked_check_boxes['bible_check_box'], 'bibles/status'),
893+ call(mocked_check_boxes['presentation_check_box'], 'presentations/status'),
894+ call(mocked_check_boxes['image_check_box'], 'images/status'),
895+ call(mocked_check_boxes['media_check_box'], 'media/status'),
896+ call(mocked_check_boxes['custom_check_box'], 'custom/status'),
897+ call(mocked_check_boxes['song_usage_check_box'], 'songusage/status'),
898+ call(mocked_check_boxes['alert_check_box'], 'alerts/status')])
899+ mocked_screen_selection_widget.save.assert_called_once()
900+ mocked_qwizard_accept.assert_called_once()
901+
902+ @patch('openlp.core.ui.firsttimewizard.Settings')
903+ def test_accept_method_theme_not_selected(self, mocked_settings):
904+ """
905+ Test the FirstTimeForm.accept method when there is no default theme selected
906+ """
907+ # GIVEN: An instance of FirstTimeForm
908+ frw = FirstTimeForm(None)
909+ with patch.object(frw, '_set_plugin_status'), patch.object(frw, 'screen_selection_widget'), \
910+ patch.object(frw, 'theme_combo_box', **{'currentIndex.return_value': '-1'}):
911+
912+ # WHEN: Calling accept and the currentIndex method of the theme_combo_box returns -1
913+ frw.accept()
914+
915+ # THEN: OpenLP should not try to save a theme name
916+ mocked_settings.setValue.assert_not_called()
917+
918+ @patch('openlp.core.ui.firsttimeform.Settings')
919+ def test_accept_method_theme_selected(self, mocked_settings):
920+ """
921+ Test the FirstTimeForm.accept method when a default theme is selected
922+ """
923+ # GIVEN: An instance of FirstTimeForm
924+ frw = FirstTimeForm(None)
925+ with patch.object(frw, '_set_plugin_status'), \
926+ patch.object(frw, 'screen_selection_widget'), \
927+ patch.object(
928+ frw, 'theme_combo_box', **{'currentIndex.return_value': 0, 'currentText.return_value': 'Test Item'}):
929+
930+ # WHEN: Calling accept and the currentIndex method of the theme_combo_box returns 0
931+ frw.accept()
932+
933+ # THEN: The 'currentItem' in the combobox should have been set as the default theme.
934+ mocked_settings().setValue.assert_called_once_with('themes/global theme', 'Test Item')
935+
936+ @patch('openlp.core.ui.firsttimewizard.QtWidgets.QWizard.reject')
937 @patch('openlp.core.ui.firsttimeform.time')
938 @patch('openlp.core.ui.firsttimeform.get_thread_worker')
939 @patch('openlp.core.ui.firsttimeform.is_thread_finished')
940- def test_on_cancel_button_clicked(self, mocked_is_thread_finished, mocked_get_thread_worker, mocked_time):
941+ def test_reject_method(
942+ self, mocked_is_thread_finished, mocked_get_thread_worker, mocked_time, mocked_qwizard_reject):
943 """
944- Test that the cancel button click slot shuts down the threads correctly
945+ Test that the reject method shuts down the threads correctly
946 """
947 # GIVEN: A FRW, some mocked threads and workers (that isn't quite done) and other mocked stuff
948 mocked_worker = MagicMock()
949@@ -235,17 +305,47 @@
950 frw.thumbnail_download_threads = ['test_thread']
951 with patch.object(frw.application, 'set_normal_cursor') as mocked_set_normal_cursor:
952
953- # WHEN: on_cancel_button_clicked() is called
954- frw.on_cancel_button_clicked()
955+ # WHEN: the reject method is called
956+ frw.reject()
957
958 # THEN: The right things should be called in the right order
959- assert frw.was_cancelled is True, 'The was_cancelled property should have been set to True'
960 mocked_get_thread_worker.assert_called_once_with('test_thread')
961 mocked_worker.cancel_download.assert_called_once()
962 mocked_is_thread_finished.assert_called_with('test_thread')
963 assert mocked_is_thread_finished.call_count == 2, 'isRunning() should have been called twice'
964 mocked_time.sleep.assert_called_once_with(0.1)
965- mocked_set_normal_cursor.assert_called_once_with()
966+ mocked_set_normal_cursor.assert_called_once()
967+ mocked_qwizard_reject.assert_called_once()
968+
969+ @patch('openlp.core.ui.firsttimeform.ProxyDialog')
970+ def test_on_custom_button_clicked(self, mocked_proxy_dialog):
971+ """
972+ Test _on_custom_button when it is called whe the 'internet settings' (CustomButton1) button is not clicked.
973+ """
974+ # GIVEN: An instance of the FirstTimeForm
975+ frw = FirstTimeForm(None)
976+
977+ # WHEN: Calling _on_custom_button_clicked with a different button to the 'internet settings button.
978+ frw._on_custom_button_clicked(QtWidgets.QWizard.CustomButton2)
979+
980+ # THEN: The ProxyDialog should not be shown.
981+ mocked_proxy_dialog.assert_not_called()
982+
983+ @patch('openlp.core.ui.firsttimeform.ProxyDialog')
984+ def test_on_custom_button_clicked_internet_settings(self, mocked_proxy_dialog):
985+ """
986+ Test _on_custom_button when it is called when the 'internet settings' (CustomButton1) button is clicked.
987+ """
988+ # GIVEN: An instance of the FirstTimeForm
989+ frw = FirstTimeForm(None)
990+
991+ # WHEN: Calling _on_custom_button_clicked with the constant for the 'internet settings' button (CustomButton1)
992+ frw._on_custom_button_clicked(QtWidgets.QWizard.CustomButton1)
993+
994+ # THEN: The ProxyDialog should be shown.
995+ mocked_proxy_dialog.assert_called_with(frw)
996+ mocked_proxy_dialog().retranslate_ui.assert_called_once()
997+ mocked_proxy_dialog().exec.assert_called_once()
998
999 @patch('openlp.core.ui.firsttimeform.critical_error_message_box')
1000 def test__parse_config_invalid_config(self, mocked_critical_error_message_box):
1001@@ -279,8 +379,8 @@
1002
1003 # THEN: the critical_error_message_box should have been called
1004 mocked_message_box.critical.assert_called_once_with(
1005- first_time_form, 'Network Error', 'There was a network error attempting to connect to retrieve '
1006- 'initial configuration information', 'OK')
1007+ first_time_form, 'Network Error',
1008+ 'There was a network error attempting to connect to retrieve initial configuration information', 'OK')
1009
1010 @patch('openlp.core.ui.firsttimewizard.Settings')
1011 def test_on_projectors_check_box_checked(self, MockSettings):
1012
1013=== modified file 'tests/functional/openlp_plugins/songs/test_openlpimporter.py'
1014--- tests/functional/openlp_plugins/songs/test_openlpimporter.py 2019-02-14 15:09:09 +0000
1015+++ tests/functional/openlp_plugins/songs/test_openlpimporter.py 2019-03-08 21:25:50 +0000
1016@@ -22,6 +22,7 @@
1017 """
1018 This module contains tests for the OpenLP song importer.
1019 """
1020+from pathlib import Path
1021 from unittest import TestCase
1022 from unittest.mock import MagicMock, patch
1023
1024@@ -66,10 +67,9 @@
1025 importer.stop_import_flag = True
1026
1027 # WHEN: Import source is not a list
1028- for source in ['not a list', 0]:
1029- importer.import_source = source
1030+ importer.import_source = Path()
1031
1032- # THEN: do_import should return none and the progress bar maximum should not be set.
1033- assert importer.do_import() is None, 'do_import should return None when import_source is not a list'
1034- assert mocked_import_wizard.progress_bar.setMaximum.called is False, \
1035- 'setMaximum on import_wizard.progress_bar should not have been called'
1036+ # THEN: do_import should return none and the progress bar maximum should not be set.
1037+ assert importer.do_import() is None, 'do_import should return None when import_source is not a list'
1038+ assert mocked_import_wizard.progress_bar.setMaximum.called is False, \
1039+ 'setMaximum on import_wizard.progress_bar should not have been called'