From b8bbb4391c367c8546e156c8f53995a83a84bc94 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sat, 16 Apr 2016 14:51:42 +0100 Subject: [PATCH 01/23] move code from presentations --- openlp/core/common/__init__.py | 32 +++++++++ openlp/plugins/media/mediaplugin.py | 72 ++++++++++++++++++- .../presentations/lib/pdfcontroller.py | 28 ++------ 3 files changed, 109 insertions(+), 23 deletions(-) diff --git a/openlp/core/common/__init__.py b/openlp/core/common/__init__.py index b8a1a4d2e..a1ce05abd 100644 --- a/openlp/core/common/__init__.py +++ b/openlp/core/common/__init__.py @@ -24,6 +24,7 @@ The :mod:`common` module contains most of the components and libraries that make OpenLP work. """ import hashlib + import logging import os import re @@ -31,6 +32,7 @@ import sys import traceback from ipaddress import IPv4Address, IPv6Address, AddressValueError from shutil import which +from subprocess import check_output, CalledProcessError, STDOUT from PyQt5 import QtCore, QtGui from PyQt5.QtCore import QCryptographicHash as QHash @@ -247,6 +249,10 @@ from .applocation import AppLocation from .actions import ActionList from .languagemanager import LanguageManager +if is_win(): + from subprocess import STARTUPINFO, STARTF_USESHOWWINDOW + + def add_actions(target, actions): """ @@ -371,3 +377,29 @@ def clean_filename(filename): if not isinstance(filename, str): filename = str(filename, 'utf-8') return INVALID_FILE_CHARS.sub('_', CONTROL_CHARS.sub('', filename)) + + +def check_binary(program_path): + """ + Function that checks whether a binary exists. + + :param program_path:The full path to the binary to check. + :return: program output to be parsed + """ + log.debug('testing program_path: %s', program_path) + try: + # Setup startupinfo options for check_output to avoid console popping up on windows + if is_win(): + startupinfo = STARTUPINFO() + startupinfo.dwFlags |= STARTF_USESHOWWINDOW + else: + startupinfo = None + runlog = check_output([program_path, '--help'], stderr=STDOUT, startupinfo=startupinfo) + except CalledProcessError as e: + runlog = e.output + except Exception: + trace_error_handler(log) + runlog = '' + log.debug('check_output returned: %s' % runlog) + return runlog + diff --git a/openlp/plugins/media/mediaplugin.py b/openlp/plugins/media/mediaplugin.py index daeb4dc2c..73b631831 100644 --- a/openlp/plugins/media/mediaplugin.py +++ b/openlp/plugins/media/mediaplugin.py @@ -27,7 +27,7 @@ import logging from PyQt5 import QtCore -from openlp.core.common import Settings, translate +from openlp.core.common import Settings, translate, check_binary from openlp.core.lib import Plugin, StringContent, build_icon from openlp.plugins.media.lib import MediaMediaItem, MediaTab @@ -62,6 +62,51 @@ class MediaPlugin(Plugin): """ super().initialise() + def check_pre_conditions(self): + """ + Check it we have a valid environment. + :return: true or false + """ + log.debug('check_installed Pdf') + self.mudrawbin = '' + self.gsbin = '' + self.also_supports = [] + # Use the user defined program if given + if Settings().value('presentations/enable_pdf_program'): + pdf_program = Settings().value('presentations/pdf_program') + program_type = self.check_binary('mediainfo') + if program_type == 'gs': + self.gsbin = pdf_program + elif program_type == 'mudraw': + self.mudrawbin = pdf_program + else: + # Fallback to autodetection + application_path = AppLocation.get_directory(AppLocation.AppDir) + if is_win(): + # for windows we only accept mudraw.exe in the base folder + application_path = AppLocation.get_directory(AppLocation.AppDir) + if os.path.isfile(os.path.join(application_path, 'mudraw.exe')): + self.mudrawbin = os.path.join(application_path, 'mudraw.exe') + else: + DEVNULL = open(os.devnull, 'wb') + # First try to find mupdf + self.mudrawbin = which('mudraw') + # if mupdf isn't installed, fallback to ghostscript + if not self.mudrawbin: + self.gsbin = which('gs') + # Last option: check if mudraw is placed in OpenLP base folder + if not self.mudrawbin and not self.gsbin: + application_path = AppLocation.get_directory(AppLocation.AppDir) + if os.path.isfile(os.path.join(application_path, 'mudraw')): + self.mudrawbin = os.path.join(application_path, 'mudraw') + if self.mudrawbin: + self.also_supports = ['xps', 'oxps'] + return True + elif self.gsbin: + return True + else: + return False + def app_startup(self): """ Override app_startup() in order to do nothing @@ -137,3 +182,28 @@ class MediaPlugin(Plugin): Add html code to htmlbuilder. """ return self.media_controller.get_media_display_html() + + +def process_check_binary(program_path): + """ + Function that checks whether a binary is either ghostscript or mudraw or neither. + Is also used from presentationtab.py + + :param program_path:The full path to the binary to check. + :return: Type of the binary, 'gs' if ghostscript, 'mudraw' if mudraw, None if invalid. + """ + program_type = None + runlog = check_binary(program_path) + # Analyse the output to see it the program is mudraw, ghostscript or neither + for line in runlog.splitlines(): + decoded_line = line.decode() + found_mudraw = re.search('usage: mudraw.*', decoded_line, re.IGNORECASE) + if found_mudraw: + program_type = 'mudraw' + break + found_gs = re.search('GPL Ghostscript.*', decoded_line, re.IGNORECASE) + if found_gs: + program_type = 'gs' + break + log.debug('in check_binary, found: %s', program_type) + return program_type diff --git a/openlp/plugins/presentations/lib/pdfcontroller.py b/openlp/plugins/presentations/lib/pdfcontroller.py index dbea84327..0ef9cb29b 100644 --- a/openlp/plugins/presentations/lib/pdfcontroller.py +++ b/openlp/plugins/presentations/lib/pdfcontroller.py @@ -22,13 +22,12 @@ import os import logging -from tempfile import NamedTemporaryFile import re from shutil import which -from subprocess import check_output, CalledProcessError, STDOUT +from subprocess import check_output, CalledProcessError -from openlp.core.common import AppLocation -from openlp.core.common import Settings, is_win, trace_error_handler +from openlp.core.common import AppLocation, check_binary +from openlp.core.common import Settings, is_win from openlp.core.lib import ScreenList from .presentationcontroller import PresentationController, PresentationDocument @@ -61,7 +60,7 @@ class PdfController(PresentationController): self.check_installed() @staticmethod - def check_binary(program_path): + def process_check_binary(program_path): """ Function that checks whether a binary is either ghostscript or mudraw or neither. Is also used from presentationtab.py @@ -70,22 +69,7 @@ class PdfController(PresentationController): :return: Type of the binary, 'gs' if ghostscript, 'mudraw' if mudraw, None if invalid. """ program_type = None - runlog = '' - log.debug('testing program_path: %s', program_path) - try: - # Setup startupinfo options for check_output to avoid console popping up on windows - if is_win(): - startupinfo = STARTUPINFO() - startupinfo.dwFlags |= STARTF_USESHOWWINDOW - else: - startupinfo = None - runlog = check_output([program_path, '--help'], stderr=STDOUT, startupinfo=startupinfo) - except CalledProcessError as e: - runlog = e.output - except Exception: - trace_error_handler(log) - runlog = '' - log.debug('check_output returned: %s' % runlog) + runlog = check_binary(program_path) # Analyse the output to see it the program is mudraw, ghostscript or neither for line in runlog.splitlines(): decoded_line = line.decode() @@ -122,7 +106,7 @@ class PdfController(PresentationController): # Use the user defined program if given if Settings().value('presentations/enable_pdf_program'): pdf_program = Settings().value('presentations/pdf_program') - program_type = self.check_binary(pdf_program) + program_type = self.process_check_binary(pdf_program) if program_type == 'gs': self.gsbin = pdf_program elif program_type == 'mudraw': From 40981701e97cd15818a178cb74d3e4b29777d4b3 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sat, 16 Apr 2016 15:43:31 +0100 Subject: [PATCH 02/23] fix checks --- openlp/core/ui/media/mediacontroller.py | 2 +- openlp/plugins/media/mediaplugin.py | 61 +++++-------------------- 2 files changed, 12 insertions(+), 51 deletions(-) diff --git a/openlp/core/ui/media/mediacontroller.py b/openlp/core/ui/media/mediacontroller.py index cf116e861..71e0f1903 100644 --- a/openlp/core/ui/media/mediacontroller.py +++ b/openlp/core/ui/media/mediacontroller.py @@ -296,7 +296,7 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties): tooltip=translate('OpenLP.SlideController', 'Stop playing media.'), triggers=controller.send_to_plugins) controller.mediabar.add_toolbar_action('playbackLoop', text='media_playback_loop', - icon=':/slides/media_playback_stop.png', checked=False, + icon=':/media/media_repeat.png', checked=False, tooltip=translate('OpenLP.SlideController', 'Loop playing media.'), triggers=controller.send_to_plugins) controller.position_label = QtWidgets.QLabel() diff --git a/openlp/plugins/media/mediaplugin.py b/openlp/plugins/media/mediaplugin.py index 73b631831..4f9c4a0b1 100644 --- a/openlp/plugins/media/mediaplugin.py +++ b/openlp/plugins/media/mediaplugin.py @@ -24,10 +24,13 @@ The Media plugin """ import logging +import os +import re +from shutil import which from PyQt5 import QtCore -from openlp.core.common import Settings, translate, check_binary +from openlp.core.common import AppLocation, Settings, translate, check_binary, is_win from openlp.core.lib import Plugin, StringContent, build_icon from openlp.plugins.media.lib import MediaMediaItem, MediaTab @@ -67,45 +70,9 @@ class MediaPlugin(Plugin): Check it we have a valid environment. :return: true or false """ - log.debug('check_installed Pdf') - self.mudrawbin = '' - self.gsbin = '' - self.also_supports = [] + log.debug('check_installed Mediainfo') # Use the user defined program if given - if Settings().value('presentations/enable_pdf_program'): - pdf_program = Settings().value('presentations/pdf_program') - program_type = self.check_binary('mediainfo') - if program_type == 'gs': - self.gsbin = pdf_program - elif program_type == 'mudraw': - self.mudrawbin = pdf_program - else: - # Fallback to autodetection - application_path = AppLocation.get_directory(AppLocation.AppDir) - if is_win(): - # for windows we only accept mudraw.exe in the base folder - application_path = AppLocation.get_directory(AppLocation.AppDir) - if os.path.isfile(os.path.join(application_path, 'mudraw.exe')): - self.mudrawbin = os.path.join(application_path, 'mudraw.exe') - else: - DEVNULL = open(os.devnull, 'wb') - # First try to find mupdf - self.mudrawbin = which('mudraw') - # if mupdf isn't installed, fallback to ghostscript - if not self.mudrawbin: - self.gsbin = which('gs') - # Last option: check if mudraw is placed in OpenLP base folder - if not self.mudrawbin and not self.gsbin: - application_path = AppLocation.get_directory(AppLocation.AppDir) - if os.path.isfile(os.path.join(application_path, 'mudraw')): - self.mudrawbin = os.path.join(application_path, 'mudraw') - if self.mudrawbin: - self.also_supports = ['xps', 'oxps'] - return True - elif self.gsbin: - return True - else: - return False + return process_check_binary('mediainfo') def app_startup(self): """ @@ -194,16 +161,10 @@ def process_check_binary(program_path): """ program_type = None runlog = check_binary(program_path) - # Analyse the output to see it the program is mudraw, ghostscript or neither + print(runlog) + # Analyse the output to see it the program is mediainfo for line in runlog.splitlines(): decoded_line = line.decode() - found_mudraw = re.search('usage: mudraw.*', decoded_line, re.IGNORECASE) - if found_mudraw: - program_type = 'mudraw' - break - found_gs = re.search('GPL Ghostscript.*', decoded_line, re.IGNORECASE) - if found_gs: - program_type = 'gs' - break - log.debug('in check_binary, found: %s', program_type) - return program_type + if re.search('MediaInfo Command line', decoded_line, re.IGNORECASE): + return True + return False From 278ec2bed2adfe2a61d91e614a28aaa416d86e95 Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Sun, 17 Apr 2016 02:15:23 -0700 Subject: [PATCH 03/23] Update projector UI strings to Python3 format --- openlp/core/ui/projector/editform.py | 21 ++-- openlp/core/ui/projector/manager.py | 124 ++++++++++--------- openlp/core/ui/projector/sourceselectform.py | 26 ++-- 3 files changed, 96 insertions(+), 75 deletions(-) diff --git a/openlp/core/ui/projector/editform.py b/openlp/core/ui/projector/editform.py index 4b06f486f..4996cc75f 100644 --- a/openlp/core/ui/projector/editform.py +++ b/openlp/core/ui/projector/editform.py @@ -182,9 +182,10 @@ class ProjectorEditForm(QDialog, Ui_ProjectorEditForm): QtWidgets.QMessageBox.warning(self, translate('OpenLP.ProjectorEdit', 'Duplicate Name'), translate('OpenLP.ProjectorEdit', - 'There is already an entry with name "%s" in ' - 'the database as ID "%s".
' - 'Please enter a different name.' % (name, record.id))) + 'There is already an entry with name "{name}" in ' + 'the database as ID "{record}".
' + 'Please enter a different name.'.format(name=name, + record=record.id))) valid = False return adx = self.ip_text.text() @@ -198,17 +199,17 @@ class ProjectorEditForm(QDialog, Ui_ProjectorEditForm): QtWidgets.QMessageBox.warning(self, translate('OpenLP.ProjectorWizard', 'Duplicate IP Address'), translate('OpenLP.ProjectorWizard', - 'IP address "%s"
is already in the database as ID %s.' - '

Please Enter a different IP address.' % - (adx, ip.id))) + 'IP address "{ip}"
is already in the database ' + 'as ID {data}.

Please Enter a different ' + 'IP address.'.format(ip=adx, data=ip.id))) valid = False return else: QtWidgets.QMessageBox.warning(self, translate('OpenLP.ProjectorWizard', 'Invalid IP Address'), translate('OpenLP.ProjectorWizard', - 'IP address "%s"
is not a valid IP address.' - '

Please enter a valid IP address.' % adx)) + 'IP address "{ip}"
is not a valid IP address.' + '

Please enter a valid IP address.'.format(ip=adx))) valid = False return port = int(self.port_text.text()) @@ -219,8 +220,8 @@ class ProjectorEditForm(QDialog, Ui_ProjectorEditForm): 'Port numbers below 1000 are reserved for admin use only, ' '
and port numbers above 32767 are not currently usable.' '

Please enter a valid port number between ' - ' 1000 and 32767.' - '

Default PJLink port is %s' % PJLINK_PORT)) + '1000 and 32767.

' + 'Default PJLink port is {port}'.format(port=PJLINK_PORT))) valid = False if valid: self.projector.ip = self.ip_text.text() diff --git a/openlp/core/ui/projector/manager.py b/openlp/core/ui/projector/manager.py index fc40ee386..7c0166f95 100644 --- a/openlp/core/ui/projector/manager.py +++ b/openlp/core/ui/projector/manager.py @@ -344,7 +344,7 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QWidget, Ui_ProjectorManager, real_projector = item.data(QtCore.Qt.UserRole) projector_name = str(item.text()) visible = real_projector.link.status_connect >= S_CONNECTED - log.debug('(%s) Building menu - visible = %s' % (projector_name, visible)) + log.debug('({name}) Building menu - visible = {visible}'.format(name=projector_name, visible=visible)) self.delete_action.setVisible(True) self.edit_action.setVisible(True) self.connect_action.setVisible(not visible) @@ -394,7 +394,7 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QWidget, Ui_ProjectorManager, projectordb=self.projectordb, edit=edit) source = source_select_form.exec(projector.link) - log.debug('(%s) source_select_form() returned %s' % (projector.link.ip, source)) + log.debug('({ip}) source_select_form() returned {data}'.format(ip=projector.link.ip, data=source)) if source is not None and source > 0: projector.link.set_input_source(str(source)) return @@ -473,8 +473,9 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QWidget, Ui_ProjectorManager, return projector = list_item.data(QtCore.Qt.UserRole) msg = QtWidgets.QMessageBox() - msg.setText(translate('OpenLP.ProjectorManager', 'Delete projector (%s) %s?') % (projector.link.ip, - projector.link.name)) + msg.setText(translate('OpenLP.ProjectorManager', + 'Delete projector ({ip}) {name}?'.format(ip=projector.link.ip, + name=projector.link.name))) msg.setInformativeText(translate('OpenLP.ProjectorManager', 'Are you sure you want to delete this projector?')) msg.setStandardButtons(msg.Cancel | msg.Ok) msg.setDefaultButton(msg.Cancel) @@ -522,7 +523,7 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QWidget, Ui_ProjectorManager, list_item = None deleted = self.projectordb.delete_projector(projector.db_item) for item in self.projector_list: - log.debug('New projector list - item: %s %s' % (item.link.ip, item.link.name)) + log.debug('New projector list - item: {ip} {name}'.format(ip=item.link.ip, name=item.link.name)) def on_disconnect_projector(self, opt=None): """ @@ -627,53 +628,58 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QWidget, Ui_ProjectorManager, """ lwi = self.projector_list_widget.item(self.projector_list_widget.currentRow()) projector = lwi.data(QtCore.Qt.UserRole) - message = '%s: %s
' % (translate('OpenLP.ProjectorManager', 'Name'), - projector.link.name) - message = '%s%s: %s
' % (message, translate('OpenLP.ProjectorManager', 'IP'), - projector.link.ip) - message = '%s%s: %s
' % (message, translate('OpenLP.ProjectorManager', 'Port'), - projector.link.port) - message = '%s%s: %s
' % (message, translate('OpenLP.ProjectorManager', 'Notes'), - projector.link.notes) - message = '%s

' % message + message = '{title}: {data}
'.format(title=translate('OpenLP.ProjectorManager', 'Name'), + data=projector.link.name) + message += '{title}: {data}
'.format(title=translate('OpenLP.ProjectorManager', 'IP'), + data=projector.link.ip) + message += '{title}: {data}
'.format(title=translate('OpenLP.ProjectorManager', 'Port'), + data=projector.link.port) + message += '{title}: {data}
'.format(title=translate('OpenLP.ProjectorManager', 'Notes'), + data=projector.link.notes) + message += '

' if projector.link.manufacturer is None: - message = '%s%s' % (message, translate('OpenLP.ProjectorManager', - 'Projector information not available at this time.')) + message += translate('OpenLP.ProjectorManager', 'Projector information not available at this time.') else: - message = '%s%s: %s
' % (message, translate('OpenLP.ProjectorManager', 'Projector Name'), - projector.link.pjlink_name) - message = '%s%s: %s
' % (message, translate('OpenLP.ProjectorManager', 'Manufacturer'), - projector.link.manufacturer) - message = '%s%s: %s
' % (message, translate('OpenLP.ProjectorManager', 'Model'), - projector.link.model) - message = '%s%s: %s

' % (message, translate('OpenLP.ProjectorManager', 'Other info'), - projector.link.other_info) - message = '%s%s: %s
' % (message, translate('OpenLP.ProjectorManager', 'Power status'), - ERROR_MSG[projector.link.power]) - message = '%s%s: %s
' % (message, translate('OpenLP.ProjectorManager', 'Shutter is'), - translate('OpenLP.ProjectorManager', 'Closed') - if projector.link.shutter else translate('OpenLP', 'Open')) + message += '{title}: {data}
'.format(title=translate('OpenLP.ProjectorManager', + 'Projector Name'), + data=projector.link.pjlink_name) + message += '{title}: {data}
'.format(title=translate('OpenLP.ProjectorManager', 'Manufacturer'), + data=projector.link.manufacturer) + message += '{title}: {data}
'.format(title=translate('OpenLP.ProjectorManager', 'Model'), + data=projector.link.model) + message += '{title}: {data}

'.format(title=translate('OpenLP.ProjectorManager', + 'Other info'), + data=projector.link.other_info) + message += '{title}: {data}
'.format(title=translate('OpenLP.ProjectorManager', 'Power status'), + data=ERROR_MSG[projector.link.power]) + message += '{title}: {data}
'.format(title=translate('OpenLP.ProjectorManager', 'Shutter is'), + data=translate('OpenLP.ProjectorManager', 'Closed') + if projector.link.shutter + else translate('OpenLP', 'Open')) message = '%s%s: %s
' % (message, translate('OpenLP.ProjectorManager', 'Current source input is'), projector.link.source) count = 1 for item in projector.link.lamp: - message = '%s %s %s (%s) %s: %s
' % (message, - translate('OpenLP.ProjectorManager', 'Lamp'), - count, - translate('OpenLP.ProjectorManager', 'On') - if item['On'] - else translate('OpenLP.ProjectorManager', 'Off'), - translate('OpenLP.ProjectorManager', 'Hours'), - item['Hours']) - count = count + 1 - message = '%s

' % message + message += '{title} {count} {status} '.format(title=translate('OpenLP.ProjectorManager', + 'Lamp'), + count=count, + status=translate('OpenLP.ProjectorManager', + ' is on') + if item['On'] + else translate('OpenLP.ProjectorManager', + 'is off')) + + message += '{title}: {hours}
'.format(title=translate('OpenLP.ProjectorManager', 'Hours'), + hours=item['Hours']) + count += 1 + message += '

' if projector.link.projector_errors is None: - message = '%s%s' % (message, translate('OpenLP.ProjectorManager', 'No current errors or warnings')) + message += translate('OpenLP.ProjectorManager', 'No current errors or warnings') else: - message = '%s%s' % (message, translate('OpenLP.ProjectorManager', 'Current errors/warnings')) + message += '{data}'.format(data=translate('OpenLP.ProjectorManager', 'Current errors/warnings')) for (key, val) in projector.link.projector_errors.items(): - message = '%s%s: %s
' % (message, key, ERROR_MSG[val]) + message += '{key}: {data}
'.format(key=key, data=ERROR_MSG[val]) QtWidgets.QMessageBox.information(self, translate('OpenLP.ProjectorManager', 'Projector Information'), message) def _add_projector(self, projector): @@ -743,7 +749,7 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QWidget, Ui_ProjectorManager, if start: item.link.connect_to_host() for item in self.projector_list: - log.debug('New projector list - item: (%s) %s' % (item.link.ip, item.link.name)) + log.debug('New projector list - item: ({ip}) {name}'.format(ip=item.link.ip, name=item.link.name)) @pyqtSlot(str) def add_projector_from_wizard(self, ip, opts=None): @@ -753,7 +759,7 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QWidget, Ui_ProjectorManager, :param ip: IP address of new record item to find :param opts: Needed by PyQt5 """ - log.debug('add_projector_from_wizard(ip=%s)' % ip) + log.debug('add_projector_from_wizard(ip={ip})'.format(ip=ip)) item = self.projectordb.get_projector_by_ip(ip) self.add_projector(item) @@ -764,7 +770,7 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QWidget, Ui_ProjectorManager, :param projector: Projector() instance of projector with updated information """ - log.debug('edit_projector_from_wizard(ip=%s)' % projector.ip) + log.debug('edit_projector_from_wizard(ip={ip})'.format(ip=projector.ip)) self.old_projector.link.name = projector.name self.old_projector.link.ip = projector.ip self.old_projector.link.pin = None if projector.pin == '' else projector.pin @@ -816,7 +822,9 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QWidget, Ui_ProjectorManager, else: status_code = status message = ERROR_MSG[status] if msg is None else msg - log.debug('(%s) updateStatus(status=%s) message: "%s"' % (item.link.name, status_code, message)) + log.debug('({name}) updateStatus(status={status}) message: "{message}"'.format(name=item.link.name, + status=status_code, + message=message)) if status in STATUS_ICONS: if item.status == status: return @@ -826,14 +834,14 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QWidget, Ui_ProjectorManager, status_code = ERROR_STRING[status] elif status in STATUS_STRING: status_code = STATUS_STRING[status] - log.debug('(%s) Updating icon with %s' % (item.link.name, status_code)) + log.debug('({name}) Updating icon with {code}'.format(name=item.link.name, code=status_code)) item.widget.setIcon(item.icon) self.update_icons() def get_toolbar_item(self, name, enabled=False, hidden=False): item = self.one_toolbar.findChild(QtWidgets.QAction, name) if item == 0: - log.debug('No item found with name "%s"' % name) + log.debug('No item found with name "{name}"'.format(name=name)) return item.setVisible(False if hidden else True) item.setEnabled(True if enabled else False) @@ -918,11 +926,13 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QWidget, Ui_ProjectorManager, :param name: Name from QListWidgetItem """ - QtWidgets.QMessageBox.warning(self, translate('OpenLP.ProjectorManager', - '"%s" Authentication Error' % name), + # Build the title separately so we can make it easier for translators + title = '"{name}" '.format(name=name) + title += translate('OpenLP.ProjectorManager', 'Authentication Error') + QtWidgets.QMessageBox.warning(self, title, '
There was an authentication error while trying to connect.' '

Please verify your PIN setting ' - 'for projector item "%s"' % name) + 'for projector item "{name}"'.format(name=name)) @pyqtSlot(str) def no_authentication_error(self, name): @@ -932,11 +942,13 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QWidget, Ui_ProjectorManager, :param name: Name from QListWidgetItem """ - QtWidgets.QMessageBox.warning(self, translate('OpenLP.ProjectorManager', - '"%s" No Authentication Error' % name), + # Build the title separately so we can make it easier for translators + title = '"{name}" '.format(name=name) + title += translate('OpenLP.ProjectorManager', 'No Authentication Error') + QtWidgets.QMessageBox.warning(self, title, '
PIN is set and projector does not require authentication.' '

Please verify your PIN setting ' - 'for projector item "%s"' % name) + 'for projector item "{name}"'.format(name=name)) class ProjectorItem(QObject): @@ -972,5 +984,5 @@ def not_implemented(function): QtWidgets.QMessageBox.information(None, translate('OpenLP.ProjectorManager', 'Not Implemented Yet'), translate('OpenLP.ProjectorManager', - 'Function "%s"
has not been implemented yet.' - '
Please check back again later.' % function)) + 'Function "{function}"
has not been implemented yet.' + '
Please check back again later.'.format(function=function))) diff --git a/openlp/core/ui/projector/sourceselectform.py b/openlp/core/ui/projector/sourceselectform.py index 11efcdb08..7d73f6a5a 100644 --- a/openlp/core/ui/projector/sourceselectform.py +++ b/openlp/core/ui/projector/sourceselectform.py @@ -115,7 +115,7 @@ def Build_Tab(group, source_key, default, projector, projectordb, edit=False): if edit: for key in sourcelist: item = QLineEdit() - item.setObjectName('source_key_%s' % key) + item.setObjectName('source_key_{key}'.format(key=key)) source_item = projectordb.get_source_by_code(code=key, projector_id=projector.db_item.id) if source_item is None: item.setText(PJLINK_DEFAULT_CODES[key]) @@ -161,7 +161,7 @@ def set_button_tooltip(bar): button.setToolTip(translate('OpenLP.SourceSelectForm', 'Save changes and return to OpenLP')) else: - log.debug('No tooltip for button {}'.format(button.text())) + log.debug('No tooltip for button {text}'.format(text=button.text())) class FingerTabBarWidget(QTabBar): @@ -359,16 +359,20 @@ class SourceSelectTabs(QDialog): continue item = self.projectordb.get_source_by_code(code=code, projector_id=projector.id) if item is None: - log.debug("(%s) Adding new source text %s: %s" % (projector.ip, code, text)) + log.debug("({ip}) Adding new source text {code}: {text}".format(ip=projector.ip, + code=code, + text=text)) item = ProjectorSource(projector_id=projector.id, code=code, text=text) else: item.text = text - log.debug('(%s) Updating source code %s with text="%s"' % (projector.ip, item.code, item.text)) + log.debug('({ip}) Updating source code {code} with text="{text}"'.format(ip=projector.ip, + code=item.code, + text=item.text)) self.projectordb.add_source(item) selected = 0 else: selected = self.button_group.checkedId() - log.debug('SourceSelectTabs().accepted() Setting source to %s' % selected) + log.debug('SourceSelectTabs().accepted() Setting source to {selected}'.format(selected=selected)) self.done(selected) @@ -417,7 +421,7 @@ class SourceSelectSingle(QDialog): if self.edit: for key in keys: item = QLineEdit() - item.setObjectName('source_key_%s' % key) + item.setObjectName('source_key_{key}'.format(key=key)) source_item = self.projectordb.get_source_by_code(code=key, projector_id=self.projector.db_item.id) if source_item is None: item.setText(PJLINK_DEFAULT_CODES[key]) @@ -498,14 +502,18 @@ class SourceSelectSingle(QDialog): continue item = self.projectordb.get_source_by_code(code=code, projector_id=projector.id) if item is None: - log.debug("(%s) Adding new source text %s: %s" % (projector.ip, code, text)) + log.debug("({ip}) Adding new source text {code}: {text}".format(ip=projector.ip, + code=code, + text=text)) item = ProjectorSource(projector_id=projector.id, code=code, text=text) else: item.text = text - log.debug('(%s) Updating source code %s with text="%s"' % (projector.ip, item.code, item.text)) + log.debug('({ip}) Updating source code {code} with text="{text}"'.format(ip=projector.ip, + code=item.code, + text=item.text)) self.projectordb.add_source(item) selected = 0 else: selected = self.button_group.checkedId() - log.debug('SourceSelectDialog().accepted() Setting source to %s' % selected) + log.debug('SourceSelectDialog().accepted() Setting source to {selected}'.format(selected=selected)) self.done(selected) From 1288da1b873007340b2b9e5d8cb79107a09730c3 Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Sun, 17 Apr 2016 02:30:30 -0700 Subject: [PATCH 04/23] Added multiple lamp test --- .../openlp_core_lib/test_projector_pjlink1.py | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tests/functional/openlp_core_lib/test_projector_pjlink1.py b/tests/functional/openlp_core_lib/test_projector_pjlink1.py index a3d99e884..4a789e094 100644 --- a/tests/functional/openlp_core_lib/test_projector_pjlink1.py +++ b/tests/functional/openlp_core_lib/test_projector_pjlink1.py @@ -107,3 +107,30 @@ class TestPJLink(TestCase): # THEN: process_inpt method should have been called with 31 mock_process_inpt.called_with('31', "process_inpt should have been called with 31") + + @patch.object(pjlink_test, 'projectorReceivedData') + def projector_process_multiple_lamp_test(self, mock_projectorReceivedData): + """ + Test setting multiple lamp on/off and hours + """ + # GIVEN: Test object + pjlink = pjlink_test + + # WHEN: Call process_command with lamp data + pjlink.process_command('LAMP', '11111 1 22222 0 33333 1') + + # THEN: Lamp should have been set with status=ON and hours=22222 + self.assertEquals(len(pjlink.lamp), 3, + 'Projector should have 3 lamps specified') + self.assertEquals(pjlink.lamp[0]['On'], True, + 'Lamp 1 power status should have been set to TRUE') + self.assertEquals(pjlink.lamp[0]['Hours'], 11111, + 'Lamp 1 hours should have been set to 11111') + self.assertEquals(pjlink.lamp[1]['On'], False, + 'Lamp 2 power status should have been set to FALSE') + self.assertEquals(pjlink.lamp[1]['Hours'], 22222, + 'Lamp 2 hours should have been set to 22222') + self.assertEquals(pjlink.lamp[2]['On'], True, + 'Lamp 3 power status should have been set to TRUE') + self.assertEquals(pjlink.lamp[2]['Hours'], 33333, + 'Lamp 3 hours should have been set to 33333') From 16ed511a935bdbc87614989c9ec0b57d9f80a6d1 Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Sun, 17 Apr 2016 02:33:48 -0700 Subject: [PATCH 05/23] Fix notes in multiple lamp test --- tests/functional/openlp_core_lib/test_projector_pjlink1.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/functional/openlp_core_lib/test_projector_pjlink1.py b/tests/functional/openlp_core_lib/test_projector_pjlink1.py index 4a789e094..04198b717 100644 --- a/tests/functional/openlp_core_lib/test_projector_pjlink1.py +++ b/tests/functional/openlp_core_lib/test_projector_pjlink1.py @@ -119,7 +119,7 @@ class TestPJLink(TestCase): # WHEN: Call process_command with lamp data pjlink.process_command('LAMP', '11111 1 22222 0 33333 1') - # THEN: Lamp should have been set with status=ON and hours=22222 + # THEN: Lamp should have been set with proper lamp status self.assertEquals(len(pjlink.lamp), 3, 'Projector should have 3 lamps specified') self.assertEquals(pjlink.lamp[0]['On'], True, From 210cb0be3130a1f1a074794c5b101434fd9d89b4 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sun, 17 Apr 2016 19:48:50 +0100 Subject: [PATCH 06/23] head --- .../functional/openlp_core_common/test_projector_utilities.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/functional/openlp_core_common/test_projector_utilities.py b/tests/functional/openlp_core_common/test_projector_utilities.py index d29267de0..aebdd7509 100644 --- a/tests/functional/openlp_core_common/test_projector_utilities.py +++ b/tests/functional/openlp_core_common/test_projector_utilities.py @@ -23,13 +23,12 @@ Package to test the openlp.core.ui.projector.networkutils package. """ -import os - from unittest import TestCase from openlp.core.common import verify_ip_address, md5_hash, qmd5_hash from tests.resources.projector.data import TEST_PIN, TEST_SALT, TEST_HASH + salt = TEST_SALT pin = TEST_PIN test_hash = TEST_HASH From 6767ba504c6ee6098d27bfa47588dd180f0f0553 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sun, 17 Apr 2016 19:57:03 +0100 Subject: [PATCH 07/23] colorbutton --- openlp/core/lib/__init__.py | 1 - openlp/core/lib/colorbutton.py | 82 -------- openlp/core/ui/generaltab.py | 3 +- openlp/core/ui/lib/__init__.py | 2 + openlp/core/ui/media/playertab.py | 3 +- openlp/core/ui/themeform.py | 1 + openlp/core/ui/themewizard.py | 3 +- .../openlp_core_lib/test_color_button.py | 199 ------------------ 8 files changed, 9 insertions(+), 285 deletions(-) delete mode 100644 openlp/core/lib/colorbutton.py delete mode 100644 tests/functional/openlp_core_lib/test_color_button.py diff --git a/openlp/core/lib/__init__.py b/openlp/core/lib/__init__.py index 6e62bbf9c..80663d93a 100644 --- a/openlp/core/lib/__init__.py +++ b/openlp/core/lib/__init__.py @@ -312,7 +312,6 @@ def create_separated_list(string_list): return translate('OpenLP.core.lib', '%s, %s', 'Locale list separator: start') % (string_list[0], merged) -from .colorbutton import ColorButton from .exceptions import ValidationError from .filedialog import FileDialog from .screen import ScreenList diff --git a/openlp/core/lib/colorbutton.py b/openlp/core/lib/colorbutton.py deleted file mode 100644 index ebb093581..000000000 --- a/openlp/core/lib/colorbutton.py +++ /dev/null @@ -1,82 +0,0 @@ -# -*- coding: utf-8 -*- -# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 - -############################################################################### -# OpenLP - Open Source Lyrics Projection # -# --------------------------------------------------------------------------- # -# Copyright (c) 2008-2016 OpenLP Developers # -# --------------------------------------------------------------------------- # -# This program is free software; you can redistribute it and/or modify it # -# under the terms of the GNU General Public License as published by the Free # -# Software Foundation; version 2 of the License. # -# # -# This program is distributed in the hope that it will be useful, but WITHOUT # -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # -# more details. # -# # -# You should have received a copy of the GNU General Public License along # -# with this program; if not, write to the Free Software Foundation, Inc., 59 # -# Temple Place, Suite 330, Boston, MA 02111-1307 USA # -############################################################################### - -""" -Provide a custom widget based on QPushButton for the selection of colors -""" -from PyQt5 import QtCore, QtGui, QtWidgets - -from openlp.core.common import translate - - -class ColorButton(QtWidgets.QPushButton): - """ - Subclasses QPushbutton to create a "Color Chooser" button - """ - - colorChanged = QtCore.pyqtSignal(str) - - def __init__(self, parent=None): - """ - Initialise the ColorButton - """ - super(ColorButton, self).__init__() - self.parent = parent - self.change_color('#ffffff') - self.setToolTip(translate('OpenLP.ColorButton', 'Click to select a color.')) - self.clicked.connect(self.on_clicked) - - def change_color(self, color): - """ - Sets the _color variable and the background color. - - :param color: String representation of a hexidecimal color - """ - self._color = color - self.setStyleSheet('background-color: %s' % color) - - @property - def color(self): - """ - Property method to return the color variable - - :return: String representation of a hexidecimal color - """ - return self._color - - @color.setter - def color(self, color): - """ - Property setter to change the instance color - - :param color: String representation of a hexidecimal color - """ - self.change_color(color) - - def on_clicked(self): - """ - Handle the PushButton clicked signal, showing the ColorDialog and validating the input - """ - new_color = QtWidgets.QColorDialog.getColor(QtGui.QColor(self._color), self.parent) - if new_color.isValid() and self._color != new_color.name(): - self.change_color(new_color.name()) - self.colorChanged.emit(new_color.name()) diff --git a/openlp/core/ui/generaltab.py b/openlp/core/ui/generaltab.py index be2630b35..816e947ba 100644 --- a/openlp/core/ui/generaltab.py +++ b/openlp/core/ui/generaltab.py @@ -27,7 +27,8 @@ import logging from PyQt5 import QtCore, QtGui, QtWidgets from openlp.core.common import Registry, Settings, UiStrings, translate, get_images_filter -from openlp.core.lib import SettingsTab, ScreenList, ColorButton, build_icon +from openlp.core.lib import SettingsTab, ScreenList, build_icon +from openlp.core.ui.lib.colorbutton import ColorButton log = logging.getLogger(__name__) diff --git a/openlp/core/ui/lib/__init__.py b/openlp/core/ui/lib/__init__.py index 02bded5b0..bff725924 100644 --- a/openlp/core/ui/lib/__init__.py +++ b/openlp/core/ui/lib/__init__.py @@ -19,3 +19,5 @@ # with this program; if not, write to the Free Software Foundation, Inc., 59 # # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### + +from openlp.core.ui.lib.colorbutton import ColorButton \ No newline at end of file diff --git a/openlp/core/ui/media/playertab.py b/openlp/core/ui/media/playertab.py index ed34993ca..1fca21450 100644 --- a/openlp/core/ui/media/playertab.py +++ b/openlp/core/ui/media/playertab.py @@ -26,9 +26,10 @@ import platform from PyQt5 import QtCore, QtWidgets from openlp.core.common import Registry, Settings, UiStrings, translate -from openlp.core.lib import ColorButton, SettingsTab +from openlp.core.lib import SettingsTab from openlp.core.lib.ui import create_button from openlp.core.ui.media import get_media_players, set_media_players +from openlp.core.ui.lib.colorbutton import ColorButton class MediaQCheckBox(QtWidgets.QCheckBox): diff --git a/openlp/core/ui/themeform.py b/openlp/core/ui/themeform.py index 20143ddaa..fc231a859 100644 --- a/openlp/core/ui/themeform.py +++ b/openlp/core/ui/themeform.py @@ -31,6 +31,7 @@ from openlp.core.common import Registry, RegistryProperties, UiStrings, translat from openlp.core.lib.theme import BackgroundType, BackgroundGradientType from openlp.core.lib.ui import critical_error_message_box from openlp.core.ui import ThemeLayoutForm +from openlp.core.ui.lib.colorbutton import ColorButton from .themewizard import Ui_ThemeWizard log = logging.getLogger(__name__) diff --git a/openlp/core/ui/themewizard.py b/openlp/core/ui/themewizard.py index b041a0905..ab8854ef2 100644 --- a/openlp/core/ui/themewizard.py +++ b/openlp/core/ui/themewizard.py @@ -25,9 +25,10 @@ The Create/Edit theme wizard from PyQt5 import QtCore, QtGui, QtWidgets from openlp.core.common import UiStrings, translate, is_macosx -from openlp.core.lib import build_icon, ColorButton +from openlp.core.lib import build_icon from openlp.core.lib.theme import HorizontalType, BackgroundType, BackgroundGradientType from openlp.core.lib.ui import add_welcome_page, create_valign_selection_widgets +from openlp.core.ui.lib.colorbutton import ColorButton class Ui_ThemeWizard(object): diff --git a/tests/functional/openlp_core_lib/test_color_button.py b/tests/functional/openlp_core_lib/test_color_button.py deleted file mode 100644 index ea71b3bf9..000000000 --- a/tests/functional/openlp_core_lib/test_color_button.py +++ /dev/null @@ -1,199 +0,0 @@ -# -*- coding: utf-8 -*- -# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 - -############################################################################### -# OpenLP - Open Source Lyrics Projection # -# --------------------------------------------------------------------------- # -# Copyright (c) 2008-2016 OpenLP Developers # -# --------------------------------------------------------------------------- # -# This program is free software; you can redistribute it and/or modify it # -# under the terms of the GNU General Public License as published by the Free # -# Software Foundation; version 2 of the License. # -# # -# This program is distributed in the hope that it will be useful, but WITHOUT # -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # -# more details. # -# # -# You should have received a copy of the GNU General Public License along # -# with this program; if not, write to the Free Software Foundation, Inc., 59 # -# Temple Place, Suite 330, Boston, MA 02111-1307 USA # -############################################################################### -""" -This module contains tests for the openlp.core.lib.filedialog module -""" -from unittest import TestCase - -from openlp.core.lib.colorbutton import ColorButton -from tests.functional import MagicMock, call, patch - - -class TestColorDialog(TestCase): - """ - Test the :class:`~openlp.core.lib.colorbutton.ColorButton` class - """ - def setUp(self): - self.change_color_patcher = patch('openlp.core.lib.colorbutton.ColorButton.change_color') - self.clicked_patcher = patch('openlp.core.lib.colorbutton.ColorButton.clicked') - self.color_changed_patcher = patch('openlp.core.lib.colorbutton.ColorButton.colorChanged') - self.qt_gui_patcher = patch('openlp.core.lib.colorbutton.QtWidgets') - self.translate_patcher = patch('openlp.core.lib.colorbutton.translate', **{'return_value': 'Tool Tip Text'}) - self.addCleanup(self.change_color_patcher.stop) - self.addCleanup(self.clicked_patcher.stop) - self.addCleanup(self.color_changed_patcher.stop) - self.addCleanup(self.qt_gui_patcher.stop) - self.addCleanup(self.translate_patcher.stop) - self.mocked_change_color = self.change_color_patcher.start() - self.mocked_clicked = self.clicked_patcher.start() - self.mocked_color_changed = self.color_changed_patcher.start() - self.mocked_qt_widgets = self.qt_gui_patcher.start() - self.mocked_translate = self.translate_patcher.start() - - def constructor_test(self): - """ - Test that constructing a ColorButton object works correctly - """ - - # GIVEN: The ColorButton class, a mocked change_color, setToolTip methods and clicked signal - with patch('openlp.core.lib.colorbutton.ColorButton.setToolTip') as mocked_set_tool_tip: - - # WHEN: The ColorButton object is instantiated - widget = ColorButton() - - # THEN: The widget __init__ method should have the correct properties and methods called - self.assertEqual(widget.parent, None, - 'The parent should be the same as the one that the class was instianted with') - self.mocked_change_color.assert_called_once_with('#ffffff') - mocked_set_tool_tip.assert_called_once_with('Tool Tip Text') - self.mocked_clicked.connect.assert_called_once_with(widget.on_clicked) - - def change_color_test(self): - """ - Test that change_color sets the new color and the stylesheet - """ - self.change_color_patcher.stop() - - # GIVEN: An instance of the ColorButton object, and a mocked out setStyleSheet - with patch('openlp.core.lib.colorbutton.ColorButton.setStyleSheet') as mocked_set_style_sheet: - widget = ColorButton() - - # WHEN: Changing the color - widget.change_color('#000000') - - # THEN: The _color attribute should be set to #000000 and setStyleSheet should have been called twice - self.assertEqual(widget._color, '#000000', '_color should have been set to #000000') - mocked_set_style_sheet.assert_has_calls( - [call('background-color: #ffffff'), call('background-color: #000000')]) - - self.mocked_change_color = self.change_color_patcher.start() - - def color_test(self): - """ - Test that the color property method returns the set color - """ - - # GIVEN: An instance of ColorButton, with a set _color attribute - widget = ColorButton() - widget._color = '#000000' - - # WHEN: Accesing the color property - value = widget.color - - # THEN: The value set in _color should be returned - self.assertEqual(value, '#000000', 'The value returned should be equal to the one we set') - - def color_test(self): - """ - Test that the color property method returns the set color - """ - - # GIVEN: An instance of ColorButton, with a set _color attribute - widget = ColorButton() - widget._color = '#000000' - - # WHEN: Accesing the color property - value = widget.color - - # THEN: The value set in _color should be returned - self.assertEqual(value, '#000000', 'The value returned should be equal to the one we set') - - def color_setter_test(self): - """ - Test that the color property setter method sets the color - """ - - # GIVEN: An instance of ColorButton, with a mocked __init__ - with patch('openlp.core.lib.colorbutton.ColorButton.__init__', **{'return_value': None}): - widget = ColorButton() - - # WHEN: Setting the color property - widget.color = '#000000' - - # THEN: Then change_color should have been called with the value we set - self.mocked_change_color.assert_called_once_with('#000000') - - def on_clicked_invalid_color_test(self): - """ - Test the on_click method when an invalid color has been supplied - """ - - # GIVEN: An instance of ColorButton, and a set _color attribute - widget = ColorButton() - self.mocked_change_color.reset_mock() - self.mocked_color_changed.reset_mock() - widget._color = '#000000' - - # WHEN: The on_clicked method is called, and the color is invalid - self.mocked_qt_widgets.QColorDialog.getColor.return_value = MagicMock(**{'isValid.return_value': False}) - widget.on_clicked() - - # THEN: change_color should not have been called and the colorChanged signal should not have been emitted - self.assertEqual( - self.mocked_change_color.call_count, 0, 'change_color should not have been called with an invalid color') - self.assertEqual( - self.mocked_color_changed.emit.call_count, 0, - 'colorChange signal should not have been emitted with an invalid color') - - def on_clicked_same_color_test(self): - """ - Test the on_click method when a new color has not been chosen - """ - - # GIVEN: An instance of ColorButton, and a set _color attribute - widget = ColorButton() - self.mocked_change_color.reset_mock() - self.mocked_color_changed.reset_mock() - widget._color = '#000000' - - # WHEN: The on_clicked method is called, and the color is valid, but the same as the existing color - self.mocked_qt_widgets.QColorDialog.getColor.return_value = MagicMock( - **{'isValid.return_value': True, 'name.return_value': '#000000'}) - widget.on_clicked() - - # THEN: change_color should not have been called and the colorChanged signal should not have been emitted - self.assertEqual( - self.mocked_change_color.call_count, 0, - 'change_color should not have been called when the color has not changed') - self.assertEqual( - self.mocked_color_changed.emit.call_count, 0, - 'colorChange signal should not have been emitted when the color has not changed') - - def on_clicked_new_color_test(self): - """ - Test the on_click method when a new color has been chosen and is valid - """ - - # GIVEN: An instance of ColorButton, and a set _color attribute - widget = ColorButton() - self.mocked_change_color.reset_mock() - self.mocked_color_changed.reset_mock() - widget._color = '#000000' - - # WHEN: The on_clicked method is called, and the color is valid, and different to the existing color - self.mocked_qt_widgets.QColorDialog.getColor.return_value = MagicMock( - **{'isValid.return_value': True, 'name.return_value': '#ffffff'}) - widget.on_clicked() - - # THEN: change_color should have been called and the colorChanged signal should have been emitted - self.mocked_change_color.assert_called_once_with('#ffffff') - self.mocked_color_changed.emit.assert_called_once_with('#ffffff') From b2147045b270e42ffc44a82013f9f5b9a0b14dc8 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sun, 17 Apr 2016 20:06:17 +0100 Subject: [PATCH 08/23] colorbutton2 --- openlp/core/lib/__init__.py | 2 +- openlp/core/lib/dockwidget.py | 56 -------------------------- openlp/plugins/alerts/lib/alertstab.py | 3 +- openlp/plugins/images/lib/imagetab.py | 3 +- 4 files changed, 5 insertions(+), 59 deletions(-) delete mode 100644 openlp/core/lib/dockwidget.py diff --git a/openlp/core/lib/__init__.py b/openlp/core/lib/__init__.py index 80663d93a..6cae02598 100644 --- a/openlp/core/lib/__init__.py +++ b/openlp/core/lib/__init__.py @@ -325,7 +325,7 @@ from .settingstab import SettingsTab from .serviceitem import ServiceItem, ServiceItemType, ItemCapabilities from .htmlbuilder import build_html, build_lyrics_format_css, build_lyrics_outline_css from .toolbar import OpenLPToolbar -from .dockwidget import OpenLPDockWidget +from openlp.core.ui.lib.dockwidget import OpenLPDockWidget from .imagemanager import ImageManager from .renderer import Renderer from .mediamanageritem import MediaManagerItem diff --git a/openlp/core/lib/dockwidget.py b/openlp/core/lib/dockwidget.py deleted file mode 100644 index 4a8217af0..000000000 --- a/openlp/core/lib/dockwidget.py +++ /dev/null @@ -1,56 +0,0 @@ -# -*- coding: utf-8 -*- -# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 - -############################################################################### -# OpenLP - Open Source Lyrics Projection # -# --------------------------------------------------------------------------- # -# Copyright (c) 2008-2016 OpenLP Developers # -# --------------------------------------------------------------------------- # -# This program is free software; you can redistribute it and/or modify it # -# under the terms of the GNU General Public License as published by the Free # -# Software Foundation; version 2 of the License. # -# # -# This program is distributed in the hope that it will be useful, but WITHOUT # -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # -# more details. # -# # -# You should have received a copy of the GNU General Public License along # -# with this program; if not, write to the Free Software Foundation, Inc., 59 # -# Temple Place, Suite 330, Boston, MA 02111-1307 USA # -############################################################################### - -""" -Provide additional functionality required by OpenLP from the inherited QDockWidget. -""" - -import logging - -from PyQt5 import QtWidgets - -from openlp.core.lib import ScreenList, build_icon - -log = logging.getLogger(__name__) - - -class OpenLPDockWidget(QtWidgets.QDockWidget): - """ - Custom DockWidget class to handle events - """ - def __init__(self, parent=None, name=None, icon=None): - """ - Initialise the DockWidget - """ - log.debug('Initialise the %s widget' % name) - super(OpenLPDockWidget, self).__init__(parent) - if name: - self.setObjectName(name) - if icon: - self.setWindowIcon(build_icon(icon)) - # Sort out the minimum width. - screens = ScreenList() - main_window_docbars = screens.current['size'].width() // 5 - if main_window_docbars > 300: - self.setMinimumWidth(300) - else: - self.setMinimumWidth(main_window_docbars) diff --git a/openlp/plugins/alerts/lib/alertstab.py b/openlp/plugins/alerts/lib/alertstab.py index 2875493b6..2859a71ce 100644 --- a/openlp/plugins/alerts/lib/alertstab.py +++ b/openlp/plugins/alerts/lib/alertstab.py @@ -23,8 +23,9 @@ from PyQt5 import QtGui, QtWidgets from openlp.core.common import Settings, UiStrings, translate -from openlp.core.lib import ColorButton, SettingsTab +from openlp.core.lib import SettingsTab from openlp.core.lib.ui import create_valign_selection_widgets +from openlp.core.ui.lib.colorbutton import ColorButton class AlertsTab(SettingsTab): diff --git a/openlp/plugins/images/lib/imagetab.py b/openlp/plugins/images/lib/imagetab.py index 80578dc56..2cc6776b1 100644 --- a/openlp/plugins/images/lib/imagetab.py +++ b/openlp/plugins/images/lib/imagetab.py @@ -23,7 +23,8 @@ from PyQt5 import QtWidgets from openlp.core.common import Settings, UiStrings, translate -from openlp.core.lib import ColorButton, SettingsTab +from openlp.core.lib import SettingsTab +from openlp.core.ui.lib.colorbutton import ColorButton class ImageTab(SettingsTab): From 34f00cda9211bca9e2443b1db918af9c64517b08 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sun, 17 Apr 2016 20:09:46 +0100 Subject: [PATCH 09/23] dnd and files --- openlp/core/lib/__init__.py | 1 - openlp/core/lib/mediamanageritem.py | 4 +- openlp/core/ui/lib/__init__.py | 3 +- openlp/core/ui/lib/colorbutton.py | 82 ++++++++ openlp/core/ui/lib/dockwidget.py | 56 +++++ openlp/core/{ => ui}/lib/listwidgetwithdnd.py | 0 .../functional/openlp_core_ui_lib/__init__.py | 0 .../openlp_core_ui_lib/test_color_button.py | 199 ++++++++++++++++++ 8 files changed, 341 insertions(+), 4 deletions(-) create mode 100644 openlp/core/ui/lib/colorbutton.py create mode 100644 openlp/core/ui/lib/dockwidget.py rename openlp/core/{ => ui}/lib/listwidgetwithdnd.py (100%) create mode 100644 tests/functional/openlp_core_ui_lib/__init__.py create mode 100644 tests/functional/openlp_core_ui_lib/test_color_button.py diff --git a/openlp/core/lib/__init__.py b/openlp/core/lib/__init__.py index 6cae02598..dd19e1033 100644 --- a/openlp/core/lib/__init__.py +++ b/openlp/core/lib/__init__.py @@ -315,7 +315,6 @@ def create_separated_list(string_list): from .exceptions import ValidationError from .filedialog import FileDialog from .screen import ScreenList -from .listwidgetwithdnd import ListWidgetWithDnD from .treewidgetwithdnd import TreeWidgetWithDnD from .formattingtags import FormattingTags from .spelltextedit import SpellTextEdit diff --git a/openlp/core/lib/mediamanageritem.py b/openlp/core/lib/mediamanageritem.py index 04df1d38a..ac0edfdf4 100644 --- a/openlp/core/lib/mediamanageritem.py +++ b/openlp/core/lib/mediamanageritem.py @@ -29,10 +29,10 @@ import re from PyQt5 import QtCore, QtGui, QtWidgets from openlp.core.common import Registry, RegistryProperties, Settings, UiStrings, translate -from openlp.core.lib import FileDialog, OpenLPToolbar, ServiceItem, StringContent, ListWidgetWithDnD, \ - ServiceItemContext +from openlp.core.lib import FileDialog, OpenLPToolbar, ServiceItem, StringContent, ServiceItemContext from openlp.core.lib.searchedit import SearchEdit from openlp.core.lib.ui import create_widget_action, critical_error_message_box +from openlp.core.ui.lib.listwidgetwithdnd import ListWidgetWithDnD log = logging.getLogger(__name__) diff --git a/openlp/core/ui/lib/__init__.py b/openlp/core/ui/lib/__init__.py index bff725924..d7c67697f 100644 --- a/openlp/core/ui/lib/__init__.py +++ b/openlp/core/ui/lib/__init__.py @@ -20,4 +20,5 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### -from openlp.core.ui.lib.colorbutton import ColorButton \ No newline at end of file +from openlp.core.ui.lib.colorbutton import ColorButton +from openlp.core.ui.lib.listwidgetwithdnd import ListWidgetWithDnD diff --git a/openlp/core/ui/lib/colorbutton.py b/openlp/core/ui/lib/colorbutton.py new file mode 100644 index 000000000..ebb093581 --- /dev/null +++ b/openlp/core/ui/lib/colorbutton.py @@ -0,0 +1,82 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2016 OpenLP Developers # +# --------------------------------------------------------------------------- # +# This program is free software; you can redistribute it and/or modify it # +# under the terms of the GNU General Public License as published by the Free # +# Software Foundation; version 2 of the License. # +# # +# This program is distributed in the hope that it will be useful, but WITHOUT # +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # +# more details. # +# # +# You should have received a copy of the GNU General Public License along # +# with this program; if not, write to the Free Software Foundation, Inc., 59 # +# Temple Place, Suite 330, Boston, MA 02111-1307 USA # +############################################################################### + +""" +Provide a custom widget based on QPushButton for the selection of colors +""" +from PyQt5 import QtCore, QtGui, QtWidgets + +from openlp.core.common import translate + + +class ColorButton(QtWidgets.QPushButton): + """ + Subclasses QPushbutton to create a "Color Chooser" button + """ + + colorChanged = QtCore.pyqtSignal(str) + + def __init__(self, parent=None): + """ + Initialise the ColorButton + """ + super(ColorButton, self).__init__() + self.parent = parent + self.change_color('#ffffff') + self.setToolTip(translate('OpenLP.ColorButton', 'Click to select a color.')) + self.clicked.connect(self.on_clicked) + + def change_color(self, color): + """ + Sets the _color variable and the background color. + + :param color: String representation of a hexidecimal color + """ + self._color = color + self.setStyleSheet('background-color: %s' % color) + + @property + def color(self): + """ + Property method to return the color variable + + :return: String representation of a hexidecimal color + """ + return self._color + + @color.setter + def color(self, color): + """ + Property setter to change the instance color + + :param color: String representation of a hexidecimal color + """ + self.change_color(color) + + def on_clicked(self): + """ + Handle the PushButton clicked signal, showing the ColorDialog and validating the input + """ + new_color = QtWidgets.QColorDialog.getColor(QtGui.QColor(self._color), self.parent) + if new_color.isValid() and self._color != new_color.name(): + self.change_color(new_color.name()) + self.colorChanged.emit(new_color.name()) diff --git a/openlp/core/ui/lib/dockwidget.py b/openlp/core/ui/lib/dockwidget.py new file mode 100644 index 000000000..4a8217af0 --- /dev/null +++ b/openlp/core/ui/lib/dockwidget.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2016 OpenLP Developers # +# --------------------------------------------------------------------------- # +# This program is free software; you can redistribute it and/or modify it # +# under the terms of the GNU General Public License as published by the Free # +# Software Foundation; version 2 of the License. # +# # +# This program is distributed in the hope that it will be useful, but WITHOUT # +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # +# more details. # +# # +# You should have received a copy of the GNU General Public License along # +# with this program; if not, write to the Free Software Foundation, Inc., 59 # +# Temple Place, Suite 330, Boston, MA 02111-1307 USA # +############################################################################### + +""" +Provide additional functionality required by OpenLP from the inherited QDockWidget. +""" + +import logging + +from PyQt5 import QtWidgets + +from openlp.core.lib import ScreenList, build_icon + +log = logging.getLogger(__name__) + + +class OpenLPDockWidget(QtWidgets.QDockWidget): + """ + Custom DockWidget class to handle events + """ + def __init__(self, parent=None, name=None, icon=None): + """ + Initialise the DockWidget + """ + log.debug('Initialise the %s widget' % name) + super(OpenLPDockWidget, self).__init__(parent) + if name: + self.setObjectName(name) + if icon: + self.setWindowIcon(build_icon(icon)) + # Sort out the minimum width. + screens = ScreenList() + main_window_docbars = screens.current['size'].width() // 5 + if main_window_docbars > 300: + self.setMinimumWidth(300) + else: + self.setMinimumWidth(main_window_docbars) diff --git a/openlp/core/lib/listwidgetwithdnd.py b/openlp/core/ui/lib/listwidgetwithdnd.py similarity index 100% rename from openlp/core/lib/listwidgetwithdnd.py rename to openlp/core/ui/lib/listwidgetwithdnd.py diff --git a/tests/functional/openlp_core_ui_lib/__init__.py b/tests/functional/openlp_core_ui_lib/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/functional/openlp_core_ui_lib/test_color_button.py b/tests/functional/openlp_core_ui_lib/test_color_button.py new file mode 100644 index 000000000..ef6d4f93d --- /dev/null +++ b/tests/functional/openlp_core_ui_lib/test_color_button.py @@ -0,0 +1,199 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2016 OpenLP Developers # +# --------------------------------------------------------------------------- # +# This program is free software; you can redistribute it and/or modify it # +# under the terms of the GNU General Public License as published by the Free # +# Software Foundation; version 2 of the License. # +# # +# This program is distributed in the hope that it will be useful, but WITHOUT # +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # +# more details. # +# # +# You should have received a copy of the GNU General Public License along # +# with this program; if not, write to the Free Software Foundation, Inc., 59 # +# Temple Place, Suite 330, Boston, MA 02111-1307 USA # +############################################################################### +""" +This module contains tests for the openlp.core.lib.filedialog module +""" +from unittest import TestCase + +from openlp.core.ui.lib.colorbutton import ColorButton +from tests.functional import MagicMock, call, patch + + +class TestColorDialog(TestCase): + """ + Test the :class:`~openlp.core.lib.colorbutton.ColorButton` class + """ + def setUp(self): + self.change_color_patcher = patch('openlp.core.lib.colorbutton.ColorButton.change_color') + self.clicked_patcher = patch('openlp.core.lib.colorbutton.ColorButton.clicked') + self.color_changed_patcher = patch('openlp.core.lib.colorbutton.ColorButton.colorChanged') + self.qt_gui_patcher = patch('openlp.core.lib.colorbutton.QtWidgets') + self.translate_patcher = patch('openlp.core.lib.colorbutton.translate', **{'return_value': 'Tool Tip Text'}) + self.addCleanup(self.change_color_patcher.stop) + self.addCleanup(self.clicked_patcher.stop) + self.addCleanup(self.color_changed_patcher.stop) + self.addCleanup(self.qt_gui_patcher.stop) + self.addCleanup(self.translate_patcher.stop) + self.mocked_change_color = self.change_color_patcher.start() + self.mocked_clicked = self.clicked_patcher.start() + self.mocked_color_changed = self.color_changed_patcher.start() + self.mocked_qt_widgets = self.qt_gui_patcher.start() + self.mocked_translate = self.translate_patcher.start() + + def constructor_test(self): + """ + Test that constructing a ColorButton object works correctly + """ + + # GIVEN: The ColorButton class, a mocked change_color, setToolTip methods and clicked signal + with patch('openlp.core.lib.colorbutton.ColorButton.setToolTip') as mocked_set_tool_tip: + + # WHEN: The ColorButton object is instantiated + widget = ColorButton() + + # THEN: The widget __init__ method should have the correct properties and methods called + self.assertEqual(widget.parent, None, + 'The parent should be the same as the one that the class was instianted with') + self.mocked_change_color.assert_called_once_with('#ffffff') + mocked_set_tool_tip.assert_called_once_with('Tool Tip Text') + self.mocked_clicked.connect.assert_called_once_with(widget.on_clicked) + + def change_color_test(self): + """ + Test that change_color sets the new color and the stylesheet + """ + self.change_color_patcher.stop() + + # GIVEN: An instance of the ColorButton object, and a mocked out setStyleSheet + with patch('openlp.core.lib.colorbutton.ColorButton.setStyleSheet') as mocked_set_style_sheet: + widget = ColorButton() + + # WHEN: Changing the color + widget.change_color('#000000') + + # THEN: The _color attribute should be set to #000000 and setStyleSheet should have been called twice + self.assertEqual(widget._color, '#000000', '_color should have been set to #000000') + mocked_set_style_sheet.assert_has_calls( + [call('background-color: #ffffff'), call('background-color: #000000')]) + + self.mocked_change_color = self.change_color_patcher.start() + + def color_test(self): + """ + Test that the color property method returns the set color + """ + + # GIVEN: An instance of ColorButton, with a set _color attribute + widget = ColorButton() + widget._color = '#000000' + + # WHEN: Accesing the color property + value = widget.color + + # THEN: The value set in _color should be returned + self.assertEqual(value, '#000000', 'The value returned should be equal to the one we set') + + def color_test(self): + """ + Test that the color property method returns the set color + """ + + # GIVEN: An instance of ColorButton, with a set _color attribute + widget = ColorButton() + widget._color = '#000000' + + # WHEN: Accesing the color property + value = widget.color + + # THEN: The value set in _color should be returned + self.assertEqual(value, '#000000', 'The value returned should be equal to the one we set') + + def color_setter_test(self): + """ + Test that the color property setter method sets the color + """ + + # GIVEN: An instance of ColorButton, with a mocked __init__ + with patch('openlp.core.lib.colorbutton.ColorButton.__init__', **{'return_value': None}): + widget = ColorButton() + + # WHEN: Setting the color property + widget.color = '#000000' + + # THEN: Then change_color should have been called with the value we set + self.mocked_change_color.assert_called_once_with('#000000') + + def on_clicked_invalid_color_test(self): + """ + Test the on_click method when an invalid color has been supplied + """ + + # GIVEN: An instance of ColorButton, and a set _color attribute + widget = ColorButton() + self.mocked_change_color.reset_mock() + self.mocked_color_changed.reset_mock() + widget._color = '#000000' + + # WHEN: The on_clicked method is called, and the color is invalid + self.mocked_qt_widgets.QColorDialog.getColor.return_value = MagicMock(**{'isValid.return_value': False}) + widget.on_clicked() + + # THEN: change_color should not have been called and the colorChanged signal should not have been emitted + self.assertEqual( + self.mocked_change_color.call_count, 0, 'change_color should not have been called with an invalid color') + self.assertEqual( + self.mocked_color_changed.emit.call_count, 0, + 'colorChange signal should not have been emitted with an invalid color') + + def on_clicked_same_color_test(self): + """ + Test the on_click method when a new color has not been chosen + """ + + # GIVEN: An instance of ColorButton, and a set _color attribute + widget = ColorButton() + self.mocked_change_color.reset_mock() + self.mocked_color_changed.reset_mock() + widget._color = '#000000' + + # WHEN: The on_clicked method is called, and the color is valid, but the same as the existing color + self.mocked_qt_widgets.QColorDialog.getColor.return_value = MagicMock( + **{'isValid.return_value': True, 'name.return_value': '#000000'}) + widget.on_clicked() + + # THEN: change_color should not have been called and the colorChanged signal should not have been emitted + self.assertEqual( + self.mocked_change_color.call_count, 0, + 'change_color should not have been called when the color has not changed') + self.assertEqual( + self.mocked_color_changed.emit.call_count, 0, + 'colorChange signal should not have been emitted when the color has not changed') + + def on_clicked_new_color_test(self): + """ + Test the on_click method when a new color has been chosen and is valid + """ + + # GIVEN: An instance of ColorButton, and a set _color attribute + widget = ColorButton() + self.mocked_change_color.reset_mock() + self.mocked_color_changed.reset_mock() + widget._color = '#000000' + + # WHEN: The on_clicked method is called, and the color is valid, and different to the existing color + self.mocked_qt_widgets.QColorDialog.getColor.return_value = MagicMock( + **{'isValid.return_value': True, 'name.return_value': '#ffffff'}) + widget.on_clicked() + + # THEN: change_color should have been called and the colorChanged signal should have been emitted + self.mocked_change_color.assert_called_once_with('#ffffff') + self.mocked_color_changed.emit.assert_called_once_with('#ffffff') From bdeff60a9747171ec2e1da37afbaadcf7b49d1ec Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sun, 17 Apr 2016 20:32:15 +0100 Subject: [PATCH 10/23] updates --- openlp/core/lib/__init__.py | 3 --- openlp/core/lib/mediamanageritem.py | 3 ++- openlp/core/ui/lib/__init__.py | 3 +++ openlp/core/{ => ui}/lib/toolbar.py | 0 openlp/core/{ => ui}/lib/treewidgetwithdnd.py | 0 openlp/core/ui/mainwindow.py | 5 +++-- openlp/core/ui/media/mediacontroller.py | 12 +++++++----- openlp/core/ui/projector/manager.py | 2 +- openlp/core/ui/servicemanager.py | 3 ++- openlp/core/ui/slidecontroller.py | 6 ++++-- openlp/core/ui/thememanager.py | 3 ++- openlp/plugins/images/lib/mediaitem.py | 5 +++-- .../test_listpreviewwidget.py | 2 +- 13 files changed, 28 insertions(+), 19 deletions(-) rename openlp/core/{ => ui}/lib/toolbar.py (100%) rename openlp/core/{ => ui}/lib/treewidgetwithdnd.py (100%) rename tests/interfaces/{openlp_core_ui => openlp_core_ui_lib}/test_listpreviewwidget.py (98%) diff --git a/openlp/core/lib/__init__.py b/openlp/core/lib/__init__.py index dd19e1033..e56cb0d61 100644 --- a/openlp/core/lib/__init__.py +++ b/openlp/core/lib/__init__.py @@ -315,7 +315,6 @@ def create_separated_list(string_list): from .exceptions import ValidationError from .filedialog import FileDialog from .screen import ScreenList -from .treewidgetwithdnd import TreeWidgetWithDnD from .formattingtags import FormattingTags from .spelltextedit import SpellTextEdit from .plugin import PluginStatus, StringContent, Plugin @@ -323,8 +322,6 @@ from .pluginmanager import PluginManager from .settingstab import SettingsTab from .serviceitem import ServiceItem, ServiceItemType, ItemCapabilities from .htmlbuilder import build_html, build_lyrics_format_css, build_lyrics_outline_css -from .toolbar import OpenLPToolbar -from openlp.core.ui.lib.dockwidget import OpenLPDockWidget from .imagemanager import ImageManager from .renderer import Renderer from .mediamanageritem import MediaManagerItem diff --git a/openlp/core/lib/mediamanageritem.py b/openlp/core/lib/mediamanageritem.py index ac0edfdf4..5af90c1b7 100644 --- a/openlp/core/lib/mediamanageritem.py +++ b/openlp/core/lib/mediamanageritem.py @@ -29,10 +29,11 @@ import re from PyQt5 import QtCore, QtGui, QtWidgets from openlp.core.common import Registry, RegistryProperties, Settings, UiStrings, translate -from openlp.core.lib import FileDialog, OpenLPToolbar, ServiceItem, StringContent, ServiceItemContext +from openlp.core.lib import FileDialog, ServiceItem, StringContent, ServiceItemContext from openlp.core.lib.searchedit import SearchEdit from openlp.core.lib.ui import create_widget_action, critical_error_message_box from openlp.core.ui.lib.listwidgetwithdnd import ListWidgetWithDnD +from openlp.core.ui.lib.toolbar import OpenLPToolbar log = logging.getLogger(__name__) diff --git a/openlp/core/ui/lib/__init__.py b/openlp/core/ui/lib/__init__.py index d7c67697f..8b8bd991d 100644 --- a/openlp/core/ui/lib/__init__.py +++ b/openlp/core/ui/lib/__init__.py @@ -22,3 +22,6 @@ from openlp.core.ui.lib.colorbutton import ColorButton from openlp.core.ui.lib.listwidgetwithdnd import ListWidgetWithDnD +from openlp.core.ui.lib.treewidgetwithdnd import TreeWidgetWithDnD +from openlp.core.ui.lib.toolbar import OpenLPToolbar +from openlp.core.ui.lib.dockwidget import OpenLPDockWidget \ No newline at end of file diff --git a/openlp/core/lib/toolbar.py b/openlp/core/ui/lib/toolbar.py similarity index 100% rename from openlp/core/lib/toolbar.py rename to openlp/core/ui/lib/toolbar.py diff --git a/openlp/core/lib/treewidgetwithdnd.py b/openlp/core/ui/lib/treewidgetwithdnd.py similarity index 100% rename from openlp/core/lib/treewidgetwithdnd.py rename to openlp/core/ui/lib/treewidgetwithdnd.py diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index 228969ad1..e586e6928 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -38,8 +38,7 @@ from openlp.core.common import Registry, RegistryProperties, AppLocation, Langua check_directory_exists, translate, is_win, is_macosx, add_actions from openlp.core.common.actions import ActionList, CategoryOrder from openlp.core.common.versionchecker import get_application_version -from openlp.core.lib import Renderer, OpenLPDockWidget, PluginManager, ImageManager, PluginStatus, ScreenList, \ - build_icon +from openlp.core.lib import Renderer, PluginManager, ImageManager, PluginStatus, ScreenList, build_icon from openlp.core.lib.ui import UiStrings, create_action from openlp.core.ui import AboutForm, SettingsForm, ServiceManager, ThemeManager, LiveController, PluginForm, \ MediaDockManager, ShortcutListForm, FormattingTagForm, PreviewController @@ -47,6 +46,8 @@ from openlp.core.ui.firsttimeform import FirstTimeForm from openlp.core.ui.media import MediaController from openlp.core.ui.printserviceform import PrintServiceForm from openlp.core.ui.projector.manager import ProjectorManager +from openlp.core.ui.lib.toolbar import OpenLPToolbar +from openlp.core.ui.lib.dockwidget import OpenLPDockWidget log = logging.getLogger(__name__) diff --git a/openlp/core/ui/media/mediacontroller.py b/openlp/core/ui/media/mediacontroller.py index cf116e861..d95c51531 100644 --- a/openlp/core/ui/media/mediacontroller.py +++ b/openlp/core/ui/media/mediacontroller.py @@ -29,14 +29,16 @@ import datetime from PyQt5 import QtCore, QtWidgets from openlp.core.common import OpenLPMixin, Registry, RegistryMixin, RegistryProperties, Settings, UiStrings, translate -from openlp.core.lib import OpenLPToolbar, ItemCapabilities +from openlp.core.lib import ItemCapabilities from openlp.core.lib.ui import critical_error_message_box -from openlp.core.ui.media import MediaState, MediaInfo, MediaType, get_media_players, set_media_players,\ - parse_optical_path -from openlp.core.ui.media.vendor.mediainfoWrapper import MediaInfoWrapper -from openlp.core.ui.media.mediaplayer import MediaPlayer from openlp.core.common import AppLocation from openlp.core.ui import DisplayControllerType +from openlp.core.ui.media.vendor.mediainfoWrapper import MediaInfoWrapper +from openlp.core.ui.media.mediaplayer import MediaPlayer +from openlp.core.ui.media import MediaState, MediaInfo, MediaType, get_media_players, set_media_players,\ + parse_optical_path +from openlp.core.ui.lib.toolbar import OpenLPToolbar +from openlp.core.ui.lib.dockwidget import OpenLPDockWidget log = logging.getLogger(__name__) diff --git a/openlp/core/ui/projector/manager.py b/openlp/core/ui/projector/manager.py index fc40ee386..8efe34b10 100644 --- a/openlp/core/ui/projector/manager.py +++ b/openlp/core/ui/projector/manager.py @@ -35,7 +35,7 @@ from PyQt5.QtWidgets import QWidget from openlp.core.common import RegistryProperties, Settings, OpenLPMixin, \ RegistryMixin, translate -from openlp.core.lib import OpenLPToolbar +from openlp.core.ui.lib import OpenLPToolbar from openlp.core.lib.ui import create_widget_action from openlp.core.lib.projector import DialogSourceStyle from openlp.core.lib.projector.constants import * diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index 66cbdf1b7..82b489344 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -35,9 +35,10 @@ from PyQt5 import QtCore, QtGui, QtWidgets from openlp.core.common import Registry, RegistryProperties, AppLocation, Settings, ThemeLevel, OpenLPMixin, \ RegistryMixin, check_directory_exists, UiStrings, translate, split_filename, delete_file from openlp.core.common.actions import ActionList, CategoryOrder -from openlp.core.lib import OpenLPToolbar, ServiceItem, ItemCapabilities, PluginStatus, build_icon +from openlp.core.lib import ServiceItem, ItemCapabilities, PluginStatus, build_icon from openlp.core.lib.ui import critical_error_message_box, create_widget_action, find_and_set_in_combo_box from openlp.core.ui import ServiceNoteForm, ServiceItemEditForm, StartTimeForm +from openlp.core.ui.lib import OpenLPToolbar from openlp.core.common.languagemanager import format_time diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py index 96ce82868..7ec4bfe29 100644 --- a/openlp/core/ui/slidecontroller.py +++ b/openlp/core/ui/slidecontroller.py @@ -33,9 +33,11 @@ from PyQt5 import QtCore, QtGui, QtWidgets from openlp.core.common import Registry, RegistryProperties, Settings, SlideLimits, UiStrings, translate, \ RegistryMixin, OpenLPMixin from openlp.core.common.actions import ActionList, CategoryOrder -from openlp.core.lib import OpenLPToolbar, ItemCapabilities, ServiceItem, ImageSource, ServiceItemAction, \ - ScreenList, build_icon, build_html +from openlp.core.lib import ItemCapabilities, ServiceItem, ImageSource, ServiceItemAction, ScreenList, build_icon, \ + build_html from openlp.core.lib.ui import create_action +from openlp.core.ui.lib.toolbar import OpenLPToolbar +from openlp.core.ui.lib.dockwidget import OpenLPDockWidget from openlp.core.ui import HideMode, MainDisplay, Display, DisplayControllerType from openlp.core.ui.listpreviewwidget import ListPreviewWidget diff --git a/openlp/core/ui/thememanager.py b/openlp/core/ui/thememanager.py index bb8a1a8a7..32975e9aa 100644 --- a/openlp/core/ui/thememanager.py +++ b/openlp/core/ui/thememanager.py @@ -31,11 +31,12 @@ from PyQt5 import QtCore, QtGui, QtWidgets from openlp.core.common import Registry, RegistryProperties, AppLocation, Settings, OpenLPMixin, RegistryMixin, \ check_directory_exists, UiStrings, translate, is_win, get_filesystem_encoding, delete_file -from openlp.core.lib import FileDialog, ImageSource, OpenLPToolbar, ValidationError, get_text_file_string, build_icon, \ +from openlp.core.lib import FileDialog, ImageSource, ValidationError, get_text_file_string, build_icon, \ check_item_selected, create_thumb, validate_thumb from openlp.core.lib.theme import ThemeXML, BackgroundType from openlp.core.lib.ui import critical_error_message_box, create_widget_action from openlp.core.ui import FileRenameForm, ThemeForm +from openlp.core.ui.lib import OpenLPToolbar from openlp.core.common.languagemanager import get_locale_key diff --git a/openlp/plugins/images/lib/mediaitem.py b/openlp/plugins/images/lib/mediaitem.py index 80a49f81c..d127fba4b 100644 --- a/openlp/plugins/images/lib/mediaitem.py +++ b/openlp/plugins/images/lib/mediaitem.py @@ -27,9 +27,10 @@ from PyQt5 import QtCore, QtGui, QtWidgets from openlp.core.common import Registry, AppLocation, Settings, UiStrings, check_directory_exists, translate, \ delete_file, get_images_filter -from openlp.core.lib import ItemCapabilities, MediaManagerItem, ServiceItemContext, StringContent, TreeWidgetWithDnD,\ - build_icon, check_item_selected, create_thumb, validate_thumb +from openlp.core.lib import ItemCapabilities, MediaManagerItem, ServiceItemContext, StringContent, build_icon, \ + check_item_selected, create_thumb, validate_thumb from openlp.core.lib.ui import create_widget_action, critical_error_message_box +from openlp.core.ui.lib.treewidgetwithdnd import TreeWidgetWithDnD from openlp.core.common.languagemanager import get_locale_key from openlp.plugins.images.forms import AddGroupForm, ChooseGroupForm from openlp.plugins.images.lib.db import ImageFilenames, ImageGroups diff --git a/tests/interfaces/openlp_core_ui/test_listpreviewwidget.py b/tests/interfaces/openlp_core_ui_lib/test_listpreviewwidget.py similarity index 98% rename from tests/interfaces/openlp_core_ui/test_listpreviewwidget.py rename to tests/interfaces/openlp_core_ui_lib/test_listpreviewwidget.py index b4e5fdbf0..7c2a7f999 100644 --- a/tests/interfaces/openlp_core_ui/test_listpreviewwidget.py +++ b/tests/interfaces/openlp_core_ui_lib/test_listpreviewwidget.py @@ -29,7 +29,7 @@ from PyQt5 import QtGui, QtWidgets from openlp.core.common import Registry from openlp.core.lib import ServiceItem -from openlp.core.ui import listpreviewwidget +from openlp.core.ui.lib.listwidgetwithdnd import ListWidgetWithDnD from tests.interfaces import MagicMock, patch from tests.utils.osdinteraction import read_service_from_file from tests.helpers.testmixin import TestMixin From 760b34f35a2e27f2186756bdd3db1ae6cb658894 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sun, 17 Apr 2016 20:42:14 +0100 Subject: [PATCH 11/23] fix --- .../openlp_core_ui_lib/test_color_button.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/functional/openlp_core_ui_lib/test_color_button.py b/tests/functional/openlp_core_ui_lib/test_color_button.py index ef6d4f93d..b65b81448 100644 --- a/tests/functional/openlp_core_ui_lib/test_color_button.py +++ b/tests/functional/openlp_core_ui_lib/test_color_button.py @@ -33,11 +33,11 @@ class TestColorDialog(TestCase): Test the :class:`~openlp.core.lib.colorbutton.ColorButton` class """ def setUp(self): - self.change_color_patcher = patch('openlp.core.lib.colorbutton.ColorButton.change_color') - self.clicked_patcher = patch('openlp.core.lib.colorbutton.ColorButton.clicked') - self.color_changed_patcher = patch('openlp.core.lib.colorbutton.ColorButton.colorChanged') - self.qt_gui_patcher = patch('openlp.core.lib.colorbutton.QtWidgets') - self.translate_patcher = patch('openlp.core.lib.colorbutton.translate', **{'return_value': 'Tool Tip Text'}) + self.change_color_patcher = patch('openlp.core.ui.lib.colorbutton.ColorButton.change_color') + self.clicked_patcher = patch('openlp.core.ui.lib.colorbutton.ColorButton.clicked') + self.color_changed_patcher = patch('openlp.core.ui.lib.colorbutton.ColorButton.colorChanged') + self.qt_gui_patcher = patch('openlp.core.ui.lib.colorbutton.QtWidgets') + self.translate_patcher = patch('openlp.core.ui.lib.colorbutton.translate', **{'return_value': 'Tool Tip Text'}) self.addCleanup(self.change_color_patcher.stop) self.addCleanup(self.clicked_patcher.stop) self.addCleanup(self.color_changed_patcher.stop) @@ -55,7 +55,7 @@ class TestColorDialog(TestCase): """ # GIVEN: The ColorButton class, a mocked change_color, setToolTip methods and clicked signal - with patch('openlp.core.lib.colorbutton.ColorButton.setToolTip') as mocked_set_tool_tip: + with patch('openlp.core.ui.lib.colorbutton.ColorButton.setToolTip') as mocked_set_tool_tip: # WHEN: The ColorButton object is instantiated widget = ColorButton() @@ -74,7 +74,7 @@ class TestColorDialog(TestCase): self.change_color_patcher.stop() # GIVEN: An instance of the ColorButton object, and a mocked out setStyleSheet - with patch('openlp.core.lib.colorbutton.ColorButton.setStyleSheet') as mocked_set_style_sheet: + with patch('openlp.core.ui.lib.colorbutton.ColorButton.setStyleSheet') as mocked_set_style_sheet: widget = ColorButton() # WHEN: Changing the color @@ -123,7 +123,7 @@ class TestColorDialog(TestCase): """ # GIVEN: An instance of ColorButton, with a mocked __init__ - with patch('openlp.core.lib.colorbutton.ColorButton.__init__', **{'return_value': None}): + with patch('openlp.core.ui.lib.colorbutton.ColorButton.__init__', **{'return_value': None}): widget = ColorButton() # WHEN: Setting the color property From 1942a8ac147942126f0622179ed8528e6511e010 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sun, 17 Apr 2016 21:11:55 +0100 Subject: [PATCH 12/23] fix --- openlp/core/ui/lib/__init__.py | 2 +- tests/interfaces/openlp_core_ui_lib/test_listpreviewwidget.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/openlp/core/ui/lib/__init__.py b/openlp/core/ui/lib/__init__.py index 8b8bd991d..e3bc60f55 100644 --- a/openlp/core/ui/lib/__init__.py +++ b/openlp/core/ui/lib/__init__.py @@ -24,4 +24,4 @@ from openlp.core.ui.lib.colorbutton import ColorButton from openlp.core.ui.lib.listwidgetwithdnd import ListWidgetWithDnD from openlp.core.ui.lib.treewidgetwithdnd import TreeWidgetWithDnD from openlp.core.ui.lib.toolbar import OpenLPToolbar -from openlp.core.ui.lib.dockwidget import OpenLPDockWidget \ No newline at end of file +from openlp.core.ui.lib.dockwidget import OpenLPDockWidget diff --git a/tests/interfaces/openlp_core_ui_lib/test_listpreviewwidget.py b/tests/interfaces/openlp_core_ui_lib/test_listpreviewwidget.py index 7c2a7f999..f5cefa960 100644 --- a/tests/interfaces/openlp_core_ui_lib/test_listpreviewwidget.py +++ b/tests/interfaces/openlp_core_ui_lib/test_listpreviewwidget.py @@ -20,7 +20,7 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### """ - Package to test the openlp.core.ui.listpreviewwidget. + Package to test the openlp.core.ui.lib.listpreviewwidget. """ from unittest import TestCase @@ -29,7 +29,7 @@ from PyQt5 import QtGui, QtWidgets from openlp.core.common import Registry from openlp.core.lib import ServiceItem -from openlp.core.ui.lib.listwidgetwithdnd import ListWidgetWithDnD +from openlp.core.ui.lib import ListWidgetWithDnD from tests.interfaces import MagicMock, patch from tests.utils.osdinteraction import read_service_from_file from tests.helpers.testmixin import TestMixin From b2ed6bb84c693aeea8d73998a5343bcd7c9de787 Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Sun, 17 Apr 2016 16:47:44 -0700 Subject: [PATCH 13/23] Fix split in string formatting --- openlp/core/ui/projector/manager.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/openlp/core/ui/projector/manager.py b/openlp/core/ui/projector/manager.py index 7c0166f95..f33165e12 100644 --- a/openlp/core/ui/projector/manager.py +++ b/openlp/core/ui/projector/manager.py @@ -926,9 +926,8 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QWidget, Ui_ProjectorManager, :param name: Name from QListWidgetItem """ - # Build the title separately so we can make it easier for translators - title = '"{name}" '.format(name=name) - title += translate('OpenLP.ProjectorManager', 'Authentication Error') + title = '"{name} {message}" '.format(name=name, + message=translate('OpenLP.ProjectorManager', 'Authentication Error')) QtWidgets.QMessageBox.warning(self, title, '
There was an authentication error while trying to connect.' '

Please verify your PIN setting ' @@ -942,9 +941,8 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QWidget, Ui_ProjectorManager, :param name: Name from QListWidgetItem """ - # Build the title separately so we can make it easier for translators - title = '"{name}" '.format(name=name) - title += translate('OpenLP.ProjectorManager', 'No Authentication Error') + title = '"{name} {message}" '.format(name=name, + message-translate('OpenLP.ProjectorManager', 'No Authentication Error')) QtWidgets.QMessageBox.warning(self, title, '
PIN is set and projector does not require authentication.' '

Please verify your PIN setting ' From b5c9f96ccf9630ba9c83b389a0b89bc143d83d9b Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Sun, 17 Apr 2016 16:57:33 -0700 Subject: [PATCH 14/23] oops fix - typo --- openlp/core/ui/projector/manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/core/ui/projector/manager.py b/openlp/core/ui/projector/manager.py index f33165e12..f710e3369 100644 --- a/openlp/core/ui/projector/manager.py +++ b/openlp/core/ui/projector/manager.py @@ -942,7 +942,7 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QWidget, Ui_ProjectorManager, :param name: Name from QListWidgetItem """ title = '"{name} {message}" '.format(name=name, - message-translate('OpenLP.ProjectorManager', 'No Authentication Error')) + message=translate('OpenLP.ProjectorManager', 'No Authentication Error')) QtWidgets.QMessageBox.warning(self, title, '
PIN is set and projector does not require authentication.' '

Please verify your PIN setting ' From f2537981e4e9287fa4e5b5aae3a369060013a019 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Wed, 20 Apr 2016 17:36:37 +0100 Subject: [PATCH 15/23] update --- openlp/core/common/__init__.py | 1 - openlp/plugins/media/mediaplugin.py | 5 ++-- .../openlp_plugins/media/test_mediaplugin.py | 24 ++++++++++++++++++- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/openlp/core/common/__init__.py b/openlp/core/common/__init__.py index a1ce05abd..2c32a75d0 100644 --- a/openlp/core/common/__init__.py +++ b/openlp/core/common/__init__.py @@ -253,7 +253,6 @@ if is_win(): from subprocess import STARTUPINFO, STARTF_USESHOWWINDOW - def add_actions(target, actions): """ Adds multiple actions to a menu or toolbar in one command. diff --git a/openlp/plugins/media/mediaplugin.py b/openlp/plugins/media/mediaplugin.py index 4f9c4a0b1..5f3f4f3ef 100644 --- a/openlp/plugins/media/mediaplugin.py +++ b/openlp/plugins/media/mediaplugin.py @@ -153,11 +153,10 @@ class MediaPlugin(Plugin): def process_check_binary(program_path): """ - Function that checks whether a binary is either ghostscript or mudraw or neither. - Is also used from presentationtab.py + Function that checks whether a binary MediaInfo is present :param program_path:The full path to the binary to check. - :return: Type of the binary, 'gs' if ghostscript, 'mudraw' if mudraw, None if invalid. + :return: If exists or not """ program_type = None runlog = check_binary(program_path) diff --git a/tests/functional/openlp_plugins/media/test_mediaplugin.py b/tests/functional/openlp_plugins/media/test_mediaplugin.py index 1e11de4fa..e7852fb0c 100644 --- a/tests/functional/openlp_plugins/media/test_mediaplugin.py +++ b/tests/functional/openlp_plugins/media/test_mediaplugin.py @@ -25,7 +25,7 @@ Test the media plugin from unittest import TestCase from openlp.core import Registry -from openlp.plugins.media.mediaplugin import MediaPlugin +from openlp.plugins.media.mediaplugin import MediaPlugin, process_check_binary from tests.functional import MagicMock, patch from tests.helpers.testmixin import TestMixin @@ -63,3 +63,25 @@ class MediaPluginTest(TestCase, TestMixin): self.assertIsInstance(MediaPlugin.about(), str) # THEN: about() should return a non-empty string self.assertNotEquals(len(MediaPlugin.about()), 0) + + def process_check_binary_pass_test(self): + """ + Test that the Process check returns true if found + """ + # GIVEN: A media plugin instance + # WHEN: function is called with the correct name + result = process_check_binary("MediaInfo") + + # THEN: The the result should be True + self.assertFalse(result, "Media info should have been found") + + def process_check_binary_fail_test(self): + """ + Test that the Process check returns false if not found + """ + # GIVEN: A media plugin instance + # WHEN: function is called with the wrong name + result = process_check_binary("MediaInfo1") + + # THEN: The the result should be True + self.assertTrue(result, "Media info should not have been found") From bd8ddf75064904c98b1c022559656e4cb4fffd7b Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Thu, 21 Apr 2016 17:26:34 +0100 Subject: [PATCH 16/23] fix tests --- openlp/core/common/__init__.py | 2 +- openlp/plugins/media/mediaplugin.py | 6 +++--- openlp/plugins/presentations/lib/pdfcontroller.py | 4 ++-- .../openlp_plugins/media/test_mediaplugin.py | 14 +++++++++----- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/openlp/core/common/__init__.py b/openlp/core/common/__init__.py index 2c32a75d0..2384252fc 100644 --- a/openlp/core/common/__init__.py +++ b/openlp/core/common/__init__.py @@ -378,7 +378,7 @@ def clean_filename(filename): return INVALID_FILE_CHARS.sub('_', CONTROL_CHARS.sub('', filename)) -def check_binary(program_path): +def check_binary_exists(program_path): """ Function that checks whether a binary exists. diff --git a/openlp/plugins/media/mediaplugin.py b/openlp/plugins/media/mediaplugin.py index 5f3f4f3ef..1d5529084 100644 --- a/openlp/plugins/media/mediaplugin.py +++ b/openlp/plugins/media/mediaplugin.py @@ -30,7 +30,7 @@ from shutil import which from PyQt5 import QtCore -from openlp.core.common import AppLocation, Settings, translate, check_binary, is_win +from openlp.core.common import AppLocation, Settings, translate, check_binary_exists, is_win from openlp.core.lib import Plugin, StringContent, build_icon from openlp.plugins.media.lib import MediaMediaItem, MediaTab @@ -159,8 +159,8 @@ def process_check_binary(program_path): :return: If exists or not """ program_type = None - runlog = check_binary(program_path) - print(runlog) + runlog = check_binary_exists(program_path) + print(runlog, type(runlog)) # Analyse the output to see it the program is mediainfo for line in runlog.splitlines(): decoded_line = line.decode() diff --git a/openlp/plugins/presentations/lib/pdfcontroller.py b/openlp/plugins/presentations/lib/pdfcontroller.py index 0ef9cb29b..48150a9f2 100644 --- a/openlp/plugins/presentations/lib/pdfcontroller.py +++ b/openlp/plugins/presentations/lib/pdfcontroller.py @@ -26,7 +26,7 @@ import re from shutil import which from subprocess import check_output, CalledProcessError -from openlp.core.common import AppLocation, check_binary +from openlp.core.common import AppLocation, check_binary_exists from openlp.core.common import Settings, is_win from openlp.core.lib import ScreenList from .presentationcontroller import PresentationController, PresentationDocument @@ -69,7 +69,7 @@ class PdfController(PresentationController): :return: Type of the binary, 'gs' if ghostscript, 'mudraw' if mudraw, None if invalid. """ program_type = None - runlog = check_binary(program_path) + runlog = check_binary_exists(program_path) # Analyse the output to see it the program is mudraw, ghostscript or neither for line in runlog.splitlines(): decoded_line = line.decode() diff --git a/tests/functional/openlp_plugins/media/test_mediaplugin.py b/tests/functional/openlp_plugins/media/test_mediaplugin.py index e7852fb0c..c49cdbaa4 100644 --- a/tests/functional/openlp_plugins/media/test_mediaplugin.py +++ b/tests/functional/openlp_plugins/media/test_mediaplugin.py @@ -64,24 +64,28 @@ class MediaPluginTest(TestCase, TestMixin): # THEN: about() should return a non-empty string self.assertNotEquals(len(MediaPlugin.about()), 0) - def process_check_binary_pass_test(self): + @patch('openlp.plugins.media.mediaplugin.check_binary_exists') + def process_check_binary_pass_test(self, mocked_checked_binary_exists): """ Test that the Process check returns true if found """ # GIVEN: A media plugin instance # WHEN: function is called with the correct name - result = process_check_binary("MediaInfo") + mocked_checked_binary_exists.return_value = str.encode('MediaInfo Command line') + result = process_check_binary('MediaInfo') # THEN: The the result should be True - self.assertFalse(result, "Media info should have been found") + self.assertTrue(result, 'Mediainfo should have been found') - def process_check_binary_fail_test(self): + @patch('openlp.plugins.media.mediaplugin.check_binary_exists') + def process_check_binary_fail_test(self, mocked_checked_binary_exists): """ Test that the Process check returns false if not found """ # GIVEN: A media plugin instance # WHEN: function is called with the wrong name + mocked_checked_binary_exists.return_value = str.encode('MediaInfo1 Command line') result = process_check_binary("MediaInfo1") # THEN: The the result should be True - self.assertTrue(result, "Media info should not have been found") + self.assertFalse(result, "Mediainfo should not have been found") From 20acc909515dd101ecafa14a17c42863c888b8d2 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Fri, 22 Apr 2016 17:37:21 +0100 Subject: [PATCH 17/23] Pep8 --- openlp/core/common/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openlp/core/common/__init__.py b/openlp/core/common/__init__.py index 2384252fc..f3076a86f 100644 --- a/openlp/core/common/__init__.py +++ b/openlp/core/common/__init__.py @@ -401,4 +401,3 @@ def check_binary_exists(program_path): runlog = '' log.debug('check_output returned: %s' % runlog) return runlog - From 38996c81cc694bf906dde4eba4afdd7c480f2505 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Fri, 22 Apr 2016 19:25:57 +0100 Subject: [PATCH 18/23] more files --- openlp/core/ui/__init__.py | 2 +- openlp/core/ui/lib/__init__.py | 11 +- openlp/core/ui/mediadockmanager.py | 71 ---- openlp/core/ui/wizard.py | 308 ------------------ .../plugins/bibles/forms/bibleimportform.py | 2 +- .../plugins/bibles/forms/bibleupgradeform.py | 2 +- .../songs/forms/duplicatesongremovalform.py | 2 +- openlp/plugins/songs/forms/songexportform.py | 2 +- openlp/plugins/songs/forms/songimportform.py | 2 +- openlp/plugins/songs/lib/importer.py | 2 +- .../songs/lib/importers/foilpresenter.py | 2 +- openlp/plugins/songs/lib/importers/openlp.py | 2 +- .../plugins/songs/lib/importers/openlyrics.py | 2 +- .../songs/lib/importers/powerpraise.py | 2 +- .../lib/importers/presentationmanager.py | 3 +- .../songs/lib/importers/propresenter.py | 2 +- .../plugins/songs/lib/importers/songimport.py | 2 +- .../songs/lib/importers/songshowplus.py | 2 +- 18 files changed, 22 insertions(+), 399 deletions(-) delete mode 100644 openlp/core/ui/mediadockmanager.py delete mode 100644 openlp/core/ui/wizard.py diff --git a/openlp/core/ui/__init__.py b/openlp/core/ui/__init__.py index c6777c756..0f0b14b05 100644 --- a/openlp/core/ui/__init__.py +++ b/openlp/core/ui/__init__.py @@ -113,7 +113,7 @@ from .settingsform import SettingsForm from .formattingtagform import FormattingTagForm from .formattingtagcontroller import FormattingTagController from .shortcutlistform import ShortcutListForm -from .mediadockmanager import MediaDockManager +from openlp.core.ui.lib.mediadockmanager import MediaDockManager from .servicemanager import ServiceManager from .thememanager import ThemeManager from .projector.manager import ProjectorManager diff --git a/openlp/core/ui/lib/__init__.py b/openlp/core/ui/lib/__init__.py index e3bc60f55..2bb3ac157 100644 --- a/openlp/core/ui/lib/__init__.py +++ b/openlp/core/ui/lib/__init__.py @@ -20,8 +20,9 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### -from openlp.core.ui.lib.colorbutton import ColorButton -from openlp.core.ui.lib.listwidgetwithdnd import ListWidgetWithDnD -from openlp.core.ui.lib.treewidgetwithdnd import TreeWidgetWithDnD -from openlp.core.ui.lib.toolbar import OpenLPToolbar -from openlp.core.ui.lib.dockwidget import OpenLPDockWidget +from .colorbutton import ColorButton +from .listwidgetwithdnd import ListWidgetWithDnD +from .treewidgetwithdnd import TreeWidgetWithDnD +from .toolbar import OpenLPToolbar +from .dockwidget import OpenLPDockWidget +from .wizard import OpenLPWizard, WizardStrings diff --git a/openlp/core/ui/mediadockmanager.py b/openlp/core/ui/mediadockmanager.py deleted file mode 100644 index ad786b3a0..000000000 --- a/openlp/core/ui/mediadockmanager.py +++ /dev/null @@ -1,71 +0,0 @@ -# -*- coding: utf-8 -*- -# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 - -############################################################################### -# OpenLP - Open Source Lyrics Projection # -# --------------------------------------------------------------------------- # -# Copyright (c) 2008-2016 OpenLP Developers # -# --------------------------------------------------------------------------- # -# This program is free software; you can redistribute it and/or modify it # -# under the terms of the GNU General Public License as published by the Free # -# Software Foundation; version 2 of the License. # -# # -# This program is distributed in the hope that it will be useful, but WITHOUT # -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # -# more details. # -# # -# You should have received a copy of the GNU General Public License along # -# with this program; if not, write to the Free Software Foundation, Inc., 59 # -# Temple Place, Suite 330, Boston, MA 02111-1307 USA # -############################################################################### -""" -The media manager dock. -""" -import logging - -from openlp.core.lib import StringContent - -log = logging.getLogger(__name__) - - -class MediaDockManager(object): - """ - Provide a repository for MediaManagerItems - """ - def __init__(self, media_dock): - """ - Initialise the media dock - """ - self.media_dock = media_dock - - def add_item_to_dock(self, media_item): - """ - Add a MediaManagerItem to the dock - If the item has been added before, it's silently skipped - - :param media_item: The item to add to the dock - """ - visible_title = media_item.plugin.get_string(StringContent.VisibleName) - log.debug('Inserting %s dock' % visible_title['title']) - match = False - for dock_index in range(self.media_dock.count()): - if self.media_dock.widget(dock_index).settings_section == media_item.plugin.name: - match = True - break - if not match: - self.media_dock.addItem(media_item, visible_title['title']) - - def remove_dock(self, media_item): - """ - Removes a MediaManagerItem from the dock - - :param media_item: The item to add to the dock - """ - visible_title = media_item.plugin.get_string(StringContent.VisibleName) - log.debug('remove %s dock' % visible_title['title']) - for dock_index in range(self.media_dock.count()): - if self.media_dock.widget(dock_index): - if self.media_dock.widget(dock_index).settings_section == media_item.plugin.name: - self.media_dock.widget(dock_index).setVisible(False) - self.media_dock.removeItem(dock_index) diff --git a/openlp/core/ui/wizard.py b/openlp/core/ui/wizard.py deleted file mode 100644 index 3835056fb..000000000 --- a/openlp/core/ui/wizard.py +++ /dev/null @@ -1,308 +0,0 @@ -# -*- coding: utf-8 -*- -# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 - -############################################################################### -# OpenLP - Open Source Lyrics Projection # -# --------------------------------------------------------------------------- # -# Copyright (c) 2008-2016 OpenLP Developers # -# --------------------------------------------------------------------------- # -# This program is free software; you can redistribute it and/or modify it # -# under the terms of the GNU General Public License as published by the Free # -# Software Foundation; version 2 of the License. # -# # -# This program is distributed in the hope that it will be useful, but WITHOUT # -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # -# more details. # -# # -# You should have received a copy of the GNU General Public License along # -# with this program; if not, write to the Free Software Foundation, Inc., 59 # -# Temple Place, Suite 330, Boston, MA 02111-1307 USA # -############################################################################### -""" -The :mod:``wizard`` module provides generic wizard tools for OpenLP. -""" -import logging -import os - -from PyQt5 import QtGui, QtWidgets - -from openlp.core.common import Registry, RegistryProperties, Settings, UiStrings, translate, is_macosx -from openlp.core.lib import build_icon -from openlp.core.lib.ui import add_welcome_page - -log = logging.getLogger(__name__) - - -class WizardStrings(object): - """ - Provide standard strings for wizards to use. - """ - # Applications/Formats we import from or export to. These get used in - # multiple places but do not need translating unless you find evidence of - # the writers translating their own product name. - CSV = 'CSV' - OS = 'OpenSong' - OSIS = 'OSIS' - ZEF = 'Zefania' - # These strings should need a good reason to be retranslated elsewhere. - FinishedImport = translate('OpenLP.Ui', 'Finished import.') - FormatLabel = translate('OpenLP.Ui', 'Format:') - HeaderStyle = '%s' - Importing = translate('OpenLP.Ui', 'Importing') - ImportingType = translate('OpenLP.Ui', 'Importing "%s"...') - ImportSelect = translate('OpenLP.Ui', 'Select Import Source') - ImportSelectLong = translate('OpenLP.Ui', 'Select the import format and the location to import from.') - OpenTypeFile = translate('OpenLP.Ui', 'Open %s File') - OpenTypeFolder = translate('OpenLP.Ui', 'Open %s Folder') - PercentSymbolFormat = translate('OpenLP.Ui', '%p%') - Ready = translate('OpenLP.Ui', 'Ready.') - StartingImport = translate('OpenLP.Ui', 'Starting import...') - YouSpecifyFile = translate('OpenLP.Ui', 'You need to specify one %s file to import from.', - 'A file type e.g. OpenSong') - YouSpecifyFiles = translate('OpenLP.Ui', 'You need to specify at least one %s file to import from.', - 'A file type e.g. OpenSong') - YouSpecifyFolder = translate('OpenLP.Ui', 'You need to specify one %s folder to import from.', - 'A song format e.g. PowerSong') - - -class OpenLPWizard(QtWidgets.QWizard, RegistryProperties): - """ - Generic OpenLP wizard to provide generic functionality and a unified look - and feel. - - ``parent`` - The QWidget-derived parent of the wizard. - - ``plugin`` - Plugin this wizard is part of. The plugin will be saved in the "plugin" variable. - The plugin will also be used as basis for the file dialog methods this class provides. - - ``name`` - The object name this wizard should have. - - ``image`` - The image to display on the "welcome" page of the wizard. Should be 163x350. - - ``add_progress_page`` - Whether to add a progress page with a progressbar at the end of the wizard. - """ - def __init__(self, parent, plugin, name, image, add_progress_page=True): - """ - Constructor - """ - super(OpenLPWizard, self).__init__(parent) - self.plugin = plugin - self.with_progress_page = add_progress_page - self.setObjectName(name) - self.open_icon = build_icon(':/general/general_open.png') - self.delete_icon = build_icon(':/general/general_delete.png') - self.finish_button = self.button(QtWidgets.QWizard.FinishButton) - self.cancel_button = self.button(QtWidgets.QWizard.CancelButton) - self.setupUi(image) - self.register_fields() - self.custom_init() - self.custom_signals() - self.currentIdChanged.connect(self.on_current_id_changed) - if self.with_progress_page: - self.error_copy_to_button.clicked.connect(self.on_error_copy_to_button_clicked) - self.error_save_to_button.clicked.connect(self.on_error_save_to_button_clicked) - - def setupUi(self, image): - """ - Set up the wizard UI. - :param image: path to start up image - """ - self.setWindowIcon(build_icon(u':/icon/openlp-logo.svg')) - self.setModal(True) - self.setOptions(QtWidgets.QWizard.IndependentPages | - QtWidgets.QWizard.NoBackButtonOnStartPage | QtWidgets.QWizard.NoBackButtonOnLastPage) - if is_macosx(): - self.setPixmap(QtWidgets.QWizard.BackgroundPixmap, QtGui.QPixmap(':/wizards/openlp-osx-wizard.png')) - else: - self.setWizardStyle(QtWidgets.QWizard.ModernStyle) - add_welcome_page(self, image) - self.add_custom_pages() - if self.with_progress_page: - self.add_progress_page() - self.retranslateUi() - - def register_fields(self): - """ - Hook method for wizards to register any fields they need. - """ - pass - - def custom_init(self): - """ - Hook method for custom initialisation - """ - pass - - def custom_signals(self): - """ - Hook method for adding custom signals - """ - pass - - def add_custom_pages(self): - """ - Hook method for wizards to add extra pages - """ - pass - - def add_progress_page(self): - """ - Add the progress page for the wizard. This page informs the user how - the wizard is progressing with its task. - """ - self.progress_page = QtWidgets.QWizardPage() - self.progress_page.setObjectName('progress_page') - self.progress_layout = QtWidgets.QVBoxLayout(self.progress_page) - self.progress_layout.setContentsMargins(48, 48, 48, 48) - self.progress_layout.setObjectName('progress_layout') - self.progress_label = QtWidgets.QLabel(self.progress_page) - self.progress_label.setObjectName('progress_label') - self.progress_label.setWordWrap(True) - self.progress_layout.addWidget(self.progress_label) - self.progress_bar = QtWidgets.QProgressBar(self.progress_page) - self.progress_bar.setObjectName('progress_bar') - self.progress_layout.addWidget(self.progress_bar) - # Add a QTextEdit and a copy to file and copy to clipboard button to be - # able to provide feedback to the user. Hidden by default. - self.error_report_text_edit = QtWidgets.QTextEdit(self.progress_page) - self.error_report_text_edit.setObjectName('error_report_text_edit') - self.error_report_text_edit.setHidden(True) - self.error_report_text_edit.setReadOnly(True) - self.progress_layout.addWidget(self.error_report_text_edit) - self.error_button_layout = QtWidgets.QHBoxLayout() - self.error_button_layout.setObjectName('error_button_layout') - spacer = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) - self.error_button_layout.addItem(spacer) - self.error_copy_to_button = QtWidgets.QPushButton(self.progress_page) - self.error_copy_to_button.setObjectName('error_copy_to_button') - self.error_copy_to_button.setHidden(True) - self.error_copy_to_button.setIcon(build_icon(':/system/system_edit_copy.png')) - self.error_button_layout.addWidget(self.error_copy_to_button) - self.error_save_to_button = QtWidgets.QPushButton(self.progress_page) - self.error_save_to_button.setObjectName('error_save_to_button') - self.error_save_to_button.setHidden(True) - self.error_save_to_button.setIcon(build_icon(':/general/general_save.png')) - self.error_button_layout.addWidget(self.error_save_to_button) - self.progress_layout.addLayout(self.error_button_layout) - self.addPage(self.progress_page) - - def exec(self): - """ - Run the wizard. - """ - self.set_defaults() - return QtWidgets.QWizard.exec(self) - - def reject(self): - """ - Stop the wizard on cancel button, close button or ESC key. - """ - log.debug('Wizard cancelled by user.') - if self.with_progress_page and self.currentPage() == self.progress_page: - Registry().execute('openlp_stop_wizard') - self.done(QtWidgets.QDialog.Rejected) - - def on_current_id_changed(self, page_id): - """ - Perform necessary functions depending on which wizard page is active. - :param page_id: current page number - """ - if self.with_progress_page and self.page(page_id) == self.progress_page: - self.pre_wizard() - self.perform_wizard() - self.post_wizard() - else: - self.custom_page_changed(page_id) - - def custom_page_changed(self, page_id): - """ - Called when changing to a page other than the progress page - :param page_id: current page number - """ - pass - - def on_error_copy_to_button_clicked(self): - """ - Called when the ``error_copy_to_button`` has been clicked. - """ - pass - - def on_error_save_to_button_clicked(self): - """ - Called when the ``error_save_to_button`` has been clicked. - """ - pass - - def increment_progress_bar(self, status_text, increment=1): - """ - Update the wizard progress page. - - :param status_text: Current status information to display. - :param increment: The value to increment the progress bar by. - """ - log.debug('IncrementBar %s', status_text) - self.progress_label.setText(status_text) - if increment > 0: - self.progress_bar.setValue(self.progress_bar.value() + increment) - self.application.process_events() - - def pre_wizard(self): - """ - Prepare the UI for the import. - """ - self.finish_button.setVisible(False) - self.progress_bar.setMinimum(0) - self.progress_bar.setMaximum(1188) - self.progress_bar.setValue(0) - - def post_wizard(self): - """ - Clean up the UI after the import has finished. - """ - self.progress_bar.setValue(self.progress_bar.maximum()) - self.finish_button.setVisible(True) - self.cancel_button.setVisible(False) - self.application.process_events() - - def get_file_name(self, title, editbox, setting_name, filters=''): - """ - Opens a QFileDialog and saves the filename to the given editbox. - - :param title: The title of the dialog (unicode). - :param editbox: An editbox (QLineEdit). - :param setting_name: The place where to save the last opened directory. - :param filters: The file extension filters. It should contain the file description - as well as the file extension. For example:: - - 'OpenLP 2 Databases (*.sqlite)' - """ - if filters: - filters += ';;' - filters += '%s (*)' % UiStrings().AllFiles - filename, filter_used = QtWidgets.QFileDialog.getOpenFileName( - self, title, os.path.dirname(Settings().value(self.plugin.settings_section + '/' + setting_name)), - filters) - if filename: - editbox.setText(filename) - Settings().setValue(self.plugin.settings_section + '/' + setting_name, filename) - - def get_folder(self, title, editbox, setting_name): - """ - Opens a QFileDialog and saves the selected folder to the given editbox. - - :param title: The title of the dialog (unicode). - :param editbox: An editbox (QLineEdit). - :param setting_name: The place where to save the last opened directory. - """ - folder = QtWidgets.QFileDialog.getExistingDirectory( - self, title, Settings().value(self.plugin.settings_section + '/' + setting_name), - QtWidgets.QFileDialog.ShowDirsOnly) - if folder: - editbox.setText(folder) - Settings().setValue(self.plugin.settings_section + '/' + setting_name, folder) diff --git a/openlp/plugins/bibles/forms/bibleimportform.py b/openlp/plugins/bibles/forms/bibleimportform.py index 27dbea963..45efe0e5f 100644 --- a/openlp/plugins/bibles/forms/bibleimportform.py +++ b/openlp/plugins/bibles/forms/bibleimportform.py @@ -31,7 +31,7 @@ from PyQt5 import QtWidgets from openlp.core.common import AppLocation, Settings, UiStrings, translate, clean_filename from openlp.core.lib.db import delete_database from openlp.core.lib.ui import critical_error_message_box -from openlp.core.ui.wizard import OpenLPWizard, WizardStrings +from openlp.core.ui.lib.wizard import OpenLPWizard, WizardStrings from openlp.core.common.languagemanager import get_locale_key from openlp.plugins.bibles.lib.manager import BibleFormat from openlp.plugins.bibles.lib.db import BiblesResourcesDB, clean_filename diff --git a/openlp/plugins/bibles/forms/bibleupgradeform.py b/openlp/plugins/bibles/forms/bibleupgradeform.py index 611e6ead3..11771e9aa 100644 --- a/openlp/plugins/bibles/forms/bibleupgradeform.py +++ b/openlp/plugins/bibles/forms/bibleupgradeform.py @@ -32,7 +32,7 @@ from PyQt5 import QtCore, QtWidgets from openlp.core.common import Registry, AppLocation, UiStrings, Settings, check_directory_exists, translate, \ delete_file from openlp.core.lib.ui import critical_error_message_box -from openlp.core.ui.wizard import OpenLPWizard, WizardStrings +from openlp.core.ui.lib.wizard import OpenLPWizard, WizardStrings from openlp.plugins.bibles.lib.db import BibleDB, BibleMeta, OldBibleDB, BiblesResourcesDB from openlp.plugins.bibles.lib.http import BSExtract, BGExtract, CWExtract diff --git a/openlp/plugins/songs/forms/duplicatesongremovalform.py b/openlp/plugins/songs/forms/duplicatesongremovalform.py index 0fa4ee670..26de9507f 100644 --- a/openlp/plugins/songs/forms/duplicatesongremovalform.py +++ b/openlp/plugins/songs/forms/duplicatesongremovalform.py @@ -30,7 +30,7 @@ import os from PyQt5 import QtCore, QtWidgets from openlp.core.common import Registry, RegistryProperties, translate -from openlp.core.ui.wizard import OpenLPWizard, WizardStrings +from openlp.core.ui.lib.wizard import OpenLPWizard, WizardStrings from openlp.plugins.songs.lib import delete_song from openlp.plugins.songs.lib.db import Song, MediaFile from openlp.plugins.songs.forms.songreviewwidget import SongReviewWidget diff --git a/openlp/plugins/songs/forms/songexportform.py b/openlp/plugins/songs/forms/songexportform.py index ee35ea7e5..ba8e2738a 100644 --- a/openlp/plugins/songs/forms/songexportform.py +++ b/openlp/plugins/songs/forms/songexportform.py @@ -30,7 +30,7 @@ from PyQt5 import QtCore, QtWidgets from openlp.core.common import Registry, UiStrings, translate from openlp.core.lib import create_separated_list, build_icon from openlp.core.lib.ui import critical_error_message_box -from openlp.core.ui.wizard import OpenLPWizard, WizardStrings +from openlp.core.ui.lib.wizard import OpenLPWizard, WizardStrings from openlp.plugins.songs.lib.db import Song from openlp.plugins.songs.lib.openlyricsexport import OpenLyricsExport diff --git a/openlp/plugins/songs/forms/songimportform.py b/openlp/plugins/songs/forms/songimportform.py index 9058324fc..7a6af3981 100644 --- a/openlp/plugins/songs/forms/songimportform.py +++ b/openlp/plugins/songs/forms/songimportform.py @@ -31,7 +31,7 @@ from PyQt5 import QtCore, QtWidgets from openlp.core.common import RegistryProperties, Settings, UiStrings, translate from openlp.core.lib import FileDialog from openlp.core.lib.ui import critical_error_message_box -from openlp.core.ui.wizard import OpenLPWizard, WizardStrings +from openlp.core.ui.lib.wizard import OpenLPWizard, WizardStrings from openlp.plugins.songs.lib.importer import SongFormat, SongFormatSelect log = logging.getLogger(__name__) diff --git a/openlp/plugins/songs/lib/importer.py b/openlp/plugins/songs/lib/importer.py index 47f6edb46..7b9101306 100644 --- a/openlp/plugins/songs/lib/importer.py +++ b/openlp/plugins/songs/lib/importer.py @@ -26,7 +26,7 @@ import os import logging from openlp.core.common import translate, UiStrings, is_win -from openlp.core.ui.wizard import WizardStrings +from openlp.core.ui.lib.wizard import WizardStrings from .importers.opensong import OpenSongImport from .importers.easyslides import EasySlidesImport from .importers.openlp import OpenLPSongImport diff --git a/openlp/plugins/songs/lib/importers/foilpresenter.py b/openlp/plugins/songs/lib/importers/foilpresenter.py index b1b12960a..061f50a9f 100644 --- a/openlp/plugins/songs/lib/importers/foilpresenter.py +++ b/openlp/plugins/songs/lib/importers/foilpresenter.py @@ -90,7 +90,7 @@ import os from lxml import etree, objectify from openlp.core.lib import translate -from openlp.core.ui.wizard import WizardStrings +from openlp.core.ui.lib.wizard import WizardStrings from openlp.plugins.songs.lib import clean_song, VerseType from openlp.plugins.songs.lib.importers.songimport import SongImport from openlp.plugins.songs.lib.db import Author, Book, Song, Topic diff --git a/openlp/plugins/songs/lib/importers/openlp.py b/openlp/plugins/songs/lib/importers/openlp.py index b914ed1e1..e17fe138f 100644 --- a/openlp/plugins/songs/lib/importers/openlp.py +++ b/openlp/plugins/songs/lib/importers/openlp.py @@ -31,7 +31,7 @@ from sqlalchemy.orm.exc import UnmappedClassError from openlp.core.common import translate from openlp.core.lib.db import BaseModel -from openlp.core.ui.wizard import WizardStrings +from openlp.core.ui.lib.wizard import WizardStrings from openlp.plugins.songs.lib import clean_song from openlp.plugins.songs.lib.db import Author, Book, Song, Topic, MediaFile from .songimport import SongImport diff --git a/openlp/plugins/songs/lib/importers/openlyrics.py b/openlp/plugins/songs/lib/importers/openlyrics.py index c7bde403a..f60023cdf 100644 --- a/openlp/plugins/songs/lib/importers/openlyrics.py +++ b/openlp/plugins/songs/lib/importers/openlyrics.py @@ -29,7 +29,7 @@ import os from lxml import etree -from openlp.core.ui.wizard import WizardStrings +from openlp.core.ui.lib.wizard import WizardStrings from openlp.plugins.songs.lib.importers.songimport import SongImport from openlp.plugins.songs.lib.ui import SongStrings from openlp.plugins.songs.lib.openlyricsxml import OpenLyrics, OpenLyricsError diff --git a/openlp/plugins/songs/lib/importers/powerpraise.py b/openlp/plugins/songs/lib/importers/powerpraise.py index b93eed0fe..93a360542 100644 --- a/openlp/plugins/songs/lib/importers/powerpraise.py +++ b/openlp/plugins/songs/lib/importers/powerpraise.py @@ -27,7 +27,7 @@ Powerpraise song files into the current database. import os from lxml import objectify -from openlp.core.ui.wizard import WizardStrings +from openlp.core.ui.lib.wizard import WizardStrings from .songimport import SongImport diff --git a/openlp/plugins/songs/lib/importers/presentationmanager.py b/openlp/plugins/songs/lib/importers/presentationmanager.py index da31ce953..c26f11312 100644 --- a/openlp/plugins/songs/lib/importers/presentationmanager.py +++ b/openlp/plugins/songs/lib/importers/presentationmanager.py @@ -26,10 +26,11 @@ Presentationmanager song files into the current database. import os import re + import chardet from lxml import objectify, etree -from openlp.core.ui.wizard import WizardStrings +from openlp.core.ui.lib.wizard import WizardStrings from .songimport import SongImport diff --git a/openlp/plugins/songs/lib/importers/propresenter.py b/openlp/plugins/songs/lib/importers/propresenter.py index cddf0e52b..55e05a08f 100644 --- a/openlp/plugins/songs/lib/importers/propresenter.py +++ b/openlp/plugins/songs/lib/importers/propresenter.py @@ -29,7 +29,7 @@ import base64 import logging from lxml import objectify -from openlp.core.ui.wizard import WizardStrings +from openlp.core.ui.lib.wizard import WizardStrings from openlp.plugins.songs.lib import strip_rtf from .songimport import SongImport diff --git a/openlp/plugins/songs/lib/importers/songimport.py b/openlp/plugins/songs/lib/importers/songimport.py index 54c82da29..835386b26 100644 --- a/openlp/plugins/songs/lib/importers/songimport.py +++ b/openlp/plugins/songs/lib/importers/songimport.py @@ -28,7 +28,7 @@ import os from PyQt5 import QtCore from openlp.core.common import Registry, AppLocation, check_directory_exists, translate -from openlp.core.ui.wizard import WizardStrings +from openlp.core.ui.lib.wizard import WizardStrings from openlp.plugins.songs.lib import clean_song, VerseType from openlp.plugins.songs.lib.db import Song, Author, Topic, Book, MediaFile from openlp.plugins.songs.lib.ui import SongStrings diff --git a/openlp/plugins/songs/lib/importers/songshowplus.py b/openlp/plugins/songs/lib/importers/songshowplus.py index 4851894ab..d9a205e22 100644 --- a/openlp/plugins/songs/lib/importers/songshowplus.py +++ b/openlp/plugins/songs/lib/importers/songshowplus.py @@ -29,7 +29,7 @@ import logging import re import struct -from openlp.core.ui.wizard import WizardStrings +from openlp.core.ui.lib.wizard import WizardStrings from openlp.plugins.songs.lib import VerseType, retrieve_windows_encoding from openlp.plugins.songs.lib.importers.songimport import SongImport From 0d755e33549e116cb9998f912c1ea9d6fda44c0e Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Fri, 22 Apr 2016 19:32:45 +0100 Subject: [PATCH 19/23] more files --- openlp/core/ui/__init__.py | 3 +- openlp/core/ui/lib/__init__.py | 3 + openlp/core/ui/listpreviewwidget.py | 226 ---------------------------- openlp/core/ui/mainwindow.py | 3 +- openlp/core/ui/slidecontroller.py | 3 +- 5 files changed, 8 insertions(+), 230 deletions(-) delete mode 100644 openlp/core/ui/listpreviewwidget.py diff --git a/openlp/core/ui/__init__.py b/openlp/core/ui/__init__.py index 0f0b14b05..599efd8e7 100644 --- a/openlp/core/ui/__init__.py +++ b/openlp/core/ui/__init__.py @@ -113,7 +113,6 @@ from .settingsform import SettingsForm from .formattingtagform import FormattingTagForm from .formattingtagcontroller import FormattingTagController from .shortcutlistform import ShortcutListForm -from openlp.core.ui.lib.mediadockmanager import MediaDockManager from .servicemanager import ServiceManager from .thememanager import ThemeManager from .projector.manager import ProjectorManager @@ -121,7 +120,7 @@ from .projector.tab import ProjectorTab from .projector.editform import ProjectorEditForm __all__ = ['SplashScreen', 'AboutForm', 'SettingsForm', 'MainDisplay', 'SlideController', 'ServiceManager', 'ThemeForm', - 'ThemeManager', 'MediaDockManager', 'ServiceItemEditForm', 'FirstTimeForm', 'FirstTimeLanguageForm', + 'ThemeManager', 'ServiceItemEditForm', 'FirstTimeForm', 'FirstTimeLanguageForm', 'Display', 'ServiceNoteForm', 'ThemeLayoutForm', 'FileRenameForm', 'StartTimeForm', 'MainDisplay', 'SlideController', 'DisplayController', 'GeneralTab', 'ThemesTab', 'AdvancedTab', 'PluginForm', 'FormattingTagForm', 'ShortcutListForm', 'FormattingTagController', 'SingleColumnTableWidget', diff --git a/openlp/core/ui/lib/__init__.py b/openlp/core/ui/lib/__init__.py index 2bb3ac157..d4e21e7bd 100644 --- a/openlp/core/ui/lib/__init__.py +++ b/openlp/core/ui/lib/__init__.py @@ -26,3 +26,6 @@ from .treewidgetwithdnd import TreeWidgetWithDnD from .toolbar import OpenLPToolbar from .dockwidget import OpenLPDockWidget from .wizard import OpenLPWizard, WizardStrings +from .mediadockmanager import MediaDockManager +from .listpreviewwidget import ListPreviewWidget + diff --git a/openlp/core/ui/listpreviewwidget.py b/openlp/core/ui/listpreviewwidget.py deleted file mode 100644 index 88aef818a..000000000 --- a/openlp/core/ui/listpreviewwidget.py +++ /dev/null @@ -1,226 +0,0 @@ -# -*- coding: utf-8 -*- -# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 - -############################################################################### -# OpenLP - Open Source Lyrics Projection # -# --------------------------------------------------------------------------- # -# Copyright (c) 2008-2016 OpenLP Developers # -# --------------------------------------------------------------------------- # -# This program is free software; you can redistribute it and/or modify it # -# under the terms of the GNU General Public License as published by the Free # -# Software Foundation; version 2 of the License. # -# # -# This program is distributed in the hope that it will be useful, but WITHOUT # -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # -# more details. # -# # -# You should have received a copy of the GNU General Public License along # -# with this program; if not, write to the Free Software Foundation, Inc., 59 # -# Temple Place, Suite 330, Boston, MA 02111-1307 USA # -############################################################################### -""" -The :mod:`listpreviewwidget` is a widget that lists the slides in the slide controller. -It is based on a QTableWidget but represents its contents in list form. -""" - -from PyQt5 import QtCore, QtGui, QtWidgets - -from openlp.core.common import RegistryProperties, Settings -from openlp.core.lib import ImageSource, ServiceItem - - -class ListPreviewWidget(QtWidgets.QTableWidget, RegistryProperties): - """ - A special type of QTableWidget which lists the slides in the slide controller - - :param parent: - :param screen_ratio: - """ - - def __init__(self, parent, screen_ratio): - """ - Initializes the widget to default state. - - An empty ``ServiceItem`` is used by default. replace_service_manager_item() needs to be called to make this - widget display something. - """ - super(QtWidgets.QTableWidget, self).__init__(parent) - self._setup(screen_ratio) - - def _setup(self, screen_ratio): - """ - Set up the widget - """ - self.setColumnCount(1) - self.horizontalHeader().setVisible(False) - self.setColumnWidth(0, self.parent().width()) - self.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) - self.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection) - self.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) - self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) - self.setAlternatingRowColors(True) - # Initialize variables. - self.service_item = ServiceItem() - self.screen_ratio = screen_ratio - # Connect signals - self.verticalHeader().sectionResized.connect(self.row_resized) - - def resizeEvent(self, event): - """ - Overloaded method from QTableWidget. Will recalculate the layout. - """ - self.__recalculate_layout() - - def __recalculate_layout(self): - """ - Recalculates the layout of the table widget. It will set height and width - of the table cells. QTableWidget does not adapt the cells to the widget size on its own. - """ - self.setColumnWidth(0, self.viewport().width()) - if self.service_item: - # Sort out songs, bibles, etc. - if self.service_item.is_text(): - self.resizeRowsToContents() - # Sort out image heights. - else: - height = self.viewport().width() // self.screen_ratio - max_img_row_height = Settings().value('advanced/slide max height') - # Adjust for row height cap if in use. - if isinstance(max_img_row_height, int) and max_img_row_height > 0 and height > max_img_row_height: - height = max_img_row_height - # Apply new height to slides - for frame_number in range(len(self.service_item.get_frames())): - self.setRowHeight(frame_number, height) - - def row_resized(self, row, old_height, new_height): - """ - Will scale non-image slides. - """ - # Only for non-text slides when row height cap in use - max_img_row_height = Settings().value('advanced/slide max height') - if self.service_item.is_text() or not isinstance(max_img_row_height, int) or max_img_row_height <= 0: - return - # Get and validate label widget containing slide & adjust max width - try: - self.cellWidget(row, 0).children()[1].setMaximumWidth(new_height * self.screen_ratio) - except: - return - - def screen_size_changed(self, screen_ratio): - """ - This method is called whenever the live screen size changes, which then makes a layout recalculation necessary - - :param screen_ratio: The new screen ratio - """ - self.screen_ratio = screen_ratio - self.__recalculate_layout() - - def replace_service_item(self, service_item, width, slide_number): - """ - Replace the current preview items with the ones in service_item and display the given slide - - :param service_item: The service item to insert - :param width: The width of the column - :param slide_number: The slide number to pre-select - """ - self.service_item = service_item - self.setRowCount(0) - self.clear() - self.setColumnWidth(0, width) - row = 0 - text = [] - for frame_number, frame in enumerate(self.service_item.get_frames()): - self.setRowCount(self.slide_count() + 1) - item = QtWidgets.QTableWidgetItem() - slide_height = 0 - if self.service_item.is_text(): - if frame['verseTag']: - # These tags are already translated. - verse_def = frame['verseTag'] - verse_def = '%s%s' % (verse_def[0], verse_def[1:]) - two_line_def = '%s\n%s' % (verse_def[0], verse_def[1:]) - row = two_line_def - else: - row += 1 - item.setText(frame['text']) - else: - label = QtWidgets.QLabel() - label.setContentsMargins(4, 4, 4, 4) - if self.service_item.is_media(): - label.setAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter) - else: - label.setScaledContents(True) - if self.service_item.is_command(): - pixmap = QtGui.QPixmap(frame['image']) - pixmap.setDevicePixelRatio(label.devicePixelRatio()) - label.setPixmap(pixmap) - else: - image = self.image_manager.get_image(frame['path'], ImageSource.ImagePlugin) - pixmap = QtGui.QPixmap.fromImage(image) - pixmap.setDevicePixelRatio(label.devicePixelRatio()) - label.setPixmap(pixmap) - slide_height = width // self.screen_ratio - # Setup and validate row height cap if in use. - max_img_row_height = Settings().value('advanced/slide max height') - if isinstance(max_img_row_height, int) and max_img_row_height > 0: - if slide_height > max_img_row_height: - slide_height = max_img_row_height - label.setMaximumWidth(max_img_row_height * self.screen_ratio) - label.resize(max_img_row_height * self.screen_ratio, max_img_row_height) - # Build widget with stretch padding - container = QtWidgets.QWidget() - hbox = QtWidgets.QHBoxLayout() - hbox.setContentsMargins(0, 0, 0, 0) - hbox.addWidget(label, stretch=1) - hbox.addStretch(0) - container.setLayout(hbox) - # Add to table - self.setCellWidget(frame_number, 0, container) - else: - # Add to table - self.setCellWidget(frame_number, 0, label) - row += 1 - text.append(str(row)) - self.setItem(frame_number, 0, item) - if slide_height: - self.setRowHeight(frame_number, slide_height) - self.setVerticalHeaderLabels(text) - if self.service_item.is_text(): - self.resizeRowsToContents() - self.setColumnWidth(0, self.viewport().width()) - self.change_slide(slide_number) - - def change_slide(self, slide): - """ - Switches to the given row. - """ - # Retrieve setting - autoscrolling = Settings().value('advanced/autoscrolling') - # Check if auto-scroll disabled (None) and validate value as dict containing 'dist' and 'pos' - # 'dist' represents the slide to scroll to relative to the new slide (-1 = previous, 0 = current, 1 = next) - # 'pos' represents the vert position of of the slide (0 = in view, 1 = top, 2 = middle, 3 = bottom) - if not (isinstance(autoscrolling, dict) and 'dist' in autoscrolling and 'pos' in autoscrolling and - isinstance(autoscrolling['dist'], int) and isinstance(autoscrolling['pos'], int)): - return - # prevent scrolling past list bounds - scroll_to_slide = slide + autoscrolling['dist'] - if scroll_to_slide < 0: - scroll_to_slide = 0 - if scroll_to_slide >= self.slide_count(): - scroll_to_slide = self.slide_count() - 1 - # Scroll to item if possible. - self.scrollToItem(self.item(scroll_to_slide, 0), autoscrolling['pos']) - self.selectRow(slide) - - def current_slide_number(self): - """ - Returns the position of the currently active item. Will return -1 if the widget is empty. - """ - return super(ListPreviewWidget, self).currentRow() - - def slide_count(self): - """ - Returns the number of slides this widget holds. - """ - return super(ListPreviewWidget, self).rowCount() diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index e586e6928..b13f1c187 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -41,13 +41,14 @@ from openlp.core.common.versionchecker import get_application_version from openlp.core.lib import Renderer, PluginManager, ImageManager, PluginStatus, ScreenList, build_icon from openlp.core.lib.ui import UiStrings, create_action from openlp.core.ui import AboutForm, SettingsForm, ServiceManager, ThemeManager, LiveController, PluginForm, \ - MediaDockManager, ShortcutListForm, FormattingTagForm, PreviewController + ShortcutListForm, FormattingTagForm, PreviewController from openlp.core.ui.firsttimeform import FirstTimeForm from openlp.core.ui.media import MediaController from openlp.core.ui.printserviceform import PrintServiceForm from openlp.core.ui.projector.manager import ProjectorManager from openlp.core.ui.lib.toolbar import OpenLPToolbar from openlp.core.ui.lib.dockwidget import OpenLPDockWidget +from openlp.core.ui.lib.mediadockmanager import MediaDockManager log = logging.getLogger(__name__) diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py index 7ec4bfe29..ea2abe5fb 100644 --- a/openlp/core/ui/slidecontroller.py +++ b/openlp/core/ui/slidecontroller.py @@ -38,8 +38,9 @@ from openlp.core.lib import ItemCapabilities, ServiceItem, ImageSource, ServiceI from openlp.core.lib.ui import create_action from openlp.core.ui.lib.toolbar import OpenLPToolbar from openlp.core.ui.lib.dockwidget import OpenLPDockWidget +from openlp.core.ui.lib.listpreviewwidget import ListPreviewWidget from openlp.core.ui import HideMode, MainDisplay, Display, DisplayControllerType -from openlp.core.ui.listpreviewwidget import ListPreviewWidget + # Threshold which has to be trespassed to toggle. HIDE_MENU_THRESHOLD = 27 From 123a7f02a7934d78d4ff63337eb11196b45a6991 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Fri, 22 Apr 2016 19:32:59 +0100 Subject: [PATCH 20/23] yet more files --- openlp/core/ui/lib/listpreviewwidget.py | 226 +++++++++++++++++ openlp/core/ui/lib/mediadockmanager.py | 71 ++++++ openlp/core/ui/lib/wizard.py | 308 ++++++++++++++++++++++++ 3 files changed, 605 insertions(+) create mode 100644 openlp/core/ui/lib/listpreviewwidget.py create mode 100644 openlp/core/ui/lib/mediadockmanager.py create mode 100644 openlp/core/ui/lib/wizard.py diff --git a/openlp/core/ui/lib/listpreviewwidget.py b/openlp/core/ui/lib/listpreviewwidget.py new file mode 100644 index 000000000..88aef818a --- /dev/null +++ b/openlp/core/ui/lib/listpreviewwidget.py @@ -0,0 +1,226 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2016 OpenLP Developers # +# --------------------------------------------------------------------------- # +# This program is free software; you can redistribute it and/or modify it # +# under the terms of the GNU General Public License as published by the Free # +# Software Foundation; version 2 of the License. # +# # +# This program is distributed in the hope that it will be useful, but WITHOUT # +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # +# more details. # +# # +# You should have received a copy of the GNU General Public License along # +# with this program; if not, write to the Free Software Foundation, Inc., 59 # +# Temple Place, Suite 330, Boston, MA 02111-1307 USA # +############################################################################### +""" +The :mod:`listpreviewwidget` is a widget that lists the slides in the slide controller. +It is based on a QTableWidget but represents its contents in list form. +""" + +from PyQt5 import QtCore, QtGui, QtWidgets + +from openlp.core.common import RegistryProperties, Settings +from openlp.core.lib import ImageSource, ServiceItem + + +class ListPreviewWidget(QtWidgets.QTableWidget, RegistryProperties): + """ + A special type of QTableWidget which lists the slides in the slide controller + + :param parent: + :param screen_ratio: + """ + + def __init__(self, parent, screen_ratio): + """ + Initializes the widget to default state. + + An empty ``ServiceItem`` is used by default. replace_service_manager_item() needs to be called to make this + widget display something. + """ + super(QtWidgets.QTableWidget, self).__init__(parent) + self._setup(screen_ratio) + + def _setup(self, screen_ratio): + """ + Set up the widget + """ + self.setColumnCount(1) + self.horizontalHeader().setVisible(False) + self.setColumnWidth(0, self.parent().width()) + self.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) + self.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection) + self.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) + self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) + self.setAlternatingRowColors(True) + # Initialize variables. + self.service_item = ServiceItem() + self.screen_ratio = screen_ratio + # Connect signals + self.verticalHeader().sectionResized.connect(self.row_resized) + + def resizeEvent(self, event): + """ + Overloaded method from QTableWidget. Will recalculate the layout. + """ + self.__recalculate_layout() + + def __recalculate_layout(self): + """ + Recalculates the layout of the table widget. It will set height and width + of the table cells. QTableWidget does not adapt the cells to the widget size on its own. + """ + self.setColumnWidth(0, self.viewport().width()) + if self.service_item: + # Sort out songs, bibles, etc. + if self.service_item.is_text(): + self.resizeRowsToContents() + # Sort out image heights. + else: + height = self.viewport().width() // self.screen_ratio + max_img_row_height = Settings().value('advanced/slide max height') + # Adjust for row height cap if in use. + if isinstance(max_img_row_height, int) and max_img_row_height > 0 and height > max_img_row_height: + height = max_img_row_height + # Apply new height to slides + for frame_number in range(len(self.service_item.get_frames())): + self.setRowHeight(frame_number, height) + + def row_resized(self, row, old_height, new_height): + """ + Will scale non-image slides. + """ + # Only for non-text slides when row height cap in use + max_img_row_height = Settings().value('advanced/slide max height') + if self.service_item.is_text() or not isinstance(max_img_row_height, int) or max_img_row_height <= 0: + return + # Get and validate label widget containing slide & adjust max width + try: + self.cellWidget(row, 0).children()[1].setMaximumWidth(new_height * self.screen_ratio) + except: + return + + def screen_size_changed(self, screen_ratio): + """ + This method is called whenever the live screen size changes, which then makes a layout recalculation necessary + + :param screen_ratio: The new screen ratio + """ + self.screen_ratio = screen_ratio + self.__recalculate_layout() + + def replace_service_item(self, service_item, width, slide_number): + """ + Replace the current preview items with the ones in service_item and display the given slide + + :param service_item: The service item to insert + :param width: The width of the column + :param slide_number: The slide number to pre-select + """ + self.service_item = service_item + self.setRowCount(0) + self.clear() + self.setColumnWidth(0, width) + row = 0 + text = [] + for frame_number, frame in enumerate(self.service_item.get_frames()): + self.setRowCount(self.slide_count() + 1) + item = QtWidgets.QTableWidgetItem() + slide_height = 0 + if self.service_item.is_text(): + if frame['verseTag']: + # These tags are already translated. + verse_def = frame['verseTag'] + verse_def = '%s%s' % (verse_def[0], verse_def[1:]) + two_line_def = '%s\n%s' % (verse_def[0], verse_def[1:]) + row = two_line_def + else: + row += 1 + item.setText(frame['text']) + else: + label = QtWidgets.QLabel() + label.setContentsMargins(4, 4, 4, 4) + if self.service_item.is_media(): + label.setAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter) + else: + label.setScaledContents(True) + if self.service_item.is_command(): + pixmap = QtGui.QPixmap(frame['image']) + pixmap.setDevicePixelRatio(label.devicePixelRatio()) + label.setPixmap(pixmap) + else: + image = self.image_manager.get_image(frame['path'], ImageSource.ImagePlugin) + pixmap = QtGui.QPixmap.fromImage(image) + pixmap.setDevicePixelRatio(label.devicePixelRatio()) + label.setPixmap(pixmap) + slide_height = width // self.screen_ratio + # Setup and validate row height cap if in use. + max_img_row_height = Settings().value('advanced/slide max height') + if isinstance(max_img_row_height, int) and max_img_row_height > 0: + if slide_height > max_img_row_height: + slide_height = max_img_row_height + label.setMaximumWidth(max_img_row_height * self.screen_ratio) + label.resize(max_img_row_height * self.screen_ratio, max_img_row_height) + # Build widget with stretch padding + container = QtWidgets.QWidget() + hbox = QtWidgets.QHBoxLayout() + hbox.setContentsMargins(0, 0, 0, 0) + hbox.addWidget(label, stretch=1) + hbox.addStretch(0) + container.setLayout(hbox) + # Add to table + self.setCellWidget(frame_number, 0, container) + else: + # Add to table + self.setCellWidget(frame_number, 0, label) + row += 1 + text.append(str(row)) + self.setItem(frame_number, 0, item) + if slide_height: + self.setRowHeight(frame_number, slide_height) + self.setVerticalHeaderLabels(text) + if self.service_item.is_text(): + self.resizeRowsToContents() + self.setColumnWidth(0, self.viewport().width()) + self.change_slide(slide_number) + + def change_slide(self, slide): + """ + Switches to the given row. + """ + # Retrieve setting + autoscrolling = Settings().value('advanced/autoscrolling') + # Check if auto-scroll disabled (None) and validate value as dict containing 'dist' and 'pos' + # 'dist' represents the slide to scroll to relative to the new slide (-1 = previous, 0 = current, 1 = next) + # 'pos' represents the vert position of of the slide (0 = in view, 1 = top, 2 = middle, 3 = bottom) + if not (isinstance(autoscrolling, dict) and 'dist' in autoscrolling and 'pos' in autoscrolling and + isinstance(autoscrolling['dist'], int) and isinstance(autoscrolling['pos'], int)): + return + # prevent scrolling past list bounds + scroll_to_slide = slide + autoscrolling['dist'] + if scroll_to_slide < 0: + scroll_to_slide = 0 + if scroll_to_slide >= self.slide_count(): + scroll_to_slide = self.slide_count() - 1 + # Scroll to item if possible. + self.scrollToItem(self.item(scroll_to_slide, 0), autoscrolling['pos']) + self.selectRow(slide) + + def current_slide_number(self): + """ + Returns the position of the currently active item. Will return -1 if the widget is empty. + """ + return super(ListPreviewWidget, self).currentRow() + + def slide_count(self): + """ + Returns the number of slides this widget holds. + """ + return super(ListPreviewWidget, self).rowCount() diff --git a/openlp/core/ui/lib/mediadockmanager.py b/openlp/core/ui/lib/mediadockmanager.py new file mode 100644 index 000000000..ad786b3a0 --- /dev/null +++ b/openlp/core/ui/lib/mediadockmanager.py @@ -0,0 +1,71 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2016 OpenLP Developers # +# --------------------------------------------------------------------------- # +# This program is free software; you can redistribute it and/or modify it # +# under the terms of the GNU General Public License as published by the Free # +# Software Foundation; version 2 of the License. # +# # +# This program is distributed in the hope that it will be useful, but WITHOUT # +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # +# more details. # +# # +# You should have received a copy of the GNU General Public License along # +# with this program; if not, write to the Free Software Foundation, Inc., 59 # +# Temple Place, Suite 330, Boston, MA 02111-1307 USA # +############################################################################### +""" +The media manager dock. +""" +import logging + +from openlp.core.lib import StringContent + +log = logging.getLogger(__name__) + + +class MediaDockManager(object): + """ + Provide a repository for MediaManagerItems + """ + def __init__(self, media_dock): + """ + Initialise the media dock + """ + self.media_dock = media_dock + + def add_item_to_dock(self, media_item): + """ + Add a MediaManagerItem to the dock + If the item has been added before, it's silently skipped + + :param media_item: The item to add to the dock + """ + visible_title = media_item.plugin.get_string(StringContent.VisibleName) + log.debug('Inserting %s dock' % visible_title['title']) + match = False + for dock_index in range(self.media_dock.count()): + if self.media_dock.widget(dock_index).settings_section == media_item.plugin.name: + match = True + break + if not match: + self.media_dock.addItem(media_item, visible_title['title']) + + def remove_dock(self, media_item): + """ + Removes a MediaManagerItem from the dock + + :param media_item: The item to add to the dock + """ + visible_title = media_item.plugin.get_string(StringContent.VisibleName) + log.debug('remove %s dock' % visible_title['title']) + for dock_index in range(self.media_dock.count()): + if self.media_dock.widget(dock_index): + if self.media_dock.widget(dock_index).settings_section == media_item.plugin.name: + self.media_dock.widget(dock_index).setVisible(False) + self.media_dock.removeItem(dock_index) diff --git a/openlp/core/ui/lib/wizard.py b/openlp/core/ui/lib/wizard.py new file mode 100644 index 000000000..3835056fb --- /dev/null +++ b/openlp/core/ui/lib/wizard.py @@ -0,0 +1,308 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2016 OpenLP Developers # +# --------------------------------------------------------------------------- # +# This program is free software; you can redistribute it and/or modify it # +# under the terms of the GNU General Public License as published by the Free # +# Software Foundation; version 2 of the License. # +# # +# This program is distributed in the hope that it will be useful, but WITHOUT # +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # +# more details. # +# # +# You should have received a copy of the GNU General Public License along # +# with this program; if not, write to the Free Software Foundation, Inc., 59 # +# Temple Place, Suite 330, Boston, MA 02111-1307 USA # +############################################################################### +""" +The :mod:``wizard`` module provides generic wizard tools for OpenLP. +""" +import logging +import os + +from PyQt5 import QtGui, QtWidgets + +from openlp.core.common import Registry, RegistryProperties, Settings, UiStrings, translate, is_macosx +from openlp.core.lib import build_icon +from openlp.core.lib.ui import add_welcome_page + +log = logging.getLogger(__name__) + + +class WizardStrings(object): + """ + Provide standard strings for wizards to use. + """ + # Applications/Formats we import from or export to. These get used in + # multiple places but do not need translating unless you find evidence of + # the writers translating their own product name. + CSV = 'CSV' + OS = 'OpenSong' + OSIS = 'OSIS' + ZEF = 'Zefania' + # These strings should need a good reason to be retranslated elsewhere. + FinishedImport = translate('OpenLP.Ui', 'Finished import.') + FormatLabel = translate('OpenLP.Ui', 'Format:') + HeaderStyle = '%s' + Importing = translate('OpenLP.Ui', 'Importing') + ImportingType = translate('OpenLP.Ui', 'Importing "%s"...') + ImportSelect = translate('OpenLP.Ui', 'Select Import Source') + ImportSelectLong = translate('OpenLP.Ui', 'Select the import format and the location to import from.') + OpenTypeFile = translate('OpenLP.Ui', 'Open %s File') + OpenTypeFolder = translate('OpenLP.Ui', 'Open %s Folder') + PercentSymbolFormat = translate('OpenLP.Ui', '%p%') + Ready = translate('OpenLP.Ui', 'Ready.') + StartingImport = translate('OpenLP.Ui', 'Starting import...') + YouSpecifyFile = translate('OpenLP.Ui', 'You need to specify one %s file to import from.', + 'A file type e.g. OpenSong') + YouSpecifyFiles = translate('OpenLP.Ui', 'You need to specify at least one %s file to import from.', + 'A file type e.g. OpenSong') + YouSpecifyFolder = translate('OpenLP.Ui', 'You need to specify one %s folder to import from.', + 'A song format e.g. PowerSong') + + +class OpenLPWizard(QtWidgets.QWizard, RegistryProperties): + """ + Generic OpenLP wizard to provide generic functionality and a unified look + and feel. + + ``parent`` + The QWidget-derived parent of the wizard. + + ``plugin`` + Plugin this wizard is part of. The plugin will be saved in the "plugin" variable. + The plugin will also be used as basis for the file dialog methods this class provides. + + ``name`` + The object name this wizard should have. + + ``image`` + The image to display on the "welcome" page of the wizard. Should be 163x350. + + ``add_progress_page`` + Whether to add a progress page with a progressbar at the end of the wizard. + """ + def __init__(self, parent, plugin, name, image, add_progress_page=True): + """ + Constructor + """ + super(OpenLPWizard, self).__init__(parent) + self.plugin = plugin + self.with_progress_page = add_progress_page + self.setObjectName(name) + self.open_icon = build_icon(':/general/general_open.png') + self.delete_icon = build_icon(':/general/general_delete.png') + self.finish_button = self.button(QtWidgets.QWizard.FinishButton) + self.cancel_button = self.button(QtWidgets.QWizard.CancelButton) + self.setupUi(image) + self.register_fields() + self.custom_init() + self.custom_signals() + self.currentIdChanged.connect(self.on_current_id_changed) + if self.with_progress_page: + self.error_copy_to_button.clicked.connect(self.on_error_copy_to_button_clicked) + self.error_save_to_button.clicked.connect(self.on_error_save_to_button_clicked) + + def setupUi(self, image): + """ + Set up the wizard UI. + :param image: path to start up image + """ + self.setWindowIcon(build_icon(u':/icon/openlp-logo.svg')) + self.setModal(True) + self.setOptions(QtWidgets.QWizard.IndependentPages | + QtWidgets.QWizard.NoBackButtonOnStartPage | QtWidgets.QWizard.NoBackButtonOnLastPage) + if is_macosx(): + self.setPixmap(QtWidgets.QWizard.BackgroundPixmap, QtGui.QPixmap(':/wizards/openlp-osx-wizard.png')) + else: + self.setWizardStyle(QtWidgets.QWizard.ModernStyle) + add_welcome_page(self, image) + self.add_custom_pages() + if self.with_progress_page: + self.add_progress_page() + self.retranslateUi() + + def register_fields(self): + """ + Hook method for wizards to register any fields they need. + """ + pass + + def custom_init(self): + """ + Hook method for custom initialisation + """ + pass + + def custom_signals(self): + """ + Hook method for adding custom signals + """ + pass + + def add_custom_pages(self): + """ + Hook method for wizards to add extra pages + """ + pass + + def add_progress_page(self): + """ + Add the progress page for the wizard. This page informs the user how + the wizard is progressing with its task. + """ + self.progress_page = QtWidgets.QWizardPage() + self.progress_page.setObjectName('progress_page') + self.progress_layout = QtWidgets.QVBoxLayout(self.progress_page) + self.progress_layout.setContentsMargins(48, 48, 48, 48) + self.progress_layout.setObjectName('progress_layout') + self.progress_label = QtWidgets.QLabel(self.progress_page) + self.progress_label.setObjectName('progress_label') + self.progress_label.setWordWrap(True) + self.progress_layout.addWidget(self.progress_label) + self.progress_bar = QtWidgets.QProgressBar(self.progress_page) + self.progress_bar.setObjectName('progress_bar') + self.progress_layout.addWidget(self.progress_bar) + # Add a QTextEdit and a copy to file and copy to clipboard button to be + # able to provide feedback to the user. Hidden by default. + self.error_report_text_edit = QtWidgets.QTextEdit(self.progress_page) + self.error_report_text_edit.setObjectName('error_report_text_edit') + self.error_report_text_edit.setHidden(True) + self.error_report_text_edit.setReadOnly(True) + self.progress_layout.addWidget(self.error_report_text_edit) + self.error_button_layout = QtWidgets.QHBoxLayout() + self.error_button_layout.setObjectName('error_button_layout') + spacer = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.error_button_layout.addItem(spacer) + self.error_copy_to_button = QtWidgets.QPushButton(self.progress_page) + self.error_copy_to_button.setObjectName('error_copy_to_button') + self.error_copy_to_button.setHidden(True) + self.error_copy_to_button.setIcon(build_icon(':/system/system_edit_copy.png')) + self.error_button_layout.addWidget(self.error_copy_to_button) + self.error_save_to_button = QtWidgets.QPushButton(self.progress_page) + self.error_save_to_button.setObjectName('error_save_to_button') + self.error_save_to_button.setHidden(True) + self.error_save_to_button.setIcon(build_icon(':/general/general_save.png')) + self.error_button_layout.addWidget(self.error_save_to_button) + self.progress_layout.addLayout(self.error_button_layout) + self.addPage(self.progress_page) + + def exec(self): + """ + Run the wizard. + """ + self.set_defaults() + return QtWidgets.QWizard.exec(self) + + def reject(self): + """ + Stop the wizard on cancel button, close button or ESC key. + """ + log.debug('Wizard cancelled by user.') + if self.with_progress_page and self.currentPage() == self.progress_page: + Registry().execute('openlp_stop_wizard') + self.done(QtWidgets.QDialog.Rejected) + + def on_current_id_changed(self, page_id): + """ + Perform necessary functions depending on which wizard page is active. + :param page_id: current page number + """ + if self.with_progress_page and self.page(page_id) == self.progress_page: + self.pre_wizard() + self.perform_wizard() + self.post_wizard() + else: + self.custom_page_changed(page_id) + + def custom_page_changed(self, page_id): + """ + Called when changing to a page other than the progress page + :param page_id: current page number + """ + pass + + def on_error_copy_to_button_clicked(self): + """ + Called when the ``error_copy_to_button`` has been clicked. + """ + pass + + def on_error_save_to_button_clicked(self): + """ + Called when the ``error_save_to_button`` has been clicked. + """ + pass + + def increment_progress_bar(self, status_text, increment=1): + """ + Update the wizard progress page. + + :param status_text: Current status information to display. + :param increment: The value to increment the progress bar by. + """ + log.debug('IncrementBar %s', status_text) + self.progress_label.setText(status_text) + if increment > 0: + self.progress_bar.setValue(self.progress_bar.value() + increment) + self.application.process_events() + + def pre_wizard(self): + """ + Prepare the UI for the import. + """ + self.finish_button.setVisible(False) + self.progress_bar.setMinimum(0) + self.progress_bar.setMaximum(1188) + self.progress_bar.setValue(0) + + def post_wizard(self): + """ + Clean up the UI after the import has finished. + """ + self.progress_bar.setValue(self.progress_bar.maximum()) + self.finish_button.setVisible(True) + self.cancel_button.setVisible(False) + self.application.process_events() + + def get_file_name(self, title, editbox, setting_name, filters=''): + """ + Opens a QFileDialog and saves the filename to the given editbox. + + :param title: The title of the dialog (unicode). + :param editbox: An editbox (QLineEdit). + :param setting_name: The place where to save the last opened directory. + :param filters: The file extension filters. It should contain the file description + as well as the file extension. For example:: + + 'OpenLP 2 Databases (*.sqlite)' + """ + if filters: + filters += ';;' + filters += '%s (*)' % UiStrings().AllFiles + filename, filter_used = QtWidgets.QFileDialog.getOpenFileName( + self, title, os.path.dirname(Settings().value(self.plugin.settings_section + '/' + setting_name)), + filters) + if filename: + editbox.setText(filename) + Settings().setValue(self.plugin.settings_section + '/' + setting_name, filename) + + def get_folder(self, title, editbox, setting_name): + """ + Opens a QFileDialog and saves the selected folder to the given editbox. + + :param title: The title of the dialog (unicode). + :param editbox: An editbox (QLineEdit). + :param setting_name: The place where to save the last opened directory. + """ + folder = QtWidgets.QFileDialog.getExistingDirectory( + self, title, Settings().value(self.plugin.settings_section + '/' + setting_name), + QtWidgets.QFileDialog.ShowDirsOnly) + if folder: + editbox.setText(folder) + Settings().setValue(self.plugin.settings_section + '/' + setting_name, folder) From d9d31c4626d4b24ceebe3bab6667c098884f1af1 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Fri, 22 Apr 2016 19:35:23 +0100 Subject: [PATCH 21/23] tests --- .../test_listpreviewwidget.py | 64 +++++++++---------- 1 file changed, 32 insertions(+), 32 deletions(-) rename tests/functional/{openlp_core_ui => openlp_core_ui_lib}/test_listpreviewwidget.py (87%) diff --git a/tests/functional/openlp_core_ui/test_listpreviewwidget.py b/tests/functional/openlp_core_ui_lib/test_listpreviewwidget.py similarity index 87% rename from tests/functional/openlp_core_ui/test_listpreviewwidget.py rename to tests/functional/openlp_core_ui_lib/test_listpreviewwidget.py index e9f99a8eb..0ed88cc88 100644 --- a/tests/functional/openlp_core_ui/test_listpreviewwidget.py +++ b/tests/functional/openlp_core_ui_lib/test_listpreviewwidget.py @@ -20,12 +20,12 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### """ -Package to test the openlp.core.ui.listpreviewwidget package. +Package to test the openlp.core.ui.lib.listpreviewwidget package. """ from unittest import TestCase from openlp.core.common import Settings -from openlp.core.ui.listpreviewwidget import ListPreviewWidget +from openlp.core.ui.lib.listpreviewwidget import ListPreviewWidget from openlp.core.lib import ServiceItem from tests.functional import MagicMock, patch, call @@ -38,13 +38,13 @@ class TestListPreviewWidget(TestCase): Mock out stuff for all the tests """ # Mock self.parent().width() - self.parent_patcher = patch('openlp.core.ui.listpreviewwidget.ListPreviewWidget.parent') + self.parent_patcher = patch('openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.parent') self.mocked_parent = self.parent_patcher.start() self.mocked_parent.width.return_value = 100 self.addCleanup(self.parent_patcher.stop) # Mock Settings().value() - self.Settings_patcher = patch('openlp.core.ui.listpreviewwidget.Settings') + self.Settings_patcher = patch('openlp.core.ui.lib.listpreviewwidget.Settings') self.mocked_Settings = self.Settings_patcher.start() self.mocked_Settings_obj = MagicMock() self.mocked_Settings_obj.value.return_value = None @@ -52,7 +52,7 @@ class TestListPreviewWidget(TestCase): self.addCleanup(self.Settings_patcher.stop) # Mock self.viewport().width() - self.viewport_patcher = patch('openlp.core.ui.listpreviewwidget.ListPreviewWidget.viewport') + self.viewport_patcher = patch('openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.viewport') self.mocked_viewport = self.viewport_patcher.start() self.mocked_viewport_obj = MagicMock() self.mocked_viewport_obj.width.return_value = 200 @@ -72,8 +72,8 @@ class TestListPreviewWidget(TestCase): self.assertIsNotNone(list_preview_widget, 'The ListPreviewWidget object should not be None') self.assertEquals(list_preview_widget.screen_ratio, 1, 'Should not be called') - @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.resizeRowsToContents') - @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.setRowHeight') + @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.resizeRowsToContents') + @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.setRowHeight') def replace_recalculate_layout_test_text(self, mocked_setRowHeight, mocked_resizeRowsToContents): """ Test if "Max height for non-text slides..." enabled, txt slides unchanged in replace_service_item & __recalc... @@ -104,8 +104,8 @@ class TestListPreviewWidget(TestCase): self.assertEquals(mocked_resizeRowsToContents.call_count, 2, 'Should be called') self.assertEquals(mocked_setRowHeight.call_count, 0, 'Should not be called') - @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.resizeRowsToContents') - @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.setRowHeight') + @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.resizeRowsToContents') + @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.setRowHeight') def replace_recalculate_layout_test_img(self, mocked_setRowHeight, mocked_resizeRowsToContents): """ Test if "Max height for non-text slides..." disabled, img slides unchanged in replace_service_item & __recalc... @@ -140,8 +140,8 @@ class TestListPreviewWidget(TestCase): calls = [call(0, 200), call(1, 200), call(0, 400), call(1, 400), call(0, 400), call(1, 400)] mocked_setRowHeight.assert_has_calls(calls) - @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.resizeRowsToContents') - @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.setRowHeight') + @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.resizeRowsToContents') + @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.setRowHeight') def replace_recalculate_layout_test_img_max(self, mocked_setRowHeight, mocked_resizeRowsToContents): """ Test if "Max height for non-text slides..." enabled, img slides resized in replace_service_item & __recalc... @@ -174,9 +174,9 @@ class TestListPreviewWidget(TestCase): calls = [call(0, 100), call(1, 100), call(0, 100), call(1, 100)] mocked_setRowHeight.assert_has_calls(calls) - @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.resizeRowsToContents') - @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.setRowHeight') - @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.cellWidget') + @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.resizeRowsToContents') + @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.setRowHeight') + @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.cellWidget') def row_resized_test_text(self, mocked_cellWidget, mocked_setRowHeight, mocked_resizeRowsToContents): """ Test if "Max height for non-text slides..." enabled, text-based slides not affected in row_resized. @@ -208,9 +208,9 @@ class TestListPreviewWidget(TestCase): # THEN: self.cellWidget(row, 0).children()[1].setMaximumWidth() should not be called self.assertEquals(mocked_cellWidget_child.setMaximumWidth.call_count, 0, 'Should not be called') - @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.resizeRowsToContents') - @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.setRowHeight') - @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.cellWidget') + @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.resizeRowsToContents') + @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.setRowHeight') + @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.cellWidget') def row_resized_test_img(self, mocked_cellWidget, mocked_setRowHeight, mocked_resizeRowsToContents): """ Test if "Max height for non-text slides..." disabled, image-based slides not affected in row_resized. @@ -244,9 +244,9 @@ class TestListPreviewWidget(TestCase): # THEN: self.cellWidget(row, 0).children()[1].setMaximumWidth() should not be called self.assertEquals(mocked_cellWidget_child.setMaximumWidth.call_count, 0, 'Should not be called') - @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.resizeRowsToContents') - @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.setRowHeight') - @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.cellWidget') + @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.resizeRowsToContents') + @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.setRowHeight') + @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.cellWidget') def row_resized_test_img_max(self, mocked_cellWidget, mocked_setRowHeight, mocked_resizeRowsToContents): """ Test if "Max height for non-text slides..." enabled, image-based slides are scaled in row_resized. @@ -278,10 +278,10 @@ class TestListPreviewWidget(TestCase): # THEN: self.cellWidget(row, 0).children()[1].setMaximumWidth() should be called mocked_cellWidget_child.setMaximumWidth.assert_called_once_with(150) - @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.selectRow') - @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.scrollToItem') - @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.item') - @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.slide_count') + @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.selectRow') + @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.scrollToItem') + @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.item') + @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.slide_count') def autoscroll_test_setting_invalid(self, mocked_slide_count, mocked_item, mocked_scrollToItem, mocked_selectRow): """ Test if 'advanced/autoscrolling' setting None or invalid, that no autoscrolling occurs on change_slide(). @@ -314,10 +314,10 @@ class TestListPreviewWidget(TestCase): self.assertEquals(mocked_selectRow.call_count, 0, 'Should not be called') self.assertEquals(mocked_item.call_count, 0, 'Should not be called') - @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.selectRow') - @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.scrollToItem') - @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.item') - @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.slide_count') + @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.selectRow') + @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.scrollToItem') + @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.item') + @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.slide_count') def autoscroll_test_dist_bounds(self, mocked_slide_count, mocked_item, mocked_scrollToItem, mocked_selectRow): """ Test if 'advanced/autoscrolling' setting asks to scroll beyond list bounds, that it does not beyond. @@ -344,10 +344,10 @@ class TestListPreviewWidget(TestCase): calls = [call(0, 0), call(0, 0)] mocked_item.assert_has_calls(calls) - @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.selectRow') - @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.scrollToItem') - @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.item') - @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.slide_count') + @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.selectRow') + @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.scrollToItem') + @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.item') + @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.slide_count') def autoscroll_test_normal(self, mocked_slide_count, mocked_item, mocked_scrollToItem, mocked_selectRow): """ Test if 'advanced/autoscrolling' setting valid, autoscrolling called as expected. From f2784decc7e092421585ee48d33a8020779a129b Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Fri, 22 Apr 2016 20:04:17 +0100 Subject: [PATCH 22/23] fix --- openlp/core/ui/lib/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openlp/core/ui/lib/__init__.py b/openlp/core/ui/lib/__init__.py index d4e21e7bd..6cdeac8a6 100644 --- a/openlp/core/ui/lib/__init__.py +++ b/openlp/core/ui/lib/__init__.py @@ -29,3 +29,5 @@ from .wizard import OpenLPWizard, WizardStrings from .mediadockmanager import MediaDockManager from .listpreviewwidget import ListPreviewWidget +__all__ = ['ColorButton', 'ListPreviewWidget', 'ListWidgetWithDnD', 'OpenLPToolbar', 'OpenLPDockWidget', + 'OpenLPWizard', 'WizardStrings', 'MediaDockManager', 'ListPreviewWidget'] From 37ea1c5da1a235975d65e34007f945a530049ef9 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Fri, 22 Apr 2016 20:25:28 +0100 Subject: [PATCH 23/23] fix --- tests/interfaces/openlp_core_ui_lib/test_listpreviewwidget.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/interfaces/openlp_core_ui_lib/test_listpreviewwidget.py b/tests/interfaces/openlp_core_ui_lib/test_listpreviewwidget.py index f5cefa960..3e0e48e8b 100644 --- a/tests/interfaces/openlp_core_ui_lib/test_listpreviewwidget.py +++ b/tests/interfaces/openlp_core_ui_lib/test_listpreviewwidget.py @@ -29,7 +29,7 @@ from PyQt5 import QtGui, QtWidgets from openlp.core.common import Registry from openlp.core.lib import ServiceItem -from openlp.core.ui.lib import ListWidgetWithDnD +from openlp.core.ui.lib import ListWidgetWithDnD, ListPreviewWidget from tests.interfaces import MagicMock, patch from tests.utils.osdinteraction import read_service_from_file from tests.helpers.testmixin import TestMixin @@ -48,7 +48,7 @@ class TestListPreviewWidget(TestCase, TestMixin): self.image_manager = MagicMock() self.image_manager.get_image.return_value = self.image Registry().register('image_manager', self.image_manager) - self.preview_widget = listpreviewwidget.ListPreviewWidget(self.main_window, 2) + self.preview_widget = ListPreviewWidget(self.main_window, 2) def tearDown(self): """