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: 1035 lines (+328/-210)
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/-93)
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
Tomas Groth Pending
Review via email: mp+364183@code.launchpad.net

This proposal supersedes a proposal from 2019-02-27.

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 :

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/49/ for more details

2850. By Phill

PEP fixes

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