forked from openlp/openlp
Phase 2 complete
This commit is contained in:
parent
4d68382d52
commit
15a4a93c96
@ -44,3 +44,4 @@ coverage
|
||||
tags
|
||||
output
|
||||
htmlcov
|
||||
openlp-test-projectordb.sqlite
|
||||
|
@ -27,7 +27,7 @@ import faulthandler
|
||||
import multiprocessing
|
||||
import sys
|
||||
|
||||
from openlp.core import main
|
||||
from openlp.core.app import main
|
||||
from openlp.core.common import is_win, is_macosx
|
||||
from openlp.core.common.applocation import AppLocation
|
||||
from openlp.core.common.path import create_paths
|
||||
|
@ -22,7 +22,3 @@
|
||||
"""
|
||||
The :mod:`openlp` module contains all the project produced OpenLP functionality
|
||||
"""
|
||||
|
||||
from openlp import core, plugins
|
||||
|
||||
__all__ = ['core', 'plugins']
|
||||
|
@ -26,400 +26,3 @@ The :mod:`core` module provides all core application functions
|
||||
All the core functions of the OpenLP application including the GUI, settings,
|
||||
logging and a plugin framework are contained within the openlp.core module.
|
||||
"""
|
||||
import argparse
|
||||
import logging
|
||||
import sys
|
||||
import time
|
||||
from datetime import datetime
|
||||
from traceback import format_exception
|
||||
|
||||
from PyQt5 import QtCore, QtWidgets
|
||||
|
||||
from openlp.core.common import is_macosx, is_win
|
||||
from openlp.core.common.applocation import AppLocation
|
||||
from openlp.core.common.i18n import LanguageManager, UiStrings, translate
|
||||
from openlp.core.common.mixins import OpenLPMixin
|
||||
from openlp.core.common.path import create_paths, copytree
|
||||
from openlp.core.common.registry import Registry
|
||||
from openlp.core.common.settings import Settings
|
||||
from openlp.core.version import check_for_update, get_version
|
||||
from openlp.core.lib import ScreenList
|
||||
from openlp.core.resources import qInitResources
|
||||
from openlp.core.ui import SplashScreen
|
||||
from openlp.core.ui.exceptionform import ExceptionForm
|
||||
from openlp.core.ui.firsttimeform import FirstTimeForm
|
||||
from openlp.core.ui.firsttimelanguageform import FirstTimeLanguageForm
|
||||
from openlp.core.ui.mainwindow import MainWindow
|
||||
from openlp.core.ui.style import get_application_stylesheet
|
||||
|
||||
|
||||
__all__ = ['OpenLP', 'main']
|
||||
|
||||
|
||||
log = logging.getLogger()
|
||||
|
||||
|
||||
class OpenLP(OpenLPMixin, QtWidgets.QApplication):
|
||||
"""
|
||||
The core application class. This class inherits from Qt's QApplication
|
||||
class in order to provide the core of the application.
|
||||
"""
|
||||
|
||||
args = []
|
||||
|
||||
def exec(self):
|
||||
"""
|
||||
Override exec method to allow the shared memory to be released on exit
|
||||
"""
|
||||
self.is_event_loop_active = True
|
||||
result = QtWidgets.QApplication.exec()
|
||||
self.shared_memory.detach()
|
||||
return result
|
||||
|
||||
def run(self, args):
|
||||
"""
|
||||
Run the OpenLP application.
|
||||
|
||||
:param args: Some Args
|
||||
"""
|
||||
self.is_event_loop_active = False
|
||||
# On Windows, the args passed into the constructor are ignored. Not very handy, so set the ones we want to use.
|
||||
# On Linux and FreeBSD, in order to set the WM_CLASS property for X11, we pass "OpenLP" in as a command line
|
||||
# argument. This interferes with files being passed in as command line arguments, so we remove it from the list.
|
||||
if 'OpenLP' in args:
|
||||
args.remove('OpenLP')
|
||||
self.args.extend(args)
|
||||
# Decide how many screens we have and their size
|
||||
screens = ScreenList.create(self.desktop())
|
||||
# First time checks in settings
|
||||
has_run_wizard = Settings().value('core/has run wizard')
|
||||
if not has_run_wizard:
|
||||
ftw = FirstTimeForm()
|
||||
ftw.initialize(screens)
|
||||
if ftw.exec() == QtWidgets.QDialog.Accepted:
|
||||
Settings().setValue('core/has run wizard', True)
|
||||
elif ftw.was_cancelled:
|
||||
QtCore.QCoreApplication.exit()
|
||||
sys.exit()
|
||||
# Correct stylesheet bugs
|
||||
application_stylesheet = get_application_stylesheet()
|
||||
if application_stylesheet:
|
||||
self.setStyleSheet(application_stylesheet)
|
||||
can_show_splash = Settings().value('core/show splash')
|
||||
if can_show_splash:
|
||||
self.splash = SplashScreen()
|
||||
self.splash.show()
|
||||
# make sure Qt really display the splash screen
|
||||
self.processEvents()
|
||||
# Check if OpenLP has been upgrade and if a backup of data should be created
|
||||
self.backup_on_upgrade(has_run_wizard, can_show_splash)
|
||||
# start the main app window
|
||||
self.main_window = MainWindow()
|
||||
Registry().execute('bootstrap_initialise')
|
||||
Registry().execute('bootstrap_post_set_up')
|
||||
Registry().initialise = False
|
||||
self.main_window.show()
|
||||
if can_show_splash:
|
||||
# now kill the splashscreen
|
||||
self.splash.finish(self.main_window)
|
||||
log.debug('Splashscreen closed')
|
||||
# make sure Qt really display the splash screen
|
||||
self.processEvents()
|
||||
self.main_window.repaint()
|
||||
self.processEvents()
|
||||
if not has_run_wizard:
|
||||
self.main_window.first_time()
|
||||
if Settings().value('core/update check'):
|
||||
check_for_update(self.main_window)
|
||||
self.main_window.is_display_blank()
|
||||
self.main_window.app_startup()
|
||||
return self.exec()
|
||||
|
||||
def is_already_running(self):
|
||||
"""
|
||||
Look to see if OpenLP is already running and ask if a 2nd instance is to be started.
|
||||
"""
|
||||
self.shared_memory = QtCore.QSharedMemory('OpenLP')
|
||||
if self.shared_memory.attach():
|
||||
status = QtWidgets.QMessageBox.critical(None, UiStrings().Error, UiStrings().OpenLPStart,
|
||||
QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes |
|
||||
QtWidgets.QMessageBox.No))
|
||||
if status == QtWidgets.QMessageBox.No:
|
||||
return True
|
||||
return False
|
||||
else:
|
||||
self.shared_memory.create(1)
|
||||
return False
|
||||
|
||||
def is_data_path_missing(self):
|
||||
"""
|
||||
Check if the data folder path exists.
|
||||
"""
|
||||
data_folder_path = AppLocation.get_data_path()
|
||||
if not data_folder_path.exists():
|
||||
log.critical('Database was not found in: %s', data_folder_path)
|
||||
status = QtWidgets.QMessageBox.critical(
|
||||
None, translate('OpenLP', 'Data Directory Error'),
|
||||
translate('OpenLP', 'OpenLP data folder was not found in:\n\n{path}\n\nThe location of the data folder '
|
||||
'was previously changed from the OpenLP\'s default location. If the data was '
|
||||
'stored on removable device, that device needs to be made available.\n\nYou may '
|
||||
'reset the data location back to the default location, or you can try to make the '
|
||||
'current location available.\n\nDo you want to reset to the default data location? '
|
||||
'If not, OpenLP will be closed so you can try to fix the the problem.')
|
||||
.format(path=data_folder_path),
|
||||
QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No),
|
||||
QtWidgets.QMessageBox.No)
|
||||
if status == QtWidgets.QMessageBox.No:
|
||||
# If answer was "No", return "True", it will shutdown OpenLP in def main
|
||||
log.info('User requested termination')
|
||||
return True
|
||||
# If answer was "Yes", remove the custom data path thus resetting the default location.
|
||||
Settings().remove('advanced/data path')
|
||||
log.info('Database location has been reset to the default settings.')
|
||||
return False
|
||||
|
||||
def hook_exception(self, exc_type, value, traceback):
|
||||
"""
|
||||
Add an exception hook so that any uncaught exceptions are displayed in this window rather than somewhere where
|
||||
users cannot see it and cannot report when we encounter these problems.
|
||||
|
||||
:param exc_type: The class of exception.
|
||||
:param value: The actual exception object.
|
||||
:param traceback: A traceback object with the details of where the exception occurred.
|
||||
"""
|
||||
# We can't log.exception here because the last exception no longer exists, we're actually busy handling it.
|
||||
log.critical(''.join(format_exception(exc_type, value, traceback)))
|
||||
if not hasattr(self, 'exception_form'):
|
||||
self.exception_form = ExceptionForm()
|
||||
self.exception_form.exception_text_edit.setPlainText(''.join(format_exception(exc_type, value, traceback)))
|
||||
self.set_normal_cursor()
|
||||
is_splash_visible = False
|
||||
if hasattr(self, 'splash') and self.splash.isVisible():
|
||||
is_splash_visible = True
|
||||
self.splash.hide()
|
||||
self.exception_form.exec()
|
||||
if is_splash_visible:
|
||||
self.splash.show()
|
||||
|
||||
def backup_on_upgrade(self, has_run_wizard, can_show_splash):
|
||||
"""
|
||||
Check if OpenLP has been upgraded, and ask if a backup of data should be made
|
||||
|
||||
:param has_run_wizard: OpenLP has been run before
|
||||
:param can_show_splash: Should OpenLP show the splash screen
|
||||
"""
|
||||
data_version = Settings().value('core/application version')
|
||||
openlp_version = get_version()['version']
|
||||
# New installation, no need to create backup
|
||||
if not has_run_wizard:
|
||||
Settings().setValue('core/application version', openlp_version)
|
||||
# If data_version is different from the current version ask if we should backup the data folder
|
||||
elif data_version != openlp_version:
|
||||
if can_show_splash and self.splash.isVisible():
|
||||
self.splash.hide()
|
||||
if QtWidgets.QMessageBox.question(None, translate('OpenLP', 'Backup'),
|
||||
translate('OpenLP', 'OpenLP has been upgraded, do you want to create\n'
|
||||
'a backup of the old data folder?'),
|
||||
defaultButton=QtWidgets.QMessageBox.Yes) == QtWidgets.QMessageBox.Yes:
|
||||
# Create copy of data folder
|
||||
data_folder_path = AppLocation.get_data_path()
|
||||
timestamp = time.strftime("%Y%m%d-%H%M%S")
|
||||
data_folder_backup_path = data_folder_path.with_name(data_folder_path.name + '-' + timestamp)
|
||||
try:
|
||||
copytree(data_folder_path, data_folder_backup_path)
|
||||
except OSError:
|
||||
QtWidgets.QMessageBox.warning(None, translate('OpenLP', 'Backup'),
|
||||
translate('OpenLP', 'Backup of the data folder failed!'))
|
||||
return
|
||||
message = translate('OpenLP',
|
||||
'A backup of the data folder has been created at:\n\n'
|
||||
'{text}').format(text=data_folder_backup_path)
|
||||
QtWidgets.QMessageBox.information(None, translate('OpenLP', 'Backup'), message)
|
||||
|
||||
# Update the version in the settings
|
||||
Settings().setValue('core/application version', openlp_version)
|
||||
if can_show_splash:
|
||||
self.splash.show()
|
||||
|
||||
def process_events(self):
|
||||
"""
|
||||
Wrapper to make ProcessEvents visible and named correctly
|
||||
"""
|
||||
self.processEvents()
|
||||
|
||||
def set_busy_cursor(self):
|
||||
"""
|
||||
Sets the Busy Cursor for the Application
|
||||
"""
|
||||
self.setOverrideCursor(QtCore.Qt.BusyCursor)
|
||||
self.processEvents()
|
||||
|
||||
def set_normal_cursor(self):
|
||||
"""
|
||||
Sets the Normal Cursor for the Application
|
||||
"""
|
||||
self.restoreOverrideCursor()
|
||||
self.processEvents()
|
||||
|
||||
def event(self, event):
|
||||
"""
|
||||
Enables platform specific event handling i.e. direct file opening on OS X
|
||||
|
||||
:param event: The event
|
||||
"""
|
||||
if event.type() == QtCore.QEvent.FileOpen:
|
||||
file_name = event.file()
|
||||
log.debug('Got open file event for {name}!'.format(name=file_name))
|
||||
self.args.insert(0, file_name)
|
||||
return True
|
||||
# Mac OS X should restore app window when user clicked on the OpenLP icon
|
||||
# in the Dock bar. However, OpenLP consists of multiple windows and this
|
||||
# does not work. This workaround fixes that.
|
||||
# The main OpenLP window is restored when it was previously minimized.
|
||||
elif event.type() == QtCore.QEvent.ApplicationActivate:
|
||||
if is_macosx() and hasattr(self, 'main_window'):
|
||||
if self.main_window.isMinimized():
|
||||
# Copied from QWidget.setWindowState() docs on how to restore and activate a minimized window
|
||||
# while preserving its maximized and/or full-screen state.
|
||||
self.main_window.setWindowState(self.main_window.windowState() & ~QtCore.Qt.WindowMinimized |
|
||||
QtCore.Qt.WindowActive)
|
||||
return True
|
||||
return QtWidgets.QApplication.event(self, event)
|
||||
|
||||
|
||||
def parse_options(args=None):
|
||||
"""
|
||||
Parse the command line arguments
|
||||
|
||||
:param args: list of command line arguments
|
||||
:return: a tuple of parsed options of type optparse.Value and a list of remaining argsZ
|
||||
"""
|
||||
# Set up command line options.
|
||||
parser = argparse.ArgumentParser(prog='openlp.py')
|
||||
parser.add_argument('-e', '--no-error-form', dest='no_error_form', action='store_true',
|
||||
help='Disable the error notification form.')
|
||||
parser.add_argument('-l', '--log-level', dest='loglevel', default='warning', metavar='LEVEL',
|
||||
help='Set logging to LEVEL level. Valid values are "debug", "info", "warning".')
|
||||
parser.add_argument('-p', '--portable', dest='portable', action='store_true',
|
||||
help='Specify if this should be run as a portable app, '
|
||||
'off a USB flash drive (not implemented).')
|
||||
parser.add_argument('-d', '--dev-version', dest='dev_version', action='store_true',
|
||||
help='Ignore the version file and pull the version directly from Bazaar')
|
||||
parser.add_argument('-s', '--style', dest='style', help='Set the Qt5 style (passed directly to Qt5).')
|
||||
parser.add_argument('-w', '--no-web-server', dest='no_web_server', action='store_false',
|
||||
help='Turn off the Web and Socket Server ')
|
||||
parser.add_argument('rargs', nargs='?', default=[])
|
||||
# Parse command line options and deal with them. Use args supplied pragmatically if possible.
|
||||
return parser.parse_args(args) if args else parser.parse_args()
|
||||
|
||||
|
||||
def set_up_logging(log_path):
|
||||
"""
|
||||
Setup our logging using log_path
|
||||
|
||||
:param openlp.core.common.path.Path log_path: The file to save the log to.
|
||||
:rtype: None
|
||||
"""
|
||||
create_paths(log_path, do_not_log=True)
|
||||
file_path = log_path / 'openlp.log'
|
||||
# TODO: FileHandler accepts a Path object in Py3.6
|
||||
logfile = logging.FileHandler(str(file_path), 'w', encoding='UTF-8')
|
||||
logfile.setFormatter(logging.Formatter('%(asctime)s %(name)-55s %(levelname)-8s %(message)s'))
|
||||
log.addHandler(logfile)
|
||||
if log.isEnabledFor(logging.DEBUG):
|
||||
print('Logging to: {name}'.format(name=file_path))
|
||||
|
||||
|
||||
def main(args=None):
|
||||
"""
|
||||
The main function which parses command line options and then runs
|
||||
|
||||
:param args: Some args
|
||||
"""
|
||||
args = parse_options(args)
|
||||
qt_args = []
|
||||
if args and args.loglevel.lower() in ['d', 'debug']:
|
||||
log.setLevel(logging.DEBUG)
|
||||
elif args and args.loglevel.lower() in ['w', 'warning']:
|
||||
log.setLevel(logging.WARNING)
|
||||
else:
|
||||
log.setLevel(logging.INFO)
|
||||
if args and args.style:
|
||||
qt_args.extend(['-style', args.style])
|
||||
# Throw the rest of the arguments at Qt, just in case.
|
||||
qt_args.extend(args.rargs)
|
||||
# Bug #1018855: Set the WM_CLASS property in X11
|
||||
if not is_win() and not is_macosx():
|
||||
qt_args.append('OpenLP')
|
||||
# Initialise the resources
|
||||
qInitResources()
|
||||
# Now create and actually run the application.
|
||||
application = OpenLP(qt_args)
|
||||
application.setOrganizationName('OpenLP')
|
||||
application.setOrganizationDomain('openlp.org')
|
||||
application.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps, True)
|
||||
application.setAttribute(QtCore.Qt.AA_DontCreateNativeWidgetSiblings, True)
|
||||
if args and args.portable:
|
||||
application.setApplicationName('OpenLPPortable')
|
||||
Settings.setDefaultFormat(Settings.IniFormat)
|
||||
# Get location OpenLPPortable.ini
|
||||
portable_path = (AppLocation.get_directory(AppLocation.AppDir) / '..' / '..').resolve()
|
||||
data_path = portable_path / 'Data'
|
||||
set_up_logging(portable_path / 'Other')
|
||||
log.info('Running portable')
|
||||
portable_settings_path = data_path / 'OpenLP.ini'
|
||||
# Make this our settings file
|
||||
log.info('INI file: {name}'.format(name=portable_settings_path))
|
||||
Settings.set_filename(str(portable_settings_path))
|
||||
portable_settings = Settings()
|
||||
# Set our data path
|
||||
log.info('Data path: {name}'.format(name=data_path))
|
||||
# Point to our data path
|
||||
portable_settings.setValue('advanced/data path', data_path)
|
||||
portable_settings.setValue('advanced/is portable', True)
|
||||
portable_settings.sync()
|
||||
else:
|
||||
application.setApplicationName('OpenLP')
|
||||
set_up_logging(AppLocation.get_directory(AppLocation.CacheDir))
|
||||
Registry.create()
|
||||
Registry().register('application', application)
|
||||
Registry().set_flag('no_web_server', args.no_web_server)
|
||||
application.setApplicationVersion(get_version()['version'])
|
||||
# Check if an instance of OpenLP is already running. Quit if there is a running instance and the user only wants one
|
||||
if application.is_already_running():
|
||||
sys.exit()
|
||||
# If the custom data path is missing and the user wants to restore the data path, quit OpenLP.
|
||||
if application.is_data_path_missing():
|
||||
application.shared_memory.detach()
|
||||
sys.exit()
|
||||
# Upgrade settings.
|
||||
settings = Settings()
|
||||
if settings.can_upgrade():
|
||||
now = datetime.now()
|
||||
# Only back up if OpenLP has previously run.
|
||||
if settings.value('core/has run wizard'):
|
||||
back_up_path = AppLocation.get_data_path() / (now.strftime('%Y-%m-%d %H-%M') + '.conf')
|
||||
log.info('Settings about to be upgraded. Existing settings are being backed up to {back_up_path}'
|
||||
.format(back_up_path=back_up_path))
|
||||
QtWidgets.QMessageBox.information(
|
||||
None, translate('OpenLP', 'Settings Upgrade'),
|
||||
translate('OpenLP', 'Your settings are about to upgraded. A backup will be created at {back_up_path}')
|
||||
.format(back_up_path=back_up_path))
|
||||
settings.export(back_up_path)
|
||||
settings.upgrade_settings()
|
||||
# First time checks in settings
|
||||
if not Settings().value('core/has run wizard'):
|
||||
if not FirstTimeLanguageForm().exec():
|
||||
# if cancel then stop processing
|
||||
sys.exit()
|
||||
# i18n Set Language
|
||||
language = LanguageManager.get_language()
|
||||
translators = LanguageManager.get_translators(language)
|
||||
for translator in translators:
|
||||
if not translator.isEmpty():
|
||||
application.installTranslator(translator)
|
||||
if not translators:
|
||||
log.debug('Could not find translators.')
|
||||
if args and not args.no_error_form:
|
||||
sys.excepthook = application.hook_exception
|
||||
sys.exit(application.run(qt_args))
|
||||
|
425
openlp/core/app.py
Normal file
425
openlp/core/app.py
Normal file
@ -0,0 +1,425 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
||||
|
||||
###############################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Copyright (c) 2008-2017 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:`core` module provides all core application functions
|
||||
|
||||
All the core functions of the OpenLP application including the GUI, settings,
|
||||
logging and a plugin framework are contained within the openlp.core module.
|
||||
"""
|
||||
import argparse
|
||||
import logging
|
||||
import sys
|
||||
import time
|
||||
from datetime import datetime
|
||||
from traceback import format_exception
|
||||
|
||||
from PyQt5 import QtCore, QtWidgets
|
||||
|
||||
from openlp.core.common import is_macosx, is_win
|
||||
from openlp.core.common.applocation import AppLocation
|
||||
from openlp.core.common.i18n import LanguageManager, UiStrings, translate
|
||||
from openlp.core.common.mixins import OpenLPMixin
|
||||
from openlp.core.common.path import create_paths, copytree
|
||||
from openlp.core.common.registry import Registry
|
||||
from openlp.core.common.settings import Settings
|
||||
from openlp.core.version import check_for_update, get_version
|
||||
from openlp.core.display.screens import ScreenList
|
||||
from openlp.core.resources import qInitResources
|
||||
from openlp.core.ui import SplashScreen
|
||||
from openlp.core.ui.exceptionform import ExceptionForm
|
||||
from openlp.core.ui.firsttimeform import FirstTimeForm
|
||||
from openlp.core.ui.firsttimelanguageform import FirstTimeLanguageForm
|
||||
from openlp.core.ui.mainwindow import MainWindow
|
||||
from openlp.core.ui.style import get_application_stylesheet
|
||||
|
||||
|
||||
__all__ = ['OpenLP', 'main']
|
||||
|
||||
|
||||
log = logging.getLogger()
|
||||
|
||||
|
||||
class OpenLP(OpenLPMixin, QtWidgets.QApplication):
|
||||
"""
|
||||
The core application class. This class inherits from Qt's QApplication
|
||||
class in order to provide the core of the application.
|
||||
"""
|
||||
|
||||
args = []
|
||||
|
||||
def exec(self):
|
||||
"""
|
||||
Override exec method to allow the shared memory to be released on exit
|
||||
"""
|
||||
self.is_event_loop_active = True
|
||||
result = QtWidgets.QApplication.exec()
|
||||
self.shared_memory.detach()
|
||||
return result
|
||||
|
||||
def run(self, args):
|
||||
"""
|
||||
Run the OpenLP application.
|
||||
|
||||
:param args: Some Args
|
||||
"""
|
||||
self.is_event_loop_active = False
|
||||
# On Windows, the args passed into the constructor are ignored. Not very handy, so set the ones we want to use.
|
||||
# On Linux and FreeBSD, in order to set the WM_CLASS property for X11, we pass "OpenLP" in as a command line
|
||||
# argument. This interferes with files being passed in as command line arguments, so we remove it from the list.
|
||||
if 'OpenLP' in args:
|
||||
args.remove('OpenLP')
|
||||
self.args.extend(args)
|
||||
# Decide how many screens we have and their size
|
||||
screens = ScreenList.create(self.desktop())
|
||||
# First time checks in settings
|
||||
has_run_wizard = Settings().value('core/has run wizard')
|
||||
if not has_run_wizard:
|
||||
ftw = FirstTimeForm()
|
||||
ftw.initialize(screens)
|
||||
if ftw.exec() == QtWidgets.QDialog.Accepted:
|
||||
Settings().setValue('core/has run wizard', True)
|
||||
elif ftw.was_cancelled:
|
||||
QtCore.QCoreApplication.exit()
|
||||
sys.exit()
|
||||
# Correct stylesheet bugs
|
||||
application_stylesheet = get_application_stylesheet()
|
||||
if application_stylesheet:
|
||||
self.setStyleSheet(application_stylesheet)
|
||||
can_show_splash = Settings().value('core/show splash')
|
||||
if can_show_splash:
|
||||
self.splash = SplashScreen()
|
||||
self.splash.show()
|
||||
# make sure Qt really display the splash screen
|
||||
self.processEvents()
|
||||
# Check if OpenLP has been upgrade and if a backup of data should be created
|
||||
self.backup_on_upgrade(has_run_wizard, can_show_splash)
|
||||
# start the main app window
|
||||
self.main_window = MainWindow()
|
||||
Registry().execute('bootstrap_initialise')
|
||||
Registry().execute('bootstrap_post_set_up')
|
||||
Registry().initialise = False
|
||||
self.main_window.show()
|
||||
if can_show_splash:
|
||||
# now kill the splashscreen
|
||||
self.splash.finish(self.main_window)
|
||||
log.debug('Splashscreen closed')
|
||||
# make sure Qt really display the splash screen
|
||||
self.processEvents()
|
||||
self.main_window.repaint()
|
||||
self.processEvents()
|
||||
if not has_run_wizard:
|
||||
self.main_window.first_time()
|
||||
if Settings().value('core/update check'):
|
||||
check_for_update(self.main_window)
|
||||
self.main_window.is_display_blank()
|
||||
self.main_window.app_startup()
|
||||
return self.exec()
|
||||
|
||||
def is_already_running(self):
|
||||
"""
|
||||
Look to see if OpenLP is already running and ask if a 2nd instance is to be started.
|
||||
"""
|
||||
self.shared_memory = QtCore.QSharedMemory('OpenLP')
|
||||
if self.shared_memory.attach():
|
||||
status = QtWidgets.QMessageBox.critical(None, UiStrings().Error, UiStrings().OpenLPStart,
|
||||
QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes |
|
||||
QtWidgets.QMessageBox.No))
|
||||
if status == QtWidgets.QMessageBox.No:
|
||||
return True
|
||||
return False
|
||||
else:
|
||||
self.shared_memory.create(1)
|
||||
return False
|
||||
|
||||
def is_data_path_missing(self):
|
||||
"""
|
||||
Check if the data folder path exists.
|
||||
"""
|
||||
data_folder_path = AppLocation.get_data_path()
|
||||
if not data_folder_path.exists():
|
||||
log.critical('Database was not found in: %s', data_folder_path)
|
||||
status = QtWidgets.QMessageBox.critical(
|
||||
None, translate('OpenLP', 'Data Directory Error'),
|
||||
translate('OpenLP', 'OpenLP data folder was not found in:\n\n{path}\n\nThe location of the data folder '
|
||||
'was previously changed from the OpenLP\'s default location. If the data was '
|
||||
'stored on removable device, that device needs to be made available.\n\nYou may '
|
||||
'reset the data location back to the default location, or you can try to make the '
|
||||
'current location available.\n\nDo you want to reset to the default data location? '
|
||||
'If not, OpenLP will be closed so you can try to fix the the problem.')
|
||||
.format(path=data_folder_path),
|
||||
QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No),
|
||||
QtWidgets.QMessageBox.No)
|
||||
if status == QtWidgets.QMessageBox.No:
|
||||
# If answer was "No", return "True", it will shutdown OpenLP in def main
|
||||
log.info('User requested termination')
|
||||
return True
|
||||
# If answer was "Yes", remove the custom data path thus resetting the default location.
|
||||
Settings().remove('advanced/data path')
|
||||
log.info('Database location has been reset to the default settings.')
|
||||
return False
|
||||
|
||||
def hook_exception(self, exc_type, value, traceback):
|
||||
"""
|
||||
Add an exception hook so that any uncaught exceptions are displayed in this window rather than somewhere where
|
||||
users cannot see it and cannot report when we encounter these problems.
|
||||
|
||||
:param exc_type: The class of exception.
|
||||
:param value: The actual exception object.
|
||||
:param traceback: A traceback object with the details of where the exception occurred.
|
||||
"""
|
||||
# We can't log.exception here because the last exception no longer exists, we're actually busy handling it.
|
||||
log.critical(''.join(format_exception(exc_type, value, traceback)))
|
||||
if not hasattr(self, 'exception_form'):
|
||||
self.exception_form = ExceptionForm()
|
||||
self.exception_form.exception_text_edit.setPlainText(''.join(format_exception(exc_type, value, traceback)))
|
||||
self.set_normal_cursor()
|
||||
is_splash_visible = False
|
||||
if hasattr(self, 'splash') and self.splash.isVisible():
|
||||
is_splash_visible = True
|
||||
self.splash.hide()
|
||||
self.exception_form.exec()
|
||||
if is_splash_visible:
|
||||
self.splash.show()
|
||||
|
||||
def backup_on_upgrade(self, has_run_wizard, can_show_splash):
|
||||
"""
|
||||
Check if OpenLP has been upgraded, and ask if a backup of data should be made
|
||||
|
||||
:param has_run_wizard: OpenLP has been run before
|
||||
:param can_show_splash: Should OpenLP show the splash screen
|
||||
"""
|
||||
data_version = Settings().value('core/application version')
|
||||
openlp_version = get_version()['version']
|
||||
# New installation, no need to create backup
|
||||
if not has_run_wizard:
|
||||
Settings().setValue('core/application version', openlp_version)
|
||||
# If data_version is different from the current version ask if we should backup the data folder
|
||||
elif data_version != openlp_version:
|
||||
if can_show_splash and self.splash.isVisible():
|
||||
self.splash.hide()
|
||||
if QtWidgets.QMessageBox.question(None, translate('OpenLP', 'Backup'),
|
||||
translate('OpenLP', 'OpenLP has been upgraded, do you want to create\n'
|
||||
'a backup of the old data folder?'),
|
||||
defaultButton=QtWidgets.QMessageBox.Yes) == QtWidgets.QMessageBox.Yes:
|
||||
# Create copy of data folder
|
||||
data_folder_path = AppLocation.get_data_path()
|
||||
timestamp = time.strftime("%Y%m%d-%H%M%S")
|
||||
data_folder_backup_path = data_folder_path.with_name(data_folder_path.name + '-' + timestamp)
|
||||
try:
|
||||
copytree(data_folder_path, data_folder_backup_path)
|
||||
except OSError:
|
||||
QtWidgets.QMessageBox.warning(None, translate('OpenLP', 'Backup'),
|
||||
translate('OpenLP', 'Backup of the data folder failed!'))
|
||||
return
|
||||
message = translate('OpenLP',
|
||||
'A backup of the data folder has been created at:\n\n'
|
||||
'{text}').format(text=data_folder_backup_path)
|
||||
QtWidgets.QMessageBox.information(None, translate('OpenLP', 'Backup'), message)
|
||||
|
||||
# Update the version in the settings
|
||||
Settings().setValue('core/application version', openlp_version)
|
||||
if can_show_splash:
|
||||
self.splash.show()
|
||||
|
||||
def process_events(self):
|
||||
"""
|
||||
Wrapper to make ProcessEvents visible and named correctly
|
||||
"""
|
||||
self.processEvents()
|
||||
|
||||
def set_busy_cursor(self):
|
||||
"""
|
||||
Sets the Busy Cursor for the Application
|
||||
"""
|
||||
self.setOverrideCursor(QtCore.Qt.BusyCursor)
|
||||
self.processEvents()
|
||||
|
||||
def set_normal_cursor(self):
|
||||
"""
|
||||
Sets the Normal Cursor for the Application
|
||||
"""
|
||||
self.restoreOverrideCursor()
|
||||
self.processEvents()
|
||||
|
||||
def event(self, event):
|
||||
"""
|
||||
Enables platform specific event handling i.e. direct file opening on OS X
|
||||
|
||||
:param event: The event
|
||||
"""
|
||||
if event.type() == QtCore.QEvent.FileOpen:
|
||||
file_name = event.file()
|
||||
log.debug('Got open file event for {name}!'.format(name=file_name))
|
||||
self.args.insert(0, file_name)
|
||||
return True
|
||||
# Mac OS X should restore app window when user clicked on the OpenLP icon
|
||||
# in the Dock bar. However, OpenLP consists of multiple windows and this
|
||||
# does not work. This workaround fixes that.
|
||||
# The main OpenLP window is restored when it was previously minimized.
|
||||
elif event.type() == QtCore.QEvent.ApplicationActivate:
|
||||
if is_macosx() and hasattr(self, 'main_window'):
|
||||
if self.main_window.isMinimized():
|
||||
# Copied from QWidget.setWindowState() docs on how to restore and activate a minimized window
|
||||
# while preserving its maximized and/or full-screen state.
|
||||
self.main_window.setWindowState(self.main_window.windowState() & ~QtCore.Qt.WindowMinimized |
|
||||
QtCore.Qt.WindowActive)
|
||||
return True
|
||||
return QtWidgets.QApplication.event(self, event)
|
||||
|
||||
|
||||
def parse_options(args=None):
|
||||
"""
|
||||
Parse the command line arguments
|
||||
|
||||
:param args: list of command line arguments
|
||||
:return: a tuple of parsed options of type optparse.Value and a list of remaining argsZ
|
||||
"""
|
||||
# Set up command line options.
|
||||
parser = argparse.ArgumentParser(prog='openlp.py')
|
||||
parser.add_argument('-e', '--no-error-form', dest='no_error_form', action='store_true',
|
||||
help='Disable the error notification form.')
|
||||
parser.add_argument('-l', '--log-level', dest='loglevel', default='warning', metavar='LEVEL',
|
||||
help='Set logging to LEVEL level. Valid values are "debug", "info", "warning".')
|
||||
parser.add_argument('-p', '--portable', dest='portable', action='store_true',
|
||||
help='Specify if this should be run as a portable app, '
|
||||
'off a USB flash drive (not implemented).')
|
||||
parser.add_argument('-d', '--dev-version', dest='dev_version', action='store_true',
|
||||
help='Ignore the version file and pull the version directly from Bazaar')
|
||||
parser.add_argument('-s', '--style', dest='style', help='Set the Qt5 style (passed directly to Qt5).')
|
||||
parser.add_argument('-w', '--no-web-server', dest='no_web_server', action='store_false',
|
||||
help='Turn off the Web and Socket Server ')
|
||||
parser.add_argument('rargs', nargs='?', default=[])
|
||||
# Parse command line options and deal with them. Use args supplied pragmatically if possible.
|
||||
return parser.parse_args(args) if args else parser.parse_args()
|
||||
|
||||
|
||||
def set_up_logging(log_path):
|
||||
"""
|
||||
Setup our logging using log_path
|
||||
|
||||
:param openlp.core.common.path.Path log_path: The file to save the log to.
|
||||
:rtype: None
|
||||
"""
|
||||
create_paths(log_path, do_not_log=True)
|
||||
file_path = log_path / 'openlp.log'
|
||||
# TODO: FileHandler accepts a Path object in Py3.6
|
||||
logfile = logging.FileHandler(str(file_path), 'w', encoding='UTF-8')
|
||||
logfile.setFormatter(logging.Formatter('%(asctime)s %(name)-55s %(levelname)-8s %(message)s'))
|
||||
log.addHandler(logfile)
|
||||
if log.isEnabledFor(logging.DEBUG):
|
||||
print('Logging to: {name}'.format(name=file_path))
|
||||
|
||||
|
||||
def main(args=None):
|
||||
"""
|
||||
The main function which parses command line options and then runs
|
||||
|
||||
:param args: Some args
|
||||
"""
|
||||
args = parse_options(args)
|
||||
qt_args = []
|
||||
if args and args.loglevel.lower() in ['d', 'debug']:
|
||||
log.setLevel(logging.DEBUG)
|
||||
elif args and args.loglevel.lower() in ['w', 'warning']:
|
||||
log.setLevel(logging.WARNING)
|
||||
else:
|
||||
log.setLevel(logging.INFO)
|
||||
if args and args.style:
|
||||
qt_args.extend(['-style', args.style])
|
||||
# Throw the rest of the arguments at Qt, just in case.
|
||||
qt_args.extend(args.rargs)
|
||||
# Bug #1018855: Set the WM_CLASS property in X11
|
||||
if not is_win() and not is_macosx():
|
||||
qt_args.append('OpenLP')
|
||||
# Initialise the resources
|
||||
qInitResources()
|
||||
# Now create and actually run the application.
|
||||
application = OpenLP(qt_args)
|
||||
application.setOrganizationName('OpenLP')
|
||||
application.setOrganizationDomain('openlp.org')
|
||||
application.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps, True)
|
||||
application.setAttribute(QtCore.Qt.AA_DontCreateNativeWidgetSiblings, True)
|
||||
if args and args.portable:
|
||||
application.setApplicationName('OpenLPPortable')
|
||||
Settings.setDefaultFormat(Settings.IniFormat)
|
||||
# Get location OpenLPPortable.ini
|
||||
portable_path = (AppLocation.get_directory(AppLocation.AppDir) / '..' / '..').resolve()
|
||||
data_path = portable_path / 'Data'
|
||||
set_up_logging(portable_path / 'Other')
|
||||
log.info('Running portable')
|
||||
portable_settings_path = data_path / 'OpenLP.ini'
|
||||
# Make this our settings file
|
||||
log.info('INI file: {name}'.format(name=portable_settings_path))
|
||||
Settings.set_filename(str(portable_settings_path))
|
||||
portable_settings = Settings()
|
||||
# Set our data path
|
||||
log.info('Data path: {name}'.format(name=data_path))
|
||||
# Point to our data path
|
||||
portable_settings.setValue('advanced/data path', data_path)
|
||||
portable_settings.setValue('advanced/is portable', True)
|
||||
portable_settings.sync()
|
||||
else:
|
||||
application.setApplicationName('OpenLP')
|
||||
set_up_logging(AppLocation.get_directory(AppLocation.CacheDir))
|
||||
Registry.create()
|
||||
Registry().register('application', application)
|
||||
Registry().set_flag('no_web_server', args.no_web_server)
|
||||
application.setApplicationVersion(get_version()['version'])
|
||||
# Check if an instance of OpenLP is already running. Quit if there is a running instance and the user only wants one
|
||||
if application.is_already_running():
|
||||
sys.exit()
|
||||
# If the custom data path is missing and the user wants to restore the data path, quit OpenLP.
|
||||
if application.is_data_path_missing():
|
||||
application.shared_memory.detach()
|
||||
sys.exit()
|
||||
# Upgrade settings.
|
||||
settings = Settings()
|
||||
if settings.can_upgrade():
|
||||
now = datetime.now()
|
||||
# Only back up if OpenLP has previously run.
|
||||
if settings.value('core/has run wizard'):
|
||||
back_up_path = AppLocation.get_data_path() / (now.strftime('%Y-%m-%d %H-%M') + '.conf')
|
||||
log.info('Settings about to be upgraded. Existing settings are being backed up to {back_up_path}'
|
||||
.format(back_up_path=back_up_path))
|
||||
QtWidgets.QMessageBox.information(
|
||||
None, translate('OpenLP', 'Settings Upgrade'),
|
||||
translate('OpenLP', 'Your settings are about to upgraded. A backup will be created at {back_up_path}')
|
||||
.format(back_up_path=back_up_path))
|
||||
settings.export(back_up_path)
|
||||
settings.upgrade_settings()
|
||||
# First time checks in settings
|
||||
if not Settings().value('core/has run wizard'):
|
||||
if not FirstTimeLanguageForm().exec():
|
||||
# if cancel then stop processing
|
||||
sys.exit()
|
||||
# i18n Set Language
|
||||
language = LanguageManager.get_language()
|
||||
translators = LanguageManager.get_translators(language)
|
||||
for translator in translators:
|
||||
if not translator.isEmpty():
|
||||
application.installTranslator(translator)
|
||||
if not translators:
|
||||
log.debug('Could not find translators.')
|
||||
if args and not args.no_error_form:
|
||||
sys.excepthook = application.hook_exception
|
||||
sys.exit(application.run(qt_args))
|
24
openlp/core/display/__init__.py
Normal file
24
openlp/core/display/__init__.py
Normal file
@ -0,0 +1,24 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
||||
|
||||
###############################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Copyright (c) 2008-2017 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:`~openlp.core.display` module contains all the code related to rendering and output
|
||||
"""
|
@ -29,10 +29,11 @@ from openlp.core.common.mixins import OpenLPMixin, RegistryMixin
|
||||
from openlp.core.common.path import path_to_str
|
||||
from openlp.core.common.registry import Registry, RegistryProperties
|
||||
from openlp.core.common.settings import Settings
|
||||
from openlp.core.lib import FormattingTags, ImageSource, ItemCapabilities, ScreenList, ServiceItem, expand_tags, \
|
||||
build_lyrics_format_css, build_lyrics_outline_css, build_chords_css
|
||||
from openlp.core.display.screens import ScreenList
|
||||
from openlp.core.lib import FormattingTags, ImageSource, ItemCapabilities, ServiceItem, expand_tags, build_chords_css, \
|
||||
build_lyrics_format_css, build_lyrics_outline_css
|
||||
from openlp.core.common import ThemeLevel
|
||||
from openlp.core.ui import MainDisplay
|
||||
from openlp.core.ui.maindisplay import MainDisplay
|
||||
|
||||
VERSE = 'The Lord said to {r}Noah{/r}: \n' \
|
||||
'There\'s gonna be a {su}floody{/su}, {sb}floody{/sb}\n' \
|
@ -23,7 +23,6 @@
|
||||
The :mod:`screen` module provides management functionality for a machines'
|
||||
displays.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import copy
|
||||
|
@ -612,7 +612,6 @@ def create_separated_list(string_list):
|
||||
|
||||
|
||||
from .exceptions import ValidationError
|
||||
from .screen import ScreenList
|
||||
from .formattingtags import FormattingTags
|
||||
from .plugin import PluginStatus, StringContent, Plugin
|
||||
from .pluginmanager import PluginManager
|
||||
@ -620,7 +619,6 @@ from .settingstab import SettingsTab
|
||||
from .serviceitem import ServiceItem, ServiceItemType, ItemCapabilities
|
||||
from .htmlbuilder import build_html, build_lyrics_format_css, build_lyrics_outline_css, build_chords_css
|
||||
from .imagemanager import ImageManager
|
||||
from .renderer import Renderer
|
||||
from .mediamanageritem import MediaManagerItem
|
||||
from .projector.db import ProjectorDB, Projector
|
||||
from .projector.pjlink import PJLink
|
||||
|
@ -33,7 +33,8 @@ from PyQt5 import QtCore
|
||||
|
||||
from openlp.core.common.registry import Registry
|
||||
from openlp.core.common.settings import Settings
|
||||
from openlp.core.lib import ScreenList, resize_image, image_to_byte
|
||||
from openlp.core.display.screens import ScreenList
|
||||
from openlp.core.lib import resize_image, image_to_byte
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
@ -30,7 +30,8 @@ from lxml import etree, objectify
|
||||
from openlp.core.common import de_hump
|
||||
from openlp.core.common.applocation import AppLocation
|
||||
from openlp.core.common.json import OpenLPJsonDecoder, OpenLPJsonEncoder
|
||||
from openlp.core.lib import ScreenList, str_to_bool, get_text_file_string
|
||||
from openlp.core.display.screens import ScreenList
|
||||
from openlp.core.lib import str_to_bool, get_text_file_string
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
@ -31,7 +31,8 @@ from openlp.core.common.i18n import UiStrings, translate
|
||||
from openlp.core.common.path import Path
|
||||
from openlp.core.common.registry import Registry
|
||||
from openlp.core.common.settings import Settings
|
||||
from openlp.core.lib import SettingsTab, ScreenList
|
||||
from openlp.core.display.screens import ScreenList
|
||||
from openlp.core.lib import SettingsTab
|
||||
from openlp.core.ui.lib import ColorButton, PathEdit
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
@ -28,7 +28,8 @@ import logging
|
||||
|
||||
from PyQt5 import QtWidgets
|
||||
|
||||
from openlp.core.lib import ScreenList, build_icon
|
||||
from openlp.core.display.screens import ScreenList
|
||||
from openlp.core.lib import build_icon
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
@ -40,7 +40,8 @@ from openlp.core.common.mixins import OpenLPMixin
|
||||
from openlp.core.common.path import path_to_str
|
||||
from openlp.core.common.registry import Registry, RegistryProperties
|
||||
from openlp.core.common.settings import Settings
|
||||
from openlp.core.lib import ServiceItem, ImageSource, ScreenList, build_html, expand_tags, image_to_byte
|
||||
from openlp.core.display.screens import ScreenList
|
||||
from openlp.core.lib import ServiceItem, ImageSource, build_html, expand_tags, image_to_byte
|
||||
from openlp.core.lib.theme import BackgroundType
|
||||
from openlp.core.ui import HideMode, AlertLocation, DisplayControllerType
|
||||
|
||||
|
@ -43,17 +43,19 @@ from openlp.core.common.i18n import LanguageManager, UiStrings, translate
|
||||
from openlp.core.common.path import Path, copyfile, create_paths, path_to_str, str_to_path
|
||||
from openlp.core.common.registry import Registry, RegistryProperties
|
||||
from openlp.core.common.settings import Settings
|
||||
from openlp.core.lib import Renderer, PluginManager, ImageManager, PluginStatus, ScreenList, build_icon
|
||||
from openlp.core.display.screens import ScreenList
|
||||
from openlp.core.display.renderer import Renderer
|
||||
from openlp.core.lib import PluginManager, ImageManager, PluginStatus, build_icon
|
||||
from openlp.core.lib.ui import create_action
|
||||
from openlp.core.ui import AboutForm, SettingsForm, ServiceManager, ThemeManager, LiveController, PluginForm, \
|
||||
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.dockwidget import OpenLPDockWidget
|
||||
from openlp.core.ui.lib.filedialog import FileDialog
|
||||
from openlp.core.ui.lib.mediadockmanager import MediaDockManager
|
||||
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.style import PROGRESSBAR_STYLE, get_library_stylesheet
|
||||
from openlp.core.version import get_version
|
||||
|
||||
|
@ -36,8 +36,8 @@ from openlp.core.common.i18n import UiStrings, translate
|
||||
from openlp.core.common.mixins import OpenLPMixin, RegistryMixin
|
||||
from openlp.core.common.registry import Registry, RegistryProperties
|
||||
from openlp.core.common.settings import Settings
|
||||
from openlp.core.lib import ItemCapabilities, ServiceItem, ImageSource, ServiceItemAction, ScreenList, build_icon, \
|
||||
build_html
|
||||
from openlp.core.display.screens import ScreenList
|
||||
from openlp.core.lib import ItemCapabilities, ServiceItem, ImageSource, ServiceItemAction, 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.listpreviewwidget import ListPreviewWidget
|
||||
|
@ -38,7 +38,7 @@ from PyQt5 import QtCore
|
||||
|
||||
from openlp.core.common import delete_file, get_uno_command, get_uno_instance, is_win
|
||||
from openlp.core.common.registry import Registry
|
||||
from openlp.core.lib import ScreenList
|
||||
from openlp.core.display.screens import ScreenList
|
||||
from openlp.plugins.presentations.lib.presentationcontroller import PresentationController, PresentationDocument, \
|
||||
TextType
|
||||
|
||||
|
@ -29,7 +29,7 @@ from openlp.core.common import check_binary_exists, is_win
|
||||
from openlp.core.common.applocation import AppLocation
|
||||
from openlp.core.common.path import which
|
||||
from openlp.core.common.settings import Settings
|
||||
from openlp.core.lib import ScreenList
|
||||
from openlp.core.display.screens import ScreenList
|
||||
from openlp.plugins.presentations.lib.presentationcontroller import PresentationController, PresentationDocument
|
||||
|
||||
if is_win():
|
||||
|
@ -31,7 +31,7 @@ from openlp.core.common import is_win, trace_error_handler
|
||||
from openlp.core.common.i18n import UiStrings
|
||||
from openlp.core.common.registry import Registry
|
||||
from openlp.core.common.settings import Settings
|
||||
from openlp.core.lib import ScreenList
|
||||
from openlp.core.display.screens import ScreenList
|
||||
from openlp.core.lib.ui import critical_error_message_box, translate
|
||||
from openlp.plugins.presentations.lib.presentationcontroller import PresentationController, PresentationDocument
|
||||
|
||||
|
@ -26,7 +26,7 @@ from xml.etree import ElementTree
|
||||
|
||||
from openlp.core.common import is_win
|
||||
from openlp.core.common.applocation import AppLocation
|
||||
from openlp.core.lib import ScreenList
|
||||
from openlp.core.display.screens import ScreenList
|
||||
from openlp.plugins.presentations.lib.presentationcontroller import PresentationController, PresentationDocument
|
||||
|
||||
if is_win():
|
||||
|
@ -27,7 +27,7 @@ from unittest import TestCase
|
||||
|
||||
from openlp.core.api.deploy import deploy_zipfile
|
||||
|
||||
TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', 'resources'))
|
||||
TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..', 'resources'))
|
||||
|
||||
|
||||
class TestRemoteDeploy(TestCase):
|
24
tests/functional/openlp_core/display/__init__.py
Normal file
24
tests/functional/openlp_core/display/__init__.py
Normal file
@ -0,0 +1,24 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
||||
|
||||
###############################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Copyright (c) 2008-2017 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 #
|
||||
###############################################################################
|
||||
"""
|
||||
Test the :mod:`~openlp.core.display` module
|
||||
"""
|
@ -28,8 +28,9 @@ from unittest.mock import MagicMock, patch
|
||||
from PyQt5 import QtCore
|
||||
|
||||
from openlp.core.common.registry import Registry
|
||||
from openlp.core.lib import Renderer, ScreenList, ServiceItem, FormattingTags
|
||||
from openlp.core.lib.renderer import words_split, get_start_tags
|
||||
from openlp.core.display.screens import ScreenList
|
||||
from openlp.core.display.renderer import Renderer, words_split, get_start_tags
|
||||
from openlp.core.lib import ServiceItem
|
||||
from openlp.core.lib.theme import Theme
|
||||
|
||||
|
||||
@ -83,15 +84,16 @@ class TestRenderer(TestCase):
|
||||
Test the default layout calculations
|
||||
"""
|
||||
# GIVEN: A new renderer instance.
|
||||
renderer = Renderer()
|
||||
# WHEN: given the default screen size has been created.
|
||||
# THEN: The renderer have created a default screen.
|
||||
self.assertEqual(renderer.width, 1024, 'The base renderer should be a live controller')
|
||||
self.assertEqual(renderer.height, 768, 'The base renderer should be a live controller')
|
||||
self.assertEqual(renderer.screen_ratio, 0.75, 'The base renderer should be a live controller')
|
||||
self.assertEqual(renderer.footer_start, 691, 'The base renderer should be a live controller')
|
||||
renderer = Renderer()
|
||||
|
||||
@patch('openlp.core.lib.renderer.FormattingTags.get_html_tags')
|
||||
# THEN: The renderer have created a default screen.
|
||||
assert renderer.width == 1024, 'The base renderer should be a live controller'
|
||||
assert renderer.height == 768, 'The base renderer should be a live controller'
|
||||
assert renderer.screen_ratio == 0.75, 'The base renderer should be a live controller'
|
||||
assert renderer.footer_start == 691, 'The base renderer should be a live controller'
|
||||
|
||||
@patch('openlp.core.display.renderer.FormattingTags.get_html_tags')
|
||||
def test_get_start_tags(self, mocked_get_html_tags):
|
||||
"""
|
||||
Test the get_start_tags() method
|
||||
@ -179,10 +181,10 @@ class TestRenderer(TestCase):
|
||||
# THEN: The blanks have been removed.
|
||||
self.assertListEqual(result_words, expected_words)
|
||||
|
||||
@patch('openlp.core.lib.renderer.QtWebKitWidgets.QWebView')
|
||||
@patch('openlp.core.lib.renderer.build_lyrics_format_css')
|
||||
@patch('openlp.core.lib.renderer.build_lyrics_outline_css')
|
||||
@patch('openlp.core.lib.renderer.build_chords_css')
|
||||
@patch('openlp.core.display.renderer.QtWebKitWidgets.QWebView')
|
||||
@patch('openlp.core.display.renderer.build_lyrics_format_css')
|
||||
@patch('openlp.core.display.renderer.build_lyrics_outline_css')
|
||||
@patch('openlp.core.display.renderer.build_chords_css')
|
||||
def test_set_text_rectangle(self, mock_build_chords_css, mock_outline_css, mock_lyrics_css, mock_webview):
|
||||
"""
|
||||
Test set_text_rectangle returns a proper html string
|
@ -28,7 +28,7 @@ from unittest.mock import MagicMock
|
||||
from PyQt5 import QtCore, QtWidgets
|
||||
|
||||
from openlp.core.common.registry import Registry
|
||||
from openlp.core.lib import ScreenList
|
||||
from openlp.core.display.screens import ScreenList
|
||||
|
||||
SCREEN = {
|
||||
'primary': False,
|
@ -34,7 +34,6 @@ from sqlalchemy import MetaData
|
||||
|
||||
from openlp.core.common.path import Path
|
||||
from openlp.core.lib.db import init_db, get_upgrade_op, delete_database, upgrade_db
|
||||
from openlp.core.lib.projector import upgrade as pjlink_upgrade
|
||||
|
||||
|
||||
class TestDB(TestCase):
|
||||
@ -163,16 +162,16 @@ class TestDB(TestCase):
|
||||
mocked_delete_file.assert_called_with(test_location)
|
||||
self.assertFalse(result, 'The result of delete_file should be False (was rigged that way)')
|
||||
|
||||
@patch('tests.functional.openlp_core_lib.test_db.pjlink_upgrade')
|
||||
def test_skip_db_upgrade_with_no_database(self, mocked_upgrade):
|
||||
def test_skip_db_upgrade_with_no_database(self):
|
||||
"""
|
||||
Test the upgrade_db function does not try to update a missing database
|
||||
"""
|
||||
# GIVEN: Database URL that does not (yet) exist
|
||||
url = 'sqlite:///{tmp}/test_db.sqlite'.format(tmp=self.tmp_folder)
|
||||
mocked_upgrade = MagicMock()
|
||||
|
||||
# WHEN: We attempt to upgrade a non-existant database
|
||||
upgrade_db(url, pjlink_upgrade)
|
||||
upgrade_db(url, mocked_upgrade)
|
||||
|
||||
# THEN: upgrade should NOT have been called
|
||||
self.assertFalse(mocked_upgrade.called, 'Database upgrade function should NOT have been called')
|
@ -31,12 +31,12 @@ from unittest.mock import patch
|
||||
from PyQt5 import QtGui
|
||||
|
||||
from openlp.core.common.registry import Registry
|
||||
from openlp.core.lib import ImageManager, ScreenList
|
||||
from openlp.core.lib.imagemanager import Priority
|
||||
from openlp.core.display.screens import ScreenList
|
||||
from openlp.core.lib.imagemanager import ImageManager, Priority
|
||||
|
||||
from tests.helpers.testmixin import TestMixin
|
||||
|
||||
TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', 'resources'))
|
||||
TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..', 'resources'))
|
||||
|
||||
|
||||
class TestImageManager(TestCase, TestMixin):
|
||||
@ -152,8 +152,8 @@ class TestImageManager(TestCase, TestMixin):
|
||||
# Allow the queue to process.
|
||||
self.lock.release()
|
||||
# Request some "data".
|
||||
image_bytes = self.image_manager.get_image_bytes(TEST_PATH, image4)
|
||||
image_object = self.image_manager.get_image(TEST_PATH, image3)
|
||||
self.image_manager.get_image_bytes(TEST_PATH, image4)
|
||||
self.image_manager.get_image(TEST_PATH, image3)
|
||||
# Now the mocked methods/functions do not have to sleep anymore.
|
||||
self.sleep_time = 0
|
||||
# Wait for the queue to finish.
|
@ -33,7 +33,7 @@ from openlp.core.lib import FormattingTags, build_icon, check_item_selected, cle
|
||||
create_separated_list, create_thumb, expand_chords, expand_chords_for_printing, expand_tags, find_formatting_tags, \
|
||||
get_text_file_string, image_to_byte, resize_image, str_to_bool, validate_thumb
|
||||
|
||||
TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', 'resources'))
|
||||
TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..', 'resources'))
|
||||
|
||||
|
||||
class TestLib(TestCase):
|
@ -57,7 +57,7 @@ RENDERED_VERSE = 'The Lord said to <span style="-webkit-text-fill-color:red">Noa
|
||||
'<span style="-webkit-text-fill-color:#FFA500">e</span><span style="-webkit-text-fill-color:#800080">'\
|
||||
'n</span> of the Lord\n'
|
||||
FOOTER = ['Arky Arky (Unknown)', 'Public Domain', 'CCLI 123456']
|
||||
TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', 'resources', 'service'))
|
||||
TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..', 'resources', 'service'))
|
||||
|
||||
|
||||
class TestServiceItem(TestCase):
|
378
tests/functional/openlp_core/test_app.py
Normal file
378
tests/functional/openlp_core/test_app.py
Normal file
@ -0,0 +1,378 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
||||
|
||||
###############################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Copyright (c) 2008-2017 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 #
|
||||
###############################################################################
|
||||
import os
|
||||
import sys
|
||||
from unittest import TestCase, skip
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from PyQt5 import QtCore, QtWidgets
|
||||
|
||||
from openlp.core.app import OpenLP, parse_options
|
||||
from openlp.core.common.settings import Settings
|
||||
|
||||
from tests.helpers.testmixin import TestMixin
|
||||
|
||||
TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'resources'))
|
||||
|
||||
|
||||
def test_parse_options_basic():
|
||||
"""
|
||||
Test the parse options process works
|
||||
"""
|
||||
# GIVEN: a a set of system arguments.
|
||||
sys.argv[1:] = []
|
||||
# WHEN: We we parse them to expand to options
|
||||
args = parse_options(None)
|
||||
# THEN: the following fields will have been extracted.
|
||||
assert args.dev_version is False, 'The dev_version flag should be False'
|
||||
assert args.loglevel == 'warning', 'The log level should be set to warning'
|
||||
assert args.no_error_form is False, 'The no_error_form should be set to False'
|
||||
assert args.portable is False, 'The portable flag should be set to false'
|
||||
assert args.style is None, 'There are no style flags to be processed'
|
||||
assert args.rargs == [], 'The service file should be blank'
|
||||
|
||||
|
||||
def test_parse_options_debug():
|
||||
"""
|
||||
Test the parse options process works for debug only
|
||||
"""
|
||||
# GIVEN: a a set of system arguments.
|
||||
sys.argv[1:] = ['-l debug']
|
||||
# WHEN: We we parse them to expand to options
|
||||
args = parse_options(None)
|
||||
# THEN: the following fields will have been extracted.
|
||||
assert args.dev_version is False, 'The dev_version flag should be False'
|
||||
assert args.loglevel == ' debug', 'The log level should be set to debug'
|
||||
assert args.no_error_form is False, 'The no_error_form should be set to False'
|
||||
assert args.portable is False, 'The portable flag should be set to false'
|
||||
assert args.style is None, 'There are no style flags to be processed'
|
||||
assert args.rargs == [], 'The service file should be blank'
|
||||
|
||||
|
||||
def test_parse_options_debug_and_portable():
|
||||
"""
|
||||
Test the parse options process works for debug and portable
|
||||
"""
|
||||
# GIVEN: a a set of system arguments.
|
||||
sys.argv[1:] = ['--portable']
|
||||
# WHEN: We we parse them to expand to options
|
||||
args = parse_options(None)
|
||||
# THEN: the following fields will have been extracted.
|
||||
assert args.dev_version is False, 'The dev_version flag should be False'
|
||||
assert args.loglevel == 'warning', 'The log level should be set to warning'
|
||||
assert args.no_error_form is False, 'The no_error_form should be set to False'
|
||||
assert args.portable is True, 'The portable flag should be set to true'
|
||||
assert args.style is None, 'There are no style flags to be processed'
|
||||
assert args.rargs == [], 'The service file should be blank'
|
||||
|
||||
|
||||
def test_parse_options_all_no_file():
|
||||
"""
|
||||
Test the parse options process works with two options
|
||||
"""
|
||||
# GIVEN: a a set of system arguments.
|
||||
sys.argv[1:] = ['-l debug', '-d']
|
||||
# WHEN: We we parse them to expand to options
|
||||
args = parse_options(None)
|
||||
# THEN: the following fields will have been extracted.
|
||||
assert args.dev_version is True, 'The dev_version flag should be True'
|
||||
assert args.loglevel == ' debug', 'The log level should be set to debug'
|
||||
assert args.no_error_form is False, 'The no_error_form should be set to False'
|
||||
assert args.portable is False, 'The portable flag should be set to false'
|
||||
assert args.style is None, 'There are no style flags to be processed'
|
||||
assert args.rargs == [], 'The service file should be blank'
|
||||
|
||||
|
||||
def test_parse_options_file():
|
||||
"""
|
||||
Test the parse options process works with a file
|
||||
"""
|
||||
# GIVEN: a a set of system arguments.
|
||||
sys.argv[1:] = ['dummy_temp']
|
||||
# WHEN: We we parse them to expand to options
|
||||
args = parse_options(None)
|
||||
# THEN: the following fields will have been extracted.
|
||||
assert args.dev_version is False, 'The dev_version flag should be False'
|
||||
assert args.loglevel == 'warning', 'The log level should be set to warning'
|
||||
assert args.no_error_form is False, 'The no_error_form should be set to False'
|
||||
assert args.portable is False, 'The portable flag should be set to false'
|
||||
assert args.style is None, 'There are no style flags to be processed'
|
||||
assert args.rargs == 'dummy_temp', 'The service file should not be blank'
|
||||
|
||||
|
||||
def test_parse_options_file_and_debug():
|
||||
"""
|
||||
Test the parse options process works with a file and the debug log level
|
||||
"""
|
||||
# GIVEN: a a set of system arguments.
|
||||
sys.argv[1:] = ['-l debug', 'dummy_temp']
|
||||
# WHEN: We we parse them to expand to options
|
||||
args = parse_options(None)
|
||||
# THEN: the following fields will have been extracted.
|
||||
assert args.dev_version is False, 'The dev_version flag should be False'
|
||||
assert args.loglevel == ' debug', 'The log level should be set to debug'
|
||||
assert args.no_error_form is False, 'The no_error_form should be set to False'
|
||||
assert args.portable is False, 'The portable flag should be set to false'
|
||||
assert args.style is None, 'There are no style flags to be processed'
|
||||
assert args.rargs == 'dummy_temp', 'The service file should not be blank'
|
||||
|
||||
|
||||
@skip('Figure out why this is causing a segfault')
|
||||
class TestOpenLP(TestCase):
|
||||
"""
|
||||
Test the OpenLP app class
|
||||
"""
|
||||
@patch('openlp.core.app.QtWidgets.QApplication.exec')
|
||||
def test_exec(self, mocked_exec):
|
||||
"""
|
||||
Test the exec method
|
||||
"""
|
||||
# GIVEN: An app
|
||||
app = OpenLP([])
|
||||
app.shared_memory = MagicMock()
|
||||
mocked_exec.return_value = False
|
||||
|
||||
# WHEN: exec() is called
|
||||
result = app.exec()
|
||||
|
||||
# THEN: The right things should be called
|
||||
assert app.is_event_loop_active is True
|
||||
mocked_exec.assert_called_once_with()
|
||||
app.shared_memory.detach.assert_called_once_with()
|
||||
assert result is False
|
||||
|
||||
@patch('openlp.core.app.QtCore.QSharedMemory')
|
||||
def test_is_already_running_not_running(self, MockedSharedMemory):
|
||||
"""
|
||||
Test the is_already_running() method when OpenLP is NOT running
|
||||
"""
|
||||
# GIVEN: An OpenLP app and some mocks
|
||||
mocked_shared_memory = MagicMock()
|
||||
mocked_shared_memory.attach.return_value = False
|
||||
MockedSharedMemory.return_value = mocked_shared_memory
|
||||
app = OpenLP([])
|
||||
|
||||
# WHEN: is_already_running() is called
|
||||
result = app.is_already_running()
|
||||
|
||||
# THEN: The result should be false
|
||||
MockedSharedMemory.assert_called_once_with('OpenLP')
|
||||
mocked_shared_memory.attach.assert_called_once_with()
|
||||
mocked_shared_memory.create.assert_called_once_with(1)
|
||||
assert result is False
|
||||
|
||||
@patch('openlp.core.app.QtWidgets.QMessageBox.critical')
|
||||
@patch('openlp.core.app.QtWidgets.QMessageBox.StandardButtons')
|
||||
@patch('openlp.core.app.QtCore.QSharedMemory')
|
||||
def test_is_already_running_is_running_continue(self, MockedSharedMemory, MockedStandardButtons, mocked_critical):
|
||||
"""
|
||||
Test the is_already_running() method when OpenLP IS running and the user chooses to continue
|
||||
"""
|
||||
# GIVEN: An OpenLP app and some mocks
|
||||
mocked_shared_memory = MagicMock()
|
||||
mocked_shared_memory.attach.return_value = True
|
||||
MockedSharedMemory.return_value = mocked_shared_memory
|
||||
MockedStandardButtons.return_value = 0
|
||||
mocked_critical.return_value = QtWidgets.QMessageBox.Yes
|
||||
app = OpenLP([])
|
||||
|
||||
# WHEN: is_already_running() is called
|
||||
result = app.is_already_running()
|
||||
|
||||
# THEN: The result should be false
|
||||
MockedSharedMemory.assert_called_once_with('OpenLP')
|
||||
mocked_shared_memory.attach.assert_called_once_with()
|
||||
MockedStandardButtons.assert_called_once_with(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
|
||||
mocked_critical.assert_called_once_with(None, 'Error', 'OpenLP is already running. Do you wish to continue?', 0)
|
||||
assert result is False
|
||||
|
||||
@patch('openlp.core.app.QtWidgets.QMessageBox.critical')
|
||||
@patch('openlp.core.app.QtWidgets.QMessageBox.StandardButtons')
|
||||
@patch('openlp.core.app.QtCore.QSharedMemory')
|
||||
def test_is_already_running_is_running_stop(self, MockedSharedMemory, MockedStandardButtons, mocked_critical):
|
||||
"""
|
||||
Test the is_already_running() method when OpenLP IS running and the user chooses to stop
|
||||
"""
|
||||
# GIVEN: An OpenLP app and some mocks
|
||||
mocked_shared_memory = MagicMock()
|
||||
mocked_shared_memory.attach.return_value = True
|
||||
MockedSharedMemory.return_value = mocked_shared_memory
|
||||
MockedStandardButtons.return_value = 0
|
||||
mocked_critical.return_value = QtWidgets.QMessageBox.No
|
||||
app = OpenLP([])
|
||||
|
||||
# WHEN: is_already_running() is called
|
||||
result = app.is_already_running()
|
||||
|
||||
# THEN: The result should be false
|
||||
MockedSharedMemory.assert_called_once_with('OpenLP')
|
||||
mocked_shared_memory.attach.assert_called_once_with()
|
||||
MockedStandardButtons.assert_called_once_with(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
|
||||
mocked_critical.assert_called_once_with(None, 'Error', 'OpenLP is already running. Do you wish to continue?', 0)
|
||||
assert result is True
|
||||
|
||||
def test_process_events(self):
|
||||
"""
|
||||
Test that the app.process_events() method simply calls the Qt method
|
||||
"""
|
||||
# GIVEN: An app
|
||||
app = OpenLP([])
|
||||
|
||||
# WHEN: process_events() is called
|
||||
with patch.object(app, 'processEvents') as mocked_processEvents:
|
||||
app.process_events()
|
||||
|
||||
# THEN: processEvents was called
|
||||
mocked_processEvents.assert_called_once_with()
|
||||
|
||||
def test_set_busy_cursor(self):
|
||||
"""
|
||||
Test that the set_busy_cursor() method sets the cursor
|
||||
"""
|
||||
# GIVEN: An app
|
||||
app = OpenLP([])
|
||||
|
||||
# WHEN: set_busy_cursor() is called
|
||||
with patch.object(app, 'setOverrideCursor') as mocked_setOverrideCursor, \
|
||||
patch.object(app, 'processEvents') as mocked_processEvents:
|
||||
app.set_busy_cursor()
|
||||
|
||||
# THEN: The cursor should have been set
|
||||
mocked_setOverrideCursor.assert_called_once_with(QtCore.Qt.BusyCursor)
|
||||
mocked_processEvents.assert_called_once_with()
|
||||
|
||||
def test_set_normal_cursor(self):
|
||||
"""
|
||||
Test that the set_normal_cursor() method resets the cursor
|
||||
"""
|
||||
# GIVEN: An app
|
||||
app = OpenLP([])
|
||||
|
||||
# WHEN: set_normal_cursor() is called
|
||||
with patch.object(app, 'restoreOverrideCursor') as mocked_restoreOverrideCursor, \
|
||||
patch.object(app, 'processEvents') as mocked_processEvents:
|
||||
app.set_normal_cursor()
|
||||
|
||||
# THEN: The cursor should have been set
|
||||
mocked_restoreOverrideCursor.assert_called_once_with()
|
||||
mocked_processEvents.assert_called_once_with()
|
||||
|
||||
|
||||
class TestInit(TestCase, TestMixin):
|
||||
def setUp(self):
|
||||
self.build_settings()
|
||||
with patch('openlp.core.app.OpenLPMixin.__init__') as constructor:
|
||||
constructor.return_value = None
|
||||
self.openlp = OpenLP(list())
|
||||
|
||||
def tearDown(self):
|
||||
self.destroy_settings()
|
||||
del self.openlp
|
||||
|
||||
def test_event(self):
|
||||
"""
|
||||
Test the reimplemented event method
|
||||
"""
|
||||
# GIVEN: A file path and a QEvent.
|
||||
file_path = os.path.join(TEST_PATH, 'church.jpg')
|
||||
mocked_file_method = MagicMock(return_value=file_path)
|
||||
event = QtCore.QEvent(QtCore.QEvent.FileOpen)
|
||||
event.file = mocked_file_method
|
||||
|
||||
# WHEN: Call the vent method.
|
||||
result = self.openlp.event(event)
|
||||
|
||||
# THEN: The path should be inserted.
|
||||
self.assertTrue(result, "The method should have returned True.")
|
||||
mocked_file_method.assert_called_once_with()
|
||||
self.assertEqual(self.openlp.args[0], file_path, "The path should be in args.")
|
||||
|
||||
@patch('openlp.core.app.is_macosx')
|
||||
def test_application_activate_event(self, mocked_is_macosx):
|
||||
"""
|
||||
Test that clicking on the dock icon on Mac OS X restores the main window if it is minimized
|
||||
"""
|
||||
# GIVEN: Mac OS X and an ApplicationActivate event
|
||||
mocked_is_macosx.return_value = True
|
||||
event = MagicMock()
|
||||
event.type.return_value = QtCore.QEvent.ApplicationActivate
|
||||
mocked_main_window = MagicMock()
|
||||
self.openlp.main_window = mocked_main_window
|
||||
|
||||
# WHEN: The icon in the dock is clicked
|
||||
result = self.openlp.event(event)
|
||||
|
||||
# THEN:
|
||||
self.assertTrue(result, "The method should have returned True.")
|
||||
# self.assertFalse(self.openlp.main_window.isMinimized())
|
||||
|
||||
@patch('openlp.core.app.get_version')
|
||||
@patch('openlp.core.app.QtWidgets.QMessageBox.question')
|
||||
def test_backup_on_upgrade_first_install(self, mocked_question, mocked_get_version):
|
||||
"""
|
||||
Test that we don't try to backup on a new install
|
||||
"""
|
||||
# GIVEN: Mocked data version and OpenLP version which are the same
|
||||
old_install = False
|
||||
MOCKED_VERSION = {
|
||||
'full': '2.2.0-bzr000',
|
||||
'version': '2.2.0',
|
||||
'build': 'bzr000'
|
||||
}
|
||||
Settings().setValue('core/application version', '2.2.0')
|
||||
mocked_get_version.return_value = MOCKED_VERSION
|
||||
mocked_question.return_value = QtWidgets.QMessageBox.No
|
||||
|
||||
# WHEN: We check if a backup should be created
|
||||
self.openlp.backup_on_upgrade(old_install, False)
|
||||
|
||||
# THEN: It should not ask if we want to create a backup
|
||||
self.assertEqual(Settings().value('core/application version'), '2.2.0', 'Version should be the same!')
|
||||
self.assertEqual(mocked_question.call_count, 0, 'No question should have been asked!')
|
||||
|
||||
@patch('openlp.core.app.get_version')
|
||||
@patch('openlp.core.app.QtWidgets.QMessageBox.question')
|
||||
def test_backup_on_upgrade(self, mocked_question, mocked_get_version):
|
||||
"""
|
||||
Test that we try to backup on a new install
|
||||
"""
|
||||
# GIVEN: Mocked data version and OpenLP version which are different
|
||||
old_install = True
|
||||
MOCKED_VERSION = {
|
||||
'full': '2.2.0-bzr000',
|
||||
'version': '2.2.0',
|
||||
'build': 'bzr000'
|
||||
}
|
||||
Settings().setValue('core/application version', '2.0.5')
|
||||
self.openlp.splash = MagicMock()
|
||||
self.openlp.splash.isVisible.return_value = True
|
||||
mocked_get_version.return_value = MOCKED_VERSION
|
||||
mocked_question.return_value = QtWidgets.QMessageBox.No
|
||||
|
||||
# WHEN: We check if a backup should be created
|
||||
self.openlp.backup_on_upgrade(old_install, True)
|
||||
|
||||
# THEN: It should ask if we want to create a backup
|
||||
self.assertEqual(Settings().value('core/application version'), '2.2.0', 'Version should be upgraded!')
|
||||
self.assertEqual(mocked_question.call_count, 1, 'A question should have been asked!')
|
||||
self.openlp.splash.hide.assert_called_once_with()
|
||||
self.openlp.splash.show.assert_called_once_with()
|
@ -1,273 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
||||
|
||||
###############################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Copyright (c) 2008-2017 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 #
|
||||
###############################################################################
|
||||
import sys
|
||||
from unittest import TestCase, skip
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from PyQt5 import QtCore, QtWidgets
|
||||
|
||||
from openlp.core import OpenLP, parse_options
|
||||
|
||||
|
||||
class TestInitFunctions(TestCase):
|
||||
|
||||
def test_parse_options_basic(self):
|
||||
"""
|
||||
Test the parse options process works
|
||||
|
||||
"""
|
||||
# GIVEN: a a set of system arguments.
|
||||
sys.argv[1:] = []
|
||||
# WHEN: We we parse them to expand to options
|
||||
args = parse_options(None)
|
||||
# THEN: the following fields will have been extracted.
|
||||
self.assertFalse(args.dev_version, 'The dev_version flag should be False')
|
||||
self.assertEquals(args.loglevel, 'warning', 'The log level should be set to warning')
|
||||
self.assertFalse(args.no_error_form, 'The no_error_form should be set to False')
|
||||
self.assertFalse(args.portable, 'The portable flag should be set to false')
|
||||
self.assertEquals(args.style, None, 'There are no style flags to be processed')
|
||||
self.assertEquals(args.rargs, [], 'The service file should be blank')
|
||||
|
||||
def test_parse_options_debug(self):
|
||||
"""
|
||||
Test the parse options process works for debug only
|
||||
|
||||
"""
|
||||
# GIVEN: a a set of system arguments.
|
||||
sys.argv[1:] = ['-l debug']
|
||||
# WHEN: We we parse them to expand to options
|
||||
args = parse_options(None)
|
||||
# THEN: the following fields will have been extracted.
|
||||
self.assertFalse(args.dev_version, 'The dev_version flag should be False')
|
||||
self.assertEquals(args.loglevel, ' debug', 'The log level should be set to debug')
|
||||
self.assertFalse(args.no_error_form, 'The no_error_form should be set to False')
|
||||
self.assertFalse(args.portable, 'The portable flag should be set to false')
|
||||
self.assertEquals(args.style, None, 'There are no style flags to be processed')
|
||||
self.assertEquals(args.rargs, [], 'The service file should be blank')
|
||||
|
||||
def test_parse_options_debug_and_portable(self):
|
||||
"""
|
||||
Test the parse options process works for debug and portable
|
||||
|
||||
"""
|
||||
# GIVEN: a a set of system arguments.
|
||||
sys.argv[1:] = ['--portable']
|
||||
# WHEN: We we parse them to expand to options
|
||||
args = parse_options(None)
|
||||
# THEN: the following fields will have been extracted.
|
||||
self.assertFalse(args.dev_version, 'The dev_version flag should be False')
|
||||
self.assertEquals(args.loglevel, 'warning', 'The log level should be set to warning')
|
||||
self.assertFalse(args.no_error_form, 'The no_error_form should be set to False')
|
||||
self.assertTrue(args.portable, 'The portable flag should be set to true')
|
||||
self.assertEquals(args.style, None, 'There are no style flags to be processed')
|
||||
self.assertEquals(args.rargs, [], 'The service file should be blank')
|
||||
|
||||
def test_parse_options_all_no_file(self):
|
||||
"""
|
||||
Test the parse options process works with two options
|
||||
|
||||
"""
|
||||
# GIVEN: a a set of system arguments.
|
||||
sys.argv[1:] = ['-l debug', '-d']
|
||||
# WHEN: We we parse them to expand to options
|
||||
args = parse_options(None)
|
||||
# THEN: the following fields will have been extracted.
|
||||
self.assertTrue(args.dev_version, 'The dev_version flag should be True')
|
||||
self.assertEquals(args.loglevel, ' debug', 'The log level should be set to debug')
|
||||
self.assertFalse(args.no_error_form, 'The no_error_form should be set to False')
|
||||
self.assertFalse(args.portable, 'The portable flag should be set to false')
|
||||
self.assertEquals(args.style, None, 'There are no style flags to be processed')
|
||||
self.assertEquals(args.rargs, [], 'The service file should be blank')
|
||||
|
||||
def test_parse_options_file(self):
|
||||
"""
|
||||
Test the parse options process works with a file
|
||||
|
||||
"""
|
||||
# GIVEN: a a set of system arguments.
|
||||
sys.argv[1:] = ['dummy_temp']
|
||||
# WHEN: We we parse them to expand to options
|
||||
args = parse_options(None)
|
||||
# THEN: the following fields will have been extracted.
|
||||
self.assertFalse(args.dev_version, 'The dev_version flag should be False')
|
||||
self.assertEquals(args.loglevel, 'warning', 'The log level should be set to warning')
|
||||
self.assertFalse(args.no_error_form, 'The no_error_form should be set to False')
|
||||
self.assertFalse(args.portable, 'The portable flag should be set to false')
|
||||
self.assertEquals(args.style, None, 'There are no style flags to be processed')
|
||||
self.assertEquals(args.rargs, 'dummy_temp', 'The service file should not be blank')
|
||||
|
||||
def test_parse_options_file_and_debug(self):
|
||||
"""
|
||||
Test the parse options process works with a file and the debug log level
|
||||
"""
|
||||
# GIVEN: a a set of system arguments.
|
||||
sys.argv[1:] = ['-l debug', 'dummy_temp']
|
||||
# WHEN: We we parse them to expand to options
|
||||
args = parse_options(None)
|
||||
# THEN: the following fields will have been extracted.
|
||||
self.assertFalse(args.dev_version, 'The dev_version flag should be False')
|
||||
self.assertEquals(args.loglevel, ' debug', 'The log level should be set to debug')
|
||||
self.assertFalse(args.no_error_form, 'The no_error_form should be set to False')
|
||||
self.assertFalse(args.portable, 'The portable flag should be set to false')
|
||||
self.assertEquals(args.style, None, 'There are no style flags to be processed')
|
||||
self.assertEquals(args.rargs, 'dummy_temp', 'The service file should not be blank')
|
||||
|
||||
|
||||
@skip('Figure out why this is causing a segfault')
|
||||
class TestOpenLP(TestCase):
|
||||
"""
|
||||
Test the OpenLP app class
|
||||
"""
|
||||
@patch('openlp.core.QtWidgets.QApplication.exec')
|
||||
def test_exec(self, mocked_exec):
|
||||
"""
|
||||
Test the exec method
|
||||
"""
|
||||
# GIVEN: An app
|
||||
app = OpenLP([])
|
||||
app.shared_memory = MagicMock()
|
||||
mocked_exec.return_value = False
|
||||
|
||||
# WHEN: exec() is called
|
||||
result = app.exec()
|
||||
|
||||
# THEN: The right things should be called
|
||||
assert app.is_event_loop_active is True
|
||||
mocked_exec.assert_called_once_with()
|
||||
app.shared_memory.detach.assert_called_once_with()
|
||||
assert result is False
|
||||
|
||||
@patch('openlp.core.QtCore.QSharedMemory')
|
||||
def test_is_already_running_not_running(self, MockedSharedMemory):
|
||||
"""
|
||||
Test the is_already_running() method when OpenLP is NOT running
|
||||
"""
|
||||
# GIVEN: An OpenLP app and some mocks
|
||||
mocked_shared_memory = MagicMock()
|
||||
mocked_shared_memory.attach.return_value = False
|
||||
MockedSharedMemory.return_value = mocked_shared_memory
|
||||
app = OpenLP([])
|
||||
|
||||
# WHEN: is_already_running() is called
|
||||
result = app.is_already_running()
|
||||
|
||||
# THEN: The result should be false
|
||||
MockedSharedMemory.assert_called_once_with('OpenLP')
|
||||
mocked_shared_memory.attach.assert_called_once_with()
|
||||
mocked_shared_memory.create.assert_called_once_with(1)
|
||||
assert result is False
|
||||
|
||||
@patch('openlp.core.QtWidgets.QMessageBox.critical')
|
||||
@patch('openlp.core.QtWidgets.QMessageBox.StandardButtons')
|
||||
@patch('openlp.core.QtCore.QSharedMemory')
|
||||
def test_is_already_running_is_running_continue(self, MockedSharedMemory, MockedStandardButtons, mocked_critical):
|
||||
"""
|
||||
Test the is_already_running() method when OpenLP IS running and the user chooses to continue
|
||||
"""
|
||||
# GIVEN: An OpenLP app and some mocks
|
||||
mocked_shared_memory = MagicMock()
|
||||
mocked_shared_memory.attach.return_value = True
|
||||
MockedSharedMemory.return_value = mocked_shared_memory
|
||||
MockedStandardButtons.return_value = 0
|
||||
mocked_critical.return_value = QtWidgets.QMessageBox.Yes
|
||||
app = OpenLP([])
|
||||
|
||||
# WHEN: is_already_running() is called
|
||||
result = app.is_already_running()
|
||||
|
||||
# THEN: The result should be false
|
||||
MockedSharedMemory.assert_called_once_with('OpenLP')
|
||||
mocked_shared_memory.attach.assert_called_once_with()
|
||||
MockedStandardButtons.assert_called_once_with(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
|
||||
mocked_critical.assert_called_once_with(None, 'Error', 'OpenLP is already running. Do you wish to continue?', 0)
|
||||
assert result is False
|
||||
|
||||
@patch('openlp.core.QtWidgets.QMessageBox.critical')
|
||||
@patch('openlp.core.QtWidgets.QMessageBox.StandardButtons')
|
||||
@patch('openlp.core.QtCore.QSharedMemory')
|
||||
def test_is_already_running_is_running_stop(self, MockedSharedMemory, MockedStandardButtons, mocked_critical):
|
||||
"""
|
||||
Test the is_already_running() method when OpenLP IS running and the user chooses to stop
|
||||
"""
|
||||
# GIVEN: An OpenLP app and some mocks
|
||||
mocked_shared_memory = MagicMock()
|
||||
mocked_shared_memory.attach.return_value = True
|
||||
MockedSharedMemory.return_value = mocked_shared_memory
|
||||
MockedStandardButtons.return_value = 0
|
||||
mocked_critical.return_value = QtWidgets.QMessageBox.No
|
||||
app = OpenLP([])
|
||||
|
||||
# WHEN: is_already_running() is called
|
||||
result = app.is_already_running()
|
||||
|
||||
# THEN: The result should be false
|
||||
MockedSharedMemory.assert_called_once_with('OpenLP')
|
||||
mocked_shared_memory.attach.assert_called_once_with()
|
||||
MockedStandardButtons.assert_called_once_with(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
|
||||
mocked_critical.assert_called_once_with(None, 'Error', 'OpenLP is already running. Do you wish to continue?', 0)
|
||||
assert result is True
|
||||
|
||||
def test_process_events(self):
|
||||
"""
|
||||
Test that the app.process_events() method simply calls the Qt method
|
||||
"""
|
||||
# GIVEN: An app
|
||||
app = OpenLP([])
|
||||
|
||||
# WHEN: process_events() is called
|
||||
with patch.object(app, 'processEvents') as mocked_processEvents:
|
||||
app.process_events()
|
||||
|
||||
# THEN: processEvents was called
|
||||
mocked_processEvents.assert_called_once_with()
|
||||
|
||||
def test_set_busy_cursor(self):
|
||||
"""
|
||||
Test that the set_busy_cursor() method sets the cursor
|
||||
"""
|
||||
# GIVEN: An app
|
||||
app = OpenLP([])
|
||||
|
||||
# WHEN: set_busy_cursor() is called
|
||||
with patch.object(app, 'setOverrideCursor') as mocked_setOverrideCursor, \
|
||||
patch.object(app, 'processEvents') as mocked_processEvents:
|
||||
app.set_busy_cursor()
|
||||
|
||||
# THEN: The cursor should have been set
|
||||
mocked_setOverrideCursor.assert_called_once_with(QtCore.Qt.BusyCursor)
|
||||
mocked_processEvents.assert_called_once_with()
|
||||
|
||||
def test_set_normal_cursor(self):
|
||||
"""
|
||||
Test that the set_normal_cursor() method resets the cursor
|
||||
"""
|
||||
# GIVEN: An app
|
||||
app = OpenLP([])
|
||||
|
||||
# WHEN: set_normal_cursor() is called
|
||||
with patch.object(app, 'restoreOverrideCursor') as mocked_restoreOverrideCursor, \
|
||||
patch.object(app, 'processEvents') as mocked_processEvents:
|
||||
app.set_normal_cursor()
|
||||
|
||||
# THEN: The cursor should have been set
|
||||
mocked_restoreOverrideCursor.assert_called_once_with()
|
||||
mocked_processEvents.assert_called_once_with()
|
@ -30,7 +30,8 @@ from PyQt5 import QtCore
|
||||
from openlp.core.common import is_macosx
|
||||
from openlp.core.common.path import Path
|
||||
from openlp.core.common.registry import Registry
|
||||
from openlp.core.lib import ScreenList, PluginManager
|
||||
from openlp.core.display.screens import ScreenList
|
||||
from openlp.core.lib import PluginManager
|
||||
from openlp.core.ui import MainDisplay, AudioPlayer
|
||||
from openlp.core.ui.maindisplay import TRANSPARENT_STYLESHEET, OPAQUE_STYLESHEET
|
||||
|
@ -27,8 +27,8 @@ from unittest.mock import MagicMock, patch
|
||||
|
||||
from PyQt5 import QtCore, QtGui
|
||||
|
||||
from openlp.core import Registry
|
||||
from openlp.core.lib import ImageSource, ServiceItemAction
|
||||
from openlp.core.common.registry import Registry
|
||||
from openlp.core.lib import ServiceItemAction
|
||||
from openlp.core.ui import SlideController, LiveController, PreviewController
|
||||
from openlp.core.ui.slidecontroller import InfoLabel, WIDE_MENU, NON_TEXT_MENU
|
||||
|
@ -27,7 +27,7 @@ from unittest.mock import MagicMock, patch
|
||||
|
||||
from PyQt5 import QtCore
|
||||
|
||||
from openlp.core import Settings
|
||||
from openlp.core.common.settings import Settings
|
||||
from openlp.core.common.path import Path
|
||||
from openlp.plugins.media.lib.mediaitem import MediaMediaItem
|
||||
|
||||
|
@ -23,9 +23,9 @@
|
||||
Test the media plugin
|
||||
"""
|
||||
from unittest import TestCase
|
||||
from unittest.mock import MagicMock, patch
|
||||
from unittest.mock import patch
|
||||
|
||||
from openlp.core import Registry
|
||||
from openlp.core.common.registry import Registry
|
||||
from openlp.plugins.media.mediaplugin import MediaPlugin, process_check_binary
|
||||
|
||||
from tests.helpers.testmixin import TestMixin
|
||||
|
@ -33,7 +33,7 @@ from PyQt5 import QtCore, QtGui
|
||||
from openlp.plugins.presentations.lib.pdfcontroller import PdfController, PdfDocument
|
||||
from openlp.core.common.settings import Settings
|
||||
from openlp.core.common.path import Path
|
||||
from openlp.core.lib import ScreenList
|
||||
from openlp.core.display.screens import ScreenList
|
||||
|
||||
from tests.utils.constants import TEST_RESOURCES_PATH
|
||||
from tests.helpers.testmixin import TestMixin
|
||||
|
@ -30,11 +30,11 @@ from urllib.error import URLError
|
||||
|
||||
from PyQt5 import QtWidgets
|
||||
|
||||
from openlp.core import Registry
|
||||
from openlp.core.common.registry import Registry
|
||||
from openlp.core.common.path import Path
|
||||
from openlp.plugins.songs.forms.songselectform import SongSelectForm, SearchWorker
|
||||
from openlp.plugins.songs.lib import Song
|
||||
from openlp.plugins.songs.lib.songselect import SongSelectImport, LOGIN_PAGE, LOGOUT_URL, BASE_URL
|
||||
from openlp.plugins.songs.lib.songselect import SongSelectImport, LOGOUT_URL, BASE_URL
|
||||
|
||||
from tests.helpers.songfileimport import SongImportTestHelper
|
||||
from tests.helpers.testmixin import TestMixin
|
||||
@ -308,7 +308,7 @@ class TestSongSelectImport(TestCase, TestMixin):
|
||||
importer.run_search = True
|
||||
|
||||
# WHEN: The stop method is called
|
||||
results = importer.stop()
|
||||
importer.stop()
|
||||
|
||||
# THEN: Searching should have stopped
|
||||
self.assertFalse(importer.run_search, 'Searching should have been stopped')
|
||||
|
@ -25,7 +25,7 @@ This module contains tests for the Songusage plugin.
|
||||
from unittest import TestCase
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from openlp.core import Registry
|
||||
from openlp.core.common.registry import Registry
|
||||
from openlp.plugins.songusage.lib import upgrade
|
||||
from openlp.plugins.songusage.lib.db import init_schema
|
||||
from openlp.plugins.songusage.songusageplugin import SongUsagePlugin
|
||||
|
@ -1,137 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
||||
|
||||
###############################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Copyright (c) 2008-2017 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 #
|
||||
###############################################################################
|
||||
"""
|
||||
Package to test the openlp.core.__init__ package.
|
||||
"""
|
||||
import os
|
||||
from unittest import TestCase
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from PyQt5 import QtCore, QtWidgets
|
||||
|
||||
from openlp.core import OpenLP
|
||||
from openlp.core.common.settings import Settings
|
||||
|
||||
from tests.helpers.testmixin import TestMixin
|
||||
|
||||
TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'resources'))
|
||||
|
||||
|
||||
class TestInit(TestCase, TestMixin):
|
||||
def setUp(self):
|
||||
self.build_settings()
|
||||
with patch('openlp.core.OpenLPMixin.__init__') as constructor:
|
||||
constructor.return_value = None
|
||||
self.openlp = OpenLP(list())
|
||||
|
||||
def tearDown(self):
|
||||
self.destroy_settings()
|
||||
del self.openlp
|
||||
|
||||
def test_event(self):
|
||||
"""
|
||||
Test the reimplemented event method
|
||||
"""
|
||||
# GIVEN: A file path and a QEvent.
|
||||
file_path = os.path.join(TEST_PATH, 'church.jpg')
|
||||
mocked_file_method = MagicMock(return_value=file_path)
|
||||
event = QtCore.QEvent(QtCore.QEvent.FileOpen)
|
||||
event.file = mocked_file_method
|
||||
|
||||
# WHEN: Call the vent method.
|
||||
result = self.openlp.event(event)
|
||||
|
||||
# THEN: The path should be inserted.
|
||||
self.assertTrue(result, "The method should have returned True.")
|
||||
mocked_file_method.assert_called_once_with()
|
||||
self.assertEqual(self.openlp.args[0], file_path, "The path should be in args.")
|
||||
|
||||
@patch('openlp.core.is_macosx')
|
||||
def test_application_activate_event(self, mocked_is_macosx):
|
||||
"""
|
||||
Test that clicking on the dock icon on Mac OS X restores the main window if it is minimized
|
||||
"""
|
||||
# GIVEN: Mac OS X and an ApplicationActivate event
|
||||
mocked_is_macosx.return_value = True
|
||||
event = MagicMock()
|
||||
event.type.return_value = QtCore.QEvent.ApplicationActivate
|
||||
mocked_main_window = MagicMock()
|
||||
self.openlp.main_window = mocked_main_window
|
||||
|
||||
# WHEN: The icon in the dock is clicked
|
||||
result = self.openlp.event(event)
|
||||
|
||||
# THEN:
|
||||
self.assertTrue(result, "The method should have returned True.")
|
||||
# self.assertFalse(self.openlp.main_window.isMinimized())
|
||||
|
||||
def test_backup_on_upgrade_first_install(self):
|
||||
"""
|
||||
Test that we don't try to backup on a new install
|
||||
"""
|
||||
# GIVEN: Mocked data version and OpenLP version which are the same
|
||||
old_install = False
|
||||
MOCKED_VERSION = {
|
||||
'full': '2.2.0-bzr000',
|
||||
'version': '2.2.0',
|
||||
'build': 'bzr000'
|
||||
}
|
||||
Settings().setValue('core/application version', '2.2.0')
|
||||
with patch('openlp.core.get_version') as mocked_get_version,\
|
||||
patch('openlp.core.QtWidgets.QMessageBox.question') as mocked_question:
|
||||
mocked_get_version.return_value = MOCKED_VERSION
|
||||
mocked_question.return_value = QtWidgets.QMessageBox.No
|
||||
|
||||
# WHEN: We check if a backup should be created
|
||||
self.openlp.backup_on_upgrade(old_install, False)
|
||||
|
||||
# THEN: It should not ask if we want to create a backup
|
||||
self.assertEqual(Settings().value('core/application version'), '2.2.0', 'Version should be the same!')
|
||||
self.assertEqual(mocked_question.call_count, 0, 'No question should have been asked!')
|
||||
|
||||
def test_backup_on_upgrade(self):
|
||||
"""
|
||||
Test that we try to backup on a new install
|
||||
"""
|
||||
# GIVEN: Mocked data version and OpenLP version which are different
|
||||
old_install = True
|
||||
MOCKED_VERSION = {
|
||||
'full': '2.2.0-bzr000',
|
||||
'version': '2.2.0',
|
||||
'build': 'bzr000'
|
||||
}
|
||||
Settings().setValue('core/application version', '2.0.5')
|
||||
self.openlp.splash = MagicMock()
|
||||
self.openlp.splash.isVisible.return_value = True
|
||||
with patch('openlp.core.get_version') as mocked_get_version, \
|
||||
patch('openlp.core.QtWidgets.QMessageBox.question') as mocked_question:
|
||||
mocked_get_version.return_value = MOCKED_VERSION
|
||||
mocked_question.return_value = QtWidgets.QMessageBox.No
|
||||
|
||||
# WHEN: We check if a backup should be created
|
||||
self.openlp.backup_on_upgrade(old_install, True)
|
||||
|
||||
# THEN: It should ask if we want to create a backup
|
||||
self.assertEqual(Settings().value('core/application version'), '2.2.0', 'Version should be upgraded!')
|
||||
self.assertEqual(mocked_question.call_count, 1, 'A question should have been asked!')
|
||||
self.openlp.splash.hide.assert_called_once_with()
|
||||
self.openlp.splash.show.assert_called_once_with()
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user