merge trunk

This commit is contained in:
Tomas Groth 2017-10-10 21:34:48 +02:00
commit 4ab22f6d6e
353 changed files with 3120 additions and 2926 deletions

View File

@ -44,3 +44,4 @@ coverage
tags
output
htmlcov
openlp-test-projectordb.sqlite

View File

@ -27,16 +27,26 @@ import faulthandler
import multiprocessing
import sys
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 import main
from openlp.core.common.path import create_paths
def set_up_fault_handling():
"""
Set up the Python fault handler
"""
# Create the cache directory if it doesn't exist, and enable the fault handler to log to an error log file
create_paths(AppLocation.get_directory(AppLocation.CacheDir))
faulthandler.enable(open(str(AppLocation.get_directory(AppLocation.CacheDir) / 'error.log'), 'wb'))
faulthandler.enable(open(str(AppLocation.get_directory(AppLocation.CacheDir) / 'error.log'), 'wb'))
if __name__ == '__main__':
"""
Instantiate and run the application.
"""
set_up_fault_handling()
# Add support for using multiprocessing from frozen Windows executable (built using PyInstaller),
# see https://docs.python.org/3/library/multiprocessing.html#multiprocessing.freeze_support
if is_win():

View File

@ -22,7 +22,3 @@
"""
The :mod:`openlp` module contains all the project produced OpenLP functionality
"""
from openlp import core, plugins
__all__ = ['core', 'plugins']

View File

@ -26,396 +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, QtGui, QtWidgets
from openlp.core.common import Registry, OpenLPMixin, AppLocation, LanguageManager, Settings, UiStrings, \
check_directory_exists, is_macosx, is_win, translate
from openlp.core.common.path import Path, copytree
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
"""
check_directory_exists(log_path, 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))

View File

@ -25,7 +25,8 @@ Download and "install" the remote web client
import os
from zipfile import ZipFile
from openlp.core.common import AppLocation, Registry
from openlp.core.common.applocation import AppLocation
from openlp.core.common.registry import Registry
from openlp.core.common.httputils import url_get_file, get_web_page, get_url_file_size

View File

@ -27,7 +27,9 @@ import json
from openlp.core.api.http.endpoint import Endpoint
from openlp.core.api.http import requires_auth
from openlp.core.common import Registry, AppLocation, Settings
from openlp.core.common.applocation import AppLocation
from openlp.core.common.registry import Registry
from openlp.core.common.settings import Settings
from openlp.core.lib import ItemCapabilities, create_thumb
log = logging.getLogger(__name__)

View File

@ -19,13 +19,17 @@
# 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.api.endpoint.core` module contains the core API endpoints
"""
import logging
import os
from openlp.core.api.http.endpoint import Endpoint
from openlp.core.api.http import requires_auth
from openlp.core.common import Registry, UiStrings, translate
from openlp.core.lib import image_to_byte, PluginStatus, StringContent
from openlp.core.api.http.endpoint import Endpoint
from openlp.core.common.registry import Registry
from openlp.core.common.i18n import UiStrings, translate
from openlp.core.lib import PluginStatus, StringContent, image_to_byte
template_dir = 'templates'

View File

@ -24,11 +24,11 @@ import json
import re
import urllib
from urllib.parse import urlparse
from webob import Response
from openlp.core.api.http.errors import NotFound
from openlp.core.common import Registry, AppLocation
from openlp.core.common.applocation import AppLocation
from openlp.core.common.registry import Registry
from openlp.core.lib import PluginStatus, image_to_byte

View File

@ -22,9 +22,9 @@
import logging
import json
from openlp.core.api.http.endpoint import Endpoint
from openlp.core.api.http import requires_auth
from openlp.core.common import Registry
from openlp.core.api.http.endpoint import Endpoint
from openlp.core.common.registry import Registry
log = logging.getLogger(__name__)

View File

@ -22,12 +22,12 @@
"""
The Endpoint class, which provides plugins with a way to serve their own portion of the API
"""
import os
from openlp.core.common import AppLocation
from mako.template import Template
from openlp.core.common.applocation import AppLocation
class Endpoint(object):
"""

View File

@ -19,31 +19,31 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`http` module contains the API web server. This is a lightweight web server used by remotes to interact
with OpenLP. It uses JSON to communicate with the remotes.
"""
import logging
import time
from PyQt5 import QtCore, QtWidgets
from waitress import serve
from openlp.core.api.http import register_endpoint
from openlp.core.api.http import application
from openlp.core.common import AppLocation, RegistryMixin, RegistryProperties, OpenLPMixin, \
Settings, Registry, UiStrings, check_directory_exists
from openlp.core.lib import translate
from openlp.core.api.deploy import download_and_check, download_sha256
from openlp.core.api.poll import Poller
from openlp.core.api.endpoint.controller import controller_endpoint, api_controller_endpoint
from openlp.core.api.endpoint.core import chords_endpoint, stage_endpoint, blank_endpoint, main_endpoint
from openlp.core.api.endpoint.service import service_endpoint, api_service_endpoint
from openlp.core.api.endpoint.remote import remote_endpoint
from openlp.core.api.http import register_endpoint
from openlp.core.api.http import application
from openlp.core.api.poll import Poller
from openlp.core.common.applocation import AppLocation
from openlp.core.common.i18n import UiStrings
from openlp.core.common.mixins import OpenLPMixin, RegistryMixin
from openlp.core.common.path import create_paths
from openlp.core.common.registry import RegistryProperties, Registry
from openlp.core.common.settings import Settings
from openlp.core.common.i18n import translate
log = logging.getLogger(__name__)
@ -115,11 +115,11 @@ class HttpServer(RegistryMixin, RegistryProperties, OpenLPMixin):
Create the internal file structure if it does not exist
:return:
"""
check_directory_exists(AppLocation.get_section_data_path('remotes') / 'assets')
check_directory_exists(AppLocation.get_section_data_path('remotes') / 'images')
check_directory_exists(AppLocation.get_section_data_path('remotes') / 'static')
check_directory_exists(AppLocation.get_section_data_path('remotes') / 'static' / 'index')
check_directory_exists(AppLocation.get_section_data_path('remotes') / 'templates')
create_paths(AppLocation.get_section_data_path('remotes') / 'assets',
AppLocation.get_section_data_path('remotes') / 'images',
AppLocation.get_section_data_path('remotes') / 'static',
AppLocation.get_section_data_path('remotes') / 'static' / 'index',
AppLocation.get_section_data_path('remotes') / 'templates')
def first_time(self):
"""

View File

@ -31,7 +31,7 @@ import re
from webob import Request, Response
from webob.static import DirectoryApp
from openlp.core.common import AppLocation
from openlp.core.common.applocation import AppLocation
from openlp.core.api.http.errors import HttpError, NotFound, ServerError

View File

@ -22,8 +22,9 @@
import json
from openlp.core.common import RegistryProperties, Settings
from openlp.core.common.httputils import get_web_page
from openlp.core.common.registry import RegistryProperties
from openlp.core.common.settings import Settings
class Poller(RegistryProperties):

View File

@ -19,10 +19,14 @@
# 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.api.tab` module contains the settings tab for the API
"""
from PyQt5 import QtCore, QtGui, QtNetwork, QtWidgets
from openlp.core.common import UiStrings, Registry, Settings, translate
from openlp.core.common.i18n import UiStrings, translate
from openlp.core.common.registry import Registry
from openlp.core.common.settings import Settings
from openlp.core.lib import SettingsTab
ZERO_URL = '0.0.0.0'

View File

@ -19,12 +19,10 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`http` module contains the API web server. This is a lightweight web server used by remotes to interact
with OpenLP. It uses JSON to communicate with the remotes.
"""
import asyncio
import websockets
import json
@ -33,7 +31,9 @@ import time
from PyQt5 import QtCore
from openlp.core.common import Settings, RegistryProperties, OpenLPMixin, Registry
from openlp.core.common.mixins import OpenLPMixin
from openlp.core.common.registry import Registry, RegistryProperties
from openlp.core.common.settings import Settings
log = logging.getLogger(__name__)

425
openlp/core/app.py Normal file
View 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))

View File

@ -35,7 +35,7 @@ from ipaddress import IPv4Address, IPv6Address, AddressValueError
from shutil import which
from subprocess import check_output, CalledProcessError, STDOUT
from PyQt5 import QtCore, QtGui
from PyQt5 import QtGui
from PyQt5.QtCore import QCryptographicHash as QHash
log = logging.getLogger(__name__ + '.__init__')
@ -56,30 +56,10 @@ def trace_error_handler(logger):
"""
log_string = "OpenLP Error trace"
for tb in traceback.extract_stack():
log_string += '\n File {file} at line {line} \n\t called {data}'.format(file=tb[0],
line=tb[1],
data=tb[3])
log_string += '\n File {file} at line {line} \n\t called {data}'.format(file=tb[0], line=tb[1], data=tb[3])
logger.error(log_string)
def check_directory_exists(directory, do_not_log=False):
"""
Check a directory exists and if not create it
:param openlp.core.common.path.Path directory: The directory to make sure exists
:param bool do_not_log: To not log anything. This is need for the start up, when the log isn't ready.
:rtype: None
"""
if not do_not_log:
log.debug('check_directory_exists {text}'.format(text=directory))
try:
if not directory.exists():
directory.mkdir(parents=True)
except IOError:
if not do_not_log:
log.exception('failed to check if directory exists or create directory')
def extension_loader(glob_pattern, excluded_files=[]):
"""
A utility function to find and load OpenLP extensions, such as plugins, presentation and media controllers and
@ -90,6 +70,7 @@ def extension_loader(glob_pattern, excluded_files=[]):
:param list[str] excluded_files: A list of file names to exclude that the glob pattern may find.
:rtype: None
"""
from openlp.core.common.applocation import AppLocation
app_dir = AppLocation.get_directory(AppLocation.AppDir)
for extension_path in app_dir.glob(glob_pattern):
extension_path = extension_path.relative_to(app_dir)
@ -137,19 +118,6 @@ class ThemeLevel(object):
Song = 3
def translate(context, text, comment=None, qt_translate=QtCore.QCoreApplication.translate):
"""
A special shortcut method to wrap around the Qt5 translation functions. This abstracts the translation procedure so
that we can change it if at a later date if necessary, without having to redo the whole of OpenLP.
:param context: The translation context, used to give each string a context or a namespace.
:param text: The text to put into the translation tables for translation.
:param comment: An identifying string for when the same text is used in different roles within the same context.
:param qt_translate:
"""
return qt_translate(context, text, comment)
class SlideLimits(object):
"""
Provides an enumeration for behaviour of OpenLP at the end limits of each service item when pressing the up/down
@ -203,7 +171,7 @@ def verify_ipv4(addr):
:returns: bool
"""
try:
valid = IPv4Address(addr)
IPv4Address(addr)
return True
except AddressValueError:
return False
@ -217,7 +185,7 @@ def verify_ipv6(addr):
:returns: bool
"""
try:
valid = IPv6Address(addr)
IPv6Address(addr)
return True
except AddressValueError:
return False
@ -290,20 +258,6 @@ def clean_button_text(button_text):
return button_text.replace('&', '').replace('< ', '').replace(' >', '')
from .openlpmixin import OpenLPMixin
from .registry import Registry
from .registrymixin import RegistryMixin
from .registryproperties import RegistryProperties
from .uistrings import UiStrings
from .settings import Settings
from .applocation import AppLocation
from .actions import ActionList
from .languagemanager import LanguageManager
if is_win():
from subprocess import STARTUPINFO, STARTF_USESHOWWINDOW
def add_actions(target, actions):
"""
Adds multiple actions to a menu or toolbar in one command.
@ -394,6 +348,7 @@ def get_images_filter():
"""
Returns a filter string for a file dialog containing all the supported image formats.
"""
from openlp.core.common.i18n import translate
global IMAGES_FILTER
if not IMAGES_FILTER:
log.debug('Generating images filter.')
@ -446,6 +401,7 @@ def check_binary_exists(program_path):
try:
# Setup startupinfo options for check_output to avoid console popping up on windows
if is_win():
from subprocess import STARTUPINFO, STARTF_USESHOWWINDOW
startupinfo = STARTUPINFO()
startupinfo.dwFlags |= STARTF_USESHOWWINDOW
else:

View File

@ -27,7 +27,7 @@ import logging
from PyQt5 import QtCore, QtGui, QtWidgets
from openlp.core.common import Settings
from openlp.core.common.settings import Settings
log = logging.getLogger(__name__)

View File

@ -26,8 +26,10 @@ import logging
import os
import sys
from openlp.core.common import Settings, is_win, is_macosx
from openlp.core.common.path import Path
import openlp
from openlp.core.common import get_frozen_path, is_win, is_macosx
from openlp.core.common.path import Path, create_paths
from openlp.core.common.settings import Settings
if not is_win() and not is_macosx():
try:
@ -36,10 +38,6 @@ if not is_win() and not is_macosx():
except ImportError:
XDG_BASE_AVAILABLE = False
import openlp
from openlp.core.common import check_directory_exists, get_frozen_path
log = logging.getLogger(__name__)
FROZEN_APP_PATH = Path(sys.argv[0]).parent
@ -88,7 +86,7 @@ class AppLocation(object):
path = Settings().value('advanced/data path')
else:
path = AppLocation.get_directory(AppLocation.DataDir)
check_directory_exists(path)
create_paths(path)
return path
@staticmethod
@ -121,7 +119,7 @@ class AppLocation(object):
:rtype: openlp.core.common.path.Path
"""
path = AppLocation.get_data_path() / section
check_directory_exists(path)
create_paths(path)
return path

View File

@ -30,7 +30,8 @@ from random import randint
import requests
from openlp.core.common import Registry, trace_error_handler
from openlp.core.common import trace_error_handler
from openlp.core.common.registry import Registry
log = logging.getLogger(__name__ + '.__init__')

556
openlp/core/common/i18n.py Normal file
View File

@ -0,0 +1,556 @@
# -*- 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:`languages` module provides a list of language names with utility functions.
"""
import itertools
import locale
import logging
import re
from collections import namedtuple
from PyQt5 import QtCore, QtWidgets
from openlp.core.common import is_win, is_macosx
from openlp.core.common.applocation import AppLocation
from openlp.core.common.settings import Settings
log = logging.getLogger(__name__)
# Due to dependency issues, this HAS to be at the top of the file
def translate(context, text, comment=None, qt_translate=QtCore.QCoreApplication.translate):
"""
A special shortcut method to wrap around the Qt5 translation functions. This abstracts the translation procedure so
that we can change it if at a later date if necessary, without having to redo the whole of OpenLP.
:param context: The translation context, used to give each string a context or a namespace.
:param text: The text to put into the translation tables for translation.
:param comment: An identifying string for when the same text is used in different roles within the same context.
:param qt_translate:
"""
return qt_translate(context, text, comment)
Language = namedtuple('Language', ['id', 'name', 'code'])
ICU_COLLATOR = None
DIGITS_OR_NONDIGITS = re.compile(r'\d+|\D+', re.UNICODE)
LANGUAGES = sorted([
Language(1, translate('common.languages', '(Afan) Oromo', 'Language code: om'), 'om'),
Language(2, translate('common.languages', 'Abkhazian', 'Language code: ab'), 'ab'),
Language(3, translate('common.languages', 'Afar', 'Language code: aa'), 'aa'),
Language(4, translate('common.languages', 'Afrikaans', 'Language code: af'), 'af'),
Language(5, translate('common.languages', 'Albanian', 'Language code: sq'), 'sq'),
Language(6, translate('common.languages', 'Amharic', 'Language code: am'), 'am'),
Language(140, translate('common.languages', 'Amuzgo', 'Language code: amu'), 'amu'),
Language(152, translate('common.languages', 'Ancient Greek', 'Language code: grc'), 'grc'),
Language(7, translate('common.languages', 'Arabic', 'Language code: ar'), 'ar'),
Language(8, translate('common.languages', 'Armenian', 'Language code: hy'), 'hy'),
Language(9, translate('common.languages', 'Assamese', 'Language code: as'), 'as'),
Language(10, translate('common.languages', 'Aymara', 'Language code: ay'), 'ay'),
Language(11, translate('common.languages', 'Azerbaijani', 'Language code: az'), 'az'),
Language(12, translate('common.languages', 'Bashkir', 'Language code: ba'), 'ba'),
Language(13, translate('common.languages', 'Basque', 'Language code: eu'), 'eu'),
Language(14, translate('common.languages', 'Bengali', 'Language code: bn'), 'bn'),
Language(15, translate('common.languages', 'Bhutani', 'Language code: dz'), 'dz'),
Language(16, translate('common.languages', 'Bihari', 'Language code: bh'), 'bh'),
Language(17, translate('common.languages', 'Bislama', 'Language code: bi'), 'bi'),
Language(18, translate('common.languages', 'Breton', 'Language code: br'), 'br'),
Language(19, translate('common.languages', 'Bulgarian', 'Language code: bg'), 'bg'),
Language(20, translate('common.languages', 'Burmese', 'Language code: my'), 'my'),
Language(21, translate('common.languages', 'Byelorussian', 'Language code: be'), 'be'),
Language(142, translate('common.languages', 'Cakchiquel', 'Language code: cak'), 'cak'),
Language(22, translate('common.languages', 'Cambodian', 'Language code: km'), 'km'),
Language(23, translate('common.languages', 'Catalan', 'Language code: ca'), 'ca'),
Language(24, translate('common.languages', 'Chinese', 'Language code: zh'), 'zh'),
Language(141, translate('common.languages', 'Comaltepec Chinantec', 'Language code: cco'), 'cco'),
Language(25, translate('common.languages', 'Corsican', 'Language code: co'), 'co'),
Language(26, translate('common.languages', 'Croatian', 'Language code: hr'), 'hr'),
Language(27, translate('common.languages', 'Czech', 'Language code: cs'), 'cs'),
Language(28, translate('common.languages', 'Danish', 'Language code: da'), 'da'),
Language(29, translate('common.languages', 'Dutch', 'Language code: nl'), 'nl'),
Language(30, translate('common.languages', 'English', 'Language code: en'), 'en'),
Language(31, translate('common.languages', 'Esperanto', 'Language code: eo'), 'eo'),
Language(32, translate('common.languages', 'Estonian', 'Language code: et'), 'et'),
Language(33, translate('common.languages', 'Faeroese', 'Language code: fo'), 'fo'),
Language(34, translate('common.languages', 'Fiji', 'Language code: fj'), 'fj'),
Language(35, translate('common.languages', 'Finnish', 'Language code: fi'), 'fi'),
Language(36, translate('common.languages', 'French', 'Language code: fr'), 'fr'),
Language(37, translate('common.languages', 'Frisian', 'Language code: fy'), 'fy'),
Language(38, translate('common.languages', 'Galician', 'Language code: gl'), 'gl'),
Language(39, translate('common.languages', 'Georgian', 'Language code: ka'), 'ka'),
Language(40, translate('common.languages', 'German', 'Language code: de'), 'de'),
Language(41, translate('common.languages', 'Greek', 'Language code: el'), 'el'),
Language(42, translate('common.languages', 'Greenlandic', 'Language code: kl'), 'kl'),
Language(43, translate('common.languages', 'Guarani', 'Language code: gn'), 'gn'),
Language(44, translate('common.languages', 'Gujarati', 'Language code: gu'), 'gu'),
Language(143, translate('common.languages', 'Haitian Creole', 'Language code: ht'), 'ht'),
Language(45, translate('common.languages', 'Hausa', 'Language code: ha'), 'ha'),
Language(46, translate('common.languages', 'Hebrew (former iw)', 'Language code: he'), 'he'),
Language(144, translate('common.languages', 'Hiligaynon', 'Language code: hil'), 'hil'),
Language(47, translate('common.languages', 'Hindi', 'Language code: hi'), 'hi'),
Language(48, translate('common.languages', 'Hungarian', 'Language code: hu'), 'hu'),
Language(49, translate('common.languages', 'Icelandic', 'Language code: is'), 'is'),
Language(50, translate('common.languages', 'Indonesian (former in)', 'Language code: id'), 'id'),
Language(51, translate('common.languages', 'Interlingua', 'Language code: ia'), 'ia'),
Language(52, translate('common.languages', 'Interlingue', 'Language code: ie'), 'ie'),
Language(54, translate('common.languages', 'Inuktitut (Eskimo)', 'Language code: iu'), 'iu'),
Language(53, translate('common.languages', 'Inupiak', 'Language code: ik'), 'ik'),
Language(55, translate('common.languages', 'Irish', 'Language code: ga'), 'ga'),
Language(56, translate('common.languages', 'Italian', 'Language code: it'), 'it'),
Language(145, translate('common.languages', 'Jakalteko', 'Language code: jac'), 'jac'),
Language(57, translate('common.languages', 'Japanese', 'Language code: ja'), 'ja'),
Language(58, translate('common.languages', 'Javanese', 'Language code: jw'), 'jw'),
Language(150, translate('common.languages', 'K\'iche\'', 'Language code: quc'), 'quc'),
Language(59, translate('common.languages', 'Kannada', 'Language code: kn'), 'kn'),
Language(60, translate('common.languages', 'Kashmiri', 'Language code: ks'), 'ks'),
Language(61, translate('common.languages', 'Kazakh', 'Language code: kk'), 'kk'),
Language(146, translate('common.languages', 'Kekchí ', 'Language code: kek'), 'kek'),
Language(62, translate('common.languages', 'Kinyarwanda', 'Language code: rw'), 'rw'),
Language(63, translate('common.languages', 'Kirghiz', 'Language code: ky'), 'ky'),
Language(64, translate('common.languages', 'Kirundi', 'Language code: rn'), 'rn'),
Language(65, translate('common.languages', 'Korean', 'Language code: ko'), 'ko'),
Language(66, translate('common.languages', 'Kurdish', 'Language code: ku'), 'ku'),
Language(67, translate('common.languages', 'Laothian', 'Language code: lo'), 'lo'),
Language(68, translate('common.languages', 'Latin', 'Language code: la'), 'la'),
Language(69, translate('common.languages', 'Latvian, Lettish', 'Language code: lv'), 'lv'),
Language(70, translate('common.languages', 'Lingala', 'Language code: ln'), 'ln'),
Language(71, translate('common.languages', 'Lithuanian', 'Language code: lt'), 'lt'),
Language(72, translate('common.languages', 'Macedonian', 'Language code: mk'), 'mk'),
Language(73, translate('common.languages', 'Malagasy', 'Language code: mg'), 'mg'),
Language(74, translate('common.languages', 'Malay', 'Language code: ms'), 'ms'),
Language(75, translate('common.languages', 'Malayalam', 'Language code: ml'), 'ml'),
Language(76, translate('common.languages', 'Maltese', 'Language code: mt'), 'mt'),
Language(148, translate('common.languages', 'Mam', 'Language code: mam'), 'mam'),
Language(77, translate('common.languages', 'Maori', 'Language code: mi'), 'mi'),
Language(147, translate('common.languages', 'Maori', 'Language code: mri'), 'mri'),
Language(78, translate('common.languages', 'Marathi', 'Language code: mr'), 'mr'),
Language(79, translate('common.languages', 'Moldavian', 'Language code: mo'), 'mo'),
Language(80, translate('common.languages', 'Mongolian', 'Language code: mn'), 'mn'),
Language(149, translate('common.languages', 'Nahuatl', 'Language code: nah'), 'nah'),
Language(81, translate('common.languages', 'Nauru', 'Language code: na'), 'na'),
Language(82, translate('common.languages', 'Nepali', 'Language code: ne'), 'ne'),
Language(83, translate('common.languages', 'Norwegian', 'Language code: no'), 'no'),
Language(84, translate('common.languages', 'Occitan', 'Language code: oc'), 'oc'),
Language(85, translate('common.languages', 'Oriya', 'Language code: or'), 'or'),
Language(86, translate('common.languages', 'Pashto, Pushto', 'Language code: ps'), 'ps'),
Language(87, translate('common.languages', 'Persian', 'Language code: fa'), 'fa'),
Language(151, translate('common.languages', 'Plautdietsch', 'Language code: pdt'), 'pdt'),
Language(88, translate('common.languages', 'Polish', 'Language code: pl'), 'pl'),
Language(89, translate('common.languages', 'Portuguese', 'Language code: pt'), 'pt'),
Language(90, translate('common.languages', 'Punjabi', 'Language code: pa'), 'pa'),
Language(91, translate('common.languages', 'Quechua', 'Language code: qu'), 'qu'),
Language(92, translate('common.languages', 'Rhaeto-Romance', 'Language code: rm'), 'rm'),
Language(93, translate('common.languages', 'Romanian', 'Language code: ro'), 'ro'),
Language(94, translate('common.languages', 'Russian', 'Language code: ru'), 'ru'),
Language(95, translate('common.languages', 'Samoan', 'Language code: sm'), 'sm'),
Language(96, translate('common.languages', 'Sangro', 'Language code: sg'), 'sg'),
Language(97, translate('common.languages', 'Sanskrit', 'Language code: sa'), 'sa'),
Language(98, translate('common.languages', 'Scots Gaelic', 'Language code: gd'), 'gd'),
Language(99, translate('common.languages', 'Serbian', 'Language code: sr'), 'sr'),
Language(100, translate('common.languages', 'Serbo-Croatian', 'Language code: sh'), 'sh'),
Language(101, translate('common.languages', 'Sesotho', 'Language code: st'), 'st'),
Language(102, translate('common.languages', 'Setswana', 'Language code: tn'), 'tn'),
Language(103, translate('common.languages', 'Shona', 'Language code: sn'), 'sn'),
Language(104, translate('common.languages', 'Sindhi', 'Language code: sd'), 'sd'),
Language(105, translate('common.languages', 'Singhalese', 'Language code: si'), 'si'),
Language(106, translate('common.languages', 'Siswati', 'Language code: ss'), 'ss'),
Language(107, translate('common.languages', 'Slovak', 'Language code: sk'), 'sk'),
Language(108, translate('common.languages', 'Slovenian', 'Language code: sl'), 'sl'),
Language(109, translate('common.languages', 'Somali', 'Language code: so'), 'so'),
Language(110, translate('common.languages', 'Spanish', 'Language code: es'), 'es'),
Language(111, translate('common.languages', 'Sudanese', 'Language code: su'), 'su'),
Language(112, translate('common.languages', 'Swahili', 'Language code: sw'), 'sw'),
Language(113, translate('common.languages', 'Swedish', 'Language code: sv'), 'sv'),
Language(114, translate('common.languages', 'Tagalog', 'Language code: tl'), 'tl'),
Language(115, translate('common.languages', 'Tajik', 'Language code: tg'), 'tg'),
Language(116, translate('common.languages', 'Tamil', 'Language code: ta'), 'ta'),
Language(117, translate('common.languages', 'Tatar', 'Language code: tt'), 'tt'),
Language(118, translate('common.languages', 'Tegulu', 'Language code: te'), 'te'),
Language(119, translate('common.languages', 'Thai', 'Language code: th'), 'th'),
Language(120, translate('common.languages', 'Tibetan', 'Language code: bo'), 'bo'),
Language(121, translate('common.languages', 'Tigrinya', 'Language code: ti'), 'ti'),
Language(122, translate('common.languages', 'Tonga', 'Language code: to'), 'to'),
Language(123, translate('common.languages', 'Tsonga', 'Language code: ts'), 'ts'),
Language(124, translate('common.languages', 'Turkish', 'Language code: tr'), 'tr'),
Language(125, translate('common.languages', 'Turkmen', 'Language code: tk'), 'tk'),
Language(126, translate('common.languages', 'Twi', 'Language code: tw'), 'tw'),
Language(127, translate('common.languages', 'Uigur', 'Language code: ug'), 'ug'),
Language(128, translate('common.languages', 'Ukrainian', 'Language code: uk'), 'uk'),
Language(129, translate('common.languages', 'Urdu', 'Language code: ur'), 'ur'),
Language(153, translate('common.languages', 'Uspanteco', 'Language code: usp'), 'usp'),
Language(130, translate('common.languages', 'Uzbek', 'Language code: uz'), 'uz'),
Language(131, translate('common.languages', 'Vietnamese', 'Language code: vi'), 'vi'),
Language(132, translate('common.languages', 'Volapuk', 'Language code: vo'), 'vo'),
Language(133, translate('common.languages', 'Welch', 'Language code: cy'), 'cy'),
Language(134, translate('common.languages', 'Wolof', 'Language code: wo'), 'wo'),
Language(135, translate('common.languages', 'Xhosa', 'Language code: xh'), 'xh'),
Language(136, translate('common.languages', 'Yiddish (former ji)', 'Language code: yi'), 'yi'),
Language(137, translate('common.languages', 'Yoruba', 'Language code: yo'), 'yo'),
Language(138, translate('common.languages', 'Zhuang', 'Language code: za'), 'za'),
Language(139, translate('common.languages', 'Zulu', 'Language code: zu'), 'zu')
], key=lambda language: language.name)
class LanguageManager(object):
"""
Helper for Language selection
"""
__qm_list__ = {}
auto_language = False
@staticmethod
def get_translators(language):
"""
Set up a translator to use in this instance of OpenLP
:param language: The language to load into the translator
"""
if LanguageManager.auto_language:
language = QtCore.QLocale.system().name()
lang_path = str(AppLocation.get_directory(AppLocation.LanguageDir))
app_translator = QtCore.QTranslator()
app_translator.load(language, lang_path)
# A translator for buttons and other default strings provided by Qt.
if not is_win() and not is_macosx():
lang_path = QtCore.QLibraryInfo.location(QtCore.QLibraryInfo.TranslationsPath)
# As of Qt5, the core translations come in 2 files per language
default_translator = QtCore.QTranslator()
default_translator.load('qt_%s' % language, lang_path)
base_translator = QtCore.QTranslator()
base_translator.load('qtbase_%s' % language, lang_path)
return app_translator, default_translator, base_translator
@staticmethod
def find_qm_files():
"""
Find all available language files in this OpenLP install
"""
log.debug('Translation files: {files}'.format(files=AppLocation.get_directory(AppLocation.LanguageDir)))
trans_dir = QtCore.QDir(str(AppLocation.get_directory(AppLocation.LanguageDir)))
file_names = trans_dir.entryList(['*.qm'], QtCore.QDir.Files, QtCore.QDir.Name)
# Remove qm files from the list which start with "qt".
file_names = [file_ for file_ in file_names if not file_.startswith('qt')]
return list(map(trans_dir.filePath, file_names))
@staticmethod
def language_name(qm_file):
"""
Load the language name from a language file
:param qm_file: The file to obtain the name from
"""
translator = QtCore.QTranslator()
translator.load(qm_file)
return translator.translate('OpenLP.MainWindow', 'English', 'Please add the name of your language here')
@staticmethod
def get_language():
"""
Retrieve a saved language to use from settings
"""
language = Settings().value('core/language')
language = str(language)
log.info("Language file: '{language}' Loaded from conf file".format(language=language))
if re.match(r'[[].*[]]', language):
LanguageManager.auto_language = True
language = re.sub(r'[\[\]]', '', language)
return language
@staticmethod
def set_language(action, message=True):
"""
Set the language to translate OpenLP into
:param action: The language menu option
:param message: Display the message option
"""
language = 'en'
if action:
action_name = str(action.objectName())
if action_name == 'autoLanguageItem':
LanguageManager.auto_language = True
else:
LanguageManager.auto_language = False
qm_list = LanguageManager.get_qm_list()
language = str(qm_list[action_name])
if LanguageManager.auto_language:
language = '[{language}]'.format(language=language)
Settings().setValue('core/language', language)
log.info("Language file: '{language}' written to conf file".format(language=language))
if message:
QtWidgets.QMessageBox.information(None,
translate('OpenLP.LanguageManager', 'Language'),
translate('OpenLP.LanguageManager',
'Please restart OpenLP to use your new language setting.'))
@staticmethod
def init_qm_list():
"""
Initialise the list of available translations
"""
LanguageManager.__qm_list__ = {}
qm_files = LanguageManager.find_qm_files()
for counter, qmf in enumerate(qm_files):
reg_ex = QtCore.QRegExp("^.*i18n/(.*).qm")
if reg_ex.exactMatch(qmf):
name = '{regex}'.format(regex=reg_ex.cap(1))
LanguageManager.__qm_list__[
'{count:>2d} {name}'.format(count=counter + 1, name=LanguageManager.language_name(qmf))] = name
@staticmethod
def get_qm_list():
"""
Return the list of available translations
"""
if not LanguageManager.__qm_list__:
LanguageManager.init_qm_list()
return LanguageManager.__qm_list__
class UiStrings(object):
"""
Provide standard strings for objects to use.
"""
__instance__ = None
def __new__(cls):
"""
Override the default object creation method to return a single instance.
"""
if not cls.__instance__:
cls.__instance__ = object.__new__(cls)
return cls.__instance__
def __init__(self):
"""
These strings should need a good reason to be retranslated elsewhere.
Should some/more/less of these have an &amp; attached?
"""
self.About = translate('OpenLP.Ui', 'About')
self.Add = translate('OpenLP.Ui', '&Add')
self.AddGroup = translate('OpenLP.Ui', 'Add group')
self.AddGroupDot = translate('OpenLP.Ui', 'Add group.')
self.Advanced = translate('OpenLP.Ui', 'Advanced')
self.AllFiles = translate('OpenLP.Ui', 'All Files')
self.Automatic = translate('OpenLP.Ui', 'Automatic')
self.BackgroundColor = translate('OpenLP.Ui', 'Background Color')
self.BackgroundColorColon = translate('OpenLP.Ui', 'Background color:')
self.BibleShortSearchTitle = translate('OpenLP.Ui', 'Search is Empty or too Short')
self.BibleShortSearch = translate('OpenLP.Ui', '<strong>The search you have entered is empty or shorter '
'than 3 characters long.</strong><br><br>Please try again with '
'a longer search.')
self.BibleNoBiblesTitle = translate('OpenLP.Ui', 'No Bibles Available')
self.BibleNoBibles = translate('OpenLP.Ui', '<strong>There are no Bibles currently installed.</strong><br><br>'
'Please use the Import Wizard to install one or more Bibles.')
self.Bottom = translate('OpenLP.Ui', 'Bottom')
self.Browse = translate('OpenLP.Ui', 'Browse...')
self.Cancel = translate('OpenLP.Ui', 'Cancel')
self.CCLINumberLabel = translate('OpenLP.Ui', 'CCLI number:')
self.CCLISongNumberLabel = translate('OpenLP.Ui', 'CCLI song number:')
self.CreateService = translate('OpenLP.Ui', 'Create a new service.')
self.ConfirmDelete = translate('OpenLP.Ui', 'Confirm Delete')
self.Continuous = translate('OpenLP.Ui', 'Continuous')
self.Default = translate('OpenLP.Ui', 'Default')
self.DefaultColor = translate('OpenLP.Ui', 'Default Color:')
self.DefaultServiceName = translate('OpenLP.Ui', 'Service %Y-%m-%d %H-%M',
'This may not contain any of the following characters: /\\?*|<>[]":+\n'
'See http://docs.python.org/library/datetime'
'.html#strftime-strptime-behavior for more information.')
self.Delete = translate('OpenLP.Ui', '&Delete')
self.DisplayStyle = translate('OpenLP.Ui', 'Display style:')
self.Duplicate = translate('OpenLP.Ui', 'Duplicate Error')
self.Edit = translate('OpenLP.Ui', '&Edit')
self.EmptyField = translate('OpenLP.Ui', 'Empty Field')
self.Error = translate('OpenLP.Ui', 'Error')
self.Export = translate('OpenLP.Ui', 'Export')
self.File = translate('OpenLP.Ui', 'File')
self.FontSizePtUnit = translate('OpenLP.Ui', 'pt', 'Abbreviated font pointsize unit')
self.Help = translate('OpenLP.Ui', 'Help')
self.Hours = translate('OpenLP.Ui', 'h', 'The abbreviated unit for hours')
self.IFdSs = translate('OpenLP.Ui', 'Invalid Folder Selected', 'Singular')
self.IFSs = translate('OpenLP.Ui', 'Invalid File Selected', 'Singular')
self.IFSp = translate('OpenLP.Ui', 'Invalid Files Selected', 'Plural')
self.Image = translate('OpenLP.Ui', 'Image')
self.Import = translate('OpenLP.Ui', 'Import')
self.LayoutStyle = translate('OpenLP.Ui', 'Layout style:')
self.Live = translate('OpenLP.Ui', 'Live')
self.LiveBGError = translate('OpenLP.Ui', 'Live Background Error')
self.LiveToolbar = translate('OpenLP.Ui', 'Live Toolbar')
self.Load = translate('OpenLP.Ui', 'Load')
self.Manufacturer = translate('OpenLP.Ui', 'Manufacturer', 'Singular')
self.Manufacturers = translate('OpenLP.Ui', 'Manufacturers', 'Plural')
self.Model = translate('OpenLP.Ui', 'Model', 'Singular')
self.Models = translate('OpenLP.Ui', 'Models', 'Plural')
self.Minutes = translate('OpenLP.Ui', 'm', 'The abbreviated unit for minutes')
self.Middle = translate('OpenLP.Ui', 'Middle')
self.New = translate('OpenLP.Ui', 'New')
self.NewService = translate('OpenLP.Ui', 'New Service')
self.NewTheme = translate('OpenLP.Ui', 'New Theme')
self.NextTrack = translate('OpenLP.Ui', 'Next Track')
self.NFdSs = translate('OpenLP.Ui', 'No Folder Selected', 'Singular')
self.NFSs = translate('OpenLP.Ui', 'No File Selected', 'Singular')
self.NFSp = translate('OpenLP.Ui', 'No Files Selected', 'Plural')
self.NISs = translate('OpenLP.Ui', 'No Item Selected', 'Singular')
self.NISp = translate('OpenLP.Ui', 'No Items Selected', 'Plural')
self.NoResults = translate('OpenLP.Ui', 'No Search Results')
self.OpenLP = translate('OpenLP.Ui', 'OpenLP')
self.OpenLPv2AndUp = translate('OpenLP.Ui', 'OpenLP 2.0 and up')
self.OpenLPStart = translate('OpenLP.Ui', 'OpenLP is already running. Do you wish to continue?')
self.OpenService = translate('OpenLP.Ui', 'Open service.')
self.OptionalShowInFooter = translate('OpenLP.Ui', 'Optional, this will be displayed in footer.')
self.OptionalHideInFooter = translate('OpenLP.Ui', 'Optional, this won\'t be displayed in footer.')
self.PlaySlidesInLoop = translate('OpenLP.Ui', 'Play Slides in Loop')
self.PlaySlidesToEnd = translate('OpenLP.Ui', 'Play Slides to End')
self.Preview = translate('OpenLP.Ui', 'Preview')
self.PreviewToolbar = translate('OpenLP.Ui', 'Preview Toolbar')
self.PrintService = translate('OpenLP.Ui', 'Print Service')
self.Projector = translate('OpenLP.Ui', 'Projector', 'Singular')
self.Projectors = translate('OpenLP.Ui', 'Projectors', 'Plural')
self.ReplaceBG = translate('OpenLP.Ui', 'Replace Background')
self.ReplaceLiveBG = translate('OpenLP.Ui', 'Replace live background.')
self.ReplaceLiveBGDisabled = translate('OpenLP.Ui', 'Replace live background is not available when the WebKit '
'player is disabled.')
self.ResetBG = translate('OpenLP.Ui', 'Reset Background')
self.ResetLiveBG = translate('OpenLP.Ui', 'Reset live background.')
self.RequiredShowInFooter = translate('OpenLP.Ui', 'Required, this will be displayed in footer.')
self.Seconds = translate('OpenLP.Ui', 's', 'The abbreviated unit for seconds')
self.SaveAndPreview = translate('OpenLP.Ui', 'Save && Preview')
self.Search = translate('OpenLP.Ui', 'Search')
self.SearchThemes = translate('OpenLP.Ui', 'Search Themes...', 'Search bar place holder text ')
self.SelectDelete = translate('OpenLP.Ui', 'You must select an item to delete.')
self.SelectEdit = translate('OpenLP.Ui', 'You must select an item to edit.')
self.Settings = translate('OpenLP.Ui', 'Settings')
self.SaveService = translate('OpenLP.Ui', 'Save Service')
self.Service = translate('OpenLP.Ui', 'Service')
self.ShortResults = translate('OpenLP.Ui', 'Please type more text to use \'Search As You Type\'')
self.Split = translate('OpenLP.Ui', 'Optional &Split')
self.SplitToolTip = translate('OpenLP.Ui',
'Split a slide into two only if it does not fit on the screen as one slide.')
self.StartingImport = translate('OpenLP.Ui', 'Starting import...')
self.StopPlaySlidesInLoop = translate('OpenLP.Ui', 'Stop Play Slides in Loop')
self.StopPlaySlidesToEnd = translate('OpenLP.Ui', 'Stop Play Slides to End')
self.Theme = translate('OpenLP.Ui', 'Theme', 'Singular')
self.Themes = translate('OpenLP.Ui', 'Themes', 'Plural')
self.Tools = translate('OpenLP.Ui', 'Tools')
self.Top = translate('OpenLP.Ui', 'Top')
self.UnsupportedFile = translate('OpenLP.Ui', 'Unsupported File')
self.VersePerSlide = translate('OpenLP.Ui', 'Verse Per Slide')
self.VersePerLine = translate('OpenLP.Ui', 'Verse Per Line')
self.Version = translate('OpenLP.Ui', 'Version')
self.View = translate('OpenLP.Ui', 'View')
self.ViewMode = translate('OpenLP.Ui', 'View Mode')
self.Video = translate('OpenLP.Ui', 'Video')
self.WebDownloadText = translate('OpenLP.Ui', 'Web Interface, Download and Install latest Version')
book_chapter = translate('OpenLP.Ui', 'Book Chapter')
chapter = translate('OpenLP.Ui', 'Chapter')
verse = translate('OpenLP.Ui', 'Verse')
gap = ' | '
psalm = translate('OpenLP.Ui', 'Psalm')
may_shorten = translate('OpenLP.Ui', 'Book names may be shortened from full names, for an example Ps 23 = '
'Psalm 23')
bible_scripture_items = \
[book_chapter, gap, psalm, ' 23<br>',
book_chapter, '%(range)s', chapter, gap, psalm, ' 23%(range)s24<br>',
book_chapter, '%(verse)s', verse, '%(range)s', verse, gap, psalm, ' 23%(verse)s1%(range)s2<br>',
book_chapter, '%(verse)s', verse, '%(range)s', verse, '%(list)s', verse, '%(range)s', verse, gap, psalm,
' 23%(verse)s1%(range)s2%(list)s5%(range)s6<br>',
book_chapter, '%(verse)s', verse, '%(range)s', verse, '%(list)s', chapter, '%(verse)s', verse, '%(range)s',
verse, gap, psalm, ' 23%(verse)s1%(range)s2%(list)s24%(verse)s1%(range)s3<br>',
book_chapter, '%(verse)s', verse, '%(range)s', chapter, '%(verse)s', verse, gap, psalm,
' 23%(verse)s1%(range)s24%(verse)s1<br><br>', may_shorten]
itertools.chain.from_iterable(itertools.repeat(strings, 1) if isinstance(strings, str)
else strings for strings in bible_scripture_items)
self.BibleScriptureError = ''.join(str(joined) for joined in bible_scripture_items)
def format_time(text, local_time):
"""
Workaround for Python built-in time formatting function time.strftime().
time.strftime() accepts only ascii characters. This function accepts
unicode string and passes individual % placeholders to time.strftime().
This ensures only ascii characters are passed to time.strftime().
:param text: The text to be processed.
:param local_time: The time to be used to add to the string. This is a time object
"""
def match_formatting(match):
"""
Format the match
"""
return local_time.strftime(match.group())
return re.sub(r'\%[a-zA-Z]', match_formatting, text)
def get_locale_key(string):
"""
Creates a key for case insensitive, locale aware string sorting.
:param string: The corresponding string.
"""
string = string.lower()
# ICU is the prefered way to handle locale sort key, we fallback to locale.strxfrm which will work in most cases.
global ICU_COLLATOR
try:
if ICU_COLLATOR is None:
import icu
language = LanguageManager.get_language()
icu_locale = icu.Locale(language)
ICU_COLLATOR = icu.Collator.createInstance(icu_locale)
return ICU_COLLATOR.getSortKey(string)
except:
return locale.strxfrm(string).encode()
def get_natural_key(string):
"""
Generate a key for locale aware natural string sorting.
:param string: string to be sorted by
Returns a list of string compare keys and integers.
"""
key = DIGITS_OR_NONDIGITS.findall(string)
key = [int(part) if part.isdigit() else get_locale_key(part) for part in key]
# Python 3 does not support comparison of different types anymore. So make sure, that we do not compare str
# and int.
if string and string[0].isdigit():
return [b''] + key
return key
def get_language(name):
"""
Find the language by its name or code.
:param name: The name or abbreviation of the language.
:return: The first match as a Language namedtuple or None
"""
if name:
name_lower = name.lower()
name_title = name_lower[:1].upper() + name_lower[1:]
for language in LANGUAGES:
if language.name == name_title or language.code == name_lower:
return language
return None

View File

@ -1,210 +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 #
###############################################################################
"""
The :mod:`languagemanager` module provides all the translation settings and language file loading for OpenLP.
"""
import locale
import logging
import re
from PyQt5 import QtCore, QtWidgets
from openlp.core.common import AppLocation, Settings, translate, is_win, is_macosx
log = logging.getLogger(__name__)
ICU_COLLATOR = None
DIGITS_OR_NONDIGITS = re.compile(r'\d+|\D+', re.UNICODE)
class LanguageManager(object):
"""
Helper for Language selection
"""
__qm_list__ = {}
auto_language = False
@staticmethod
def get_translators(language):
"""
Set up a translator to use in this instance of OpenLP
:param language: The language to load into the translator
"""
if LanguageManager.auto_language:
language = QtCore.QLocale.system().name()
lang_path = str(AppLocation.get_directory(AppLocation.LanguageDir))
app_translator = QtCore.QTranslator()
app_translator.load(language, lang_path)
# A translator for buttons and other default strings provided by Qt.
if not is_win() and not is_macosx():
lang_path = QtCore.QLibraryInfo.location(QtCore.QLibraryInfo.TranslationsPath)
# As of Qt5, the core translations come in 2 files per language
default_translator = QtCore.QTranslator()
default_translator.load('qt_%s' % language, lang_path)
base_translator = QtCore.QTranslator()
base_translator.load('qtbase_%s' % language, lang_path)
return app_translator, default_translator, base_translator
@staticmethod
def find_qm_files():
"""
Find all available language files in this OpenLP install
"""
log.debug('Translation files: {files}'.format(files=AppLocation.get_directory(AppLocation.LanguageDir)))
trans_dir = QtCore.QDir(str(AppLocation.get_directory(AppLocation.LanguageDir)))
file_names = trans_dir.entryList(['*.qm'], QtCore.QDir.Files, QtCore.QDir.Name)
# Remove qm files from the list which start with "qt".
file_names = [file_ for file_ in file_names if not file_.startswith('qt')]
return list(map(trans_dir.filePath, file_names))
@staticmethod
def language_name(qm_file):
"""
Load the language name from a language file
:param qm_file: The file to obtain the name from
"""
translator = QtCore.QTranslator()
translator.load(qm_file)
return translator.translate('OpenLP.MainWindow', 'English', 'Please add the name of your language here')
@staticmethod
def get_language():
"""
Retrieve a saved language to use from settings
"""
language = Settings().value('core/language')
language = str(language)
log.info("Language file: '{language}' Loaded from conf file".format(language=language))
if re.match(r'[[].*[]]', language):
LanguageManager.auto_language = True
language = re.sub(r'[\[\]]', '', language)
return language
@staticmethod
def set_language(action, message=True):
"""
Set the language to translate OpenLP into
:param action: The language menu option
:param message: Display the message option
"""
language = 'en'
if action:
action_name = str(action.objectName())
if action_name == 'autoLanguageItem':
LanguageManager.auto_language = True
else:
LanguageManager.auto_language = False
qm_list = LanguageManager.get_qm_list()
language = str(qm_list[action_name])
if LanguageManager.auto_language:
language = '[{language}]'.format(language=language)
Settings().setValue('core/language', language)
log.info("Language file: '{language}' written to conf file".format(language=language))
if message:
QtWidgets.QMessageBox.information(None,
translate('OpenLP.LanguageManager', 'Language'),
translate('OpenLP.LanguageManager',
'Please restart OpenLP to use your new language setting.'))
@staticmethod
def init_qm_list():
"""
Initialise the list of available translations
"""
LanguageManager.__qm_list__ = {}
qm_files = LanguageManager.find_qm_files()
for counter, qmf in enumerate(qm_files):
reg_ex = QtCore.QRegExp("^.*i18n/(.*).qm")
if reg_ex.exactMatch(qmf):
name = '{regex}'.format(regex=reg_ex.cap(1))
LanguageManager.__qm_list__[
'{count:>2d} {name}'.format(count=counter + 1, name=LanguageManager.language_name(qmf))] = name
@staticmethod
def get_qm_list():
"""
Return the list of available translations
"""
if not LanguageManager.__qm_list__:
LanguageManager.init_qm_list()
return LanguageManager.__qm_list__
def format_time(text, local_time):
"""
Workaround for Python built-in time formatting function time.strftime().
time.strftime() accepts only ascii characters. This function accepts
unicode string and passes individual % placeholders to time.strftime().
This ensures only ascii characters are passed to time.strftime().
:param text: The text to be processed.
:param local_time: The time to be used to add to the string. This is a time object
"""
def match_formatting(match):
"""
Format the match
"""
return local_time.strftime(match.group())
return re.sub(r'\%[a-zA-Z]', match_formatting, text)
def get_locale_key(string):
"""
Creates a key for case insensitive, locale aware string sorting.
:param string: The corresponding string.
"""
string = string.lower()
# ICU is the prefered way to handle locale sort key, we fallback to locale.strxfrm which will work in most cases.
global ICU_COLLATOR
try:
if ICU_COLLATOR is None:
import icu
language = LanguageManager.get_language()
icu_locale = icu.Locale(language)
ICU_COLLATOR = icu.Collator.createInstance(icu_locale)
return ICU_COLLATOR.getSortKey(string)
except:
return locale.strxfrm(string).encode()
def get_natural_key(string):
"""
Generate a key for locale aware natural string sorting.
:param string: string to be sorted by
Returns a list of string compare keys and integers.
"""
key = DIGITS_OR_NONDIGITS.findall(string)
key = [int(part) if part.isdigit() else get_locale_key(part) for part in key]
# Python 3 does not support comparison of different types anymore. So make sure, that we do not compare str
# and int.
if string and string[0].isdigit():
return [b''] + key
return key

View File

@ -1,201 +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 #
###############################################################################
"""
The :mod:`languages` module provides a list of language names with utility functions.
"""
from collections import namedtuple
from openlp.core.common import translate
Language = namedtuple('Language', ['id', 'name', 'code'])
languages = sorted([
Language(1, translate('common.languages', '(Afan) Oromo', 'Language code: om'), 'om'),
Language(2, translate('common.languages', 'Abkhazian', 'Language code: ab'), 'ab'),
Language(3, translate('common.languages', 'Afar', 'Language code: aa'), 'aa'),
Language(4, translate('common.languages', 'Afrikaans', 'Language code: af'), 'af'),
Language(5, translate('common.languages', 'Albanian', 'Language code: sq'), 'sq'),
Language(6, translate('common.languages', 'Amharic', 'Language code: am'), 'am'),
Language(140, translate('common.languages', 'Amuzgo', 'Language code: amu'), 'amu'),
Language(152, translate('common.languages', 'Ancient Greek', 'Language code: grc'), 'grc'),
Language(7, translate('common.languages', 'Arabic', 'Language code: ar'), 'ar'),
Language(8, translate('common.languages', 'Armenian', 'Language code: hy'), 'hy'),
Language(9, translate('common.languages', 'Assamese', 'Language code: as'), 'as'),
Language(10, translate('common.languages', 'Aymara', 'Language code: ay'), 'ay'),
Language(11, translate('common.languages', 'Azerbaijani', 'Language code: az'), 'az'),
Language(12, translate('common.languages', 'Bashkir', 'Language code: ba'), 'ba'),
Language(13, translate('common.languages', 'Basque', 'Language code: eu'), 'eu'),
Language(14, translate('common.languages', 'Bengali', 'Language code: bn'), 'bn'),
Language(15, translate('common.languages', 'Bhutani', 'Language code: dz'), 'dz'),
Language(16, translate('common.languages', 'Bihari', 'Language code: bh'), 'bh'),
Language(17, translate('common.languages', 'Bislama', 'Language code: bi'), 'bi'),
Language(18, translate('common.languages', 'Breton', 'Language code: br'), 'br'),
Language(19, translate('common.languages', 'Bulgarian', 'Language code: bg'), 'bg'),
Language(20, translate('common.languages', 'Burmese', 'Language code: my'), 'my'),
Language(21, translate('common.languages', 'Byelorussian', 'Language code: be'), 'be'),
Language(142, translate('common.languages', 'Cakchiquel', 'Language code: cak'), 'cak'),
Language(22, translate('common.languages', 'Cambodian', 'Language code: km'), 'km'),
Language(23, translate('common.languages', 'Catalan', 'Language code: ca'), 'ca'),
Language(24, translate('common.languages', 'Chinese', 'Language code: zh'), 'zh'),
Language(141, translate('common.languages', 'Comaltepec Chinantec', 'Language code: cco'), 'cco'),
Language(25, translate('common.languages', 'Corsican', 'Language code: co'), 'co'),
Language(26, translate('common.languages', 'Croatian', 'Language code: hr'), 'hr'),
Language(27, translate('common.languages', 'Czech', 'Language code: cs'), 'cs'),
Language(28, translate('common.languages', 'Danish', 'Language code: da'), 'da'),
Language(29, translate('common.languages', 'Dutch', 'Language code: nl'), 'nl'),
Language(30, translate('common.languages', 'English', 'Language code: en'), 'en'),
Language(31, translate('common.languages', 'Esperanto', 'Language code: eo'), 'eo'),
Language(32, translate('common.languages', 'Estonian', 'Language code: et'), 'et'),
Language(33, translate('common.languages', 'Faeroese', 'Language code: fo'), 'fo'),
Language(34, translate('common.languages', 'Fiji', 'Language code: fj'), 'fj'),
Language(35, translate('common.languages', 'Finnish', 'Language code: fi'), 'fi'),
Language(36, translate('common.languages', 'French', 'Language code: fr'), 'fr'),
Language(37, translate('common.languages', 'Frisian', 'Language code: fy'), 'fy'),
Language(38, translate('common.languages', 'Galician', 'Language code: gl'), 'gl'),
Language(39, translate('common.languages', 'Georgian', 'Language code: ka'), 'ka'),
Language(40, translate('common.languages', 'German', 'Language code: de'), 'de'),
Language(41, translate('common.languages', 'Greek', 'Language code: el'), 'el'),
Language(42, translate('common.languages', 'Greenlandic', 'Language code: kl'), 'kl'),
Language(43, translate('common.languages', 'Guarani', 'Language code: gn'), 'gn'),
Language(44, translate('common.languages', 'Gujarati', 'Language code: gu'), 'gu'),
Language(143, translate('common.languages', 'Haitian Creole', 'Language code: ht'), 'ht'),
Language(45, translate('common.languages', 'Hausa', 'Language code: ha'), 'ha'),
Language(46, translate('common.languages', 'Hebrew (former iw)', 'Language code: he'), 'he'),
Language(144, translate('common.languages', 'Hiligaynon', 'Language code: hil'), 'hil'),
Language(47, translate('common.languages', 'Hindi', 'Language code: hi'), 'hi'),
Language(48, translate('common.languages', 'Hungarian', 'Language code: hu'), 'hu'),
Language(49, translate('common.languages', 'Icelandic', 'Language code: is'), 'is'),
Language(50, translate('common.languages', 'Indonesian (former in)', 'Language code: id'), 'id'),
Language(51, translate('common.languages', 'Interlingua', 'Language code: ia'), 'ia'),
Language(52, translate('common.languages', 'Interlingue', 'Language code: ie'), 'ie'),
Language(54, translate('common.languages', 'Inuktitut (Eskimo)', 'Language code: iu'), 'iu'),
Language(53, translate('common.languages', 'Inupiak', 'Language code: ik'), 'ik'),
Language(55, translate('common.languages', 'Irish', 'Language code: ga'), 'ga'),
Language(56, translate('common.languages', 'Italian', 'Language code: it'), 'it'),
Language(145, translate('common.languages', 'Jakalteko', 'Language code: jac'), 'jac'),
Language(57, translate('common.languages', 'Japanese', 'Language code: ja'), 'ja'),
Language(58, translate('common.languages', 'Javanese', 'Language code: jw'), 'jw'),
Language(150, translate('common.languages', 'K\'iche\'', 'Language code: quc'), 'quc'),
Language(59, translate('common.languages', 'Kannada', 'Language code: kn'), 'kn'),
Language(60, translate('common.languages', 'Kashmiri', 'Language code: ks'), 'ks'),
Language(61, translate('common.languages', 'Kazakh', 'Language code: kk'), 'kk'),
Language(146, translate('common.languages', 'Kekchí ', 'Language code: kek'), 'kek'),
Language(62, translate('common.languages', 'Kinyarwanda', 'Language code: rw'), 'rw'),
Language(63, translate('common.languages', 'Kirghiz', 'Language code: ky'), 'ky'),
Language(64, translate('common.languages', 'Kirundi', 'Language code: rn'), 'rn'),
Language(65, translate('common.languages', 'Korean', 'Language code: ko'), 'ko'),
Language(66, translate('common.languages', 'Kurdish', 'Language code: ku'), 'ku'),
Language(67, translate('common.languages', 'Laothian', 'Language code: lo'), 'lo'),
Language(68, translate('common.languages', 'Latin', 'Language code: la'), 'la'),
Language(69, translate('common.languages', 'Latvian, Lettish', 'Language code: lv'), 'lv'),
Language(70, translate('common.languages', 'Lingala', 'Language code: ln'), 'ln'),
Language(71, translate('common.languages', 'Lithuanian', 'Language code: lt'), 'lt'),
Language(72, translate('common.languages', 'Macedonian', 'Language code: mk'), 'mk'),
Language(73, translate('common.languages', 'Malagasy', 'Language code: mg'), 'mg'),
Language(74, translate('common.languages', 'Malay', 'Language code: ms'), 'ms'),
Language(75, translate('common.languages', 'Malayalam', 'Language code: ml'), 'ml'),
Language(76, translate('common.languages', 'Maltese', 'Language code: mt'), 'mt'),
Language(148, translate('common.languages', 'Mam', 'Language code: mam'), 'mam'),
Language(77, translate('common.languages', 'Maori', 'Language code: mi'), 'mi'),
Language(147, translate('common.languages', 'Maori', 'Language code: mri'), 'mri'),
Language(78, translate('common.languages', 'Marathi', 'Language code: mr'), 'mr'),
Language(79, translate('common.languages', 'Moldavian', 'Language code: mo'), 'mo'),
Language(80, translate('common.languages', 'Mongolian', 'Language code: mn'), 'mn'),
Language(149, translate('common.languages', 'Nahuatl', 'Language code: nah'), 'nah'),
Language(81, translate('common.languages', 'Nauru', 'Language code: na'), 'na'),
Language(82, translate('common.languages', 'Nepali', 'Language code: ne'), 'ne'),
Language(83, translate('common.languages', 'Norwegian', 'Language code: no'), 'no'),
Language(84, translate('common.languages', 'Occitan', 'Language code: oc'), 'oc'),
Language(85, translate('common.languages', 'Oriya', 'Language code: or'), 'or'),
Language(86, translate('common.languages', 'Pashto, Pushto', 'Language code: ps'), 'ps'),
Language(87, translate('common.languages', 'Persian', 'Language code: fa'), 'fa'),
Language(151, translate('common.languages', 'Plautdietsch', 'Language code: pdt'), 'pdt'),
Language(88, translate('common.languages', 'Polish', 'Language code: pl'), 'pl'),
Language(89, translate('common.languages', 'Portuguese', 'Language code: pt'), 'pt'),
Language(90, translate('common.languages', 'Punjabi', 'Language code: pa'), 'pa'),
Language(91, translate('common.languages', 'Quechua', 'Language code: qu'), 'qu'),
Language(92, translate('common.languages', 'Rhaeto-Romance', 'Language code: rm'), 'rm'),
Language(93, translate('common.languages', 'Romanian', 'Language code: ro'), 'ro'),
Language(94, translate('common.languages', 'Russian', 'Language code: ru'), 'ru'),
Language(95, translate('common.languages', 'Samoan', 'Language code: sm'), 'sm'),
Language(96, translate('common.languages', 'Sangro', 'Language code: sg'), 'sg'),
Language(97, translate('common.languages', 'Sanskrit', 'Language code: sa'), 'sa'),
Language(98, translate('common.languages', 'Scots Gaelic', 'Language code: gd'), 'gd'),
Language(99, translate('common.languages', 'Serbian', 'Language code: sr'), 'sr'),
Language(100, translate('common.languages', 'Serbo-Croatian', 'Language code: sh'), 'sh'),
Language(101, translate('common.languages', 'Sesotho', 'Language code: st'), 'st'),
Language(102, translate('common.languages', 'Setswana', 'Language code: tn'), 'tn'),
Language(103, translate('common.languages', 'Shona', 'Language code: sn'), 'sn'),
Language(104, translate('common.languages', 'Sindhi', 'Language code: sd'), 'sd'),
Language(105, translate('common.languages', 'Singhalese', 'Language code: si'), 'si'),
Language(106, translate('common.languages', 'Siswati', 'Language code: ss'), 'ss'),
Language(107, translate('common.languages', 'Slovak', 'Language code: sk'), 'sk'),
Language(108, translate('common.languages', 'Slovenian', 'Language code: sl'), 'sl'),
Language(109, translate('common.languages', 'Somali', 'Language code: so'), 'so'),
Language(110, translate('common.languages', 'Spanish', 'Language code: es'), 'es'),
Language(111, translate('common.languages', 'Sudanese', 'Language code: su'), 'su'),
Language(112, translate('common.languages', 'Swahili', 'Language code: sw'), 'sw'),
Language(113, translate('common.languages', 'Swedish', 'Language code: sv'), 'sv'),
Language(114, translate('common.languages', 'Tagalog', 'Language code: tl'), 'tl'),
Language(115, translate('common.languages', 'Tajik', 'Language code: tg'), 'tg'),
Language(116, translate('common.languages', 'Tamil', 'Language code: ta'), 'ta'),
Language(117, translate('common.languages', 'Tatar', 'Language code: tt'), 'tt'),
Language(118, translate('common.languages', 'Tegulu', 'Language code: te'), 'te'),
Language(119, translate('common.languages', 'Thai', 'Language code: th'), 'th'),
Language(120, translate('common.languages', 'Tibetan', 'Language code: bo'), 'bo'),
Language(121, translate('common.languages', 'Tigrinya', 'Language code: ti'), 'ti'),
Language(122, translate('common.languages', 'Tonga', 'Language code: to'), 'to'),
Language(123, translate('common.languages', 'Tsonga', 'Language code: ts'), 'ts'),
Language(124, translate('common.languages', 'Turkish', 'Language code: tr'), 'tr'),
Language(125, translate('common.languages', 'Turkmen', 'Language code: tk'), 'tk'),
Language(126, translate('common.languages', 'Twi', 'Language code: tw'), 'tw'),
Language(127, translate('common.languages', 'Uigur', 'Language code: ug'), 'ug'),
Language(128, translate('common.languages', 'Ukrainian', 'Language code: uk'), 'uk'),
Language(129, translate('common.languages', 'Urdu', 'Language code: ur'), 'ur'),
Language(153, translate('common.languages', 'Uspanteco', 'Language code: usp'), 'usp'),
Language(130, translate('common.languages', 'Uzbek', 'Language code: uz'), 'uz'),
Language(131, translate('common.languages', 'Vietnamese', 'Language code: vi'), 'vi'),
Language(132, translate('common.languages', 'Volapuk', 'Language code: vo'), 'vo'),
Language(133, translate('common.languages', 'Welch', 'Language code: cy'), 'cy'),
Language(134, translate('common.languages', 'Wolof', 'Language code: wo'), 'wo'),
Language(135, translate('common.languages', 'Xhosa', 'Language code: xh'), 'xh'),
Language(136, translate('common.languages', 'Yiddish (former ji)', 'Language code: yi'), 'yi'),
Language(137, translate('common.languages', 'Yoruba', 'Language code: yo'), 'yo'),
Language(138, translate('common.languages', 'Zhuang', 'Language code: za'), 'za'),
Language(139, translate('common.languages', 'Zulu', 'Language code: zu'), 'zu')
], key=lambda language: language.name)
def get_language(name):
"""
Find the language by its name or code.
:param name: The name or abbreviation of the language.
:return: The first match as a Language namedtuple or None
"""
if name:
name_lower = name.lower()
name_title = name_lower[:1].upper() + name_lower[1:]
for language in languages:
if language.name == name_title or language.code == name_lower:
return language
return None

View File

@ -25,7 +25,8 @@ Provide Error Handling and login Services
import logging
import inspect
from openlp.core.common import trace_error_handler
from openlp.core.common import trace_error_handler, de_hump
from openlp.core.common.registry import Registry
DO_NOT_TRACE_EVENTS = ['timerEvent', 'paintEvent', 'drag_enter_event', 'drop_event', 'on_controller_size_changed',
'preview_size_changed', 'resizeEvent']
@ -90,3 +91,32 @@ class OpenLPMixin(object):
"""
trace_error_handler(self.logger)
self.logger.exception(message)
class RegistryMixin(object):
"""
This adds registry components to classes to use at run time.
"""
def __init__(self, parent):
"""
Register the class and bootstrap hooks.
"""
try:
super(RegistryMixin, self).__init__(parent)
except TypeError:
super(RegistryMixin, self).__init__()
Registry().register(de_hump(self.__class__.__name__), self)
Registry().register_function('bootstrap_initialise', self.bootstrap_initialise)
Registry().register_function('bootstrap_post_set_up', self.bootstrap_post_set_up)
def bootstrap_initialise(self):
"""
Dummy method to be overridden
"""
pass
def bootstrap_post_set_up(self):
"""
Dummy method to be overridden
"""
pass

View File

@ -19,6 +19,7 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
import logging
import shutil
from contextlib import suppress
@ -29,6 +30,45 @@ if is_win():
else:
from pathlib import PosixPath as PathVariant
log = logging.getLogger(__name__)
class Path(PathVariant):
"""
Subclass pathlib.Path, so we can add json conversion methods
"""
@staticmethod
def encode_json(obj, base_path=None, **kwargs):
"""
Create a Path object from a dictionary representation. The dictionary has been constructed by JSON encoding of
a JSON reprensation of a Path object.
:param dict[str] obj: The dictionary representation
:param openlp.core.common.path.Path base_path: If specified, an absolute path to base the relative path off of.
:param kwargs: Contains any extra parameters. Not used!
:return: The reconstructed Path object
:rtype: openlp.core.common.path.Path
"""
path = Path(*obj['__Path__'])
if base_path and not path.is_absolute():
return base_path / path
return path
def json_object(self, base_path=None, **kwargs):
"""
Create a dictionary that can be JSON decoded.
:param openlp.core.common.path.Path base_path: If specified, an absolute path to make a relative path from.
:param kwargs: Contains any extra parameters. Not used!
:return: The dictionary representation of this Path object.
:rtype: dict[tuple]
"""
path = self
if base_path:
with suppress(ValueError):
path = path.relative_to(base_path)
return {'__Path__': path.parts}
def replace_params(args, kwargs, params):
"""
@ -179,38 +219,32 @@ def str_to_path(string):
return Path(string)
class Path(PathVariant):
def create_paths(*paths, **kwargs):
"""
Subclass pathlib.Path, so we can add json conversion methods
Create one or more paths
:param openlp.core.common.path.Path paths: The paths to create
:param bool do_not_log: To not log anything. This is need for the start up, when the log isn't ready.
:rtype: None
"""
@staticmethod
def encode_json(obj, base_path=None, **kwargs):
"""
Create a Path object from a dictionary representation. The dictionary has been constructed by JSON encoding of
a JSON reprensation of a Path object.
for path in paths:
if not kwargs.get('do_not_log', False):
log.debug('create_path {path}'.format(path=path))
try:
if not path.exists():
path.mkdir(parents=True)
except IOError:
if not kwargs.get('do_not_log', False):
log.exception('failed to check if directory exists or create directory')
:param dict[str] obj: The dictionary representation
:param openlp.core.common.path.Path base_path: If specified, an absolute path to base the relative path off of.
:param kwargs: Contains any extra parameters. Not used!
:return: The reconstructed Path object
:rtype: openlp.core.common.path.Path
"""
path = Path(*obj['__Path__'])
if base_path and not path.is_absolute():
return base_path / path
return path
def json_object(self, base_path=None, **kwargs):
"""
Create a dictionary that can be JSON decoded.
def files_to_paths(file_names):
"""
Convert a list of file names in to a list of file paths.
:param openlp.core.common.path.Path base_path: If specified, an absolute path to make a relative path from.
:param kwargs: Contains any extra parameters. Not used!
:return: The dictionary representation of this Path object.
:rtype: dict[tuple]
"""
path = self
if base_path:
with suppress(ValueError):
path = path.relative_to(base_path)
return {'__Path__': path.parts}
:param list[str] file_names: The list of file names to convert.
:return: The list converted to file paths
:rtype: openlp.core.common.path.Path
"""
if file_names:
return [str_to_path(file_name) for file_name in file_names]

View File

@ -25,7 +25,7 @@ Provide Registry Services
import logging
import sys
from openlp.core.common import trace_error_handler
from openlp.core.common import is_win, trace_error_handler
log = logging.getLogger(__name__)
@ -176,3 +176,130 @@ class Registry(object):
"""
if key in self.working_flags:
del self.working_flags[key]
class RegistryProperties(object):
"""
This adds registry components to classes to use at run time.
"""
@property
def application(self):
"""
Adds the openlp to the class dynamically.
Windows needs to access the application in a dynamic manner.
"""
if is_win():
return Registry().get('application')
else:
if not hasattr(self, '_application') or not self._application:
self._application = Registry().get('application')
return self._application
@property
def plugin_manager(self):
"""
Adds the plugin manager to the class dynamically
"""
if not hasattr(self, '_plugin_manager') or not self._plugin_manager:
self._plugin_manager = Registry().get('plugin_manager')
return self._plugin_manager
@property
def image_manager(self):
"""
Adds the image manager to the class dynamically
"""
if not hasattr(self, '_image_manager') or not self._image_manager:
self._image_manager = Registry().get('image_manager')
return self._image_manager
@property
def media_controller(self):
"""
Adds the media controller to the class dynamically
"""
if not hasattr(self, '_media_controller') or not self._media_controller:
self._media_controller = Registry().get('media_controller')
return self._media_controller
@property
def service_manager(self):
"""
Adds the service manager to the class dynamically
"""
if not hasattr(self, '_service_manager') or not self._service_manager:
self._service_manager = Registry().get('service_manager')
return self._service_manager
@property
def preview_controller(self):
"""
Adds the preview controller to the class dynamically
"""
if not hasattr(self, '_preview_controller') or not self._preview_controller:
self._preview_controller = Registry().get('preview_controller')
return self._preview_controller
@property
def live_controller(self):
"""
Adds the live controller to the class dynamically
"""
if not hasattr(self, '_live_controller') or not self._live_controller:
self._live_controller = Registry().get('live_controller')
return self._live_controller
@property
def main_window(self):
"""
Adds the main window to the class dynamically
"""
if not hasattr(self, '_main_window') or not self._main_window:
self._main_window = Registry().get('main_window')
return self._main_window
@property
def renderer(self):
"""
Adds the Renderer to the class dynamically
"""
if not hasattr(self, '_renderer') or not self._renderer:
self._renderer = Registry().get('renderer')
return self._renderer
@property
def theme_manager(self):
"""
Adds the theme manager to the class dynamically
"""
if not hasattr(self, '_theme_manager') or not self._theme_manager:
self._theme_manager = Registry().get('theme_manager')
return self._theme_manager
@property
def settings_form(self):
"""
Adds the settings form to the class dynamically
"""
if not hasattr(self, '_settings_form') or not self._settings_form:
self._settings_form = Registry().get('settings_form')
return self._settings_form
@property
def alerts_manager(self):
"""
Adds the alerts manager to the class dynamically
"""
if not hasattr(self, '_alerts_manager') or not self._alerts_manager:
self._alerts_manager = Registry().get('alerts_manager')
return self._alerts_manager
@property
def projector_manager(self):
"""
Adds the projector manager to the class dynamically
"""
if not hasattr(self, '_projector_manager') or not self._projector_manager:
self._projector_manager = Registry().get('projector_manager')
return self._projector_manager

View File

@ -1,152 +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 #
###############################################################################
"""
Provide Registry values for adding to classes
"""
from openlp.core.common import Registry, is_win
class RegistryProperties(object):
"""
This adds registry components to classes to use at run time.
"""
@property
def application(self):
"""
Adds the openlp to the class dynamically.
Windows needs to access the application in a dynamic manner.
"""
if is_win():
return Registry().get('application')
else:
if not hasattr(self, '_application') or not self._application:
self._application = Registry().get('application')
return self._application
@property
def plugin_manager(self):
"""
Adds the plugin manager to the class dynamically
"""
if not hasattr(self, '_plugin_manager') or not self._plugin_manager:
self._plugin_manager = Registry().get('plugin_manager')
return self._plugin_manager
@property
def image_manager(self):
"""
Adds the image manager to the class dynamically
"""
if not hasattr(self, '_image_manager') or not self._image_manager:
self._image_manager = Registry().get('image_manager')
return self._image_manager
@property
def media_controller(self):
"""
Adds the media controller to the class dynamically
"""
if not hasattr(self, '_media_controller') or not self._media_controller:
self._media_controller = Registry().get('media_controller')
return self._media_controller
@property
def service_manager(self):
"""
Adds the service manager to the class dynamically
"""
if not hasattr(self, '_service_manager') or not self._service_manager:
self._service_manager = Registry().get('service_manager')
return self._service_manager
@property
def preview_controller(self):
"""
Adds the preview controller to the class dynamically
"""
if not hasattr(self, '_preview_controller') or not self._preview_controller:
self._preview_controller = Registry().get('preview_controller')
return self._preview_controller
@property
def live_controller(self):
"""
Adds the live controller to the class dynamically
"""
if not hasattr(self, '_live_controller') or not self._live_controller:
self._live_controller = Registry().get('live_controller')
return self._live_controller
@property
def main_window(self):
"""
Adds the main window to the class dynamically
"""
if not hasattr(self, '_main_window') or not self._main_window:
self._main_window = Registry().get('main_window')
return self._main_window
@property
def renderer(self):
"""
Adds the Renderer to the class dynamically
"""
if not hasattr(self, '_renderer') or not self._renderer:
self._renderer = Registry().get('renderer')
return self._renderer
@property
def theme_manager(self):
"""
Adds the theme manager to the class dynamically
"""
if not hasattr(self, '_theme_manager') or not self._theme_manager:
self._theme_manager = Registry().get('theme_manager')
return self._theme_manager
@property
def settings_form(self):
"""
Adds the settings form to the class dynamically
"""
if not hasattr(self, '_settings_form') or not self._settings_form:
self._settings_form = Registry().get('settings_form')
return self._settings_form
@property
def alerts_manager(self):
"""
Adds the alerts manager to the class dynamically
"""
if not hasattr(self, '_alerts_manager') or not self._alerts_manager:
self._alerts_manager = Registry().get('alerts_manager')
return self._alerts_manager
@property
def projector_manager(self):
"""
Adds the projector manager to the class dynamically
"""
if not hasattr(self, '_projector_manager') or not self._projector_manager:
self._projector_manager = Registry().get('projector_manager')
return self._projector_manager

View File

@ -28,11 +28,11 @@ import json
import os
from tempfile import gettempdir
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5 import QtCore, QtGui
from openlp.core.common import SlideLimits, ThemeLevel, UiStrings, is_linux, is_win, translate
from openlp.core.common import SlideLimits, ThemeLevel, is_linux, is_win
from openlp.core.common.json import OpenLPJsonDecoder, OpenLPJsonEncoder
from openlp.core.common.path import Path, str_to_path
from openlp.core.common.path import Path, str_to_path, files_to_paths
log = logging.getLogger(__name__)
@ -62,18 +62,6 @@ def media_players_conv(string):
return string
def file_names_conv(file_names):
"""
Convert a list of file names in to a list of file paths.
:param list[str] file_names: The list of file names to convert.
:return: The list converted to file paths
:rtype: openlp.core.common.path.Path
"""
if file_names:
return [str_to_path(file_name) for file_name in file_names]
class Settings(QtCore.QSettings):
"""
Class to wrap QSettings.
@ -116,7 +104,7 @@ class Settings(QtCore.QSettings):
'advanced/default service enabled': True,
'advanced/default service hour': 11,
'advanced/default service minute': 0,
'advanced/default service name': UiStrings().DefaultServiceName,
'advanced/default service name': 'Service %Y-%m-%d %H-%M',
'advanced/display size': 0,
'advanced/double click live': False,
'advanced/enable exit confirmation': True,
@ -261,9 +249,9 @@ class Settings(QtCore.QSettings):
('songs/last directory import', 'songs/last directory import', [(str_to_path, None)]),
('songs/last directory export', 'songs/last directory export', [(str_to_path, None)]),
('songusage/last directory export', 'songusage/last directory export', [(str_to_path, None)]),
('core/recent files', 'core/recent files', [(file_names_conv, None)]),
('media/media files', 'media/media files', [(file_names_conv, None)]),
('presentations/presentations files', 'presentations/presentations files', [(file_names_conv, None)]),
('core/recent files', 'core/recent files', [(files_to_paths, None)]),
('media/media files', 'media/media files', [(files_to_paths, None)]),
('presentations/presentations files', 'presentations/presentations files', [(files_to_paths, None)]),
('core/logo file', 'core/logo file', [(str_to_path, None)]),
('presentations/last directory', 'presentations/last directory', [(str_to_path, None)]),
('images/last directory', 'images/last directory', [(str_to_path, None)]),
@ -298,6 +286,7 @@ class Settings(QtCore.QSettings):
"""
# Make sure the string is translated (when building the dict the string is not translated because the translate
# function was not set up as this stage).
from openlp.core.common.i18n import UiStrings
Settings.__default_settings__['advanced/default service name'] = UiStrings().DefaultServiceName
def __init__(self, *args):
@ -609,11 +598,5 @@ class Settings(QtCore.QSettings):
if file_record.find('@Invalid()') == -1:
file_record = file_record.replace('%20', ' ')
export_conf_file.write(file_record)
except OSError as ose:
QtWidgets.QMessageBox.critical(self, translate('OpenLP.MainWindow', 'Export setting error'),
translate('OpenLP.MainWindow',
'An error occurred while exporting the settings: {err}'
).format(err=ose.strerror),
QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Ok))
finally:
temp_path.unlink()

View File

@ -1,187 +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 #
###############################################################################
"""
The :mod:`uistrings` module provides standard strings for OpenLP.
"""
import logging
import itertools
from openlp.core.common import translate
log = logging.getLogger(__name__)
class UiStrings(object):
"""
Provide standard strings for objects to use.
"""
__instance__ = None
def __new__(cls):
"""
Override the default object creation method to return a single instance.
"""
if not cls.__instance__:
cls.__instance__ = object.__new__(cls)
return cls.__instance__
def __init__(self):
"""
These strings should need a good reason to be retranslated elsewhere.
Should some/more/less of these have an &amp; attached?
"""
self.About = translate('OpenLP.Ui', 'About')
self.Add = translate('OpenLP.Ui', '&Add')
self.AddGroup = translate('OpenLP.Ui', 'Add group')
self.AddGroupDot = translate('OpenLP.Ui', 'Add group.')
self.Advanced = translate('OpenLP.Ui', 'Advanced')
self.AllFiles = translate('OpenLP.Ui', 'All Files')
self.Automatic = translate('OpenLP.Ui', 'Automatic')
self.BackgroundColor = translate('OpenLP.Ui', 'Background Color')
self.BackgroundColorColon = translate('OpenLP.Ui', 'Background color:')
self.BibleShortSearchTitle = translate('OpenLP.Ui', 'Search is Empty or too Short')
self.BibleShortSearch = translate('OpenLP.Ui', '<strong>The search you have entered is empty or shorter '
'than 3 characters long.</strong><br><br>Please try again with '
'a longer search.')
self.BibleNoBiblesTitle = translate('OpenLP.Ui', 'No Bibles Available')
self.BibleNoBibles = translate('OpenLP.Ui', '<strong>There are no Bibles currently installed.</strong><br><br>'
'Please use the Import Wizard to install one or more Bibles.')
self.Bottom = translate('OpenLP.Ui', 'Bottom')
self.Browse = translate('OpenLP.Ui', 'Browse...')
self.Cancel = translate('OpenLP.Ui', 'Cancel')
self.CCLINumberLabel = translate('OpenLP.Ui', 'CCLI number:')
self.CCLISongNumberLabel = translate('OpenLP.Ui', 'CCLI song number:')
self.CreateService = translate('OpenLP.Ui', 'Create a new service.')
self.ConfirmDelete = translate('OpenLP.Ui', 'Confirm Delete')
self.Continuous = translate('OpenLP.Ui', 'Continuous')
self.Default = translate('OpenLP.Ui', 'Default')
self.DefaultColor = translate('OpenLP.Ui', 'Default Color:')
self.DefaultServiceName = translate('OpenLP.Ui', 'Service %Y-%m-%d %H-%M',
'This may not contain any of the following characters: /\\?*|<>[]":+\n'
'See http://docs.python.org/library/datetime'
'.html#strftime-strptime-behavior for more information.')
self.Delete = translate('OpenLP.Ui', '&Delete')
self.DisplayStyle = translate('OpenLP.Ui', 'Display style:')
self.Duplicate = translate('OpenLP.Ui', 'Duplicate Error')
self.Edit = translate('OpenLP.Ui', '&Edit')
self.EmptyField = translate('OpenLP.Ui', 'Empty Field')
self.Error = translate('OpenLP.Ui', 'Error')
self.Export = translate('OpenLP.Ui', 'Export')
self.File = translate('OpenLP.Ui', 'File')
self.FontSizePtUnit = translate('OpenLP.Ui', 'pt', 'Abbreviated font pointsize unit')
self.Help = translate('OpenLP.Ui', 'Help')
self.Hours = translate('OpenLP.Ui', 'h', 'The abbreviated unit for hours')
self.IFdSs = translate('OpenLP.Ui', 'Invalid Folder Selected', 'Singular')
self.IFSs = translate('OpenLP.Ui', 'Invalid File Selected', 'Singular')
self.IFSp = translate('OpenLP.Ui', 'Invalid Files Selected', 'Plural')
self.Image = translate('OpenLP.Ui', 'Image')
self.Import = translate('OpenLP.Ui', 'Import')
self.LayoutStyle = translate('OpenLP.Ui', 'Layout style:')
self.Live = translate('OpenLP.Ui', 'Live')
self.LiveBGError = translate('OpenLP.Ui', 'Live Background Error')
self.LiveToolbar = translate('OpenLP.Ui', 'Live Toolbar')
self.Load = translate('OpenLP.Ui', 'Load')
self.Manufacturer = translate('OpenLP.Ui', 'Manufacturer', 'Singular')
self.Manufacturers = translate('OpenLP.Ui', 'Manufacturers', 'Plural')
self.Model = translate('OpenLP.Ui', 'Model', 'Singular')
self.Models = translate('OpenLP.Ui', 'Models', 'Plural')
self.Minutes = translate('OpenLP.Ui', 'm', 'The abbreviated unit for minutes')
self.Middle = translate('OpenLP.Ui', 'Middle')
self.New = translate('OpenLP.Ui', 'New')
self.NewService = translate('OpenLP.Ui', 'New Service')
self.NewTheme = translate('OpenLP.Ui', 'New Theme')
self.NextTrack = translate('OpenLP.Ui', 'Next Track')
self.NFdSs = translate('OpenLP.Ui', 'No Folder Selected', 'Singular')
self.NFSs = translate('OpenLP.Ui', 'No File Selected', 'Singular')
self.NFSp = translate('OpenLP.Ui', 'No Files Selected', 'Plural')
self.NISs = translate('OpenLP.Ui', 'No Item Selected', 'Singular')
self.NISp = translate('OpenLP.Ui', 'No Items Selected', 'Plural')
self.NoResults = translate('OpenLP.Ui', 'No Search Results')
self.OpenLP = translate('OpenLP.Ui', 'OpenLP')
self.OpenLPv2AndUp = translate('OpenLP.Ui', 'OpenLP 2.0 and up')
self.OpenLPStart = translate('OpenLP.Ui', 'OpenLP is already running. Do you wish to continue?')
self.OpenService = translate('OpenLP.Ui', 'Open service.')
self.OptionalShowInFooter = translate('OpenLP.Ui', 'Optional, this will be displayed in footer.')
self.OptionalHideInFooter = translate('OpenLP.Ui', 'Optional, this won\'t be displayed in footer.')
self.PlaySlidesInLoop = translate('OpenLP.Ui', 'Play Slides in Loop')
self.PlaySlidesToEnd = translate('OpenLP.Ui', 'Play Slides to End')
self.Preview = translate('OpenLP.Ui', 'Preview')
self.PreviewToolbar = translate('OpenLP.Ui', 'Preview Toolbar')
self.PrintService = translate('OpenLP.Ui', 'Print Service')
self.Projector = translate('OpenLP.Ui', 'Projector', 'Singular')
self.Projectors = translate('OpenLP.Ui', 'Projectors', 'Plural')
self.ReplaceBG = translate('OpenLP.Ui', 'Replace Background')
self.ReplaceLiveBG = translate('OpenLP.Ui', 'Replace live background.')
self.ReplaceLiveBGDisabled = translate('OpenLP.Ui', 'Replace live background is not available when the WebKit '
'player is disabled.')
self.ResetBG = translate('OpenLP.Ui', 'Reset Background')
self.ResetLiveBG = translate('OpenLP.Ui', 'Reset live background.')
self.RequiredShowInFooter = translate('OpenLP.Ui', 'Required, this will be displayed in footer.')
self.Seconds = translate('OpenLP.Ui', 's', 'The abbreviated unit for seconds')
self.SaveAndPreview = translate('OpenLP.Ui', 'Save && Preview')
self.Search = translate('OpenLP.Ui', 'Search')
self.SearchThemes = translate('OpenLP.Ui', 'Search Themes...', 'Search bar place holder text ')
self.SelectDelete = translate('OpenLP.Ui', 'You must select an item to delete.')
self.SelectEdit = translate('OpenLP.Ui', 'You must select an item to edit.')
self.Settings = translate('OpenLP.Ui', 'Settings')
self.SaveService = translate('OpenLP.Ui', 'Save Service')
self.Service = translate('OpenLP.Ui', 'Service')
self.ShortResults = translate('OpenLP.Ui', 'Please type more text to use \'Search As You Type\'')
self.Split = translate('OpenLP.Ui', 'Optional &Split')
self.SplitToolTip = translate('OpenLP.Ui',
'Split a slide into two only if it does not fit on the screen as one slide.')
self.StartingImport = translate('OpenLP.Ui', 'Starting import...')
self.StopPlaySlidesInLoop = translate('OpenLP.Ui', 'Stop Play Slides in Loop')
self.StopPlaySlidesToEnd = translate('OpenLP.Ui', 'Stop Play Slides to End')
self.Theme = translate('OpenLP.Ui', 'Theme', 'Singular')
self.Themes = translate('OpenLP.Ui', 'Themes', 'Plural')
self.Tools = translate('OpenLP.Ui', 'Tools')
self.Top = translate('OpenLP.Ui', 'Top')
self.UnsupportedFile = translate('OpenLP.Ui', 'Unsupported File')
self.VersePerSlide = translate('OpenLP.Ui', 'Verse Per Slide')
self.VersePerLine = translate('OpenLP.Ui', 'Verse Per Line')
self.Version = translate('OpenLP.Ui', 'Version')
self.View = translate('OpenLP.Ui', 'View')
self.ViewMode = translate('OpenLP.Ui', 'View Mode')
self.Video = translate('OpenLP.Ui', 'Video')
self.WebDownloadText = translate('OpenLP.Ui', 'Web Interface, Download and Install latest Version')
book_chapter = translate('OpenLP.Ui', 'Book Chapter')
chapter = translate('OpenLP.Ui', 'Chapter')
verse = translate('OpenLP.Ui', 'Verse')
gap = ' | '
psalm = translate('OpenLP.Ui', 'Psalm')
may_shorten = translate('OpenLP.Ui', 'Book names may be shortened from full names, for an example Ps 23 = '
'Psalm 23')
bible_scripture_items = \
[book_chapter, gap, psalm, ' 23<br>',
book_chapter, '%(range)s', chapter, gap, psalm, ' 23%(range)s24<br>',
book_chapter, '%(verse)s', verse, '%(range)s', verse, gap, psalm, ' 23%(verse)s1%(range)s2<br>',
book_chapter, '%(verse)s', verse, '%(range)s', verse, '%(list)s', verse, '%(range)s', verse, gap, psalm,
' 23%(verse)s1%(range)s2%(list)s5%(range)s6<br>',
book_chapter, '%(verse)s', verse, '%(range)s', verse, '%(list)s', chapter, '%(verse)s', verse, '%(range)s',
verse, gap, psalm, ' 23%(verse)s1%(range)s2%(list)s24%(verse)s1%(range)s3<br>',
book_chapter, '%(verse)s', verse, '%(range)s', chapter, '%(verse)s', verse, gap, psalm,
' 23%(verse)s1%(range)s24%(verse)s1<br><br>', may_shorten]
itertools.chain.from_iterable(itertools.repeat(strings, 1) if isinstance(strings, str)
else strings for strings in bible_scripture_items)
self.BibleScriptureError = ''.join(str(joined) for joined in bible_scripture_items)

View File

@ -20,35 +20,5 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
Provide Registry Services
The :mod:`~openlp.core.display` module contains all the code related to rendering and output
"""
from openlp.core.common import Registry, de_hump
class RegistryMixin(object):
"""
This adds registry components to classes to use at run time.
"""
def __init__(self, parent):
"""
Register the class and bootstrap hooks.
"""
try:
super(RegistryMixin, self).__init__(parent)
except TypeError:
super(RegistryMixin, self).__init__()
Registry().register(de_hump(self.__class__.__name__), self)
Registry().register_function('bootstrap_initialise', self.bootstrap_initialise)
Registry().register_function('bootstrap_post_set_up', self.bootstrap_post_set_up)
def bootstrap_initialise(self):
"""
Dummy method to be overridden
"""
pass
def bootstrap_post_set_up(self):
"""
Dummy method to be overridden
"""
pass

View File

@ -25,12 +25,15 @@ import re
from string import Template
from PyQt5 import QtGui, QtCore, QtWebKitWidgets
from openlp.core.common import Registry, RegistryProperties, OpenLPMixin, RegistryMixin, Settings
from openlp.core.common.mixins import OpenLPMixin, RegistryMixin
from openlp.core.common.path import path_to_str
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.common.registry import Registry, RegistryProperties
from openlp.core.common.settings import Settings
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' \
@ -243,6 +246,9 @@ class Renderer(OpenLPMixin, RegistryMixin, RegistryProperties):
elif item.is_capable(ItemCapabilities.CanSoftBreak):
pages = []
if '[---]' in text:
# Remove Overflow split if at start of the text
if text.startswith('[---]'):
text = text[5:]
# Remove two or more option slide breaks next to each other (causing infinite loop).
while '\n[---]\n[---]\n' in text:
text = text.replace('\n[---]\n[---]\n', '\n[---]\n')

View File

@ -23,13 +23,14 @@
The :mod:`screen` module provides management functionality for a machines'
displays.
"""
import logging
import copy
from PyQt5 import QtCore
from openlp.core.common import Registry, Settings, translate
from openlp.core.common.registry import Registry
from openlp.core.common.settings import Settings
from openlp.core.common.i18n import translate
log = logging.getLogger(__name__)

View File

@ -29,9 +29,9 @@ import os
import re
import math
from PyQt5 import QtCore, QtGui, Qt, QtWidgets
from PyQt5 import QtCore, QtGui, QtWidgets
from openlp.core.common import translate
from openlp.core.common.i18n import translate
from openlp.core.common.path import Path
log = logging.getLogger(__name__ + '.__init__')
@ -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

View File

@ -29,17 +29,19 @@ import os
from copy import copy
from urllib.parse import quote_plus as urlquote
from sqlalchemy import Table, MetaData, Column, types, create_engine, UnicodeText
from alembic.migration import MigrationContext
from alembic.operations import Operations
from sqlalchemy import Table, MetaData, Column, UnicodeText, types, create_engine
from sqlalchemy.engine.url import make_url
from sqlalchemy.exc import SQLAlchemyError, InvalidRequestError, DBAPIError, OperationalError, ProgrammingError
from sqlalchemy.orm import scoped_session, sessionmaker, mapper
from sqlalchemy.pool import NullPool
from alembic.migration import MigrationContext
from alembic.operations import Operations
from openlp.core.common import AppLocation, Settings, delete_file, translate
from openlp.core.common import delete_file
from openlp.core.common.applocation import AppLocation
from openlp.core.common.i18n import translate
from openlp.core.common.json import OpenLPJsonDecoder, OpenLPJsonEncoder
from openlp.core.common.settings import Settings
from openlp.core.lib.ui import critical_error_message_box
log = logging.getLogger(__name__)

View File

@ -24,8 +24,8 @@ Provide HTML Tag management and Formatting Tag access class
"""
import json
from openlp.core.common import Settings
from openlp.core.lib import translate
from openlp.core.common.settings import Settings
from openlp.core.common.i18n import translate
class FormattingTags(object):

View File

@ -411,7 +411,7 @@ import logging
from string import Template
from PyQt5 import QtWebKit
from openlp.core.common import Settings
from openlp.core.common.settings import Settings
from openlp.core.lib.theme import BackgroundType, BackgroundGradientType, VerticalType, HorizontalType
log = logging.getLogger(__name__)

View File

@ -31,8 +31,10 @@ import queue
from PyQt5 import QtCore
from openlp.core.common import Registry, Settings
from openlp.core.lib import ScreenList, resize_image, image_to_byte
from openlp.core.common.registry import Registry
from openlp.core.common.settings import Settings
from openlp.core.display.screens import ScreenList
from openlp.core.lib import resize_image, image_to_byte
log = logging.getLogger(__name__)

View File

@ -28,8 +28,10 @@ import re
from PyQt5 import QtCore, QtWidgets
from openlp.core.common import Registry, RegistryProperties, Settings, UiStrings, translate
from openlp.core.common.i18n import UiStrings, translate
from openlp.core.common.path import Path, 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 ServiceItem, StringContent, ServiceItemContext
from openlp.core.lib.searchedit import SearchEdit
from openlp.core.lib.ui import create_widget_action, critical_error_message_box

View File

@ -26,7 +26,9 @@ import logging
from PyQt5 import QtCore
from openlp.core.common import Registry, RegistryProperties, Settings, UiStrings
from openlp.core.common.registry import Registry, RegistryProperties
from openlp.core.common.settings import Settings
from openlp.core.common.i18n import UiStrings
from openlp.core.version import get_version
log = logging.getLogger(__name__)

View File

@ -24,8 +24,11 @@ Provide plugin management
"""
import os
from openlp.core.common import extension_loader
from openlp.core.common.applocation import AppLocation
from openlp.core.common.registry import RegistryProperties
from openlp.core.common.mixins import OpenLPMixin, RegistryMixin
from openlp.core.lib import Plugin, PluginStatus
from openlp.core.common import AppLocation, RegistryProperties, OpenLPMixin, RegistryMixin, extension_loader
class PluginManager(RegistryMixin, OpenLPMixin, RegistryProperties):

View File

@ -20,37 +20,15 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
:mod:`openlp.core.lib.projector.constants` module
Provides the constants used for projector errors/status/defaults
The :mod:`openlp.core.lib.projector.constants` module provides the constants used for projector errors/status/defaults
"""
import logging
from openlp.core.common.i18n import translate
log = logging.getLogger(__name__)
log.debug('projector_constants loaded')
from openlp.core.common import translate
__all__ = ['S_OK', 'E_GENERAL', 'E_NOT_CONNECTED', 'E_FAN', 'E_LAMP', 'E_TEMP',
'E_COVER', 'E_FILTER', 'E_AUTHENTICATION', 'E_NO_AUTHENTICATION',
'E_UNDEFINED', 'E_PARAMETER', 'E_UNAVAILABLE', 'E_PROJECTOR',
'E_INVALID_DATA', 'E_WARN', 'E_ERROR', 'E_CLASS', 'E_PREFIX',
'E_CONNECTION_REFUSED', 'E_REMOTE_HOST_CLOSED_CONNECTION', 'E_HOST_NOT_FOUND',
'E_SOCKET_ACCESS', 'E_SOCKET_RESOURCE', 'E_SOCKET_TIMEOUT', 'E_DATAGRAM_TOO_LARGE',
'E_NETWORK', 'E_ADDRESS_IN_USE', 'E_SOCKET_ADDRESS_NOT_AVAILABLE',
'E_UNSUPPORTED_SOCKET_OPERATION', 'E_PROXY_AUTHENTICATION_REQUIRED',
'E_SLS_HANDSHAKE_FAILED', 'E_UNFINISHED_SOCKET_OPERATION', 'E_PROXY_CONNECTION_REFUSED',
'E_PROXY_CONNECTION_CLOSED', 'E_PROXY_CONNECTION_TIMEOUT', 'E_PROXY_NOT_FOUND',
'E_PROXY_PROTOCOL', 'E_UNKNOWN_SOCKET_ERROR',
'S_NOT_CONNECTED', 'S_CONNECTING', 'S_CONNECTED',
'S_STATUS', 'S_OFF', 'S_INITIALIZE', 'S_STANDBY', 'S_WARMUP', 'S_ON', 'S_COOLDOWN',
'S_INFO', 'S_NETWORK_SENDING', 'S_NETWORK_RECEIVED',
'ERROR_STRING', 'CR', 'LF', 'PJLINK_ERST_DATA', 'PJLINK_ERST_STATUS', 'PJLINK_POWR_STATUS',
'PJLINK_PORT', 'PJLINK_MAX_PACKET', 'TIMEOUT', 'ERROR_MSG', 'PJLINK_ERRORS',
'STATUS_STRING', 'PJLINK_VALID_CMD', 'CONNECTION_ERRORS',
'PJLINK_DEFAULT_SOURCES', 'PJLINK_DEFAULT_CODES', 'PJLINK_DEFAULT_ITEMS']
# Set common constants.
CR = chr(0x0D) # \r
LF = chr(0x0A) # \n

View File

@ -20,39 +20,40 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
:mod:`openlp.core.lib.projector.pjlink` module
Provides the necessary functions for connecting to a PJLink-capable projector.
The :mod:`openlp.core.lib.projector.pjlink` module provides the necessary functions for connecting to a PJLink-capable
projector.
PJLink Class 1 Specifications.
http://pjlink.jbmia.or.jp/english/dl_class1.html
Section 5-1 PJLink Specifications
Section 5-5 Guidelines for Input Terminals
PJLink Class 1 Specifications
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
PJLink Class 2 Specifications.
http://pjlink.jbmia.or.jp/english/dl_class2.html
Section 5-1 PJLink Specifications
Section 5-5 Guidelines for Input Terminals
Website: http://pjlink.jbmia.or.jp/english/dl_class1.html
NOTE:
Function names follow the following syntax:
def process_CCCC(...):
WHERE:
CCCC = PJLink command being processed.
- Section 5-1 PJLink Specifications
- Section 5-5 Guidelines for Input Terminals
PJLink Class 2 Specifications
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Website: http://pjlink.jbmia.or.jp/english/dl_class2.html
- Section 5-1 PJLink Specifications
- Section 5-5 Guidelines for Input Terminals
.. note:
Function names follow the following syntax::
def process_CCCC(...):
where ``CCCC`` is the PJLink command being processed
"""
import logging
log = logging.getLogger(__name__)
log.debug('pjlink loaded')
__all__ = ['PJLink']
import re
from codecs import decode
from PyQt5 import QtCore, QtNetwork
from openlp.core.common import translate, qmd5_hash
from openlp.core.common import qmd5_hash
from openlp.core.common.i18n import translate
from openlp.core.lib.projector.constants import CONNECTION_ERRORS, CR, ERROR_MSG, ERROR_STRING, \
E_AUTHENTICATION, E_CONNECTION_REFUSED, E_GENERAL, E_INVALID_DATA, E_NETWORK, E_NOT_CONNECTED, E_OK, \
E_PARAMETER, E_PROJECTOR, E_SOCKET_TIMEOUT, E_UNAVAILABLE, E_UNDEFINED, PJLINK_ERRORS, PJLINK_ERST_DATA, \
@ -60,6 +61,11 @@ from openlp.core.lib.projector.constants import CONNECTION_ERRORS, CR, ERROR_MSG
STATUS_STRING, S_CONNECTED, S_CONNECTING, S_INFO, S_NETWORK_RECEIVED, S_NETWORK_SENDING, \
S_NOT_CONNECTED, S_OFF, S_OK, S_ON, S_STATUS
log = logging.getLogger(__name__)
log.debug('pjlink loaded')
__all__ = ['PJLink']
# Shortcuts
SocketError = QtNetwork.QAbstractSocket.SocketError
SocketSTate = QtNetwork.QAbstractSocket.SocketState

View File

@ -24,9 +24,9 @@ import logging
from PyQt5 import QtCore, QtWidgets
from openlp.core.common.settings import Settings
from openlp.core.lib import build_icon
from openlp.core.lib.ui import create_widget_action
from openlp.core.common import Settings
log = logging.getLogger(__name__)

View File

@ -23,7 +23,6 @@
The :mod:`serviceitem` provides the service item functionality including the
type and capability of an item.
"""
import datetime
import html
import logging
@ -33,8 +32,12 @@ import ntpath
from PyQt5 import QtGui
from openlp.core.common import RegistryProperties, Settings, translate, AppLocation, md5_hash
from openlp.core.lib import ImageSource, build_icon, clean_tags, expand_tags, expand_chords, create_thumb
from openlp.core.common import md5_hash
from openlp.core.common.applocation import AppLocation
from openlp.core.common.i18n import translate
from openlp.core.common.registry import RegistryProperties
from openlp.core.common.settings import Settings
from openlp.core.lib import ImageSource, build_icon, clean_tags, expand_tags, expand_chords
log = logging.getLogger(__name__)

View File

@ -23,12 +23,9 @@
The :mod:`~openlp.core.lib.settingstab` module contains the base SettingsTab class which plugins use for adding their
own tab to the settings dialog.
"""
from PyQt5 import QtWidgets
from openlp.core.common import RegistryProperties
from openlp.core.common.registry import RegistryProperties
class SettingsTab(QtWidgets.QWidget, RegistryProperties):

View File

@ -26,10 +26,12 @@ import json
import logging
from lxml import etree, objectify
from openlp.core.common import AppLocation, de_hump
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.common.path import Path, str_to_path
from openlp.core.lib import str_to_bool, ScreenList, 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__)

View File

@ -26,8 +26,10 @@ import logging
from PyQt5 import QtCore, QtGui, QtWidgets
from openlp.core.common import Registry, UiStrings, translate, is_macosx
from openlp.core.common import is_macosx
from openlp.core.common.actions import ActionList
from openlp.core.common.i18n import UiStrings, translate
from openlp.core.common.registry import Registry
from openlp.core.lib import build_icon

View File

@ -23,7 +23,7 @@ import datetime
from PyQt5 import QtGui, QtWidgets
from openlp.core.common import UiStrings, translate
from openlp.core.common.i18n import UiStrings, translate
from openlp.core.lib import build_icon
from openlp.core.lib.ui import create_button, create_button_box

View File

@ -27,7 +27,7 @@ import webbrowser
from PyQt5 import QtCore, QtWidgets
from openlp.core.version import get_version
from openlp.core.lib import translate
from openlp.core.common.i18n import translate
from .aboutdialog import UiAboutDialog

View File

@ -27,9 +27,10 @@ from datetime import datetime, timedelta
from PyQt5 import QtCore, QtGui, QtWidgets
from openlp.core.common import AppLocation, Settings, SlideLimits, UiStrings, translate
from openlp.core.common.languagemanager import format_time
from openlp.core.common.path import path_to_str
from openlp.core.common import SlideLimits
from openlp.core.common.applocation import AppLocation
from openlp.core.common.i18n import UiStrings, format_time, translate
from openlp.core.common.settings import Settings
from openlp.core.lib import SettingsTab, build_icon
from openlp.core.ui.lib import PathEdit, PathType
from openlp.core.ui.style import HAS_DARK_STYLE

View File

@ -25,7 +25,8 @@ The GUI widgets of the exception dialog.
from PyQt5 import QtGui, QtWidgets
from openlp.core.lib import translate, build_icon
from openlp.core.common.i18n import translate
from openlp.core.lib import build_icon
from openlp.core.lib.ui import create_button, create_button_box

View File

@ -70,11 +70,14 @@ try:
except ImportError:
VLC_VERSION = '-'
from openlp.core.common import RegistryProperties, Settings, UiStrings, is_linux, translate
from openlp.core.version import get_version
from openlp.core.common import is_linux
from openlp.core.common.i18n import UiStrings, translate
from openlp.core.common.registry import RegistryProperties
from openlp.core.common.settings import Settings
from openlp.core.ui.exceptiondialog import Ui_ExceptionDialog
from openlp.core.ui.lib.filedialog import FileDialog
from openlp.core.version import get_version
from .exceptiondialog import Ui_ExceptionDialog
log = logging.getLogger(__name__)

View File

@ -24,7 +24,8 @@ The UI widgets for the rename dialog
"""
from PyQt5 import QtCore, QtGui, QtWidgets
from openlp.core.lib import translate, build_icon
from openlp.core.common.i18n import translate
from openlp.core.lib import build_icon
from openlp.core.lib.ui import create_button_box

View File

@ -22,12 +22,11 @@
"""
The file rename dialog.
"""
from PyQt5 import QtCore, QtWidgets
from .filerenamedialog import Ui_FileRenameDialog
from openlp.core.common import Registry, RegistryProperties, translate
from openlp.core.common.i18n import translate
from openlp.core.common.registry import Registry, RegistryProperties
from openlp.core.ui.filerenamedialog import Ui_FileRenameDialog
class FileRenameForm(QtWidgets.QDialog, Ui_FileRenameDialog, RegistryProperties):

View File

@ -34,9 +34,12 @@ from tempfile import gettempdir
from PyQt5 import QtCore, QtWidgets
from openlp.core.common import Registry, RegistryProperties, AppLocation, Settings, check_directory_exists, \
translate, clean_button_text, trace_error_handler
from openlp.core.common.path import Path
from openlp.core.common import clean_button_text, trace_error_handler
from openlp.core.common.applocation import AppLocation
from openlp.core.common.i18n import translate
from openlp.core.common.path import Path, create_paths
from openlp.core.common.registry import Registry, RegistryProperties
from openlp.core.common.settings import Settings
from openlp.core.lib import PluginStatus, build_icon
from openlp.core.lib.ui import critical_error_message_box
from openlp.core.common.httputils import get_web_page, get_url_file_size, url_get_file, CONNECTION_TIMEOUT
@ -277,7 +280,7 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties):
self.no_internet_cancel_button.setVisible(False)
# Check if this is a re-run of the wizard.
self.has_run_wizard = Settings().value('core/has run wizard')
check_directory_exists(Path(gettempdir(), 'openlp'))
create_paths(Path(gettempdir(), 'openlp'))
def update_screen_list_combo(self):
"""
@ -597,7 +600,7 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties):
'The following files were not able to be '
'downloaded:<br \\>{text}'.format(text=file_list)))
msg.setStandardButtons(msg.Ok)
ans = msg.exec()
msg.exec()
return True
def _set_plugin_status(self, field, tag):

View File

@ -24,7 +24,7 @@ The UI widgets of the language selection dialog.
"""
from PyQt5 import QtWidgets
from openlp.core.common import translate
from openlp.core.common.i18n import translate
from openlp.core.lib import build_icon
from openlp.core.lib.ui import create_button_box

View File

@ -24,8 +24,8 @@ The language selection dialog.
"""
from PyQt5 import QtCore, QtWidgets
from openlp.core.common.i18n import LanguageManager
from openlp.core.lib.ui import create_action
from openlp.core.common import LanguageManager
from .firsttimelanguagedialog import Ui_FirstTimeLanguageDialog

View File

@ -24,8 +24,9 @@ The UI widgets for the first time wizard.
"""
from PyQt5 import QtCore, QtGui, QtWidgets
from openlp.core.common.uistrings import UiStrings
from openlp.core.common import translate, is_macosx, clean_button_text, Settings
from openlp.core.common import is_macosx, clean_button_text
from openlp.core.common.i18n import UiStrings, translate
from openlp.core.common.settings import Settings
from openlp.core.lib import build_icon
from openlp.core.lib.ui import add_welcome_page

View File

@ -24,9 +24,9 @@ The :mod:`formattingtagform` provides an Tag Edit facility. The Base set are pro
Custom tags can be defined and saved. The Custom Tag arrays are saved in a pickle so QSettings works on them. Base Tags
cannot be changed.
"""
import re
from openlp.core.common import translate
from openlp.core.common.i18n import translate
from openlp.core.lib import FormattingTags

View File

@ -24,7 +24,7 @@ The UI widgets for the formatting tags window.
"""
from PyQt5 import QtCore, QtWidgets
from openlp.core.common import UiStrings, translate
from openlp.core.common.i18n import UiStrings, translate
from openlp.core.lib import build_icon
from openlp.core.lib.ui import create_button_box

View File

@ -24,10 +24,9 @@ The :mod:`formattingtagform` provides an Tag Edit facility. The Base set are pro
Custom tags can be defined and saved. The Custom Tag arrays are saved in a json string so QSettings works on them.
Base Tags cannot be changed.
"""
from PyQt5 import QtCore, QtWidgets
from openlp.core.common import translate
from openlp.core.common.i18n import translate
from openlp.core.lib import FormattingTags
from openlp.core.ui.formattingtagdialog import Ui_FormattingTagDialog
from openlp.core.ui.formattingtagcontroller import FormattingTagController

View File

@ -26,9 +26,13 @@ import logging
from PyQt5 import QtCore, QtGui, QtWidgets
from openlp.core.common import Registry, Settings, UiStrings, translate, get_images_filter
from openlp.core.common.path import Path, path_to_str, str_to_path
from openlp.core.lib import SettingsTab, ScreenList
from openlp.core.common import get_images_filter
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.display.screens import ScreenList
from openlp.core.lib import SettingsTab
from openlp.core.ui.lib import ColorButton, PathEdit
log = logging.getLogger(__name__)

View File

@ -25,7 +25,7 @@ Provide a custom widget based on QPushButton for the selection of colors
"""
from PyQt5 import QtCore, QtGui, QtWidgets
from openlp.core.common import translate
from openlp.core.common.i18n import translate
class ColorButton(QtWidgets.QPushButton):

View File

@ -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__)

View File

@ -26,7 +26,8 @@ It is based on a QTableWidget but represents its contents in list form.
from PyQt5 import QtCore, QtGui, QtWidgets
from openlp.core.common import RegistryProperties, Settings
from openlp.core.common.registry import RegistryProperties
from openlp.core.common.settings import Settings
from openlp.core.lib import ImageSource, ItemCapabilities, ServiceItem
@ -209,21 +210,21 @@ class ListPreviewWidget(QtWidgets.QTableWidget, RegistryProperties):
Switches to the given row.
"""
# Retrieve setting
autoscrolling = Settings().value('advanced/autoscrolling')
auto_scrolling = Settings().value('advanced/autoscrolling')
# Check if auto-scroll disabled (None) and validate value as dict containing 'dist' and 'pos'
# 'dist' represents the slide to scroll to relative to the new slide (-1 = previous, 0 = current, 1 = next)
# 'pos' represents the vert position of of the slide (0 = in view, 1 = top, 2 = middle, 3 = bottom)
if not (isinstance(autoscrolling, dict) and 'dist' in autoscrolling and 'pos' in autoscrolling and
isinstance(autoscrolling['dist'], int) and isinstance(autoscrolling['pos'], int)):
if not (isinstance(auto_scrolling, dict) and 'dist' in auto_scrolling and 'pos' in auto_scrolling and
isinstance(auto_scrolling['dist'], int) and isinstance(auto_scrolling['pos'], int)):
return
# prevent scrolling past list bounds
scroll_to_slide = slide + autoscrolling['dist']
scroll_to_slide = slide + auto_scrolling['dist']
if scroll_to_slide < 0:
scroll_to_slide = 0
if scroll_to_slide >= self.slide_count():
scroll_to_slide = self.slide_count() - 1
# Scroll to item if possible.
self.scrollToItem(self.item(scroll_to_slide, 0), autoscrolling['pos'])
self.scrollToItem(self.item(scroll_to_slide, 0), auto_scrolling['pos'])
self.selectRow(slide)
def current_slide_number(self):

View File

@ -26,7 +26,8 @@ import os
from PyQt5 import QtCore, QtGui, QtWidgets
from openlp.core.common import Registry, UiStrings
from openlp.core.common.i18n import UiStrings
from openlp.core.common.registry import Registry
class ListWidgetWithDnD(QtWidgets.QListWidget):

View File

@ -23,7 +23,7 @@ from enum import Enum
from PyQt5 import QtCore, QtWidgets
from openlp.core.common import UiStrings, translate
from openlp.core.common.i18n import UiStrings, translate
from openlp.core.common.path import Path, path_to_str, str_to_path
from openlp.core.lib import build_icon
from openlp.core.ui.lib.filedialog import FileDialog

View File

@ -38,7 +38,8 @@ except ImportError:
from PyQt5 import QtCore, QtGui, QtWidgets
from openlp.core.lib import translate, FormattingTags
from openlp.core.common.i18n import translate
from openlp.core.lib import FormattingTags
from openlp.core.lib.ui import create_action
log = logging.getLogger(__name__)

View File

@ -26,7 +26,8 @@ import os
from PyQt5 import QtCore, QtGui, QtWidgets
from openlp.core.common import Registry, is_win
from openlp.core.common import is_win
from openlp.core.common.registry import Registry
class TreeWidgetWithDnD(QtWidgets.QTreeWidget):

View File

@ -23,11 +23,13 @@
The :mod:``wizard`` module provides generic wizard tools for OpenLP.
"""
import logging
import os
from PyQt5 import QtCore, QtGui, QtWidgets
from openlp.core.common import Registry, RegistryProperties, Settings, UiStrings, translate, is_macosx
from openlp.core.common import is_macosx
from openlp.core.common.i18n import UiStrings, translate
from openlp.core.common.registry import Registry, RegistryProperties
from openlp.core.common.settings import Settings
from openlp.core.lib import build_icon
from openlp.core.lib.ui import add_welcome_page
from openlp.core.ui.lib.filedialog import FileDialog

View File

@ -26,19 +26,22 @@ Some of the code for this form is based on the examples at:
* `http://www.steveheffernan.com/html5-video-player/demo-video-player.html`_
* `http://html5demos.com/two-videos`_
"""
import html
import logging
import os
from PyQt5 import QtCore, QtWidgets, QtWebKit, QtWebKitWidgets, QtGui, QtMultimedia
from openlp.core.common import AppLocation, Registry, RegistryProperties, OpenLPMixin, Settings, translate,\
is_macosx, is_win
from openlp.core.common import is_macosx, is_win
from openlp.core.common.applocation import AppLocation
from openlp.core.common.i18n import translate
from openlp.core.common.mixins import OpenLPMixin
from openlp.core.common.path import path_to_str
from openlp.core.lib import ServiceItem, ImageSource, ScreenList, build_html, expand_tags, image_to_byte
from openlp.core.common.registry import Registry, RegistryProperties
from openlp.core.common.settings import Settings
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

View File

@ -36,21 +36,26 @@ from PyQt5 import QtCore, QtGui, QtWidgets
from openlp.core.api import websockets
from openlp.core.api.http import server
from openlp.core.common import Registry, RegistryProperties, AppLocation, LanguageManager, Settings, UiStrings, \
check_directory_exists, translate, is_win, is_macosx, add_actions
from openlp.core.common import is_win, is_macosx, add_actions
from openlp.core.common.actions import ActionList, CategoryOrder
from openlp.core.common.path import Path, copyfile, path_to_str, str_to_path
from openlp.core.lib import Renderer, PluginManager, ImageManager, PluginStatus, ScreenList, build_icon
from openlp.core.common.applocation import AppLocation
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.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
@ -853,7 +858,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow, RegistryProperties):
setting_sections.extend([plugin.name for plugin in self.plugin_manager.plugins])
# Copy the settings file to the tmp dir, because we do not want to change the original one.
temp_dir_path = Path(gettempdir(), 'openlp')
check_directory_exists(temp_dir_path)
create_paths(temp_dir_path)
temp_config_path = temp_dir_path / import_file_path.name
copyfile(import_file_path, temp_config_path)
settings = Settings()
@ -896,6 +901,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow, RegistryProperties):
try:
value = import_settings.value(section_key)
except KeyError:
value = None
log.warning('The key "{key}" does not exist (anymore), so it will be skipped.'.format(key=section_key))
if value is not None:
settings.setValue('{key}'.format(key=section_key), value)
@ -929,7 +935,14 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow, RegistryProperties):
# Make sure it's a .conf file.
export_file_path = export_file_path.with_suffix('.conf')
self.save_settings()
Settings().export(export_file_path)
try:
Settings().export(export_file_path)
except OSError as ose:
QtWidgets.QMessageBox.critical(self, translate('OpenLP.MainWindow', 'Export setting error'),
translate('OpenLP.MainWindow',
'An error occurred while exporting the settings: {err}'
).format(err=ose.strerror),
QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Ok))
def on_mode_default_item_clicked(self):
"""

View File

@ -26,7 +26,7 @@ import logging
from PyQt5 import QtCore
from openlp.core.common import Settings
from openlp.core.common.settings import Settings
log = logging.getLogger(__name__ + '.__init__')

View File

@ -19,15 +19,16 @@
# 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.api.endpoint` module contains various API endpoints
"""
import logging
from openlp.core.api.http.endpoint import Endpoint
from openlp.core.api.http import requires_auth
from openlp.core.common import Registry
from openlp.core.common.registry import Registry
log = logging.getLogger(__name__)
media_endpoint = Endpoint('media')

View File

@ -29,8 +29,11 @@ import datetime
from PyQt5 import QtCore, QtWidgets
from openlp.core.api.http import register_endpoint
from openlp.core.common import OpenLPMixin, Registry, RegistryMixin, RegistryProperties, Settings, UiStrings, \
extension_loader, translate
from openlp.core.common import extension_loader
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
from openlp.core.lib.ui import critical_error_message_box
from openlp.core.ui import DisplayControllerType

View File

@ -22,7 +22,7 @@
"""
The :mod:`~openlp.core.ui.media.mediaplayer` module contains the MediaPlayer class.
"""
from openlp.core.common import RegistryProperties
from openlp.core.common.registry import RegistryProperties
from openlp.core.ui.media import MediaState

View File

@ -25,7 +25,9 @@ The :mod:`~openlp.core.ui.media.playertab` module holds the configuration tab fo
import platform
from PyQt5 import QtCore, QtWidgets
from openlp.core.common import Registry, Settings, UiStrings, translate
from openlp.core.common.i18n import UiStrings, translate
from openlp.core.common.registry import Registry
from openlp.core.common.settings import Settings
from openlp.core.lib import SettingsTab
from openlp.core.lib.ui import create_button
from openlp.core.ui.media import get_media_players, set_media_players

View File

@ -28,7 +28,7 @@ import mimetypes
from PyQt5 import QtCore, QtMultimedia, QtMultimediaWidgets
from openlp.core.lib import translate
from openlp.core.common.i18n import translate
from openlp.core.ui.media import MediaState
from openlp.core.ui.media.mediaplayer import MediaPlayer

View File

@ -31,8 +31,9 @@ import sys
import ctypes
from PyQt5 import QtWidgets
from openlp.core.common import Settings, is_win, is_macosx, is_linux
from openlp.core.lib import translate
from openlp.core.common import is_win, is_macosx, is_linux
from openlp.core.common.i18n import translate
from openlp.core.common.settings import Settings
from openlp.core.ui.media import MediaState, MediaType
from openlp.core.ui.media.mediaplayer import MediaPlayer

View File

@ -26,8 +26,8 @@ import logging
from PyQt5 import QtGui, QtWebKitWidgets
from openlp.core.common import Settings
from openlp.core.lib import translate
from openlp.core.common.settings import Settings
from openlp.core.common.i18n import translate
from openlp.core.ui.media import MediaState
from openlp.core.ui.media.mediaplayer import MediaPlayer

View File

@ -24,7 +24,7 @@ The UI widgets of the plugin view dialog
#"""
from PyQt5 import QtCore, QtWidgets
from openlp.core.common import UiStrings, translate
from openlp.core.common.i18n import UiStrings, translate
from openlp.core.lib import build_icon
from openlp.core.lib.ui import create_button_box

View File

@ -26,9 +26,10 @@ import logging
from PyQt5 import QtCore, QtWidgets
from openlp.core.common import RegistryProperties, translate
from openlp.core.common.i18n import translate
from openlp.core.common.registry import RegistryProperties
from openlp.core.lib import PluginStatus
from .plugindialog import Ui_PluginViewDialog
from openlp.core.ui.plugindialog import Ui_PluginViewDialog
log = logging.getLogger(__name__)

View File

@ -24,7 +24,7 @@ The UI widgets of the print service dialog.
"""
from PyQt5 import QtCore, QtWidgets, QtPrintSupport
from openlp.core.common import UiStrings, translate
from openlp.core.common.i18n import UiStrings, translate
from openlp.core.lib import build_icon
from openlp.core.ui.lib import SpellTextEdit

View File

@ -23,16 +23,17 @@
The actual print service dialog
"""
import datetime
import os
import html
import lxml.html
from PyQt5 import QtCore, QtGui, QtWidgets, QtPrintSupport
from openlp.core.common import Registry, RegistryProperties, Settings, UiStrings, translate
from openlp.core.common.applocation import AppLocation
from openlp.core.common.i18n import UiStrings, translate
from openlp.core.common.registry import Registry, RegistryProperties
from openlp.core.common.settings import Settings
from openlp.core.lib import get_text_file_string
from openlp.core.ui.printservicedialog import Ui_PrintServiceDialog, ZoomSize
from openlp.core.common import AppLocation
DEFAULT_CSS = """/*
Edit this file to customize the service order print. Note, that not all CSS

View File

@ -20,22 +20,22 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
:mod: `openlp.core.ui.projector.editform` module
Provides the functions for adding/editing entries in the projector database.
The :mod: `openlp.core.ui.projector.editform` module provides the functions for adding/editing entries in the projector
database.
"""
import logging
log = logging.getLogger(__name__)
log.debug('editform loaded')
from PyQt5 import QtCore, QtWidgets
from openlp.core.common import translate, verify_ip_address
from openlp.core.common import verify_ip_address
from openlp.core.common.i18n import translate
from openlp.core.lib import build_icon
from openlp.core.lib.projector.db import Projector
from openlp.core.lib.projector.constants import PJLINK_PORT
log = logging.getLogger(__name__)
log.debug('editform loaded')
class Ui_ProjectorEditForm(object):
"""

View File

@ -29,9 +29,10 @@ import logging
from PyQt5 import QtCore, QtGui, QtWidgets
from openlp.core.common import RegistryProperties, Settings, OpenLPMixin, \
RegistryMixin, translate
from openlp.core.ui.lib import OpenLPToolbar
from openlp.core.common.i18n import translate
from openlp.core.common.mixins import OpenLPMixin, RegistryMixin
from openlp.core.common.registry import RegistryProperties
from openlp.core.common.settings import Settings
from openlp.core.lib.ui import create_widget_action
from openlp.core.lib.projector import DialogSourceStyle
from openlp.core.lib.projector.constants import ERROR_MSG, ERROR_STRING, E_AUTHENTICATION, E_ERROR, \
@ -39,6 +40,7 @@ from openlp.core.lib.projector.constants import ERROR_MSG, ERROR_STRING, E_AUTHE
S_INITIALIZE, S_NOT_CONNECTED, S_OFF, S_ON, S_STANDBY, S_WARMUP
from openlp.core.lib.projector.db import ProjectorDB
from openlp.core.lib.projector.pjlink import PJLink, PJLinkUDP
from openlp.core.ui.lib import OpenLPToolbar
from openlp.core.ui.projector.editform import ProjectorEditForm
from openlp.core.ui.projector.sourceselectform import SourceSelectTabs, SourceSelectSingle

View File

@ -28,7 +28,8 @@ import logging
from PyQt5 import QtCore, QtWidgets
from openlp.core.common import translate, is_macosx
from openlp.core.common import is_macosx
from openlp.core.common.i18n import translate
from openlp.core.lib import build_icon
from openlp.core.lib.projector.db import ProjectorSource
from openlp.core.lib.projector.constants import PJLINK_DEFAULT_SOURCES, PJLINK_DEFAULT_CODES

View File

@ -20,21 +20,20 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
:mod:`openlp.core.ui.projector.tab`
Provides the settings tab in the settings dialog.
The :mod:`openlp.core.ui.projector.tab` module provides the settings tab in the settings dialog.
"""
import logging
log = logging.getLogger(__name__)
log.debug('projectortab module loaded')
from PyQt5 import QtWidgets
from openlp.core.common import Settings, UiStrings, translate
from openlp.core.common.i18n import UiStrings, translate
from openlp.core.common.settings import Settings
from openlp.core.lib import SettingsTab
from openlp.core.lib.projector import DialogSourceStyle
log = logging.getLogger(__name__)
log.debug('projectortab module loaded')
class ProjectorTab(SettingsTab):
"""

View File

@ -24,7 +24,7 @@ The UI widgets for the service item edit dialog
"""
from PyQt5 import QtWidgets
from openlp.core.common import translate
from openlp.core.common.i18n import translate
from openlp.core.lib import build_icon
from openlp.core.lib.ui import create_button_box, create_button

View File

@ -24,9 +24,8 @@ The service item edit dialog
"""
from PyQt5 import QtCore, QtWidgets
from openlp.core.common import Registry, RegistryProperties
from .serviceitemeditdialog import Ui_ServiceItemEditDialog
from openlp.core.common.registry import Registry, RegistryProperties
from openlp.core.ui.serviceitemeditdialog import Ui_ServiceItemEditDialog
class ServiceItemEditForm(QtWidgets.QDialog, Ui_ServiceItemEditDialog, RegistryProperties):

View File

@ -32,11 +32,14 @@ from tempfile import mkstemp
from PyQt5 import QtCore, QtGui, QtWidgets
from openlp.core.common import Registry, RegistryProperties, AppLocation, Settings, ThemeLevel, OpenLPMixin, \
RegistryMixin, check_directory_exists, UiStrings, translate, split_filename, delete_file
from openlp.core.common import ThemeLevel, split_filename, delete_file
from openlp.core.common.actions import ActionList, CategoryOrder
from openlp.core.common.languagemanager import format_time
from openlp.core.common.path import Path, path_to_str, str_to_path
from openlp.core.common.applocation import AppLocation
from openlp.core.common.i18n import UiStrings, format_time, translate
from openlp.core.common.mixins import OpenLPMixin, RegistryMixin
from openlp.core.common.path import Path, 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 ServiceItem, ItemCapabilities, PluginStatus, build_icon
from openlp.core.lib.ui import critical_error_message_box, create_widget_action, find_and_set_in_combo_box
from openlp.core.ui import ServiceNoteForm, ServiceItemEditForm, StartTimeForm
@ -594,7 +597,7 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa
audio_from = os.path.join(self.service_path, audio_from)
save_file = os.path.join(self.service_path, audio_to)
save_path = os.path.split(save_file)[0]
check_directory_exists(Path(save_path))
create_paths(Path(save_path))
if not os.path.exists(save_file):
shutil.copy(audio_from, save_file)
zip_file.write(audio_from, audio_to)

View File

@ -24,7 +24,8 @@ The :mod:`~openlp.core.ui.servicenoteform` module contains the `ServiceNoteForm`
"""
from PyQt5 import QtCore, QtWidgets
from openlp.core.common import Registry, RegistryProperties, translate
from openlp.core.common.i18n import translate
from openlp.core.common.registry import Registry, RegistryProperties
from openlp.core.ui.lib import SpellTextEdit
from openlp.core.lib.ui import create_button_box

View File

@ -24,7 +24,7 @@ The UI widgets of the settings dialog.
"""
from PyQt5 import QtCore, QtWidgets
from openlp.core.common import translate
from openlp.core.common.i18n import translate
from openlp.core.lib import build_icon
from openlp.core.lib.ui import create_button_box

View File

@ -27,12 +27,12 @@ import logging
from PyQt5 import QtCore, QtWidgets
from openlp.core.api import ApiTab
from openlp.core.common import Registry, RegistryProperties
from openlp.core.common.registry import Registry, RegistryProperties
from openlp.core.lib import build_icon
from openlp.core.ui import AdvancedTab, GeneralTab, ThemesTab
from openlp.core.ui.media import PlayerTab
from .settingsdialog import Ui_SettingsDialog
from openlp.core.ui.projector.tab import ProjectorTab
from openlp.core.ui.settingsdialog import Ui_SettingsDialog
log = logging.getLogger(__name__)

View File

@ -24,7 +24,7 @@ The list of shortcuts within a dialog.
"""
from PyQt5 import QtCore, QtWidgets
from openlp.core.common import translate
from openlp.core.common.i18n import translate
from openlp.core.lib import build_icon
from openlp.core.lib.ui import create_button_box

View File

@ -20,15 +20,18 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`~openlp.core.ui.shortcutlistform` module contains the form class"""
The :mod:`~openlp.core.ui.shortcutlistform` module contains the form class
"""
import logging
import re
from PyQt5 import QtCore, QtGui, QtWidgets
from openlp.core.common import RegistryProperties, Settings, translate
from openlp.core.common.actions import ActionList
from .shortcutlistdialog import Ui_ShortcutListDialog
from openlp.core.common.i18n import translate
from openlp.core.common.registry import RegistryProperties
from openlp.core.common.settings import Settings
from openlp.core.ui.shortcutlistdialog import Ui_ShortcutListDialog
REMOVE_AMPERSAND = re.compile(r'&{1}')

View File

@ -30,11 +30,14 @@ from threading import Lock
from PyQt5 import QtCore, QtGui, QtWidgets
from openlp.core.common import Registry, RegistryProperties, Settings, SlideLimits, UiStrings, translate, \
RegistryMixin, OpenLPMixin
from openlp.core.common import SlideLimits
from openlp.core.common.actions import ActionList, CategoryOrder
from openlp.core.lib import ItemCapabilities, ServiceItem, ImageSource, ServiceItemAction, ScreenList, build_icon, \
build_html
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.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

View File

@ -24,7 +24,7 @@ The UI widgets for the time dialog
"""
from PyQt5 import QtCore, QtWidgets
from openlp.core.common import UiStrings, translate
from openlp.core.common.i18n import UiStrings, translate
from openlp.core.lib import build_icon
from openlp.core.lib.ui import create_button_box

View File

@ -24,10 +24,10 @@ The actual start time form.
"""
from PyQt5 import QtCore, QtWidgets
from .starttimedialog import Ui_StartTimeDialog
from openlp.core.common import Registry, RegistryProperties, UiStrings, translate
from openlp.core.common.i18n import UiStrings, translate
from openlp.core.common.registry import Registry, RegistryProperties
from openlp.core.lib.ui import critical_error_message_box
from openlp.core.ui.starttimedialog import Ui_StartTimeDialog
class StartTimeForm(QtWidgets.QDialog, Ui_StartTimeDialog, RegistryProperties):

View File

@ -23,11 +23,12 @@
The Theme wizard
"""
import logging
import os
from PyQt5 import QtCore, QtGui, QtWidgets
from openlp.core.common import Registry, RegistryProperties, UiStrings, translate, get_images_filter, is_not_image_file
from openlp.core.common import get_images_filter, is_not_image_file
from openlp.core.common.i18n import UiStrings, translate
from openlp.core.common.registry import Registry, RegistryProperties
from openlp.core.lib.theme import BackgroundType, BackgroundGradientType
from openlp.core.lib.ui import critical_error_message_box
from openlp.core.ui import ThemeLayoutForm

Some files were not shown because too many files have changed in this diff Show More