Add proxy settings button to FTW, ftw refactors, a few fixes!

This commit is contained in:
Philip Ridout 2019-02-27 21:12:16 +00:00
parent 1434751591
commit 670c06db60
13 changed files with 310 additions and 188 deletions

View File

@ -101,7 +101,7 @@ class OpenLP(QtWidgets.QApplication):
ftw.initialize(screens) ftw.initialize(screens)
if ftw.exec() == QtWidgets.QDialog.Accepted: if ftw.exec() == QtWidgets.QDialog.Accepted:
Settings().setValue('core/has run wizard', True) Settings().setValue('core/has run wizard', True)
elif ftw.was_cancelled: else:
QtCore.QCoreApplication.exit() QtCore.QCoreApplication.exit()
sys.exit() sys.exit()
# Correct stylesheet bugs # Correct stylesheet bugs

View File

@ -158,16 +158,20 @@ def get_web_page(url, headers=None, update_openlp=False, proxy=None):
return response.text return response.text
def get_url_file_size(url): def get_url_file_size(url, proxy=None):
""" """
Get the size of a file. Get the size of a file.
:param url: The URL of the file we want to download. :param url: The URL of the file we want to download.
:param dict | ProxyMode | None proxy: ProxyMode enum or a dictionary containing the proxy servers, with their types
as the key e.g. {'http': 'http://proxyserver:port', 'https': 'https://proxyserver:port'}
""" """
retries = 0 retries = 0
if not isinstance(proxy, dict):
proxy = get_proxy_settings(mode=proxy)
while True: while True:
try: try:
response = requests.head(url, timeout=float(CONNECTION_TIMEOUT), allow_redirects=True) response = requests.head(url, proxies=proxy, timeout=float(CONNECTION_TIMEOUT), allow_redirects=True)
return int(response.headers['Content-Length']) return int(response.headers['Content-Length'])
except OSError: except OSError:
if retries > CONNECTION_RETRIES: if retries > CONNECTION_RETRIES:
@ -178,7 +182,7 @@ def get_url_file_size(url):
continue continue
def download_file(update_object, url, file_path, sha256=None): def download_file(update_object, url, file_path, sha256=None, proxy=None):
"""" """"
Download a file given a URL. The file is retrieved in chunks, giving the ability to cancel the download at any Download a file given a URL. The file is retrieved in chunks, giving the ability to cancel the download at any
point. Returns False on download error. point. Returns False on download error.
@ -187,15 +191,19 @@ def download_file(update_object, url, file_path, sha256=None):
:param url: URL to download :param url: URL to download
:param file_path: Destination file :param file_path: Destination file
:param sha256: The check sum value to be checked against the download value :param sha256: The check sum value to be checked against the download value
:param dict | ProxyMode | None proxy: ProxyMode enum or a dictionary containing the proxy servers, with their types
as the key e.g. {'http': 'http://proxyserver:port', 'https': 'https://proxyserver:port'}
""" """
block_count = 0 block_count = 0
block_size = 4096 block_size = 4096
retries = 0 retries = 0
if not isinstance(proxy, dict):
proxy = get_proxy_settings(mode=proxy)
log.debug('url_get_file: %s', url) log.debug('url_get_file: %s', url)
while retries < CONNECTION_RETRIES: while retries < CONNECTION_RETRIES:
try: try:
with file_path.open('wb') as saved_file: with file_path.open('wb') as saved_file:
response = requests.get(url, timeout=float(CONNECTION_TIMEOUT), stream=True) response = requests.get(url, proxies=proxy, timeout=float(CONNECTION_TIMEOUT), stream=True)
if sha256: if sha256:
hasher = hashlib.sha256() hasher = hashlib.sha256()
# Download until finished or canceled. # Download until finished or canceled.
@ -244,21 +252,21 @@ class DownloadWorker(ThreadWorker):
""" """
self._base_url = base_url self._base_url = base_url
self._file_name = file_name self._file_name = file_name
self._download_cancelled = False self.was_cancelled = False
super().__init__() super().__init__()
def start(self): def start(self):
""" """
Download the url to the temporary directory Download the url to the temporary directory
""" """
if self._download_cancelled: if self.was_cancelled:
self.quit.emit() self.quit.emit()
return return
try: try:
dest_path = Path(gettempdir()) / 'openlp' / self._file_name dest_path = Path(gettempdir()) / 'openlp' / self._file_name
url = '{url}{name}'.format(url=self._base_url, name=self._file_name) url = '{url}{name}'.format(url=self._base_url, name=self._file_name)
is_success = download_file(self, url, dest_path) is_success = download_file(self, url, dest_path)
if is_success and not self._download_cancelled: if is_success and not self.was_cancelled:
self.download_succeeded.emit(dest_path) self.download_succeeded.emit(dest_path)
else: else:
self.download_failed.emit() self.download_failed.emit()
@ -273,4 +281,4 @@ class DownloadWorker(ThreadWorker):
""" """
A slot to allow the download to be cancelled from outside of the thread A slot to allow the download to be cancelled from outside of the thread
""" """
self._download_cancelled = True self.was_cancelled = True

View File

@ -76,11 +76,11 @@ def get_thread_worker(thread_name):
Get the worker by the thread name Get the worker by the thread name
:param str thread_name: The name of the thread :param str thread_name: The name of the thread
:returns: The worker for this thread name :returns: The worker for this thread name, or None
""" """
thread_info = Registry().get('application').worker_threads.get(thread_name) thread_info = Registry().get('application').worker_threads.get(thread_name)
if not thread_info: if not thread_info:
raise KeyError('No thread named "{}" exists'.format(thread_name)) return
return thread_info.get('worker') return thread_info.get('worker')

View File

@ -46,6 +46,7 @@ from openlp.core.lib.ui import critical_error_message_box
from openlp.core.threading import get_thread_worker, is_thread_finished, run_thread from openlp.core.threading import get_thread_worker, is_thread_finished, run_thread
from openlp.core.ui.firsttimewizard import FirstTimePage, UiFirstTimeWizard from openlp.core.ui.firsttimewizard import FirstTimePage, UiFirstTimeWizard
from openlp.core.ui.icons import UiIcons from openlp.core.ui.icons import UiIcons
from openlp.core.widgets.widgets import ProxyDialog
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -91,7 +92,7 @@ class ThemeListWidgetItem(QtWidgets.QListWidgetItem):
class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties): class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties):
""" """
This is the Theme Import Wizard, which allows easy creation and editing of OpenLP themes. This is the FirstTimeWizard, designed to help new users to get up and running quickly.
""" """
log.info('ThemeWizardForm loaded') log.info('ThemeWizardForm loaded')
@ -103,6 +104,7 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties):
self.web_access = True self.web_access = True
self.web = '' self.web = ''
self.setup_ui(self) self.setup_ui(self)
self.customButtonClicked.connect(self._on_custom_button_clicked)
self.themes_list_widget.itemSelectionChanged.connect(self.on_themes_list_widget_selection_changed) self.themes_list_widget.itemSelectionChanged.connect(self.on_themes_list_widget_selection_changed)
self.themes_deselect_all_button.clicked.connect(self.themes_list_widget.clearSelection) self.themes_deselect_all_button.clicked.connect(self.themes_list_widget.clearSelection)
self.themes_select_all_button.clicked.connect(self.themes_list_widget.selectAll) self.themes_select_all_button.clicked.connect(self.themes_list_widget.selectAll)
@ -111,13 +113,13 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties):
""" """
Returns the id of the next FirstTimePage to go to based on enabled plugins Returns the id of the next FirstTimePage to go to based on enabled plugins
""" """
if FirstTimePage.ScreenConfig < self.currentId() < FirstTimePage.Songs and self.songs_check_box.isChecked(): if FirstTimePage.Download < self.currentId() < FirstTimePage.Songs and self.songs_check_box.isChecked():
# If the songs plugin is enabled then go to the songs page # If the songs plugin is enabled then go to the songs page
return FirstTimePage.Songs return FirstTimePage.Songs
elif FirstTimePage.ScreenConfig < self.currentId() < FirstTimePage.Bibles and self.bible_check_box.isChecked(): elif FirstTimePage.Download < self.currentId() < FirstTimePage.Bibles and self.bible_check_box.isChecked():
# Otherwise, if the Bibles plugin is enabled then go to the Bibles page # Otherwise, if the Bibles plugin is enabled then go to the Bibles page
return FirstTimePage.Bibles return FirstTimePage.Bibles
elif FirstTimePage.ScreenConfig < self.currentId() < FirstTimePage.Themes: elif FirstTimePage.Download < self.currentId() < FirstTimePage.Themes:
# Otherwise, if the current page is somewhere between the Welcome and the Themes pages, go to the themes # Otherwise, if the current page is somewhere between the Welcome and the Themes pages, go to the themes
return FirstTimePage.Themes return FirstTimePage.Themes
else: else:
@ -133,9 +135,7 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties):
if not self.web_access: if not self.web_access:
return FirstTimePage.NoInternet return FirstTimePage.NoInternet
else: else:
return FirstTimePage.Plugins return FirstTimePage.Songs
elif self.currentId() == FirstTimePage.Plugins:
return self.get_next_page_id()
elif self.currentId() == FirstTimePage.Progress: elif self.currentId() == FirstTimePage.Progress:
return -1 return -1
elif self.currentId() == FirstTimePage.NoInternet: elif self.currentId() == FirstTimePage.NoInternet:
@ -147,7 +147,7 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties):
Run the wizard. Run the wizard.
""" """
self.set_defaults() self.set_defaults()
return QtWidgets.QWizard.exec(self) return super().exec()
def initialize(self, screens): def initialize(self, screens):
""" """
@ -227,17 +227,13 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties):
""" """
self.restart() self.restart()
self.web = 'https://get.openlp.org/ftw/' self.web = 'https://get.openlp.org/ftw/'
self.cancel_button.clicked.connect(self.on_cancel_button_clicked)
self.no_internet_finish_button.clicked.connect(self.on_no_internet_finish_button_clicked)
self.no_internet_cancel_button.clicked.connect(self.on_no_internet_cancel_button_clicked)
self.currentIdChanged.connect(self.on_current_id_changed) self.currentIdChanged.connect(self.on_current_id_changed)
Registry().register_function('config_screen_changed', self.screen_selection_widget.load) Registry().register_function('config_screen_changed', self.screen_selection_widget.load)
self.no_internet_finish_button.setVisible(False)
self.no_internet_cancel_button.setVisible(False)
# Check if this is a re-run of the wizard. # Check if this is a re-run of the wizard.
self.has_run_wizard = Settings().value('core/has run wizard') self.has_run_wizard = Settings().value('core/has run wizard')
create_paths(Path(gettempdir(), 'openlp')) create_paths(Path(gettempdir(), 'openlp'))
self.theme_combo_box.clear() self.theme_combo_box.clear()
self.button(QtWidgets.QWizard.CustomButton1).setVisible(False)
if self.has_run_wizard: if self.has_run_wizard:
self.songs_check_box.setChecked(self.plugin_manager.get_plugin_by_name('songs').is_active()) self.songs_check_box.setChecked(self.plugin_manager.get_plugin_by_name('songs').is_active())
self.bible_check_box.setChecked(self.plugin_manager.get_plugin_by_name('bibles').is_active()) self.bible_check_box.setChecked(self.plugin_manager.get_plugin_by_name('bibles').is_active())
@ -260,57 +256,85 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties):
""" """
Detects Page changes and updates as appropriate. Detects Page changes and updates as appropriate.
""" """
# Keep track of the page we are at. Triggering "Cancel" causes page_id to be a -1. back_button = self.button(QtWidgets.QWizard.BackButton)
cancel_button = self.button(QtWidgets.QWizard.CancelButton)
internet_settings_button = self.button(QtWidgets.QWizard.CustomButton1)
next_button = self.button(QtWidgets.QWizard.NextButton)
back_button.setVisible(True)
next_button.setVisible(True)
internet_settings_button.setVisible(False)
self.application.process_events() self.application.process_events()
if page_id != -1: if page_id == FirstTimePage.SampleOption:
self.last_id = page_id internet_settings_button.setVisible(True)
if page_id == FirstTimePage.Download: elif page_id == FirstTimePage.Download:
self.back_button.setVisible(False) back_button.setVisible(False)
self.next_button.setVisible(False) next_button.setVisible(False)
# Set the no internet page text.
if self.has_run_wizard:
self.no_internet_label.setText(self.no_internet_text)
else:
self.no_internet_label.setText(self.no_internet_text + self.cancel_wizard_text)
self.application.set_busy_cursor() self.application.set_busy_cursor()
self._download_index() self._download_index()
self.application.set_normal_cursor() self.application.set_normal_cursor()
self.back_button.setVisible(False)
self.next_button.setVisible(True)
self.next() self.next()
elif page_id == FirstTimePage.NoInternet: elif page_id == FirstTimePage.NoInternet:
self.back_button.setVisible(False) next_button.setVisible(False)
self.next_button.setVisible(False) cancel_button.setVisible(False)
self.cancel_button.setVisible(False) internet_settings_button.setVisible(True)
self.no_internet_finish_button.setVisible(True)
if self.has_run_wizard:
self.no_internet_cancel_button.setVisible(False)
else:
self.no_internet_cancel_button.setVisible(True)
elif page_id == FirstTimePage.Plugins:
self.back_button.setVisible(False)
elif page_id == FirstTimePage.Progress: elif page_id == FirstTimePage.Progress:
back_button.setVisible(False)
next_button.setVisible(False)
self.application.set_busy_cursor() self.application.set_busy_cursor()
self._pre_wizard() self._pre_wizard()
self._perform_wizard() self._perform_wizard()
self._post_wizard() self._post_wizard()
self.application.set_normal_cursor() self.application.set_normal_cursor()
def on_cancel_button_clicked(self): def accept(self):
""" """
Process the triggering of the cancel button. Called when the user clicks 'Finish'. Reimplement it to to save the plugin status
:rtype: None
"""
self._set_plugin_status(self.songs_check_box, 'songs/status')
self._set_plugin_status(self.bible_check_box, 'bibles/status')
self._set_plugin_status(self.presentation_check_box, 'presentations/status')
self._set_plugin_status(self.image_check_box, 'images/status')
self._set_plugin_status(self.media_check_box, 'media/status')
self._set_plugin_status(self.custom_check_box, 'custom/status')
self._set_plugin_status(self.song_usage_check_box, 'songusage/status')
self._set_plugin_status(self.alert_check_box, 'alerts/status')
self.screen_selection_widget.save()
if self.theme_combo_box.currentIndex() != -1:
Settings().setValue('themes/global theme', self.theme_combo_box.currentText())
super().accept()
def reject(self):
"""
Called when the user clicks the cancel button. Reimplement it to clean up the threads.
:rtype: None
""" """
self.was_cancelled = True self.was_cancelled = True
if self.thumbnail_download_threads: # TODO: Use main thread list for thread_name in self.thumbnail_download_threads:
for thread_name in self.thumbnail_download_threads: worker = get_thread_worker(thread_name)
worker = get_thread_worker(thread_name) if worker:
if worker: worker.cancel_download()
worker.cancel_download()
# Was the thread created. # Was the thread created.
if self.thumbnail_download_threads: if self.thumbnail_download_threads:
while any([not is_thread_finished(thread_name) for thread_name in self.thumbnail_download_threads]): while any([not is_thread_finished(thread_name) for thread_name in self.thumbnail_download_threads]):
time.sleep(0.1) time.sleep(0.1)
self.application.set_normal_cursor() self.application.set_normal_cursor()
super().reject()
def _on_custom_button_clicked(self, which):
"""
Slot to handle the a click on one of the wizards custom buttons.
:param int QtWidgets.QWizard which: The button pressed
:rtype: None
"""
# Internet settings button
if which == QtWidgets.QWizard.CustomButton1:
proxy_dialog = ProxyDialog(self)
proxy_dialog.retranslate_ui()
proxy_dialog.exec()
def on_themes_list_widget_selection_changed(self): def on_themes_list_widget_selection_changed(self):
""" """
@ -330,23 +354,6 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties):
elif not item.isSelected() and cbox_index != -1: elif not item.isSelected() and cbox_index != -1:
self.theme_combo_box.removeItem(cbox_index) self.theme_combo_box.removeItem(cbox_index)
def on_no_internet_finish_button_clicked(self):
"""
Process the triggering of the "Finish" button on the No Internet page.
"""
self.application.set_busy_cursor()
self._perform_wizard()
self.application.set_normal_cursor()
Settings().setValue('core/has run wizard', True)
self.close()
def on_no_internet_cancel_button_clicked(self):
"""
Process the triggering of the "Cancel" button on the No Internet page.
"""
self.was_cancelled = True
self.close()
def update_progress(self, count, block_size): def update_progress(self, count, block_size):
""" """
Calculate and display the download progress. This method is called by download_file(). Calculate and display the download progress. This method is called by download_file().
@ -373,7 +380,7 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties):
Prepare the UI for the process. Prepare the UI for the process.
""" """
self.max_progress = 0 self.max_progress = 0
self.finish_button.setVisible(False) self.button(QtWidgets.QWizard.FinishButton).setEnabled(False)
self.application.process_events() self.application.process_events()
try: try:
# Loop through the songs list and increase for each selected item # Loop through the songs list and increase for each selected item
@ -428,58 +435,36 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties):
""" """
Clean up the UI after the process has finished. Clean up the UI after the process has finished.
""" """
complete_str = ''
if self.max_progress: if self.max_progress:
self.progress_bar.setValue(self.progress_bar.maximum()) self.progress_bar.setValue(self.progress_bar.maximum())
if self.has_run_wizard: if self.has_run_wizard:
text = translate('OpenLP.FirstTimeWizard', text = translate('OpenLP.FirstTimeWizard',
'Download complete. Click the {button} button to return to OpenLP.' 'Download complete. Click the \'{finish_button}\' button to return to OpenLP.')
).format(button=clean_button_text(self.buttonText(QtWidgets.QWizard.FinishButton)))
self.progress_label.setText(text)
else: else:
text = translate('OpenLP.FirstTimeWizard', text = translate('OpenLP.FirstTimeWizard',
'Download complete. Click the {button} button to start OpenLP.' 'Download complete. Click the \'{finish_button}\' button to start OpenLP.')
).format(button=clean_button_text(self.buttonText(QtWidgets.QWizard.FinishButton)))
self.progress_label.setText(text)
else: else:
if self.has_run_wizard: if self.has_run_wizard:
text = translate('OpenLP.FirstTimeWizard', text = translate('OpenLP.FirstTimeWizard', 'Click the \'{finish_button}\' button to return to OpenLP.')
'Click the {button} button to return to OpenLP.'
).format(button=clean_button_text(self.buttonText(QtWidgets.QWizard.FinishButton)))
self.progress_label.setText(text)
else: else:
text = translate('OpenLP.FirstTimeWizard', text = translate('OpenLP.FirstTimeWizard', 'Click the \'{finish_button}\' button to start OpenLP.')
'Click the {button} button to start OpenLP.' self.progress_label.setText(text.format(finish_button=self.finish_button_text))
).format(button=clean_button_text(self.buttonText(QtWidgets.QWizard.FinishButton))) self.button(QtWidgets.QWizard.FinishButton).setEnabled(True)
self.progress_label.setText(text) self.button(QtWidgets.QWizard.CancelButton).setVisible(False)
self.finish_button.setVisible(True)
self.finish_button.setEnabled(True)
self.cancel_button.setVisible(False)
self.next_button.setVisible(False)
self.application.process_events() self.application.process_events()
def _perform_wizard(self): def _perform_wizard(self):
""" """
Run the tasks in the wizard. Run the tasks in the wizard.
""" """
# Set plugin states
self._increment_progress_bar(translate('OpenLP.FirstTimeWizard', 'Enabling selected plugins...'))
self._set_plugin_status(self.songs_check_box, 'songs/status')
self._set_plugin_status(self.bible_check_box, 'bibles/status')
self._set_plugin_status(self.presentation_check_box, 'presentations/status')
self._set_plugin_status(self.image_check_box, 'images/status')
self._set_plugin_status(self.media_check_box, 'media/status')
self._set_plugin_status(self.custom_check_box, 'custom/status')
self._set_plugin_status(self.song_usage_check_box, 'songusage/status')
self._set_plugin_status(self.alert_check_box, 'alerts/status')
if self.web_access: if self.web_access:
if not self._download_selected(): if not self._download_selected():
critical_error_message_box(translate('OpenLP.FirstTimeWizard', 'Download Error'), critical_error_message_box(translate('OpenLP.FirstTimeWizard', 'Download Error'),
translate('OpenLP.FirstTimeWizard', 'There was a connection problem while ' translate('OpenLP.FirstTimeWizard', 'There was a connection problem while '
'downloading, so further downloads will be skipped. Try to re-run ' 'downloading, so further downloads will be skipped. Try to re-run '
'the First Time Wizard later.')) 'the First Time Wizard later.'))
self.screen_selection_widget.save()
if self.theme_combo_box.currentIndex() != -1:
Settings().setValue('themes/global theme', self.theme_combo_box.currentText())
def _download_selected(self): def _download_selected(self):
""" """

View File

@ -39,14 +39,15 @@ class FirstTimePage(object):
An enumeration class with each of the pages of the wizard. An enumeration class with each of the pages of the wizard.
""" """
Welcome = 0 Welcome = 0
ScreenConfig = 1 Plugins = 1
Download = 2 ScreenConfig = 2
NoInternet = 3 SampleOption = 3
Plugins = 4 Download = 4
Songs = 5 NoInternet = 5
Bibles = 6 Songs = 6
Themes = 7 Bibles = 7
Progress = 8 Themes = 8
Progress = 9
class ThemeListWidget(QtWidgets.QListWidget): class ThemeListWidget(QtWidgets.QListWidget):
@ -97,20 +98,13 @@ class UiFirstTimeWizard(object):
first_time_wizard.resize(550, 386) first_time_wizard.resize(550, 386)
first_time_wizard.setModal(True) first_time_wizard.setModal(True)
first_time_wizard.setOptions(QtWidgets.QWizard.IndependentPages | QtWidgets.QWizard.NoBackButtonOnStartPage | first_time_wizard.setOptions(QtWidgets.QWizard.IndependentPages | QtWidgets.QWizard.NoBackButtonOnStartPage |
QtWidgets.QWizard.NoBackButtonOnLastPage | QtWidgets.QWizard.HaveCustomButton1 | QtWidgets.QWizard.NoBackButtonOnLastPage | QtWidgets.QWizard.HaveCustomButton1)
QtWidgets.QWizard.HaveCustomButton2)
if is_macosx(): # pragma: nocover if is_macosx(): # pragma: nocover
first_time_wizard.setPixmap(QtWidgets.QWizard.BackgroundPixmap, first_time_wizard.setPixmap(QtWidgets.QWizard.BackgroundPixmap,
QtGui.QPixmap(':/wizards/openlp-osx-wizard.png')) QtGui.QPixmap(':/wizards/openlp-osx-wizard.png'))
first_time_wizard.resize(634, 386) first_time_wizard.resize(634, 386)
else: else:
first_time_wizard.setWizardStyle(QtWidgets.QWizard.ModernStyle) first_time_wizard.setWizardStyle(QtWidgets.QWizard.ModernStyle)
self.finish_button = self.button(QtWidgets.QWizard.FinishButton)
self.no_internet_finish_button = self.button(QtWidgets.QWizard.CustomButton1)
self.cancel_button = self.button(QtWidgets.QWizard.CancelButton)
self.no_internet_cancel_button = self.button(QtWidgets.QWizard.CustomButton2)
self.next_button = self.button(QtWidgets.QWizard.NextButton)
self.back_button = self.button(QtWidgets.QWizard.BackButton)
add_welcome_page(first_time_wizard, ':/wizards/wizard_firsttime.bmp') add_welcome_page(first_time_wizard, ':/wizards/wizard_firsttime.bmp')
# The screen config page # The screen config page
self.screen_page = QtWidgets.QWizardPage() self.screen_page = QtWidgets.QWizardPage()
@ -121,6 +115,18 @@ class UiFirstTimeWizard(object):
self.screen_selection_widget.load() self.screen_selection_widget.load()
self.screen_page_layout.addRow(self.screen_selection_widget) self.screen_page_layout.addRow(self.screen_selection_widget)
first_time_wizard.setPage(FirstTimePage.ScreenConfig, self.screen_page) first_time_wizard.setPage(FirstTimePage.ScreenConfig, self.screen_page)
# Download Samples page
self.resource_page = QtWidgets.QWizardPage()
self.resource_page.setObjectName('resource_page')
self.resource_page.setFinalPage(True)
self.resource_layout = QtWidgets.QVBoxLayout(self.resource_page)
self.resource_layout.setContentsMargins(50, 20, 50, 20)
self.resource_layout.setObjectName('resource_layout')
self.resource_label = QtWidgets.QLabel(self.resource_page)
self.resource_label.setObjectName('resource_label')
self.resource_label.setWordWrap(True)
self.resource_layout.addWidget(self.resource_label)
first_time_wizard.setPage(FirstTimePage.SampleOption, self.resource_page)
# The download page # The download page
self.download_page = QtWidgets.QWizardPage() self.download_page = QtWidgets.QWizardPage()
self.download_page.setObjectName('download_page') self.download_page.setObjectName('download_page')
@ -134,6 +140,7 @@ class UiFirstTimeWizard(object):
# The "you don't have an internet connection" page. # The "you don't have an internet connection" page.
self.no_internet_page = QtWidgets.QWizardPage() self.no_internet_page = QtWidgets.QWizardPage()
self.no_internet_page.setObjectName('no_internet_page') self.no_internet_page.setObjectName('no_internet_page')
self.no_internet_page.setFinalPage(True)
self.no_internet_layout = QtWidgets.QVBoxLayout(self.no_internet_page) self.no_internet_layout = QtWidgets.QVBoxLayout(self.no_internet_page)
self.no_internet_layout.setContentsMargins(50, 30, 50, 40) self.no_internet_layout.setContentsMargins(50, 30, 50, 40)
self.no_internet_layout.setObjectName('no_internet_layout') self.no_internet_layout.setObjectName('no_internet_layout')
@ -242,27 +249,32 @@ class UiFirstTimeWizard(object):
self.progress_bar.setObjectName('progress_bar') self.progress_bar.setObjectName('progress_bar')
self.progress_layout.addWidget(self.progress_bar) self.progress_layout.addWidget(self.progress_bar)
first_time_wizard.setPage(FirstTimePage.Progress, self.progress_page) first_time_wizard.setPage(FirstTimePage.Progress, self.progress_page)
self.retranslate_ui(first_time_wizard) self.retranslate_ui()
def retranslate_ui(self, first_time_wizard): def retranslate_ui(self):
""" """
Translate the UI on the fly Translate the UI on the fly
:param first_time_wizard: The wizard form :param first_time_wizard: The wizard form
""" """
first_time_wizard.setWindowTitle(translate('OpenLP.FirstTimeWizard', 'First Time Wizard')) self.finish_button_text = clean_button_text(self.buttonText(QtWidgets.QWizard.FinishButton))
back_button_text = clean_button_text(self.buttonText(QtWidgets.QWizard.BackButton))
next_button_text = clean_button_text(self.buttonText(QtWidgets.QWizard.NextButton))
self.setWindowTitle(translate('OpenLP.FirstTimeWizard', 'First Time Wizard'))
text = translate('OpenLP.FirstTimeWizard', 'Welcome to the First Time Wizard') text = translate('OpenLP.FirstTimeWizard', 'Welcome to the First Time Wizard')
first_time_wizard.title_label.setText('<span style="font-size:14pt; font-weight:600;">{text}' self.title_label.setText('<span style="font-size:14pt; font-weight:600;">{text}</span>'.format(text=text))
'</span>'.format(text=text)) self.information_label.setText(
button = clean_button_text(first_time_wizard.buttonText(QtWidgets.QWizard.NextButton))
first_time_wizard.information_label.setText(
translate('OpenLP.FirstTimeWizard', 'This wizard will help you to configure OpenLP for initial use. ' translate('OpenLP.FirstTimeWizard', 'This wizard will help you to configure OpenLP for initial use. '
'Click the {button} button below to start.').format(button=button)) 'Click the \'{next_button}\' button below to start.'
).format(next_button=next_button_text))
self.setButtonText(
QtWidgets.QWizard.CustomButton1, translate('OpenLP.FirstTimeWizard', 'Internet Settings'))
self.download_page.setTitle(translate('OpenLP.FirstTimeWizard', 'Downloading Resource Index')) self.download_page.setTitle(translate('OpenLP.FirstTimeWizard', 'Downloading Resource Index'))
self.download_page.setSubTitle(translate('OpenLP.FirstTimeWizard', 'Please wait while the resource index is ' self.download_page.setSubTitle(translate('OpenLP.FirstTimeWizard',
'downloaded.')) 'Please wait while the resource index is downloaded.'))
self.download_label.setText(translate('OpenLP.FirstTimeWizard', 'Please wait while OpenLP downloads the ' self.download_label.setText(translate('OpenLP.FirstTimeWizard',
'resource index file...')) 'Please wait while OpenLP downloads the resource index file...'))
self.plugin_page.setTitle(translate('OpenLP.FirstTimeWizard', 'Select parts of the program you wish to use')) self.plugin_page.setTitle(translate('OpenLP.FirstTimeWizard', 'Select parts of the program you wish to use'))
self.plugin_page.setSubTitle(translate('OpenLP.FirstTimeWizard', self.plugin_page.setSubTitle(translate('OpenLP.FirstTimeWizard',
'You can also change these settings after the Wizard.')) 'You can also change these settings after the Wizard.'))
@ -270,11 +282,10 @@ class UiFirstTimeWizard(object):
self.screen_page.setSubTitle(translate('OpenLP.FirstTimeWizard', self.screen_page.setSubTitle(translate('OpenLP.FirstTimeWizard',
'Choose the main display screen for OpenLP.')) 'Choose the main display screen for OpenLP.'))
self.songs_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Songs')) self.songs_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Songs'))
self.custom_check_box.setText(translate('OpenLP.FirstTimeWizard', self.custom_check_box.setText(
'Custom Slides Easier to manage than songs and they have their own' translate('OpenLP.FirstTimeWizard',
' list of slides')) 'Custom Slides Easier to manage than songs and they have their own list of slides'))
self.bible_check_box.setText(translate('OpenLP.FirstTimeWizard', self.bible_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Bibles Import and show Bibles'))
'Bibles Import and show Bibles'))
self.image_check_box.setText(translate('OpenLP.FirstTimeWizard', self.image_check_box.setText(translate('OpenLP.FirstTimeWizard',
'Images Show images or replace background with them')) 'Images Show images or replace background with them'))
self.presentation_check_box.setText(translate('OpenLP.FirstTimeWizard', self.presentation_check_box.setText(translate('OpenLP.FirstTimeWizard',
@ -283,22 +294,25 @@ class UiFirstTimeWizard(object):
self.song_usage_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Song Usage Monitor')) self.song_usage_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Song Usage Monitor'))
self.alert_check_box.setText(translate('OpenLP.FirstTimeWizard', self.alert_check_box.setText(translate('OpenLP.FirstTimeWizard',
'Alerts Display informative messages while showing other slides')) 'Alerts Display informative messages while showing other slides'))
self.resource_page.setTitle(translate('OpenLP.FirstTimeWizard', 'Resource Data'))
self.resource_page.setSubTitle(translate('OpenLP.FirstTimeWizard', 'Can OpenLP download some resource data?'))
self.resource_label.setText(
translate('OpenLP.FirstTimeWizard',
'OpenLP has collected some resources that we have permission to distribute.\n\n'
'If you would like to download some of these resources click the \'{next_button}\' button, '
'otherwise click the \'{finish_button}\' button.'
).format(next_button=next_button_text, finish_button=self.finish_button_text))
self.no_internet_page.setTitle(translate('OpenLP.FirstTimeWizard', 'No Internet Connection')) self.no_internet_page.setTitle(translate('OpenLP.FirstTimeWizard', 'No Internet Connection'))
self.no_internet_page.setSubTitle( self.no_internet_page.setSubTitle(translate('OpenLP.FirstTimeWizard', 'Cannot connect to the internet.'))
translate('OpenLP.FirstTimeWizard', 'Unable to detect an Internet connection.')) self.no_internet_label.setText(
button = clean_button_text(first_time_wizard.buttonText(QtWidgets.QWizard.FinishButton)) translate('OpenLP.FirstTimeWizard',
self.no_internet_text = translate('OpenLP.FirstTimeWizard', 'OpenLP could not connect to the internet to get information about the sample data available.\n\n'
'No Internet connection was found. The First Time Wizard needs an Internet ' 'Please check your internet connection. If your church uses a proxy server click the '
'connection in order to be able to download sample songs, Bibles and themes.' '\'Internet Settings\' button below and enter the server details there.\n\nClick the '
' Click the {button} button now to start OpenLP with initial settings and ' '\'{back_button}\' button to try again.\n\nIf you click the \'{finish_button}\' '
'no sample data.\n\nTo re-run the First Time Wizard and import this sample ' 'button you can download the data at a later time by selecting \'Re-run First Time Wizard\' '
'data at a later time, check your Internet connection and re-run this ' 'from the \'Tools\' menu in OpenLP.'
'wizard by selecting "Tools/Re-run First Time Wizard" from OpenLP.' ).format(back_button=back_button_text, finish_button=self.finish_button_text))
).format(button=button)
button = clean_button_text(first_time_wizard.buttonText(QtWidgets.QWizard.CancelButton))
self.cancel_wizard_text = translate('OpenLP.FirstTimeWizard',
'\n\nTo cancel the First Time Wizard completely (and not start OpenLP), '
'click the {button} button now.').format(button=button)
self.songs_page.setTitle(translate('OpenLP.FirstTimeWizard', 'Sample Songs')) self.songs_page.setTitle(translate('OpenLP.FirstTimeWizard', 'Sample Songs'))
self.songs_page.setSubTitle(translate('OpenLP.FirstTimeWizard', 'Select and download public domain songs.')) self.songs_page.setSubTitle(translate('OpenLP.FirstTimeWizard', 'Select and download public domain songs.'))
self.bibles_page.setTitle(translate('OpenLP.FirstTimeWizard', 'Sample Bibles')) self.bibles_page.setTitle(translate('OpenLP.FirstTimeWizard', 'Sample Bibles'))
@ -310,13 +324,8 @@ class UiFirstTimeWizard(object):
self.themes_select_all_button.setToolTip(translate('OpenLP.FirstTimeWizard', 'Select all')) self.themes_select_all_button.setToolTip(translate('OpenLP.FirstTimeWizard', 'Select all'))
self.themes_deselect_all_button.setToolTip(translate('OpenLP.FirstTimeWizard', 'Deselect all')) self.themes_deselect_all_button.setToolTip(translate('OpenLP.FirstTimeWizard', 'Deselect all'))
self.progress_page.setTitle(translate('OpenLP.FirstTimeWizard', 'Downloading and Configuring')) self.progress_page.setTitle(translate('OpenLP.FirstTimeWizard', 'Downloading and Configuring'))
self.progress_page.setSubTitle(translate('OpenLP.FirstTimeWizard', 'Please wait while resources are downloaded ' self.progress_page.setSubTitle(
'and OpenLP is configured.')) translate('OpenLP.FirstTimeWizard', 'Please wait while resources are downloaded and OpenLP is configured.'))
self.progress_label.setText(translate('OpenLP.FirstTimeWizard', 'Starting configuration process...'))
first_time_wizard.setButtonText(QtWidgets.QWizard.CustomButton1,
clean_button_text(first_time_wizard.buttonText(QtWidgets.QWizard.FinishButton)))
first_time_wizard.setButtonText(QtWidgets.QWizard.CustomButton2,
clean_button_text(first_time_wizard.buttonText(QtWidgets.QWizard.CancelButton)))
def on_projectors_check_box_clicked(self): def on_projectors_check_box_clicked(self):
# When clicking projectors_check box, change the visibility setting for Projectors panel. # When clicking projectors_check box, change the visibility setting for Projectors panel.

View File

@ -681,8 +681,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow, LogMixin, RegistryPropert
return return
first_run_wizard = FirstTimeForm(self) first_run_wizard = FirstTimeForm(self)
first_run_wizard.initialize(ScreenList()) first_run_wizard.initialize(ScreenList())
first_run_wizard.exec() if first_run_wizard.exec() == QtWidgets.QDialog.Rejected:
if first_run_wizard.was_cancelled:
return return
self.application.set_busy_cursor() self.application.set_busy_cursor()
self.first_time() self.first_time()

View File

@ -150,6 +150,34 @@ class ProxyWidget(QtWidgets.QGroupBox):
settings.setValue('advanced/proxy password', self.password_edit.text()) settings.setValue('advanced/proxy password', self.password_edit.text())
class ProxyDialog(QtWidgets.QDialog):
"""
A basic dialog to show proxy settingd
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.layout = QtWidgets.QVBoxLayout(self)
self.proxy_widget = ProxyWidget(self)
self.layout.addWidget(self.proxy_widget)
self.button_box = \
QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel, self)
self.layout.addWidget(self.button_box)
self.button_box.accepted.connect(self.accept)
self.button_box.rejected.connect(self.reject)
def accept(self):
"""
Reimplement the the accept slot so that the ProxyWidget settings can be saved.
:rtype: None
"""
self.proxy_widget.save()
super().accept()
def retranslate_ui(self):
self.proxy_widget.retranslate_ui()
self.setWindowTitle(translate('OpenLP.ProxyDialog', 'Proxy Server Settings'))
class ScreenButton(QtWidgets.QPushButton): class ScreenButton(QtWidgets.QPushButton):
""" """
A special button class that holds the screen information about it A special button class that holds the screen information about it

View File

@ -106,7 +106,7 @@ class OpenLPSongImport(SongImport):
pass pass
# Check the file type # Check the file type
if not isinstance(self.import_source, str) or not self.import_source.endswith('.sqlite'): if self.import_source.suffix != '.sqlite':
self.log_error(self.import_source, translate('SongsPlugin.OpenLPSongImport', self.log_error(self.import_source, translate('SongsPlugin.OpenLPSongImport',
'Not a valid OpenLP 2 song database.')) 'Not a valid OpenLP 2 song database.'))
return return

View File

@ -49,13 +49,6 @@ def report_song_list():
Path(translate('SongPlugin.ReportSongList', 'song_extract.csv')), Path(translate('SongPlugin.ReportSongList', 'song_extract.csv')),
translate('SongPlugin.ReportSongList', 'CSV format (*.csv)')) translate('SongPlugin.ReportSongList', 'CSV format (*.csv)'))
if report_file_path is None:
main_window.error_message(
translate('SongPlugin.ReportSongList', 'Output Path Not Selected'),
translate('SongPlugin.ReportSongList', 'You have not set a valid output location for your report. \n'
'Please select an existing path on your computer.')
)
return
report_file_path.with_suffix('.csv') report_file_path.with_suffix('.csv')
Registry().get('application').set_busy_cursor() Registry().get('application').set_busy_cursor()
try: try:

0
run_openlp.py Executable file → Normal file
View File

0
setup.py Executable file → Normal file
View File

View File

@ -224,7 +224,7 @@ class TestHttpUtils(TestCase, TestMixin):
file_size = get_url_file_size(fake_url) file_size = get_url_file_size(fake_url)
# THEN: The correct methods are called with the correct arguments and a web page is returned # THEN: The correct methods are called with the correct arguments and a web page is returned
mocked_requests.head.assert_called_once_with(fake_url, allow_redirects=True, timeout=30.0) mocked_requests.head.assert_called_once_with(fake_url, allow_redirects=True, proxies=None, timeout=30.0)
assert file_size == 100 assert file_size == 100
@patch('openlp.core.common.httputils.requests') @patch('openlp.core.common.httputils.requests')

View File

@ -27,6 +27,8 @@ import tempfile
from unittest import TestCase from unittest import TestCase
from unittest.mock import MagicMock, call, patch, DEFAULT from unittest.mock import MagicMock, call, patch, DEFAULT
from PyQt5 import QtWidgets
from openlp.core.common.path import Path from openlp.core.common.path import Path
from openlp.core.common.registry import Registry from openlp.core.common.registry import Registry
from openlp.core.ui.firsttimeform import FirstTimeForm, ThemeListWidgetItem from openlp.core.ui.firsttimeform import FirstTimeForm, ThemeListWidgetItem
@ -120,10 +122,23 @@ class TestFirstTimeForm(TestCase, TestMixin):
# THEN: The screens should be set up, and the default values initialised # THEN: The screens should be set up, and the default values initialised
assert expected_screens == frw.screens, 'The screens should be correct' assert expected_screens == frw.screens, 'The screens should be correct'
assert frw.web_access is True, 'The default value of self.web_access should be True' assert frw.web_access is True, 'The default value of self.web_access should be True'
assert frw.was_cancelled is False, 'The default value of self.was_cancelled should be False'
assert [] == frw.thumbnail_download_threads, 'The list of threads should be empty' assert [] == frw.thumbnail_download_threads, 'The list of threads should be empty'
assert frw.has_run_wizard is False, 'has_run_wizard should be False' assert frw.has_run_wizard is False, 'has_run_wizard should be False'
@patch('openlp.core.ui.firsttimewizard.QtWidgets.QWizard.exec')
def test_exec(self, mocked_qwizard_exec):
# GIVEN: An instance of FirstTimeForm
frw = FirstTimeForm(None)
with patch.object(frw, 'set_defaults') as mocked_set_defaults:
# WHEN: exec is called
frw.exec()
# THEN: The wizard should be reset and the exec methon on the super class should have been called
mocked_set_defaults.assert_called_once()
mocked_qwizard_exec.assert_called_once()
def test_set_defaults(self): def test_set_defaults(self):
""" """
Test that the default values are set when set_defaults() is run Test that the default values are set when set_defaults() is run
@ -134,8 +149,6 @@ class TestFirstTimeForm(TestCase, TestMixin):
mocked_settings = MagicMock() mocked_settings = MagicMock()
mocked_settings.value.side_effect = lambda key: {'core/has run wizard': False}[key] mocked_settings.value.side_effect = lambda key: {'core/has run wizard': False}[key]
with patch.object(frw, 'restart') as mocked_restart, \ with patch.object(frw, 'restart') as mocked_restart, \
patch.object(frw, 'cancel_button') as mocked_cancel_button, \
patch.object(frw, 'no_internet_finish_button') as mocked_no_internet_finish_btn, \
patch.object(frw, 'currentIdChanged') as mocked_currentIdChanged, \ patch.object(frw, 'currentIdChanged') as mocked_currentIdChanged, \
patch.object(frw, 'theme_combo_box') as mocked_theme_combo_box, \ patch.object(frw, 'theme_combo_box') as mocked_theme_combo_box, \
patch.object(frw, 'songs_check_box') as mocked_songs_check_box, \ patch.object(frw, 'songs_check_box') as mocked_songs_check_box, \
@ -153,12 +166,8 @@ class TestFirstTimeForm(TestCase, TestMixin):
# THEN: The default values should have been set # THEN: The default values should have been set
mocked_restart.assert_called_once() mocked_restart.assert_called_once()
assert 'https://get.openlp.org/ftw/' == frw.web, 'The default URL should be set' assert 'https://get.openlp.org/ftw/' == frw.web, 'The default URL should be set'
mocked_cancel_button.clicked.connect.assert_called_once_with(frw.on_cancel_button_clicked)
mocked_no_internet_finish_btn.clicked.connect.assert_called_once_with(
frw.on_no_internet_finish_button_clicked)
mocked_currentIdChanged.connect.assert_called_once_with(frw.on_current_id_changed) mocked_currentIdChanged.connect.assert_called_once_with(frw.on_current_id_changed)
mocked_register_function.assert_called_once_with('config_screen_changed', frw.screen_selection_widget.load) mocked_register_function.assert_called_once_with('config_screen_changed', frw.screen_selection_widget.load)
mocked_no_internet_finish_btn.setVisible.assert_called_once_with(False)
mocked_settings.value.assert_has_calls([call('core/has run wizard')]) mocked_settings.value.assert_has_calls([call('core/has run wizard')])
mocked_gettempdir.assert_called_once() mocked_gettempdir.assert_called_once()
mocked_create_paths.assert_called_once_with(Path('temp', 'openlp')) mocked_create_paths.assert_called_once_with(Path('temp', 'openlp'))
@ -177,8 +186,6 @@ class TestFirstTimeForm(TestCase, TestMixin):
mocked_settings.value.side_effect = \ mocked_settings.value.side_effect = \
lambda key: {'core/has run wizard': True, 'themes/global theme': 'Default Theme'}[key] lambda key: {'core/has run wizard': True, 'themes/global theme': 'Default Theme'}[key]
with patch.object(frw, 'restart') as mocked_restart, \ with patch.object(frw, 'restart') as mocked_restart, \
patch.object(frw, 'cancel_button') as mocked_cancel_button, \
patch.object(frw, 'no_internet_finish_button') as mocked_no_internet_finish_btn, \
patch.object(frw, 'currentIdChanged') as mocked_currentIdChanged, \ patch.object(frw, 'currentIdChanged') as mocked_currentIdChanged, \
patch.object(frw, 'theme_combo_box', **{'findText.return_value': 3}) as mocked_theme_combo_box, \ patch.object(frw, 'theme_combo_box', **{'findText.return_value': 3}) as mocked_theme_combo_box, \
patch.multiple(frw, songs_check_box=DEFAULT, bible_check_box=DEFAULT, presentation_check_box=DEFAULT, patch.multiple(frw, songs_check_box=DEFAULT, bible_check_box=DEFAULT, presentation_check_box=DEFAULT,
@ -200,12 +207,8 @@ class TestFirstTimeForm(TestCase, TestMixin):
# THEN: The default values should have been set # THEN: The default values should have been set
mocked_restart.assert_called_once() mocked_restart.assert_called_once()
assert 'https://get.openlp.org/ftw/' == frw.web, 'The default URL should be set' assert 'https://get.openlp.org/ftw/' == frw.web, 'The default URL should be set'
mocked_cancel_button.clicked.connect.assert_called_once_with(frw.on_cancel_button_clicked)
mocked_no_internet_finish_btn.clicked.connect.assert_called_once_with(
frw.on_no_internet_finish_button_clicked)
mocked_currentIdChanged.connect.assert_called_once_with(frw.on_current_id_changed) mocked_currentIdChanged.connect.assert_called_once_with(frw.on_current_id_changed)
mocked_register_function.assert_called_once_with('config_screen_changed', frw.screen_selection_widget.load) mocked_register_function.assert_called_once_with('config_screen_changed', frw.screen_selection_widget.load)
mocked_no_internet_finish_btn.setVisible.assert_called_once_with(False)
mocked_settings.value.assert_has_calls([call('core/has run wizard'), call('themes/global theme')]) mocked_settings.value.assert_has_calls([call('core/has run wizard'), call('themes/global theme')])
mocked_gettempdir.assert_called_once() mocked_gettempdir.assert_called_once()
mocked_create_paths.assert_called_once_with(Path('temp', 'openlp')) mocked_create_paths.assert_called_once_with(Path('temp', 'openlp'))
@ -219,12 +222,79 @@ class TestFirstTimeForm(TestCase, TestMixin):
mocked_theme_combo_box.findText.assert_called_once_with('Default Theme') mocked_theme_combo_box.findText.assert_called_once_with('Default Theme')
mocked_theme_combo_box.setCurrentIndex(3) mocked_theme_combo_box.setCurrentIndex(3)
@patch('openlp.core.ui.firsttimewizard.QtWidgets.QWizard.accept')
@patch('openlp.core.ui.firsttimewizard.Settings')
def test_accept_method(self, mocked_settings, mocked_qwizard_accept):
"""
Test the FirstTimeForm.accept method
"""
# GIVEN: An instance of FirstTimeForm
frw = FirstTimeForm(None)
with patch.object(frw, '_set_plugin_status') as mocked_set_plugin_status, \
patch.multiple(frw, songs_check_box=DEFAULT, bible_check_box=DEFAULT, presentation_check_box=DEFAULT,
image_check_box=DEFAULT, media_check_box=DEFAULT, custom_check_box=DEFAULT,
song_usage_check_box=DEFAULT, alert_check_box=DEFAULT) as mocked_check_boxes, \
patch.object(frw, 'screen_selection_widget') as mocked_screen_selection_widget:
# WHEN: Calling accept
frw.accept()
# THEN: The selected plugins should be enabled, the screen selection saved and the super method called
mocked_set_plugin_status.assert_has_calls([
call(mocked_check_boxes['songs_check_box'], 'songs/status'),
call(mocked_check_boxes['bible_check_box'], 'bibles/status'),
call(mocked_check_boxes['presentation_check_box'], 'presentations/status'),
call(mocked_check_boxes['image_check_box'], 'images/status'),
call(mocked_check_boxes['media_check_box'], 'media/status'),
call(mocked_check_boxes['custom_check_box'], 'custom/status'),
call(mocked_check_boxes['song_usage_check_box'], 'songusage/status'),
call(mocked_check_boxes['alert_check_box'], 'alerts/status')])
mocked_screen_selection_widget.save.assert_called_once()
mocked_qwizard_accept.assert_called_once()
@patch('openlp.core.ui.firsttimewizard.Settings')
def test_accept_method_theme_not_selected(self, mocked_settings):
"""
Test the FirstTimeForm.accept method when there is no default theme selected
"""
# GIVEN: An instance of FirstTimeForm
frw = FirstTimeForm(None)
with patch.object(frw, '_set_plugin_status'), \
patch.object(frw, 'screen_selection_widget'), \
patch.object(frw, 'theme_combo_box', **{'currentIndex.return_value': '-1'}):
# WHEN: Calling accept and the currentIndex method of the theme_combo_box returns -1
frw.accept()
# THEN: OpenLP should not try to save a theme name
mocked_settings.setValue.assert_not_called()
@patch('openlp.core.ui.firsttimeform.Settings')
def test_accept_method_theme_selected(self, mocked_settings):
"""
Test the FirstTimeForm.accept method when a default theme is selected
"""
# GIVEN: An instance of FirstTimeForm
frw = FirstTimeForm(None)
with patch.object(frw, '_set_plugin_status'), \
patch.object(frw, 'screen_selection_widget'), \
patch.object(
frw, 'theme_combo_box', **{'currentIndex.return_value': 0, 'currentText.return_value': 'Test Item'}):
# WHEN: Calling accept and the currentIndex method of the theme_combo_box returns 0
frw.accept()
# THEN: The 'currentItem' in the combobox should have been set as the default theme.
mocked_settings().setValue.assert_called_once_with('themes/global theme', 'Test Item')
@patch('openlp.core.ui.firsttimewizard.QtWidgets.QWizard.reject')
@patch('openlp.core.ui.firsttimeform.time') @patch('openlp.core.ui.firsttimeform.time')
@patch('openlp.core.ui.firsttimeform.get_thread_worker') @patch('openlp.core.ui.firsttimeform.get_thread_worker')
@patch('openlp.core.ui.firsttimeform.is_thread_finished') @patch('openlp.core.ui.firsttimeform.is_thread_finished')
def test_on_cancel_button_clicked(self, mocked_is_thread_finished, mocked_get_thread_worker, mocked_time): def test_reject_method(
self, mocked_is_thread_finished, mocked_get_thread_worker, mocked_time, mocked_qwizard_reject):
""" """
Test that the cancel button click slot shuts down the threads correctly Test that the reject method shuts down the threads correctly
""" """
# GIVEN: A FRW, some mocked threads and workers (that isn't quite done) and other mocked stuff # GIVEN: A FRW, some mocked threads and workers (that isn't quite done) and other mocked stuff
mocked_worker = MagicMock() mocked_worker = MagicMock()
@ -235,17 +305,47 @@ class TestFirstTimeForm(TestCase, TestMixin):
frw.thumbnail_download_threads = ['test_thread'] frw.thumbnail_download_threads = ['test_thread']
with patch.object(frw.application, 'set_normal_cursor') as mocked_set_normal_cursor: with patch.object(frw.application, 'set_normal_cursor') as mocked_set_normal_cursor:
# WHEN: on_cancel_button_clicked() is called # WHEN: the reject method is called
frw.on_cancel_button_clicked() frw.reject()
# THEN: The right things should be called in the right order # THEN: The right things should be called in the right order
assert frw.was_cancelled is True, 'The was_cancelled property should have been set to True'
mocked_get_thread_worker.assert_called_once_with('test_thread') mocked_get_thread_worker.assert_called_once_with('test_thread')
mocked_worker.cancel_download.assert_called_once() mocked_worker.cancel_download.assert_called_once()
mocked_is_thread_finished.assert_called_with('test_thread') mocked_is_thread_finished.assert_called_with('test_thread')
assert mocked_is_thread_finished.call_count == 2, 'isRunning() should have been called twice' assert mocked_is_thread_finished.call_count == 2, 'isRunning() should have been called twice'
mocked_time.sleep.assert_called_once_with(0.1) mocked_time.sleep.assert_called_once_with(0.1)
mocked_set_normal_cursor.assert_called_once_with() mocked_set_normal_cursor.assert_called_once()
mocked_qwizard_reject.assert_called_once()
@patch('openlp.core.ui.firsttimeform.ProxyDialog')
def test_on_custom_button_clicked(self, mocked_proxy_dialog):
"""
Test _on_custom_button when it is called whe the 'internet settings' (CustomButton1) button is not clicked.
"""
# GIVEN: An instance of the FirstTimeForm
frw = FirstTimeForm(None)
# WHEN: Calling _on_custom_button_clicked with a different button to the 'internet settings button.
frw._on_custom_button_clicked(QtWidgets.QWizard.CustomButton2)
# THEN: The ProxyDialog should not be shown.
mocked_proxy_dialog.assert_not_called()
@patch('openlp.core.ui.firsttimeform.ProxyDialog')
def test_on_custom_button_clicked_internet_settings(self, mocked_proxy_dialog):
"""
Test _on_custom_button when it is called when the 'internet settings' (CustomButton1) button is clicked.
"""
# GIVEN: An instance of the FirstTimeForm
frw = FirstTimeForm(None)
# WHEN: Calling _on_custom_button_clicked with the constant for the 'internet settings' button (CustomButton1)
frw._on_custom_button_clicked(QtWidgets.QWizard.CustomButton1)
# THEN: The ProxyDialog should be shown.
mocked_proxy_dialog.assert_called_with(frw)
mocked_proxy_dialog().retranslate_ui.assert_called_once()
mocked_proxy_dialog().exec.assert_called_once()
@patch('openlp.core.ui.firsttimeform.critical_error_message_box') @patch('openlp.core.ui.firsttimeform.critical_error_message_box')
def test__parse_config_invalid_config(self, mocked_critical_error_message_box): def test__parse_config_invalid_config(self, mocked_critical_error_message_box):