diff --git a/openlp/core/__init__.py b/openlp/core/__init__.py index 96520195d..b4da78e83 100644 --- a/openlp/core/__init__.py +++ b/openlp/core/__init__.py @@ -41,6 +41,7 @@ from traceback import format_exception from PyQt4 import QtCore, QtGui from openlp.core.lib import Receiver, check_directory_exists +from openlp.core.lib.settings import Settings from openlp.core.lib.ui import UiStrings from openlp.core.resources import qInitResources from openlp.core.ui.mainwindow import MainWindow @@ -113,15 +114,15 @@ class OpenLP(QtGui.QApplication): # Decide how many screens we have and their size screens = ScreenList.create(self.desktop()) # First time checks in settings - has_run_wizard = QtCore.QSettings().value( + has_run_wizard = Settings().value( u'general/has run wizard', QtCore.QVariant(False)).toBool() if not has_run_wizard: if FirstTimeForm(screens).exec_() == QtGui.QDialog.Accepted: - QtCore.QSettings().setValue(u'general/has run wizard', + Settings().setValue(u'general/has run wizard', QtCore.QVariant(True)) if os.name == u'nt': self.setStyleSheet(application_stylesheet) - show_splash = QtCore.QSettings().value( + show_splash = Settings().value( u'general/show splash', QtCore.QVariant(True)).toBool() if show_splash: self.splash = SplashScreen() @@ -141,7 +142,7 @@ class OpenLP(QtGui.QApplication): self.processEvents() if not has_run_wizard: self.mainWindow.firstTime() - update_check = QtCore.QSettings().value( + update_check = Settings().value( u'general/update check', QtCore.QVariant(True)).toBool() if update_check: VersionThread(self.mainWindow).start() @@ -258,7 +259,28 @@ def main(args=None): app = OpenLP(qt_args) app.setOrganizationName(u'OpenLP') app.setOrganizationDomain(u'openlp.org') - app.setApplicationName(u'OpenLP') + if options.portable: + log.info(u'Running portable') + app.setApplicationName(u'OpenLPPortable') + Settings.setDefaultFormat(Settings.IniFormat) + # Get location OpenLPPortable.ini + app_path = AppLocation.get_directory(AppLocation.AppDir) + portable_settings_file = os.path.abspath(os.path.join(app_path, u'..', + u'..', u'Data', u'OpenLP.ini')) + # Make this our settings file + log.info(u'INI file: %s', portable_settings_file) + Settings.setFilename(portable_settings_file) + portable_settings = Settings() + # Set our data path + data_path = os.path.abspath(os.path.join(app_path, + u'..', u'..', u'Data',)) + log.info(u'Data path: %s', data_path) + # Point to our data path + portable_settings.setValue(u'advanced/data path', data_path) + portable_settings.setValue(u'advanced/is portable', True) + portable_settings.sync() + else: + app.setApplicationName(u'OpenLP') app.setApplicationVersion(get_application_version()[u'version']) # Instance check if not options.testing: @@ -266,7 +288,7 @@ def main(args=None): if app.isAlreadyRunning(): sys.exit() # First time checks in settings - if not QtCore.QSettings().value(u'general/has run wizard', + if not Settings().value(u'general/has run wizard', QtCore.QVariant(False)).toBool(): if not FirstTimeLanguageForm().exec_(): # if cancel then stop processing diff --git a/openlp/core/lib/db.py b/openlp/core/lib/db.py index e097983eb..28d6f8b92 100644 --- a/openlp/core/lib/db.py +++ b/openlp/core/lib/db.py @@ -41,6 +41,7 @@ from sqlalchemy.pool import NullPool from openlp.core.lib import translate from openlp.core.lib.ui import critical_error_message_box from openlp.core.utils import AppLocation, delete_file +from openlp.core.lib.settings import Settings log = logging.getLogger(__name__) @@ -179,7 +180,7 @@ class Manager(object): The file name to use for this database. Defaults to None resulting in the plugin_name being used. """ - settings = QtCore.QSettings() + settings = Settings() settings.beginGroup(plugin_name) self.db_url = u'' self.is_dirty = False @@ -238,27 +239,30 @@ class Manager(object): ``commit`` Commit the session with this object """ - try: - self.session.add(object_instance) - if commit: - self.session.commit() - self.is_dirty = True - return True - except OperationalError: - # This exception clause is for users running MySQL which likes - # to terminate connections on its own without telling anyone. - # See bug #927473 - log.exception(u'Probably a MySQL issue - "MySQL has gone away"') - self.session.rollback() - self.session.add(object_instance) - if commit: - self.session.commit() - self.is_dirty = True - return True - except InvalidRequestError: - self.session.rollback() - log.exception(u'Object save failed') - return False + for try_count in range(3): + try: + self.session.add(object_instance) + if commit: + self.session.commit() + self.is_dirty = True + return True + except OperationalError: + # This exception clause is for users running MySQL which likes + # to terminate connections on its own without telling anyone. + # See bug #927473 + # However, other dbms can raise it, usually in a non-recoverable + # way. So we only retry 3 times. + log.exception(u'Probably a MySQL issue - "MySQL has gone away"') + self.session.rollback() + if try_count >= 2: + raise + except InvalidRequestError: + self.session.rollback() + log.exception(u'Object list save failed') + return False + except: + self.session.rollback() + raise def save_objects(self, object_list, commit=True): """ @@ -270,27 +274,30 @@ class Manager(object): ``commit`` Commit the session with this object """ - try: - self.session.add_all(object_list) - if commit: - self.session.commit() - self.is_dirty = True - return True - except OperationalError: - # This exception clause is for users running MySQL which likes - # to terminate connections on its own without telling anyone. - # See bug #927473 - log.exception(u'Probably a MySQL issue, "MySQL has gone away"') - self.session.rollback() - self.session.add_all(object_list) - if commit: - self.session.commit() - self.is_dirty = True - return True - except InvalidRequestError: - self.session.rollback() - log.exception(u'Object list save failed') - return False + for try_count in range(3): + try: + self.session.add_all(object_list) + if commit: + self.session.commit() + self.is_dirty = True + return True + except OperationalError: + # This exception clause is for users running MySQL which likes + # to terminate connections on its own without telling anyone. + # See bug #927473 + # However, other dbms can raise it, usually in a non-recoverable + # way. So we only retry 3 times. + log.exception(u'Probably a MySQL issue, "MySQL has gone away"') + self.session.rollback() + if try_count >= 2: + raise + except InvalidRequestError: + self.session.rollback() + log.exception(u'Object list save failed') + return False + except: + self.session.rollback() + raise def get_object(self, object_class, key=None): """ @@ -305,15 +312,18 @@ class Manager(object): if not key: return object_class() else: - try: - return self.session.query(object_class).get(key) - except OperationalError: - # This exception clause is for users running MySQL which likes - # to terminate connections on its own without telling anyone. - # See bug #927473 - log.exception(u'Probably a MySQL issue, "MySQL has gone away"') - self.session.rollback() - return self.session.query(object_class).get(key) + for try_count in range(3): + try: + return self.session.query(object_class).get(key) + except OperationalError: + # This exception clause is for users running MySQL which likes + # to terminate connections on its own without telling anyone. + # See bug #927473 + # However, other dbms can raise it, usually in a non-recoverable + # way. So we only retry 3 times. + log.exception(u'Probably a MySQL issue, "MySQL has gone away"') + if try_count >= 2: + raise def get_object_filtered(self, object_class, filter_clause): """ @@ -325,15 +335,18 @@ class Manager(object): ``filter_clause`` The criteria to select the object by """ - try: - return self.session.query(object_class).filter(filter_clause).first() - except OperationalError: - # This exception clause is for users running MySQL which likes - # to terminate connections on its own without telling anyone. - # See bug #927473 - log.exception(u'Probably a MySQL issue, "MySQL has gone away"') - self.session.rollback() - return self.session.query(object_class).filter(filter_clause).first() + for try_count in range(3): + try: + return self.session.query(object_class).filter(filter_clause).first() + except OperationalError: + # This exception clause is for users running MySQL which likes + # to terminate connections on its own without telling anyone. + # See bug #927473 + # However, other dbms can raise it, usually in a non-recoverable + # way. So we only retry 3 times. + log.exception(u'Probably a MySQL issue, "MySQL has gone away"') + if try_count >= 2: + raise def get_all_objects(self, object_class, filter_clause=None, order_by_ref=None): @@ -357,15 +370,18 @@ class Manager(object): query = query.order_by(*order_by_ref) elif order_by_ref is not None: query = query.order_by(order_by_ref) - try: - return query.all() - except OperationalError: - # This exception clause is for users running MySQL which likes - # to terminate connections on its own without telling anyone. - # See bug #927473 - log.exception(u'Probably a MySQL issue, "MySQL has gone away"') - self.session.rollback() - return query.all() + for try_count in range(3): + try: + return query.all() + except OperationalError: + # This exception clause is for users running MySQL which likes + # to terminate connections on its own without telling anyone. + # See bug #927473 + # However, other dbms can raise it, usually in a non-recoverable + # way. So we only retry 3 times. + log.exception(u'Probably a MySQL issue, "MySQL has gone away"') + if try_count >= 2: + raise def get_object_count(self, object_class, filter_clause=None): """ @@ -381,15 +397,18 @@ class Manager(object): query = self.session.query(object_class) if filter_clause is not None: query = query.filter(filter_clause) - try: - return query.count() - except OperationalError: - # This exception clause is for users running MySQL which likes - # to terminate connections on its own without telling anyone. - # See bug #927473 - log.exception(u'Probably a MySQL issue, "MySQL has gone away"') - self.session.rollback() - return query.count() + for try_count in range(3): + try: + return query.count() + except OperationalError: + # This exception clause is for users running MySQL which likes + # to terminate connections on its own without telling anyone. + # See bug #927473 + # However, other dbms can raise it, usually in a non-recoverable + # way. So we only retry 3 times. + log.exception(u'Probably a MySQL issue, "MySQL has gone away"') + if try_count >= 2: + raise def delete_object(self, object_class, key): """ @@ -403,25 +422,29 @@ class Manager(object): """ if key != 0: object_instance = self.get_object(object_class, key) - try: - self.session.delete(object_instance) - self.session.commit() - self.is_dirty = True - return True - except OperationalError: - # This exception clause is for users running MySQL which likes - # to terminate connections on its own without telling anyone. - # See bug #927473 - log.exception(u'Probably a MySQL issue, "MySQL has gone away"') - self.session.rollback() - self.session.delete(object_instance) - self.session.commit() - self.is_dirty = True - return True - except InvalidRequestError: - self.session.rollback() - log.exception(u'Failed to delete object') - return False + for try_count in range(3): + try: + self.session.delete(object_instance) + self.session.commit() + self.is_dirty = True + return True + except OperationalError: + # This exception clause is for users running MySQL which likes + # to terminate connections on its own without telling anyone. + # See bug #927473 + # However, other dbms can raise it, usually in a non-recoverable + # way. So we only retry 3 times. + log.exception(u'Probably a MySQL issue, "MySQL has gone away"') + self.session.rollback() + if try_count >= 2: + raise + except InvalidRequestError: + self.session.rollback() + log.exception(u'Failed to delete object') + return False + except: + self.session.rollback() + raise else: return True @@ -439,31 +462,32 @@ class Manager(object): The filter governing selection of objects to return. Defaults to None. """ - try: - query = self.session.query(object_class) - if filter_clause is not None: - query = query.filter(filter_clause) - query.delete(synchronize_session=False) - self.session.commit() - self.is_dirty = True - return True - except OperationalError: - # This exception clause is for users running MySQL which likes - # to terminate connections on its own without telling anyone. - # See bug #927473 - log.exception(u'Probably a MySQL issue, "MySQL has gone away"') - self.session.rollback() - query = self.session.query(object_class) - if filter_clause is not None: - query = query.filter(filter_clause) - query.delete(synchronize_session=False) - self.session.commit() - self.is_dirty = True - return True - except InvalidRequestError: - self.session.rollback() - log.exception(u'Failed to delete %s records', object_class.__name__) - return False + for try_count in range(3): + try: + query = self.session.query(object_class) + if filter_clause is not None: + query = query.filter(filter_clause) + query.delete(synchronize_session=False) + self.session.commit() + self.is_dirty = True + return True + except OperationalError: + # This exception clause is for users running MySQL which likes + # to terminate connections on its own without telling anyone. + # See bug #927473 + # However, other dbms can raise it, usually in a non-recoverable + # way. So we only retry 3 times. + log.exception(u'Probably a MySQL issue, "MySQL has gone away"') + self.session.rollback() + if try_count >= 2: + raise + except InvalidRequestError: + self.session.rollback() + log.exception(u'Failed to delete %s records', object_class.__name__) + return False + except: + self.session.rollback() + raise def finalise(self): """ diff --git a/openlp/core/lib/eventreceiver.py b/openlp/core/lib/eventreceiver.py index f27171db4..91149d62c 100644 --- a/openlp/core/lib/eventreceiver.py +++ b/openlp/core/lib/eventreceiver.py @@ -268,7 +268,7 @@ class Receiver(object): <> )`` """ - eventreceiver = EventReceiver() + __eventreceiver__ = EventReceiver() @staticmethod def send_message(event, msg=None): @@ -281,11 +281,11 @@ class Receiver(object): ``msg`` Defaults to *None*. The message to send with the event. """ - Receiver.eventreceiver.send_message(event, msg) + Receiver.__eventreceiver__.send_message(event, msg) @staticmethod def get_receiver(): """ - Get the global ``eventreceiver`` instance. + Get the global ``__eventreceiver__`` instance. """ - return Receiver.eventreceiver + return Receiver.__eventreceiver__ diff --git a/openlp/core/lib/formattingtags.py b/openlp/core/lib/formattingtags.py index 11fd898c3..4ac1509fc 100644 --- a/openlp/core/lib/formattingtags.py +++ b/openlp/core/lib/formattingtags.py @@ -32,6 +32,7 @@ import cPickle from PyQt4 import QtCore from openlp.core.lib import translate +from openlp.core.lib.settings import Settings class FormattingTags(object): @@ -68,7 +69,7 @@ class FormattingTags(object): if isinstance(tag[element], unicode): tag[element] = tag[element].encode('utf8') # Formatting Tags were also known as display tags. - QtCore.QSettings().setValue(u'displayTags/html_tags', + Settings().setValue(u'displayTags/html_tags', QtCore.QVariant(cPickle.dumps(tags) if tags else u'')) @staticmethod @@ -164,7 +165,7 @@ class FormattingTags(object): FormattingTags.add_html_tags(temporary_tags) # Formatting Tags were also known as display tags. - user_expands = QtCore.QSettings().value(u'displayTags/html_tags', + user_expands = Settings().value(u'displayTags/html_tags', QtCore.QVariant(u'')).toString() # cPickle only accepts str not unicode strings user_expands_string = str(user_expands) diff --git a/openlp/core/lib/mediamanageritem.py b/openlp/core/lib/mediamanageritem.py index 9bd6fc2a7..703b6e9e5 100644 --- a/openlp/core/lib/mediamanageritem.py +++ b/openlp/core/lib/mediamanageritem.py @@ -38,6 +38,7 @@ from openlp.core.lib import SettingsManager, OpenLPToolbar, ServiceItem, \ from openlp.core.lib.searchedit import SearchEdit from openlp.core.lib.ui import UiStrings, create_widget_action, \ critical_error_message_box +from openlp.core.lib.settings import Settings log = logging.getLogger(__name__) @@ -462,7 +463,7 @@ class MediaManagerItem(QtGui.QWidget): """ Allows the list click action to be determined dynamically """ - if QtCore.QSettings().value(u'advanced/double click live', + if Settings().value(u'advanced/double click live', QtCore.QVariant(False)).toBool(): self.onLiveClick() else: @@ -472,7 +473,7 @@ class MediaManagerItem(QtGui.QWidget): """ Allows the change of current item in the list to be actioned """ - if QtCore.QSettings().value(u'advanced/single click preview', + if Settings().value(u'advanced/single click preview', QtCore.QVariant(False)).toBool() and self.quickPreviewAllowed \ and self.listView.selectedIndexes() \ and self.autoSelectId == -1: diff --git a/openlp/core/lib/plugin.py b/openlp/core/lib/plugin.py index a27e496cf..7a34626ad 100644 --- a/openlp/core/lib/plugin.py +++ b/openlp/core/lib/plugin.py @@ -32,6 +32,7 @@ import logging from PyQt4 import QtCore from openlp.core.lib import Receiver +from openlp.core.lib.settings import Settings from openlp.core.lib.ui import UiStrings from openlp.core.utils import get_application_version @@ -190,7 +191,7 @@ class Plugin(QtCore.QObject): """ Sets the status of the plugin """ - self.status = QtCore.QSettings().value( + self.status = Settings().value( self.settingsSection + u'/status', QtCore.QVariant(PluginStatus.Inactive)).toInt()[0] @@ -199,7 +200,7 @@ class Plugin(QtCore.QObject): Changes the status of the plugin and remembers it """ self.status = new_status - QtCore.QSettings().setValue( + Settings().setValue( self.settingsSection + u'/status', QtCore.QVariant(self.status)) if new_status == PluginStatus.Active: self.initialise() diff --git a/openlp/core/lib/pluginmanager.py b/openlp/core/lib/pluginmanager.py index 80160911d..084d567a0 100644 --- a/openlp/core/lib/pluginmanager.py +++ b/openlp/core/lib/pluginmanager.py @@ -41,13 +41,13 @@ class PluginManager(object): and executes all the hooks, as and when necessary. """ log.info(u'Plugin manager loaded') - + __instance__ = None @staticmethod def get_instance(): """ Obtain a single instance of class. """ - return PluginManager.instance + return PluginManager.__instance__ def __init__(self, plugin_dir): """ @@ -58,7 +58,7 @@ class PluginManager(object): The directory to search for plugins. """ log.info(u'Plugin manager Initialising') - PluginManager.instance = self + PluginManager.__instance__ = self if not plugin_dir in sys.path: log.debug(u'Inserting %s into sys.path', plugin_dir) sys.path.insert(0, plugin_dir) diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index 74cdafd82..6ce51ab60 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -303,7 +303,7 @@ class Renderer(object): try: text_to_render, text = \ text.split(u'\n[---]\n', 1) - except: + except ValueError: text_to_render = text.split(u'\n[---]\n')[0] text = u'' text_to_render, raw_tags, html_tags = \ diff --git a/openlp/core/lib/settings.py b/openlp/core/lib/settings.py new file mode 100644 index 000000000..5f012c0d1 --- /dev/null +++ b/openlp/core/lib/settings.py @@ -0,0 +1,66 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2012 Raoul Snyman # +# Portions copyright (c) 2008-2012 Tim Bentley, Gerald Britton, Jonathan # +# Corwin, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, # +# Armin Köhler, Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias # +# Põldaru, Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # +# --------------------------------------------------------------------------- # +# 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:``settings`` module provides a thin wrapper for QSettings, which OpenLP +uses to manage settings persistence. +""" + +import logging + +from PyQt4 import QtCore + +log = logging.getLogger() + +class Settings(QtCore.QSettings): + """ + Class to wrap QSettings. + + * Exposes all the methods of QSettings. + * Adds functionality for OpenLP Portable. If the ``defaultFormat`` is set to + ``IniFormat``, and the path to the Ini file is set using ``setFilename``, + then the Settings constructor (without any arguments) will create a Settings + object for accessing settings stored in that Ini file. + """ + + __filePath = u'' + + @staticmethod + def setFilename(iniFile): + """ + Sets the complete path to an Ini file to be used by Settings objects. + + Does not affect existing Settings objects. + """ + Settings.__filePath = iniFile + + def __init__(self, *args): + if not args and Settings.__filePath and (Settings.defaultFormat() == + Settings.IniFormat): + QtCore.QSettings.__init__(self, Settings.__filePath, + Settings.IniFormat) + else: + QtCore.QSettings.__init__(self, *args) diff --git a/openlp/core/lib/settingsmanager.py b/openlp/core/lib/settingsmanager.py index 0fc4cac96..245b98ef8 100644 --- a/openlp/core/lib/settingsmanager.py +++ b/openlp/core/lib/settingsmanager.py @@ -34,6 +34,7 @@ import os from PyQt4 import QtCore +from openlp.core.lib.settings import Settings from openlp.core.utils import AppLocation class SettingsManager(object): @@ -58,7 +59,7 @@ class SettingsManager(object): name = u'last directory %d' % num else: name = u'last directory' - last_dir = unicode(QtCore.QSettings().value( + last_dir = unicode(Settings().value( section + u'/' + name, QtCore.QVariant(u'')).toString()) return last_dir @@ -81,7 +82,7 @@ class SettingsManager(object): name = u'last directory %d' % num else: name = u'last directory' - QtCore.QSettings().setValue( + Settings().setValue( section + u'/' + name, QtCore.QVariant(directory)) @staticmethod @@ -98,7 +99,7 @@ class SettingsManager(object): ``list`` The list of values to save. """ - settings = QtCore.QSettings() + settings = Settings() settings.beginGroup(section) old_count = settings.value( u'%s count' % name, QtCore.QVariant(0)).toInt()[0] @@ -124,7 +125,7 @@ class SettingsManager(object): ``name`` The name of the list. """ - settings = QtCore.QSettings() + settings = Settings() settings.beginGroup(section) list_count = settings.value( u'%s count' % name, QtCore.QVariant(0)).toInt()[0] diff --git a/openlp/core/lib/ui.py b/openlp/core/lib/ui.py index c0472cce8..9707886a9 100644 --- a/openlp/core/lib/ui.py +++ b/openlp/core/lib/ui.py @@ -80,6 +80,10 @@ class UiStrings(object): 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:') diff --git a/openlp/core/ui/aboutdialog.py b/openlp/core/ui/aboutdialog.py index f0908b729..211bdfb0a 100644 --- a/openlp/core/ui/aboutdialog.py +++ b/openlp/core/ui/aboutdialog.py @@ -25,7 +25,7 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### -from PyQt4 import QtCore, QtGui +from PyQt4 import QtGui from openlp.core.lib import build_icon, translate from openlp.core.lib.ui import UiStrings, create_button, create_button_box diff --git a/openlp/core/ui/advancedtab.py b/openlp/core/ui/advancedtab.py index 8b60a55ee..0f34efe13 100644 --- a/openlp/core/ui/advancedtab.py +++ b/openlp/core/ui/advancedtab.py @@ -31,10 +31,16 @@ from datetime import datetime, timedelta from PyQt4 import QtCore, QtGui +import logging +import os +import sys from openlp.core.lib import SettingsTab, translate, build_icon, Receiver +from openlp.core.lib.settings import Settings from openlp.core.lib.ui import UiStrings +from openlp.core.utils import get_images_filter, AppLocation from openlp.core.lib import SlideLimits -from openlp.core.utils import get_images_filter + +log = logging.getLogger(__name__) class AdvancedTab(SettingsTab): """ @@ -59,6 +65,7 @@ class AdvancedTab(SettingsTab): '#strftime-strptime-behavior for more information.')) self.defaultImage = u':/graphics/openlp-splash-screen.png' self.defaultColor = u'#ffffff' + self.dataExists = False self.iconPath = u':/system/system_settings.png' advanced_translated = translate('OpenLP.AdvancedTab', 'Advanced') SettingsTab.__init__(self, parent, u'Advanced', advanced_translated) @@ -151,6 +158,71 @@ class AdvancedTab(SettingsTab): self.serviceNameLayout.addRow(self.serviceNameExampleLabel, self.serviceNameExample) self.leftLayout.addWidget(self.serviceNameGroupBox) + # Data Directory + self.dataDirectoryGroupBox = QtGui.QGroupBox(self.leftColumn) + self.dataDirectoryGroupBox.setObjectName(u'dataDirectoryGroupBox') + self.dataDirectoryLayout = QtGui.QFormLayout(self.dataDirectoryGroupBox) + self.dataDirectoryLayout.setObjectName(u'dataDirectoryLayout') + self.dataDirectoryCurrentLabel = QtGui.QLabel(self.dataDirectoryGroupBox) + self.dataDirectoryCurrentLabel.setObjectName( + u'dataDirectoryCurrentLabel') + self.dataDirectoryLabel = QtGui.QLabel(self.dataDirectoryGroupBox) + self.dataDirectoryLabel.setObjectName(u'dataDirectoryLabel') + self.dataDirectoryNewLabel = QtGui.QLabel(self.dataDirectoryGroupBox) + self.dataDirectoryNewLabel.setObjectName(u'dataDirectoryCurrentLabel') + self.newDataDirectoryEdit = QtGui.QLineEdit(self.dataDirectoryGroupBox) + self.newDataDirectoryEdit.setObjectName(u'newDataDirectoryEdit') + self.newDataDirectoryEdit.setReadOnly(True) + self.newDataDirectoryHasFilesLabel = QtGui.QLabel( + self.dataDirectoryGroupBox) + self.newDataDirectoryHasFilesLabel.setObjectName( + u'newDataDirectoryHasFilesLabel') + self.newDataDirectoryHasFilesLabel.setWordWrap(True) + self.dataDirectoryBrowseButton = QtGui.QToolButton( + self.dataDirectoryGroupBox) + self.dataDirectoryBrowseButton.setObjectName( + u'dataDirectoryBrowseButton') + self.dataDirectoryBrowseButton.setIcon( + build_icon(u':/general/general_open.png')) + self.dataDirectoryDefaultButton = QtGui.QToolButton( + self.dataDirectoryGroupBox) + self.dataDirectoryDefaultButton.setObjectName( + u'dataDirectoryDefaultButton') + self.dataDirectoryDefaultButton.setIcon( + build_icon(u':/general/general_revert.png')) + self.dataDirectoryCancelButton = QtGui.QToolButton( + self.dataDirectoryGroupBox) + self.dataDirectoryCancelButton.setObjectName( + u'dataDirectoryCancelButton') + self.dataDirectoryCancelButton.setIcon( + build_icon(u':/general/general_delete.png')) + self.newDataDirectoryLabelHBox = QtGui.QHBoxLayout() + self.newDataDirectoryLabelHBox.setObjectName( + u'newDataDirectoryLabelHBox') + self.newDataDirectoryLabelHBox.addWidget(self.newDataDirectoryEdit) + self.newDataDirectoryLabelHBox.addWidget( + self.dataDirectoryBrowseButton) + self.newDataDirectoryLabelHBox.addWidget( + self.dataDirectoryDefaultButton) + self.dataDirectoryCopyCheckHBox = QtGui.QHBoxLayout() + self.dataDirectoryCopyCheckHBox.setObjectName( + u'dataDirectoryCopyCheckHBox') + self.dataDirectoryCopyCheckBox = QtGui.QCheckBox( + self.dataDirectoryGroupBox) + self.dataDirectoryCopyCheckBox.setObjectName( + u'dataDirectoryCopyCheckBox') + self.dataDirectoryCopyCheckHBox.addWidget( + self.dataDirectoryCopyCheckBox) + self.dataDirectoryCopyCheckHBox.addStretch() + self.dataDirectoryCopyCheckHBox.addWidget( + self.dataDirectoryCancelButton) + self.dataDirectoryLayout.addRow(self.dataDirectoryCurrentLabel, + self.dataDirectoryLabel) + self.dataDirectoryLayout.addRow(self.dataDirectoryNewLabel, + self.newDataDirectoryLabelHBox) + self.dataDirectoryLayout.addRow(self.dataDirectoryCopyCheckHBox) + self.dataDirectoryLayout.addRow(self.newDataDirectoryHasFilesLabel) + self.leftLayout.addWidget(self.dataDirectoryGroupBox) self.leftLayout.addStretch() # Default Image self.defaultImageGroupBox = QtGui.QGroupBox(self.rightColumn) @@ -219,7 +291,6 @@ class AdvancedTab(SettingsTab): self.x11Layout.addWidget(self.x11BypassCheckBox) self.rightLayout.addWidget(self.x11GroupBox) self.rightLayout.addStretch() - self.shouldUpdateServiceNameExample = False QtCore.QObject.connect(self.serviceNameCheckBox, QtCore.SIGNAL(u'toggled(bool)'), self.serviceNameCheckBoxToggled) @@ -243,6 +314,18 @@ class AdvancedTab(SettingsTab): QtCore.SIGNAL(u'clicked()'), self.onDefaultRevertButtonClicked) QtCore.QObject.connect(self.x11BypassCheckBox, QtCore.SIGNAL(u'toggled(bool)'), self.onX11BypassCheckBoxToggled) + QtCore.QObject.connect(self.dataDirectoryBrowseButton, + QtCore.SIGNAL(u'clicked()'), + self.onDataDirectoryBrowseButtonClicked) + QtCore.QObject.connect(self.dataDirectoryDefaultButton, + QtCore.SIGNAL(u'clicked()'), + self.onDataDirectoryDefaultButtonClicked) + QtCore.QObject.connect(self.dataDirectoryCancelButton, + QtCore.SIGNAL(u'clicked()'), + self.onDataDirectoryCancelButtonClicked) + QtCore.QObject.connect(self.dataDirectoryCopyCheckBox, + QtCore.SIGNAL(u'toggled(bool)'), + self.onDataDirectoryCopyCheckBoxToggled) QtCore.QObject.connect(self.endSlideRadioButton, QtCore.SIGNAL(u'clicked()'), self.onEndSlideButtonClicked) QtCore.QObject.connect(self.wrapSlideRadioButton, @@ -257,6 +340,8 @@ class AdvancedTab(SettingsTab): self.tabTitleVisible = UiStrings().Advanced self.uiGroupBox.setTitle( translate('OpenLP.AdvancedTab', 'UI Settings')) + self.dataDirectoryGroupBox.setTitle( + translate('OpenLP.AdvancedTab', 'Data Location')) self.recentLabel.setText( translate('OpenLP.AdvancedTab', 'Number of recent files to display:')) @@ -320,6 +405,32 @@ class AdvancedTab(SettingsTab): 'Browse for an image file to display.')) self.defaultRevertButton.setToolTip(translate('OpenLP.AdvancedTab', 'Revert to the default OpenLP logo.')) + self.dataDirectoryCurrentLabel.setText(translate('OpenLP.AdvancedTab', + 'Current path:')) + self.dataDirectoryNewLabel.setText(translate('OpenLP.AdvancedTab', + 'Custom path:')) + self.dataDirectoryBrowseButton.setToolTip( + translate('OpenLP.AdvancedTab', + 'Browse for new data file location.')) + self.dataDirectoryDefaultButton.setToolTip( + translate('OpenLP.AdvancedTab', + 'Set the data location to the default.')) + self.dataDirectoryCancelButton.setText( + translate('OpenLP.AdvancedTab', + 'Cancel')) + self.dataDirectoryCancelButton.setToolTip( + translate('OpenLP.AdvancedTab', + 'Cancel OpenLP data directory location change.')) + self.dataDirectoryCopyCheckBox.setText( + translate('OpenLP.AdvancedTab', + 'Copy data to new location.')) + self.dataDirectoryCopyCheckBox.setToolTip( + translate('OpenLP.AdvancedTab', + 'Copy the OpenLP data files to the new location.')) + self.newDataDirectoryHasFilesLabel.setText( + translate('OpenLP.AdvancedTab', + 'WARNING: New data directory location contains ' + 'OpenLP data files. These files WILL be replaced during a copy.')) self.x11GroupBox.setTitle(translate('OpenLP.AdvancedTab', 'X11')) self.x11BypassCheckBox.setText(translate('OpenLP.AdvancedTab', @@ -340,12 +451,12 @@ class AdvancedTab(SettingsTab): """ Load settings from disk. """ - settings = QtCore.QSettings() + settings = Settings() settings.beginGroup(self.settingsSection) # The max recent files value does not have an interface and so never # gets actually stored in the settings therefore the default value of # 20 will always be used. - self.recentSpinBox.setMaximum(QtCore.QSettings().value( + self.recentSpinBox.setMaximum(Settings().value( u'max recent files', QtCore.QVariant(20)).toInt()[0]) self.recentSpinBox.setValue(settings.value(u'recent file count', QtCore.QVariant(4)).toInt()[0]) @@ -397,6 +508,40 @@ class AdvancedTab(SettingsTab): else: self.nextItemRadioButton.setChecked(True) settings.endGroup() + self.dataDirectoryCopyCheckBox.hide() + self.newDataDirectoryHasFilesLabel.hide() + self.dataDirectoryCancelButton.hide() + # Since data location can be changed, make sure the path is present. + self.currentDataPath = AppLocation.get_data_path() + if not os.path.exists(self.currentDataPath): + log.error(u'Data path not found %s' % self.currentDataPath) + answer = QtGui.QMessageBox.critical(self, + translate('OpenLP.AdvancedTab', + 'Data Directory Error'), + translate('OpenLP.AdvancedTab', + 'OpenLP data directory was not found\n\n%s\n\n' + 'This data directory was previously changed from the OpenLP ' + 'default location. If the new location was on removable ' + 'media, that media needs to be made available.\n\n' + 'Click "No" to stop loading OpenLP. allowing you to fix ' + 'the the problem.\n\n' + 'Click "Yes" to reset the data directory to the default ' + 'location.' % self.currentDataPath), + QtGui.QMessageBox.StandardButtons( + QtGui.QMessageBox.Yes | + QtGui.QMessageBox.No), + QtGui.QMessageBox.No) + if answer == QtGui.QMessageBox.No: + log.info(u'User requested termination') + Receiver.send_message(u'cleanup') + sys.exit() + # Set data location to default. + settings.remove(u'advanced/data path') + self.currentDataPath = AppLocation.get_data_path() + log.warning(u'User requested data path set to default %s' + % self.currentDataPath) + self.dataDirectoryLabel.setText(os.path.abspath( + self.currentDataPath)) self.defaultColorButton.setStyleSheet( u'background-color: %s' % self.defaultColor) @@ -404,7 +549,7 @@ class AdvancedTab(SettingsTab): """ Save settings to disk. """ - settings = QtCore.QSettings() + settings = Settings() settings.beginGroup(self.settingsSection) settings.setValue(u'default service enabled', self.serviceNameCheckBox.isChecked()) @@ -446,6 +591,11 @@ class AdvancedTab(SettingsTab): self.displayChanged = False Receiver.send_message(u'slidecontroller_update_slide_limits') + def cancel(self): + # Dialogue was cancelled, remove any pending data path change. + self.onDataDirectoryCancelButtonClicked() + SettingsTab.cancel(self) + def serviceNameCheckBoxToggled(self, default_service_enabled): self.serviceNameDay.setEnabled(default_service_enabled) time_enabled = default_service_enabled and \ @@ -507,6 +657,122 @@ class AdvancedTab(SettingsTab): self.defaultFileEdit.setText(filename) self.defaultFileEdit.setFocus() + def onDataDirectoryBrowseButtonClicked(self): + """ + Browse for a new data directory location. + """ + old_root_path = unicode(self.dataDirectoryLabel.text()) + # Get the new directory location. + new_data_path = unicode(QtGui.QFileDialog.getExistingDirectory(self, + translate('OpenLP.AdvancedTab', + 'Select Data Directory Location'), old_root_path, + options = QtGui.QFileDialog.ShowDirsOnly)) + # Set the new data path. + if new_data_path: + if self.currentDataPath.lower() == new_data_path.lower(): + self.onDataDirectoryCancelButtonClicked() + return + else: + return + # Make sure they want to change the data. + answer = QtGui.QMessageBox.question(self, + translate('OpenLP.AdvancedTab', 'Confirm Data Directory Change'), + translate('OpenLP.AdvancedTab', + 'Are you sure you want to change the location of the OpenLP ' + 'data directory to:\n\n%s\n\n' + 'The data directory will be changed when OpenLP is closed.' + % new_data_path), + QtGui.QMessageBox.StandardButtons( + QtGui.QMessageBox.Yes | + QtGui.QMessageBox.No), + QtGui.QMessageBox.No) + if answer != QtGui.QMessageBox.Yes: + return + # Check if data already exists here. + self.checkDataOverwrite(new_data_path) + # Save the new location. + Receiver.send_message(u'set_new_data_path', new_data_path) + self.newDataDirectoryEdit.setText(new_data_path) + self.dataDirectoryCancelButton.show() + + def onDataDirectoryDefaultButtonClicked(self): + """ + Re-set the data directory location to the 'default' location. + """ + new_data_path = AppLocation.get_directory(AppLocation.DataDir) + if self.currentDataPath.lower() != new_data_path.lower(): + # Make sure they want to change the data location back to the default. + answer = QtGui.QMessageBox.question(self, + translate('OpenLP.AdvancedTab', 'Reset Data Directory'), + translate('OpenLP.AdvancedTab', + 'Are you sure you want to change the location of the OpenLP ' + 'data directory to the default location?\n\n' + 'This location will be used after OpenLP is closed.'), + QtGui.QMessageBox.StandardButtons( + QtGui.QMessageBox.Yes | + QtGui.QMessageBox.No), + QtGui.QMessageBox.No) + if answer != QtGui.QMessageBox.Yes: + return + self.checkDataOverwrite(new_data_path) + # Save the new location. + Receiver.send_message(u'set_new_data_path', new_data_path) + self.newDataDirectoryEdit.setText(os.path.abspath(new_data_path)) + self.dataDirectoryCancelButton.show() + else: + # We cancel the change in case user changed their mind. + self.onDataDirectoryCancelButtonClicked() + + def onDataDirectoryCopyCheckBoxToggled(self): + Receiver.send_message(u'set_copy_data', + self.dataDirectoryCopyCheckBox.isChecked()) + if self.dataExists: + if self.dataDirectoryCopyCheckBox.isChecked(): + self.newDataDirectoryHasFilesLabel.show() + else: + self.newDataDirectoryHasFilesLabel.hide() + + def checkDataOverwrite(self, data_path ): + test_path = os.path.join(data_path, u'songs') + self.dataDirectoryCopyCheckBox.show() + if os.path.exists(test_path): + self.dataExists = True + # Check is they want to replace existing data. + answer = QtGui.QMessageBox.warning(self, + translate('OpenLP.AdvancedTab', 'Overwrite Existing Data'), + translate('OpenLP.AdvancedTab', + 'WARNING: \n\n' + 'The location you have selected \n\n%s\n\n' + 'appears to contain OpenLP data files. Do you wish to replace ' + 'these files with the current data files?' + % os.path.abspath(data_path,)), + QtGui.QMessageBox.StandardButtons( + QtGui.QMessageBox.Yes | + QtGui.QMessageBox.No), + QtGui.QMessageBox.No) + if answer == QtGui.QMessageBox.Yes: + self.dataDirectoryCopyCheckBox.setChecked(True) + self.newDataDirectoryHasFilesLabel.show() + else: + self.dataDirectoryCopyCheckBox.setChecked(False) + self.newDataDirectoryHasFilesLabel.hide() + else: + self.dataExists = False + self.dataDirectoryCopyCheckBox.setChecked(True) + self.newDataDirectoryHasFilesLabel.hide() + + def onDataDirectoryCancelButtonClicked(self): + """ + Cancel the data directory location change + """ + self.newDataDirectoryEdit.clear() + self.dataDirectoryCopyCheckBox.setChecked(False) + Receiver.send_message(u'set_new_data_path', u'') + Receiver.send_message(u'set_copy_data', False) + self.dataDirectoryCopyCheckBox.hide() + self.dataDirectoryCancelButton.hide() + self.newDataDirectoryHasFilesLabel.hide() + def onDefaultRevertButtonClicked(self): self.defaultFileEdit.setText(u':/graphics/openlp-splash-screen.png') self.defaultFileEdit.setFocus() diff --git a/openlp/core/ui/firsttimeform.py b/openlp/core/ui/firsttimeform.py index c675312ef..1866b88b5 100644 --- a/openlp/core/ui/firsttimeform.py +++ b/openlp/core/ui/firsttimeform.py @@ -39,6 +39,7 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import translate, PluginStatus, Receiver, build_icon, \ check_directory_exists +from openlp.core.lib.settings import Settings from openlp.core.utils import get_web_page, AppLocation from firsttimewizard import Ui_FirstTimeWizard, FirstTimePage @@ -116,7 +117,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard): check_directory_exists(os.path.join(gettempdir(), u'openlp')) self.noInternetFinishButton.setVisible(False) # Check if this is a re-run of the wizard. - self.hasRunWizard = QtCore.QSettings().value( + self.hasRunWizard = Settings().value( u'general/has run wizard', QtCore.QVariant(False)).toBool() # Sort out internet access for downloads if self.webAccess: @@ -209,7 +210,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard): index = self.themeComboBox.findText(theme) if index == -1: self.themeComboBox.addItem(theme) - default_theme = unicode(QtCore.QSettings().value( + default_theme = unicode(Settings().value( u'themes/global theme', QtCore.QVariant(u'')).toString()) # Pre-select the current default theme. @@ -261,7 +262,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard): self._performWizard() Receiver.send_message(u'openlp_process_events') Receiver.send_message(u'cursor_normal') - QtCore.QSettings().setValue(u'general/has run wizard', + Settings().setValue(u'general/has run wizard', QtCore.QVariant(True)) self.close() @@ -460,16 +461,16 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard): os.path.join(themes_destination, theme)) # Set Default Display if self.displayComboBox.currentIndex() != -1: - QtCore.QSettings().setValue(u'General/monitor', + Settings().setValue(u'General/monitor', QtCore.QVariant(self.displayComboBox.currentIndex())) self.screens.set_current_display( self.displayComboBox.currentIndex()) # Set Global Theme if self.themeComboBox.currentIndex() != -1: - QtCore.QSettings().setValue(u'themes/global theme', + Settings().setValue(u'themes/global theme', QtCore.QVariant(self.themeComboBox.currentText())) def _setPluginStatus(self, field, tag): status = PluginStatus.Active if field.checkState() \ == QtCore.Qt.Checked else PluginStatus.Inactive - QtCore.QSettings().setValue(tag, QtCore.QVariant(status)) + Settings().setValue(tag, QtCore.QVariant(status)) diff --git a/openlp/core/ui/firsttimelanguagedialog.py b/openlp/core/ui/firsttimelanguagedialog.py index f07d7bd15..51b077039 100644 --- a/openlp/core/ui/firsttimelanguagedialog.py +++ b/openlp/core/ui/firsttimelanguagedialog.py @@ -25,7 +25,7 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### -from PyQt4 import QtCore, QtGui +from PyQt4 import QtGui from openlp.core.lib import translate from openlp.core.lib.ui import create_button_box diff --git a/openlp/core/ui/generaltab.py b/openlp/core/ui/generaltab.py index d0647d829..78358f287 100644 --- a/openlp/core/ui/generaltab.py +++ b/openlp/core/ui/generaltab.py @@ -30,6 +30,7 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import SettingsTab, Receiver, translate from openlp.core.lib.ui import UiStrings +from openlp.core.lib.settings import Settings from openlp.core.ui import ScreenList log = logging.getLogger(__name__) @@ -265,7 +266,7 @@ class GeneralTab(SettingsTab): """ Load the settings to populate the form """ - settings = QtCore.QSettings() + settings = Settings() settings.beginGroup(self.settingsSection) self.monitorComboBox.clear() self.monitorComboBox.addItems(self.screens.get_screen_list()) @@ -327,7 +328,7 @@ class GeneralTab(SettingsTab): """ Save the settings from the form """ - settings = QtCore.QSettings() + settings = Settings() settings.beginGroup(self.settingsSection) settings.setValue(u'monitor', QtCore.QVariant(self.monitorComboBox.currentIndex())) diff --git a/openlp/core/ui/maindisplay.py b/openlp/core/ui/maindisplay.py index b642240a3..eb6b6c925 100644 --- a/openlp/core/ui/maindisplay.py +++ b/openlp/core/ui/maindisplay.py @@ -38,6 +38,7 @@ from PyQt4.phonon import Phonon from openlp.core.lib import Receiver, build_html, ServiceItem, image_to_byte, \ translate, PluginManager, expand_tags from openlp.core.lib.theme import BackgroundType +from openlp.core.lib.settings import Settings from openlp.core.ui import HideMode, ScreenList, AlertLocation @@ -100,9 +101,8 @@ class Display(QtGui.QGraphicsView): self.frame.setScrollBarPolicy(QtCore.Qt.Horizontal, QtCore.Qt.ScrollBarAlwaysOff) - def resizeEvent(self, ev): - self.webView.setGeometry(0, 0, - self.width(), self.height()) + def resizeEvent(self, event): + self.webView.setGeometry(0, 0, self.width(), self.height()) def isWebLoaded(self): """ @@ -120,7 +120,6 @@ class MainDisplay(Display): Display.__init__(self, parent, live, controller) self.imageManager = imageManager self.screens = ScreenList() - self.plugins = PluginManager.get_instance().plugins self.rebuildCSS = False self.hideMode = None self.override = {} @@ -134,7 +133,7 @@ class MainDisplay(Display): self.setStyleSheet(u'border: 0px; margin: 0px; padding: 0px;') windowFlags = QtCore.Qt.FramelessWindowHint | QtCore.Qt.Tool | \ QtCore.Qt.WindowStaysOnTopHint - if QtCore.QSettings().value(u'advanced/x11 bypass wm', + if Settings().value(u'advanced/x11 bypass wm', QtCore.QVariant(True)).toBool(): windowFlags |= QtCore.Qt.X11BypassWindowManagerHint # FIXME: QtCore.Qt.SplashScreen is workaround to make display screen @@ -195,11 +194,11 @@ class MainDisplay(Display): Display.setup(self) if self.isLive: # Build the initial frame. - image_file = QtCore.QSettings().value(u'advanced/default image', + image_file = Settings().value(u'advanced/default image', QtCore.QVariant(u':/graphics/openlp-splash-screen.png'))\ .toString() background_color = QtGui.QColor() - background_color.setNamedColor(QtCore.QSettings().value( + background_color.setNamedColor(Settings().value( u'advanced/default color', QtCore.QVariant(u'#ffffff')).toString()) if not background_color.isValid(): @@ -352,7 +351,7 @@ class MainDisplay(Display): # Single screen active if self.screens.display_count == 1: # Only make visible if setting enabled. - if QtCore.QSettings().value(u'general/display on monitor', + if Settings().value(u'general/display on monitor', QtCore.QVariant(True)).toBool(): self.setVisible(True) else: @@ -401,7 +400,7 @@ class MainDisplay(Display): self.footer(serviceItem.foot_text) # if was hidden keep it hidden if self.hideMode and self.isLive and not serviceItem.is_media(): - if QtCore.QSettings().value(u'general/auto unblank', + if Settings().value(u'general/auto unblank', QtCore.QVariant(False)).toBool(): Receiver.send_message(u'slidecontroller_live_unblank') else: @@ -425,7 +424,7 @@ class MainDisplay(Display): log.debug(u'hideDisplay mode = %d', mode) if self.screens.display_count == 1: # Only make visible if setting enabled. - if not QtCore.QSettings().value(u'general/display on monitor', + if not Settings().value(u'general/display on monitor', QtCore.QVariant(True)).toBool(): return if mode == HideMode.Screen: @@ -450,7 +449,7 @@ class MainDisplay(Display): log.debug(u'showDisplay') if self.screens.display_count == 1: # Only make visible if setting enabled. - if not QtCore.QSettings().value(u'general/display on monitor', + if not Settings().value(u'general/display on monitor', QtCore.QVariant(True)).toBool(): return self.frame.evaluateJavaScript('show_blank("show");') @@ -465,7 +464,7 @@ class MainDisplay(Display): """ Hide mouse cursor when moved over display. """ - if QtCore.QSettings().value(u'advanced/hide mouse', + if Settings().value(u'advanced/hide mouse', QtCore.QVariant(False)).toBool(): self.setCursor(QtCore.Qt.BlankCursor) self.frame.evaluateJavaScript('document.body.style.cursor = "none"') diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index 3923cad26..be58e1cd6 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -29,6 +29,8 @@ import logging import os import sys import shutil +from distutils import dir_util +from distutils.errors import DistutilsFileError from tempfile import gettempdir import time from datetime import datetime @@ -38,6 +40,7 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import Renderer, build_icon, OpenLPDockWidget, \ PluginManager, Receiver, translate, ImageManager, PluginStatus from openlp.core.lib.ui import UiStrings, create_action +from openlp.core.lib.settings import Settings from openlp.core.lib import SlideLimits from openlp.core.ui import AboutForm, SettingsForm, ServiceManager, \ ThemeManager, SlideController, PluginForm, MediaDockManager, \ @@ -100,12 +103,12 @@ class Ui_MainWindow(object): # Create slide controllers self.previewController = SlideController(self) self.liveController = SlideController(self, True) - previewVisible = QtCore.QSettings().value( + previewVisible = Settings().value( u'user interface/preview panel', QtCore.QVariant(True)).toBool() self.previewController.panel.setVisible(previewVisible) - liveVisible = QtCore.QSettings().value(u'user interface/live panel', + liveVisible = Settings().value(u'user interface/live panel', QtCore.QVariant(True)).toBool() - panelLocked = QtCore.QSettings().value(u'user interface/lock panel', + panelLocked = Settings().value(u'user interface/lock panel', QtCore.QVariant(False)).toBool() self.liveController.panel.setVisible(liveVisible) # Create menu @@ -582,6 +585,8 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): # Once settings are loaded update the menu with the recent files. self.updateRecentFilesMenu() self.pluginForm = PluginForm(self) + self.newDataPath = u'' + self.copyData = False # Set up signals and slots QtCore.QObject.connect(self.importThemeItem, QtCore.SIGNAL(u'triggered()'), @@ -634,6 +639,8 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): QtCore.SIGNAL(u'config_screen_changed'), self.screenChanged) QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'mainwindow_status_text'), self.showStatusMessage) + QtCore.QObject.connect(Receiver.get_receiver(), + QtCore.SIGNAL(u'cleanup'), self.cleanUp) # Media Manager QtCore.QObject.connect(self.mediaToolBox, QtCore.SIGNAL(u'currentChanged(int)'), self.onMediaToolBoxChanged) @@ -646,6 +653,10 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'openlp_information_message'), self.onInformationMessage) + QtCore.QObject.connect(Receiver.get_receiver(), + QtCore.SIGNAL(u'set_new_data_path'), self.setNewDataPath) + QtCore.QObject.connect(Receiver.get_receiver(), + QtCore.SIGNAL(u'set_copy_data'), self.setCopyData) # warning cyclic dependency # renderer needs to call ThemeManager and # ThemeManager needs to call Renderer @@ -686,9 +697,9 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): self.previewController.screenSizeChanged() self.liveController.screenSizeChanged() log.info(u'Load data from Settings') - if QtCore.QSettings().value(u'advanced/save current plugin', + if Settings().value(u'advanced/save current plugin', QtCore.QVariant(False)).toBool(): - savedPlugin = QtCore.QSettings().value( + savedPlugin = Settings().value( u'advanced/current media plugin', QtCore.QVariant()).toInt()[0] if savedPlugin != -1: self.mediaToolBox.setCurrentIndex(savedPlugin) @@ -740,11 +751,11 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): if not isinstance(filename, unicode): filename = unicode(filename, sys.getfilesystemencoding()) self.serviceManagerContents.loadFile(filename) - elif QtCore.QSettings().value( + elif Settings().value( self.generalSettingsSection + u'/auto open', QtCore.QVariant(False)).toBool(): self.serviceManagerContents.loadLastFile() - view_mode = QtCore.QSettings().value(u'%s/view mode' % \ + view_mode = Settings().value(u'%s/view mode' % \ self.generalSettingsSection, u'default').toString() if view_mode == u'default': self.modeDefaultItem.setChecked(True) @@ -822,7 +833,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): """ Check and display message if screen blank on setup. """ - settings = QtCore.QSettings() + settings = Settings() self.liveController.mainDisplaySetBackground() if settings.value(u'%s/screen blank' % self.generalSettingsSection, QtCore.QVariant(False)).toBool(): @@ -956,9 +967,9 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): # Add plugin sections. for plugin in self.pluginManager.plugins: setting_sections.extend([plugin.name]) - settings = QtCore.QSettings() - import_settings = QtCore.QSettings(import_file_name, - QtCore.QSettings.IniFormat) + settings = Settings() + import_settings = Settings(import_file_name, + Settings.IniFormat) import_keys = import_settings.allKeys() for section_key in import_keys: # We need to handle the really bad files. @@ -1020,7 +1031,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): 'OpenLP Export Settings File (*.conf)'))) if not export_file_name: return - # Make sure it's a .conf file. + # Make sure it's a .conf file. if not export_file_name.endswith(u'conf'): export_file_name = export_file_name + u'.conf' temp_file = os.path.join(unicode(gettempdir()), @@ -1043,12 +1054,12 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): os.remove(temp_file) if os.path.exists(export_file_name): os.remove(export_file_name) - settings = QtCore.QSettings() + settings = Settings() settings.remove(self.headerSection) # Get the settings. keys = settings.allKeys() - export_settings = QtCore.QSettings(temp_file, - QtCore.QSettings.IniFormat) + export_settings = Settings(temp_file, + Settings.IniFormat) # Add a header section. # This is to insure it's our conf file for import. now = datetime.now() @@ -1106,7 +1117,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): Set OpenLP to a different view mode. """ if mode: - settings = QtCore.QSettings() + settings = Settings() settings.setValue(u'%s/view mode' % self.generalSettingsSection, mode) self.mediaManagerDock.setVisible(media) @@ -1157,7 +1168,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): else: event.ignore() else: - if QtCore.QSettings().value(u'advanced/enable exit confirmation', + if Settings().value(u'advanced/enable exit confirmation', QtCore.QVariant(True)).toBool(): ret = QtGui.QMessageBox.question(self, translate('OpenLP.MainWindow', 'Close OpenLP'), @@ -1188,9 +1199,9 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): # Clean temporary files used by services self.serviceManagerContents.cleanUp() if save_settings: - if QtCore.QSettings().value(u'advanced/save current plugin', + if Settings().value(u'advanced/save current plugin', QtCore.QVariant(False)).toBool(): - QtCore.QSettings().setValue(u'advanced/current media plugin', + Settings().setValue(u'advanced/current media plugin', QtCore.QVariant(self.mediaToolBox.currentIndex())) # Call the cleanup method to shutdown plugins. log.info(u'cleanup plugins') @@ -1198,6 +1209,9 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): if save_settings: # Save settings self.saveSettings() + # Check if we need to change the data directory + if self.newDataPath: + self.changeDataDirectory() # Close down the display if self.liveController.display: self.liveController.display.close() @@ -1271,7 +1285,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): False - Hidden """ self.previewController.panel.setVisible(visible) - QtCore.QSettings().setValue(u'user interface/preview panel', + Settings().setValue(u'user interface/preview panel', QtCore.QVariant(visible)) self.viewPreviewPanel.setChecked(visible) @@ -1303,7 +1317,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): self.viewThemeManagerItem.setEnabled(True) self.viewPreviewPanel.setEnabled(True) self.viewLivePanel.setEnabled(True) - QtCore.QSettings().setValue(u'user interface/lock panel', + Settings().setValue(u'user interface/lock panel', QtCore.QVariant(lock)) def setLivePanelVisibility(self, visible): @@ -1317,7 +1331,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): False - Hidden """ self.liveController.panel.setVisible(visible) - QtCore.QSettings().setValue(u'user interface/live panel', + Settings().setValue(u'user interface/live panel', QtCore.QVariant(visible)) self.viewLivePanel.setChecked(visible) @@ -1327,19 +1341,19 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): """ log.debug(u'Loading QSettings') # Migrate Wrap Settings to Slide Limits Settings - if QtCore.QSettings().contains(self.generalSettingsSection + + if Settings().contains(self.generalSettingsSection + u'/enable slide loop'): - if QtCore.QSettings().value(self.generalSettingsSection + + if Settings().value(self.generalSettingsSection + u'/enable slide loop', QtCore.QVariant(True)).toBool(): - QtCore.QSettings().setValue(self.advancedSettingsSection + + Settings().setValue(self.advancedSettingsSection + u'/slide limits', QtCore.QVariant(SlideLimits.Wrap)) else: - QtCore.QSettings().setValue(self.advancedSettingsSection + + Settings().setValue(self.advancedSettingsSection + u'/slide limits', QtCore.QVariant(SlideLimits.End)) - QtCore.QSettings().remove(self.generalSettingsSection + + Settings().remove(self.generalSettingsSection + u'/enable slide loop') Receiver.send_message(u'slidecontroller_update_slide_limits') - settings = QtCore.QSettings() + settings = Settings() # Remove obsolete entries. settings.remove(u'custom slide') settings.remove(u'service') @@ -1368,7 +1382,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): if self.settingsImported: return log.debug(u'Saving QSettings') - settings = QtCore.QSettings() + settings = Settings() settings.beginGroup(self.generalSettingsSection) recentFiles = QtCore.QVariant(self.recentFiles) \ if self.recentFiles else QtCore.QVariant() @@ -1394,7 +1408,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): Updates the recent file menu with the latest list of service files accessed. """ - recentFileCount = QtCore.QSettings().value( + recentFileCount = Settings().value( u'advanced/recent file count', QtCore.QVariant(4)).toInt()[0] existingRecentFiles = [recentFile for recentFile in self.recentFiles if os.path.isfile(unicode(recentFile))] @@ -1427,7 +1441,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): # The maxRecentFiles value does not have an interface and so never gets # actually stored in the settings therefore the default value of 20 will # always be used. - maxRecentFiles = QtCore.QSettings().value(u'advanced/max recent files', + maxRecentFiles = Settings().value(u'advanced/max recent files', QtCore.QVariant(20)).toInt()[0] if filename: # Add some cleanup to reduce duplication in the recent file list @@ -1474,3 +1488,45 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): self.timer_id = 0 self.loadProgressBar.hide() Receiver.send_message(u'openlp_process_events') + + def setNewDataPath(self, new_data_path): + self.newDataPath = new_data_path + + def setCopyData(self, copy_data): + self.copyData = copy_data + + def changeDataDirectory(self): + log.info(u'Changing data path to %s' % self.newDataPath ) + old_data_path = unicode(AppLocation.get_data_path()) + # Copy OpenLP data to new location if requested. + if self.copyData: + log.info(u'Copying data to new path') + try: + Receiver.send_message(u'openlp_process_events') + Receiver.send_message(u'cursor_busy') + self.showStatusMessage( + translate('OpenLP.MainWindow', + 'Copying OpenLP data to new data directory location - %s ' + '- Please wait for copy to finish' + % self.newDataPath)) + dir_util.copy_tree(old_data_path, self.newDataPath) + log.info(u'Copy sucessful') + except (IOError, os.error, DistutilsFileError), why: + Receiver.send_message(u'cursor_normal') + log.exception(u'Data copy failed %s' % unicode(why)) + QtGui.QMessageBox.critical(self, + translate('OpenLP.MainWindow', 'New Data Directory Error'), + translate('OpenLP.MainWindow', + 'OpenLP Data directory copy failed\n\n%s' + % unicode(why)), + QtGui.QMessageBox.StandardButtons( + QtGui.QMessageBox.Ok)) + return False + else: + log.info(u'No data copy requested') + # Change the location of data directory in config file. + settings = QtCore.QSettings() + settings.setValue(u'advanced/data path', self.newDataPath) + # Check if the new data path is our default. + if self.newDataPath == AppLocation.get_directory(AppLocation.DataDir): + settings.remove(u'advanced/data path') diff --git a/openlp/core/ui/media/__init__.py b/openlp/core/ui/media/__init__.py index 5c4428a61..10583ffe0 100644 --- a/openlp/core/ui/media/__init__.py +++ b/openlp/core/ui/media/__init__.py @@ -26,6 +26,8 @@ ############################################################################### import logging +from openlp.core.lib.settings import Settings + from PyQt4 import QtCore log = logging.getLogger(__name__) @@ -78,11 +80,11 @@ def get_media_players(): Here an special media player is chosen for all media actions. """ log.debug(u'get_media_players') - players = unicode(QtCore.QSettings().value(u'media/players').toString()) + players = unicode(Settings().value(u'media/players').toString()) if not players: players = u'webkit' reg_ex = QtCore.QRegExp(".*\[(.*)\].*") - if QtCore.QSettings().value(u'media/override player', + if Settings().value(u'media/override player', QtCore.QVariant(QtCore.Qt.Unchecked)).toInt()[0] == QtCore.Qt.Checked: if reg_ex.exactMatch(players): overridden_player = u'%s' % reg_ex.cap(1) @@ -107,10 +109,10 @@ def set_media_players(players_list, overridden_player=u'auto'): """ log.debug(u'set_media_players') players = u','.join(players_list) - if QtCore.QSettings().value(u'media/override player', + if Settings().value(u'media/override player', QtCore.QVariant(QtCore.Qt.Unchecked)).toInt()[0] == \ QtCore.Qt.Checked and overridden_player != u'auto': players = players.replace(overridden_player, u'[%s]' % overridden_player) - QtCore.QSettings().setValue(u'media/players', QtCore.QVariant(players)) + Settings().setValue(u'media/players', QtCore.QVariant(players)) from mediacontroller import MediaController diff --git a/openlp/core/ui/media/mediacontroller.py b/openlp/core/ui/media/mediacontroller.py index b7356fcf5..7e51cd172 100644 --- a/openlp/core/ui/media/mediacontroller.py +++ b/openlp/core/ui/media/mediacontroller.py @@ -30,6 +30,7 @@ import os from PyQt4 import QtCore, QtGui from openlp.core.lib import OpenLPToolbar, Receiver, translate +from openlp.core.lib.settings import Settings from openlp.core.lib.mediaplayer import MediaPlayer from openlp.core.lib.ui import critical_error_message_box from openlp.core.ui.media import MediaState, MediaInfo, MediaType, \ @@ -333,10 +334,9 @@ class MediaController(object): "setBackBoard", null, null, null,"visible");') # now start playing if controller.isLive and \ - (QtCore.QSettings().value(u'general/auto unblank', + (Settings().value(u'general/auto unblank', QtCore.QVariant(False)).toBool() or \ - controller.media_info.is_background == True) or \ - controller.isLive == False: + controller.media_info.is_background) or not controller.isLive: if not self.video_play([controller]): critical_error_message_box( translate('MediaPlugin.MediaItem', 'Unsupported File'), @@ -495,7 +495,7 @@ class MediaController(object): return controller = self.parent.liveController for display in self.curDisplayMediaPlayer.keys(): - if display.controller != controller or \ + if display.controller != controller or \ self.curDisplayMediaPlayer[display].state != MediaState.Playing: continue self.curDisplayMediaPlayer[display].pause(display) diff --git a/openlp/core/ui/media/phononplayer.py b/openlp/core/ui/media/phononplayer.py index c366fe339..9bc739f65 100644 --- a/openlp/core/ui/media/phononplayer.py +++ b/openlp/core/ui/media/phononplayer.py @@ -38,21 +38,21 @@ from openlp.core.ui.media import MediaState log = logging.getLogger(__name__) ADDITIONAL_EXT = { - u'audio/ac3': [u'.ac3'], - u'audio/flac': [u'.flac'], - u'audio/x-m4a': [u'.m4a'], - u'audio/midi': [u'.mid', u'.midi'], - u'audio/x-mp3': [u'.mp3'], - u'audio/mpeg': [u'.mp3', u'.mp2', u'.mpga', u'.mpega', u'.m4a'], - u'audio/qcelp': [u'.qcp'], - u'audio/x-wma': [u'.wma'], - u'audio/x-ms-wma': [u'.wma'], - u'video/x-flv': [u'.flv'], - u'video/x-matroska': [u'.mpv', u'.mkv'], - u'video/x-wmv': [u'.wmv'], - u'video/x-mpg': [u'.mpg'], - u'video/mpeg' : [u'.mp4', u'.mts'], - u'video/x-ms-wmv': [u'.wmv']} + u'audio/ac3': [u'.ac3'], + u'audio/flac': [u'.flac'], + u'audio/x-m4a': [u'.m4a'], + u'audio/midi': [u'.mid', u'.midi'], + u'audio/x-mp3': [u'.mp3'], + u'audio/mpeg': [u'.mp3', u'.mp2', u'.mpga', u'.mpega', u'.m4a'], + u'audio/qcelp': [u'.qcp'], + u'audio/x-wma': [u'.wma'], + u'audio/x-ms-wma': [u'.wma'], + u'video/x-flv': [u'.flv'], + u'video/x-matroska': [u'.mpv', u'.mkv'], + u'video/x-wmv': [u'.wmv'], + u'video/x-mpg': [u'.mpg'], + u'video/mpeg' : [u'.mp4', u'.mts'], + u'video/x-ms-wmv': [u'.wmv']} class PhononPlayer(MediaPlayer): @@ -101,7 +101,7 @@ class PhononPlayer(MediaPlayer): display.mediaObject = Phonon.MediaObject(display) Phonon.createPath(display.mediaObject, display.phononWidget) if display.hasAudio: - display.audio = Phonon.AudioOutput( \ + display.audio = Phonon.AudioOutput( Phonon.VideoCategory, display.mediaObject) Phonon.createPath(display.mediaObject, display.audio) display.phononWidget.raise_() @@ -148,18 +148,17 @@ class PhononPlayer(MediaPlayer): controller.media_info.start_time > 0: start_time = controller.media_info.start_time display.mediaObject.play() - if self.media_state_wait(display, Phonon.PlayingState): - if start_time > 0: - self.seek(display, controller.media_info.start_time*1000) - self.volume(display, controller.media_info.volume) - controller.media_info.length = \ - int(display.mediaObject.totalTime()/1000) - controller.seekSlider.setMaximum(controller.media_info.length*1000) - self.state = MediaState.Playing - display.phononWidget.raise_() - return True - else: + if not self.media_state_wait(display, Phonon.PlayingState): return False + if start_time > 0: + self.seek(display, controller.media_info.start_time * 1000) + self.volume(display, controller.media_info.volume) + controller.media_info.length = \ + int(display.mediaObject.totalTime() / 1000) + controller.seekSlider.setMaximum(controller.media_info.length * 1000) + self.state = MediaState.Playing + display.phononWidget.raise_() + return True def pause(self, display): display.mediaObject.pause() @@ -198,9 +197,9 @@ class PhononPlayer(MediaPlayer): controller = display.controller if controller.media_info.end_time > 0: if display.mediaObject.currentTime() > \ - controller.media_info.end_time*1000: + controller.media_info.end_time * 1000: self.stop(display) self.set_visible(display, False) if not controller.seekSlider.isSliderDown(): - controller.seekSlider.setSliderPosition( \ + controller.seekSlider.setSliderPosition( display.mediaObject.currentTime()) diff --git a/openlp/core/ui/media/vlcplayer.py b/openlp/core/ui/media/vlcplayer.py index 6d26f3b34..2d98fb599 100644 --- a/openlp/core/ui/media/vlcplayer.py +++ b/openlp/core/ui/media/vlcplayer.py @@ -34,6 +34,7 @@ import sys from PyQt4 import QtCore, QtGui from openlp.core.lib import Receiver +from openlp.core.lib.settings import Settings from openlp.core.lib.mediaplayer import MediaPlayer from openlp.core.ui.media import MediaState @@ -62,7 +63,7 @@ if VLC_AVAILABLE: log.debug(u'VLC could not be loaded: %s' % version) AUDIO_EXT = [ - u'*.mp3' + u'*.mp3' , u'*.wav' , u'*.ogg' ] @@ -114,7 +115,7 @@ class VlcPlayer(MediaPlayer): command_line_options = u'--no-video-title-show' if not display.hasAudio: command_line_options += u' --no-audio --no-video-title-show' - if QtCore.QSettings().value(u'advanced/hide mouse', + if Settings().value(u'advanced/hide mouse', QtCore.QVariant(False)).toBool() and \ display.controller.isLive: command_line_options += u' --mouse-hide-timeout=0' @@ -130,9 +131,9 @@ class VlcPlayer(MediaPlayer): # this is platform specific! # you have to give the id of the QFrame (or similar object) to # vlc, different platforms have different functions for this - if sys.platform == "win32": # for Windows + if sys.platform == "win32": display.vlcMediaPlayer.set_hwnd(int(display.vlcWidget.winId())) - elif sys.platform == "darwin": # for MacOS + elif sys.platform == "darwin": display.vlcMediaPlayer.set_agl(int(display.vlcWidget.winId())) else: # for Linux using the X Server @@ -181,17 +182,16 @@ class VlcPlayer(MediaPlayer): if controller.media_info.start_time > 0: start_time = controller.media_info.start_time display.vlcMediaPlayer.play() - if self.media_state_wait(display, vlc.State.Playing): - if start_time > 0: - self.seek(display, controller.media_info.start_time * 1000) - controller.media_info.length = \ - int(display.vlcMediaPlayer.get_media().get_duration() / 1000) - controller.seekSlider.setMaximum(controller.media_info.length * 1000) - self.state = MediaState.Playing - display.vlcWidget.raise_() - return True - else: + if not self.media_state_wait(display, vlc.State.Playing): return False + if start_time > 0: + self.seek(display, controller.media_info.start_time * 1000) + controller.media_info.length = \ + int(display.vlcMediaPlayer.get_media().get_duration() / 1000) + controller.seekSlider.setMaximum(controller.media_info.length * 1000) + self.state = MediaState.Playing + display.vlcWidget.raise_() + return True def pause(self, display): if display.vlcMedia.get_state() != vlc.State.Playing: diff --git a/openlp/core/ui/media/webkitplayer.py b/openlp/core/ui/media/webkitplayer.py index e3713d7ae..7df376187 100644 --- a/openlp/core/ui/media/webkitplayer.py +++ b/openlp/core/ui/media/webkitplayer.py @@ -227,33 +227,33 @@ FLASH_HTML = u""" """ VIDEO_EXT = [ - u'*.3gp' - , u'*.3gpp' - , u'*.3g2' - , u'*.3gpp2' - , u'*.aac' - , u'*.flv' - , u'*.f4a' - , u'*.f4b' - , u'*.f4p' - , u'*.f4v' - , u'*.mov' - , u'*.m4a' - , u'*.m4b' - , u'*.m4p' - , u'*.m4v' - , u'*.mkv' - , u'*.mp4' - , u'*.ogv' - , u'*.webm' - , u'*.mpg', u'*.wmv', u'*.mpeg', u'*.avi' - , u'*.swf' - ] + u'*.3gp' + , u'*.3gpp' + , u'*.3g2' + , u'*.3gpp2' + , u'*.aac' + , u'*.flv' + , u'*.f4a' + , u'*.f4b' + , u'*.f4p' + , u'*.f4v' + , u'*.mov' + , u'*.m4a' + , u'*.m4b' + , u'*.m4p' + , u'*.m4v' + , u'*.mkv' + , u'*.mp4' + , u'*.ogv' + , u'*.webm' + , u'*.mpg', u'*.wmv', u'*.mpeg', u'*.avi' + , u'*.swf' + ] AUDIO_EXT = [ - u'*.mp3' - , u'*.ogg' - ] + u'*.mp3' + , u'*.ogg' + ] class WebkitPlayer(MediaPlayer): @@ -339,7 +339,7 @@ class WebkitPlayer(MediaPlayer): else: display.frame.evaluateJavaScript(u'show_video("play");') if start_time > 0: - self.seek(display, controller.media_info.start_time*1000) + self.seek(display, controller.media_info.start_time * 1000) # TODO add playing check and get the correct media length controller.media_info.length = length self.state = MediaState.Playing @@ -375,11 +375,11 @@ class WebkitPlayer(MediaPlayer): controller = display.controller if controller.media_info.is_flash: seek = seekVal - display.frame.evaluateJavaScript( \ + display.frame.evaluateJavaScript( u'show_flash("seek", null, null, "%s");' % (seek)) else: - seek = float(seekVal)/1000 - display.frame.evaluateJavaScript( \ + seek = float(seekVal) / 1000 + display.frame.evaluateJavaScript( u'show_video("seek", null, null, null, "%f");' % (seek)) def reset(self, display): @@ -406,24 +406,24 @@ class WebkitPlayer(MediaPlayer): def update_ui(self, display): controller = display.controller if controller.media_info.is_flash: - currentTime = display.frame.evaluateJavaScript( \ + currentTime = display.frame.evaluateJavaScript( u'show_flash("currentTime");').toInt()[0] - length = display.frame.evaluateJavaScript( \ + length = display.frame.evaluateJavaScript( u'show_flash("length");').toInt()[0] else: - if display.frame.evaluateJavaScript( \ + if display.frame.evaluateJavaScript( u'show_video("isEnded");').toString() == 'true': self.stop(display) - (currentTime, ok) = display.frame.evaluateJavaScript( \ + (currentTime, ok) = display.frame.evaluateJavaScript( u'show_video("currentTime");').toFloat() # check if conversion was ok and value is not 'NaN' if ok and currentTime != float('inf'): - currentTime = int(currentTime*1000) - (length, ok) = display.frame.evaluateJavaScript( \ + currentTime = int(currentTime * 1000) + (length, ok) = display.frame.evaluateJavaScript( u'show_video("length");').toFloat() # check if conversion was ok and value is not 'NaN' if ok and length != float('inf'): - length = int(length*1000) + length = int(length * 1000) if currentTime > 0: controller.media_info.length = length controller.seekSlider.setMaximum(length) diff --git a/openlp/core/ui/pluginform.py b/openlp/core/ui/pluginform.py index 435181568..f520bb235 100644 --- a/openlp/core/ui/pluginform.py +++ b/openlp/core/ui/pluginform.py @@ -102,9 +102,9 @@ class PluginForm(QtGui.QDialog, Ui_PluginViewDialog): self.versionNumberLabel.setText(self.activePlugin.version) self.aboutTextBrowser.setHtml(self.activePlugin.about()) self.programaticChange = True - status = 1 + status = PluginStatus.Active if self.activePlugin.status == PluginStatus.Active: - status = 0 + status = PluginStatus.Inactive self.statusComboBox.setCurrentIndex(status) self.statusComboBox.setEnabled(True) self.programaticChange = False @@ -129,7 +129,7 @@ class PluginForm(QtGui.QDialog, Ui_PluginViewDialog): def onStatusComboBoxChanged(self, status): if self.programaticChange or status == PluginStatus.Disabled: return - if status == 0: + if status == PluginStatus.Inactive: Receiver.send_message(u'cursor_busy') self.activePlugin.toggleStatus(PluginStatus.Active) Receiver.send_message(u'cursor_normal') diff --git a/openlp/core/ui/printserviceform.py b/openlp/core/ui/printserviceform.py index 943f8daff..65ee03b0a 100644 --- a/openlp/core/ui/printserviceform.py +++ b/openlp/core/ui/printserviceform.py @@ -33,6 +33,7 @@ from lxml import html from openlp.core.lib import translate, get_text_file_string, Receiver from openlp.core.lib.ui import UiStrings +from openlp.core.lib.settings import Settings from openlp.core.ui.printservicedialog import Ui_PrintServiceDialog, ZoomSize from openlp.core.utils import AppLocation @@ -120,7 +121,7 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog): self.zoom = 0 self.setupUi(self) # Load the settings for the dialog. - settings = QtCore.QSettings() + settings = Settings() settings.beginGroup(u'advanced') self.slideTextCheckBox.setChecked(settings.value( u'print slide text', QtCore.QVariant(False)).toBool()) @@ -318,7 +319,7 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog): elif display == ZoomSize.TwentyFive: self.previewWidget.fitToWidth() self.previewWidget.zoomIn(0.25) - settings = QtCore.QSettings() + settings = Settings() settings.beginGroup(u'advanced') settings.setValue(u'display size', QtCore.QVariant(display)) settings.endGroup() @@ -389,7 +390,7 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog): Save the settings and close the dialog. """ # Save the settings for this dialog. - settings = QtCore.QSettings() + settings = Settings() settings.beginGroup(u'advanced') settings.setValue(u'print slide text', QtCore.QVariant(self.slideTextCheckBox.isChecked())) diff --git a/openlp/core/ui/screen.py b/openlp/core/ui/screen.py index 72c88908e..1e81bae50 100644 --- a/openlp/core/ui/screen.py +++ b/openlp/core/ui/screen.py @@ -34,6 +34,7 @@ import copy from PyQt4 import QtCore from openlp.core.lib import Receiver, translate +from openlp.core.lib.settings import Settings log = logging.getLogger(__name__) @@ -245,7 +246,7 @@ class ScreenList(object): """ Loads the screen size and the monitor number from the settings. """ - settings = QtCore.QSettings() + settings = Settings() settings.beginGroup(u'general') self.set_current_display(settings.value(u'monitor', QtCore.QVariant(self.display_count - 1)).toInt()[0]) diff --git a/openlp/core/ui/serviceitemeditdialog.py b/openlp/core/ui/serviceitemeditdialog.py index 8410f4491..7a3bdf448 100644 --- a/openlp/core/ui/serviceitemeditdialog.py +++ b/openlp/core/ui/serviceitemeditdialog.py @@ -25,7 +25,7 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### -from PyQt4 import QtCore, QtGui +from PyQt4 import QtGui from openlp.core.lib import translate from openlp.core.lib.ui import create_button_box, create_button diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index 30567f2d2..71d3d4eb4 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -40,6 +40,7 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import OpenLPToolbar, ServiceItem, Receiver, build_icon, \ ItemCapabilities, SettingsManager, translate, str_to_bool from openlp.core.lib.theme import ThemeLevel +from openlp.core.lib.settings import Settings from openlp.core.lib.ui import UiStrings, critical_error_message_box, \ create_widget_action, find_and_set_in_combo_box from openlp.core.ui import ServiceNoteForm, ServiceItemEditForm, StartTimeForm @@ -274,7 +275,7 @@ class ServiceManager(QtGui.QWidget): QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'service_item_update'), self.serviceItemUpdate) # Last little bits of setting up - self.service_theme = unicode(QtCore.QSettings().value( + self.service_theme = unicode(Settings().value( self.mainwindow.serviceManagerSettingsSection + u'/service theme', QtCore.QVariant(u'')).toString()) self.servicePath = AppLocation.get_section_data_path(u'servicemanager') @@ -352,7 +353,7 @@ class ServiceManager(QtGui.QWidget): self._fileName = unicode(fileName) self.mainwindow.setServiceModified(self.isModified(), self.shortFileName()) - QtCore.QSettings(). \ + Settings(). \ setValue(u'servicemanager/last file',QtCore.QVariant(fileName)) def fileName(self): @@ -371,7 +372,7 @@ class ServiceManager(QtGui.QWidget): """ Triggered when Config dialog is updated. """ - self.expandTabs = QtCore.QSettings().value( + self.expandTabs = Settings().value( u'advanced/expand service item', QtCore.QVariant(u'False')).toBool() @@ -444,7 +445,7 @@ class ServiceManager(QtGui.QWidget): self.setFileName(u'') self.serviceId += 1 self.setModified(False) - QtCore.QSettings(). \ + Settings(). \ setValue(u'servicemanager/last file',QtCore.QVariant(u'')) Receiver.send_message(u'servicemanager_new_service') @@ -580,10 +581,7 @@ class ServiceManager(QtGui.QWidget): return self.saveFileAs() self.mainwindow.addRecentFile(path_file_name) self.setModified(False) - try: - delete_file(temp_file_name) - except: - pass + delete_file(temp_file_name) return success def saveFileAs(self): @@ -591,17 +589,17 @@ class ServiceManager(QtGui.QWidget): Get a file name and then call :func:`ServiceManager.saveFile` to save the file. """ - default_service_enabled = QtCore.QSettings().value( + default_service_enabled = Settings().value( u'advanced/default service enabled', QtCore.QVariant(True)).toBool() if default_service_enabled: - service_day = QtCore.QSettings().value( + service_day = Settings().value( u'advanced/default service day', 7).toInt()[0] if service_day == 7: time = datetime.now() else: - service_hour = QtCore.QSettings().value( + service_hour = Settings().value( u'advanced/default service hour', 11).toInt()[0] - service_minute = QtCore.QSettings().value( + service_minute = Settings().value( u'advanced/default service minute', 0).toInt()[0] now = datetime.now() day_delta = service_day - now.weekday() @@ -609,7 +607,7 @@ class ServiceManager(QtGui.QWidget): day_delta += 7 time = now + timedelta(days=day_delta) time = time.replace(hour=service_hour, minute=service_minute) - default_pattern = unicode(QtCore.QSettings().value( + default_pattern = unicode(Settings().value( u'advanced/default service name', translate('OpenLP.AdvancedTab', 'Service %Y-%m-%d %H-%M', 'This may not contain any of the following characters: ' @@ -690,7 +688,7 @@ class ServiceManager(QtGui.QWidget): self.setFileName(fileName) self.mainwindow.addRecentFile(fileName) self.setModified(False) - QtCore.QSettings().setValue( + Settings().setValue( 'servicemanager/last file', QtCore.QVariant(fileName)) else: critical_error_message_box( @@ -732,7 +730,7 @@ class ServiceManager(QtGui.QWidget): service was last closed. Can be blank if there was no service present. """ - fileName = QtCore.QSettings(). \ + fileName = Settings(). \ value(u'servicemanager/last file',QtCore.QVariant(u'')).toString() if fileName: self.loadFile(fileName) @@ -1104,7 +1102,7 @@ class ServiceManager(QtGui.QWidget): log.debug(u'onThemeComboBoxSelected') self.service_theme = unicode(self.themeComboBox.currentText()) self.mainwindow.renderer.set_service_theme(self.service_theme) - QtCore.QSettings().setValue( + Settings().setValue( self.mainwindow.serviceManagerSettingsSection + u'/service theme', QtCore.QVariant(self.service_theme)) @@ -1285,7 +1283,7 @@ class ServiceManager(QtGui.QWidget): if self.serviceItems[item][u'service_item'].is_valid: self.mainwindow.liveController.addServiceManagerItem( self.serviceItems[item][u'service_item'], child) - if QtCore.QSettings().value( + if Settings().value( self.mainwindow.generalSettingsSection + u'/auto preview', QtCore.QVariant(False)).toBool(): item += 1 diff --git a/openlp/core/ui/servicenoteform.py b/openlp/core/ui/servicenoteform.py index fb173ee43..b115cfd40 100644 --- a/openlp/core/ui/servicenoteform.py +++ b/openlp/core/ui/servicenoteform.py @@ -25,7 +25,7 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### -from PyQt4 import QtCore, QtGui +from PyQt4 import QtGui from openlp.core.lib import translate, SpellTextEdit from openlp.core.lib.ui import create_button_box diff --git a/openlp/core/ui/settingsform.py b/openlp/core/ui/settingsform.py index 7dd02826c..d183d9d4a 100644 --- a/openlp/core/ui/settingsform.py +++ b/openlp/core/ui/settingsform.py @@ -29,7 +29,7 @@ The :mod:`settingsform` provides a user interface for the OpenLP settings """ import logging -from PyQt4 import QtGui +from PyQt4 import QtCore, QtGui from openlp.core.lib import Receiver, build_icon, PluginStatus from openlp.core.ui import AdvancedTab, GeneralTab, ThemesTab diff --git a/openlp/core/ui/shortcutlistform.py b/openlp/core/ui/shortcutlistform.py index 457525dc0..fb0e8585c 100644 --- a/openlp/core/ui/shortcutlistform.py +++ b/openlp/core/ui/shortcutlistform.py @@ -31,6 +31,7 @@ import re from PyQt4 import QtCore, QtGui from openlp.core.lib import Receiver +from openlp.core.lib.settings import Settings from openlp.core.utils import translate from openlp.core.utils.actions import ActionList from shortcutlistdialog import Ui_ShortcutListDialog @@ -337,7 +338,7 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog): Save the shortcuts. **Note**, that we do not have to load the shortcuts, as they are loaded in :class:`~openlp.core.utils.ActionList`. """ - settings = QtCore.QSettings() + settings = Settings() settings.beginGroup(u'shortcuts') for category in self.action_list.categories: # Check if the category is for internal use only. diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py index c58183c6a..2aae81888 100644 --- a/openlp/core/ui/slidecontroller.py +++ b/openlp/core/ui/slidecontroller.py @@ -35,6 +35,7 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import OpenLPToolbar, Receiver, ItemCapabilities, \ translate, build_icon, build_html, PluginManager, ServiceItem from openlp.core.lib.ui import UiStrings, create_action +from openlp.core.lib.settings import Settings from openlp.core.lib import SlideLimits, ServiceItemAction from openlp.core.ui import HideMode, MainDisplay, Display, ScreenList from openlp.core.utils.actions import ActionList, CategoryOrder @@ -237,7 +238,7 @@ class SlideController(Controller): text=UiStrings().PlaySlidesToEnd, icon=u':/media/media_time.png', checked=False, shortcuts=[], category=self.category, triggers=self.onPlaySlidesOnce) - if QtCore.QSettings().value(self.parent().generalSettingsSection + + if Settings().value(self.parent().generalSettingsSection + u'/enable slide loop', QtCore.QVariant(True)).toBool(): self.playSlidesMenu.setDefaultAction(self.playSlidesLoop) else: @@ -662,7 +663,7 @@ class SlideController(Controller): """ Updates the Slide Limits variable from the settings. """ - self.slide_limits = QtCore.QSettings().value( + self.slide_limits = Settings().value( self.parent().advancedSettingsSection + u'/slide limits', QtCore.QVariant(SlideLimits.End)).toInt()[0] @@ -692,7 +693,7 @@ class SlideController(Controller): self.playSlidesLoop.setChecked(False) self.playSlidesLoop.setIcon(build_icon(u':/media/media_time.png')) if item.is_text(): - if QtCore.QSettings().value( + if Settings().value( self.parent().songsSettingsSection + u'/display songbar', QtCore.QVariant(True)).toBool() and self.slideList: self.songMenu.show() @@ -813,11 +814,11 @@ class SlideController(Controller): QtCore.QObject.connect(action, QtCore.SIGNAL(u'triggered(bool)'), self.onTrackTriggered) - self.display.audioPlayer.repeat = QtCore.QSettings().value( + self.display.audioPlayer.repeat = Settings().value( self.parent().generalSettingsSection + \ u'/audio repeat list', QtCore.QVariant(False)).toBool() - if QtCore.QSettings().value( + if Settings().value( self.parent().generalSettingsSection + \ u'/audio start paused', QtCore.QVariant(True)).toBool(): @@ -930,7 +931,7 @@ class SlideController(Controller): Allow the main display to blank the main display at startup time """ log.debug(u'mainDisplaySetBackground live = %s' % self.isLive) - display_type = QtCore.QSettings().value( + display_type = Settings().value( self.parent().generalSettingsSection + u'/screen blank', QtCore.QVariant(u'')).toString() if self.screens.which_screen(self.window()) != \ @@ -971,11 +972,11 @@ class SlideController(Controller): self.themeScreen.setChecked(False) self.desktopScreen.setChecked(False) if checked: - QtCore.QSettings().setValue( + Settings().setValue( self.parent().generalSettingsSection + u'/screen blank', QtCore.QVariant(u'blanked')) else: - QtCore.QSettings().remove( + Settings().remove( self.parent().generalSettingsSection + u'/screen blank') self.blankPlugin() self.updatePreview() @@ -992,11 +993,11 @@ class SlideController(Controller): self.themeScreen.setChecked(checked) self.desktopScreen.setChecked(False) if checked: - QtCore.QSettings().setValue( + Settings().setValue( self.parent().generalSettingsSection + u'/screen blank', QtCore.QVariant(u'themed')) else: - QtCore.QSettings().remove( + Settings().remove( self.parent().generalSettingsSection + u'/screen blank') self.blankPlugin() self.updatePreview() @@ -1013,11 +1014,11 @@ class SlideController(Controller): self.themeScreen.setChecked(False) self.desktopScreen.setChecked(checked) if checked: - QtCore.QSettings().setValue( + Settings().setValue( self.parent().generalSettingsSection + u'/screen blank', QtCore.QVariant(u'hidden')) else: - QtCore.QSettings().remove( + Settings().remove( self.parent().generalSettingsSection + u'/screen blank') self.hidePlugin(checked) self.updatePreview() @@ -1311,7 +1312,7 @@ class SlideController(Controller): """ triggered by clicking the Preview slide items """ - if QtCore.QSettings().value(u'advanced/double click live', + if Settings().value(u'advanced/double click live', QtCore.QVariant(False)).toBool(): # Live and Preview have issues if we have video or presentations # playing in both at the same time. diff --git a/openlp/core/ui/themelayoutdialog.py b/openlp/core/ui/themelayoutdialog.py index cab9d13fd..3aa9b0ede 100644 --- a/openlp/core/ui/themelayoutdialog.py +++ b/openlp/core/ui/themelayoutdialog.py @@ -25,7 +25,7 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### -from PyQt4 import QtCore, QtGui +from PyQt4 import QtGui from openlp.core.lib import translate from openlp.core.lib.ui import create_button_box diff --git a/openlp/core/ui/thememanager.py b/openlp/core/ui/thememanager.py index 3d243e569..6f302c752 100644 --- a/openlp/core/ui/thememanager.py +++ b/openlp/core/ui/thememanager.py @@ -40,6 +40,7 @@ from openlp.core.lib import OpenLPToolbar, get_text_file_string, build_icon, \ check_directory_exists, create_thumb, validate_thumb from openlp.core.lib.theme import ThemeXML, BackgroundType, VerticalType, \ BackgroundGradientType +from openlp.core.lib.settings import Settings from openlp.core.lib.ui import UiStrings, critical_error_message_box, \ create_widget_action from openlp.core.theme import Theme @@ -164,7 +165,7 @@ class ThemeManager(QtGui.QWidget): """ Triggered when Config dialog is updated. """ - self.global_theme = unicode(QtCore.QSettings().value( + self.global_theme = unicode(Settings().value( self.settingsSection + u'/global theme', QtCore.QVariant(u'')).toString()) @@ -244,7 +245,7 @@ class ThemeManager(QtGui.QWidget): name = unicode(translate('OpenLP.ThemeManager', '%s (default)')) % self.global_theme self.themeListWidget.item(count).setText(name) - QtCore.QSettings().setValue( + Settings().setValue( self.settingsSection + u'/global theme', QtCore.QVariant(self.global_theme)) Receiver.send_message(u'theme_update_global', self.global_theme) @@ -451,7 +452,7 @@ class ThemeManager(QtGui.QWidget): theme = ThemeXML() theme.theme_name = UiStrings().Default self._writeTheme(theme, None, None) - QtCore.QSettings().setValue( + Settings().setValue( self.settingsSection + u'/global theme', QtCore.QVariant(theme.theme_name)) self.configUpdated() @@ -770,7 +771,7 @@ class ThemeManager(QtGui.QWidget): Check to see if theme has been selected and the destructive action is allowed. """ - self.global_theme = unicode(QtCore.QSettings().value( + self.global_theme = unicode(Settings().value( self.settingsSection + u'/global theme', QtCore.QVariant(u'')).toString()) if check_item_selected(self.themeListWidget, select_text): diff --git a/openlp/core/ui/themestab.py b/openlp/core/ui/themestab.py index 567308115..825a71896 100644 --- a/openlp/core/ui/themestab.py +++ b/openlp/core/ui/themestab.py @@ -30,6 +30,7 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import SettingsTab, Receiver, translate from openlp.core.lib.theme import ThemeLevel from openlp.core.lib.ui import UiStrings, find_and_set_in_combo_box +from openlp.core.lib.settings import Settings class ThemesTab(SettingsTab): """ @@ -132,7 +133,7 @@ class ThemesTab(SettingsTab): 'any themes associated with either the service or the songs.')) def load(self): - settings = QtCore.QSettings() + settings = Settings() settings.beginGroup(self.settingsSection) self.theme_level = settings.value( u'theme level', ThemeLevel.Song).toInt()[0] @@ -146,7 +147,7 @@ class ThemesTab(SettingsTab): self.SongLevelRadioButton.setChecked(True) def save(self): - settings = QtCore.QSettings() + settings = Settings() settings.beginGroup(self.settingsSection) settings.setValue(u'theme level', QtCore.QVariant(self.theme_level)) settings.setValue(u'global theme', QtCore.QVariant(self.global_theme)) @@ -183,7 +184,7 @@ class ThemesTab(SettingsTab): [u'Bible Theme', u'Song Theme'] """ # Reload as may have been triggered by the ThemeManager. - self.global_theme = unicode(QtCore.QSettings().value( + self.global_theme = unicode(Settings().value( self.settingsSection + u'/global theme', QtCore.QVariant(u'')).toString()) self.DefaultComboBox.clear() diff --git a/openlp/core/ui/wizard.py b/openlp/core/ui/wizard.py index 0b4e8ec37..d7fbf4aaa 100644 --- a/openlp/core/ui/wizard.py +++ b/openlp/core/ui/wizard.py @@ -44,20 +44,9 @@ class WizardStrings(object): # Applications/Formats we import from or export to. These get used in # multiple places but do not need translating unless you find evidence of # the writers translating their own product name. - CCLI = u'CCLI/SongSelect' CSV = u'CSV' - DB = u'DreamBeam' - EW = u'EasyWorship' - ES = u'EasySlides' - FP = u'Foilpresenter' - OL = u'OpenLyrics' OS = u'OpenSong' OSIS = u'OSIS' - PS = u'PowerSong 1.0' - SB = u'SongBeamer' - SoF = u'Songs of Fellowship' - SSP = u'SongShow Plus' - WoW = u'Words of Worship' # These strings should need a good reason to be retranslated elsewhere. FinishedImport = translate('OpenLP.Ui', 'Finished import.') FormatLabel = translate('OpenLP.Ui', 'Format:') @@ -76,10 +65,12 @@ class WizardStrings(object): PercentSymbolFormat = unicode(translate('OpenLP.Ui', '%p%')) Ready = translate('OpenLP.Ui', 'Ready.') StartingImport = translate('OpenLP.Ui', 'Starting import...') - YouSpecifyFile = unicode(translate('OpenLP.Ui', 'You need to specify at ' + YouSpecifyFile = unicode(translate('OpenLP.Ui', 'You need to specify one ' + '%s file to import from.', 'A file type e.g. OpenSong')) + YouSpecifyFiles = unicode(translate('OpenLP.Ui', 'You need to specify at ' 'least one %s file to import from.', 'A file type e.g. OpenSong')) - YouSpecifyFolder = unicode(translate('OpenLP.Ui', 'You need to specify a ' - '%s folder to import from.', 'A file type e.g. OpenSong')) + YouSpecifyFolder = unicode(translate('OpenLP.Ui', 'You need to specify one ' + '%s folder to import from.', 'A song format e.g. PowerSong')) class OpenLPWizard(QtGui.QWizard): @@ -108,7 +99,7 @@ class OpenLPWizard(QtGui.QWizard): def setupUi(self, image): """ - Set up the wizard UI + Set up the wizard UI. """ self.setModal(True) self.setWizardStyle(QtGui.QWizard.ModernStyle) diff --git a/openlp/core/utils/__init__.py b/openlp/core/utils/__init__.py index f73237c06..4a1399fb7 100644 --- a/openlp/core/utils/__init__.py +++ b/openlp/core/utils/__init__.py @@ -36,6 +36,8 @@ from subprocess import Popen, PIPE import sys import urllib2 +from openlp.core.lib.settings import Settings + from PyQt4 import QtGui, QtCore if sys.platform != u'win32' and sys.platform != u'darwin': @@ -87,7 +89,7 @@ class AppLocation(object): VersionDir = 5 CacheDir = 6 LanguageDir = 7 - + # Base path where data/config/cache dir is located BaseDir = None @@ -126,8 +128,13 @@ class AppLocation(object): """ Return the path OpenLP stores all its data under. """ - path = AppLocation.get_directory(AppLocation.DataDir) - check_directory_exists(path) + # Check if we have a different data location. + if Settings().contains(u'advanced/data path'): + path = unicode(Settings().value( + u'advanced/data path').toString()) + else: + path = AppLocation.get_directory(AppLocation.DataDir) + check_directory_exists(path) return path @staticmethod @@ -280,7 +287,7 @@ def check_latest_version(current_version): """ version_string = current_version[u'full'] # set to prod in the distribution config file. - settings = QtCore.QSettings() + settings = Settings() settings.beginGroup(u'general') last_test = unicode(settings.value(u'last version test', QtCore.QVariant(datetime.now().date())).toString()) diff --git a/openlp/core/utils/actions.py b/openlp/core/utils/actions.py index 271a7c884..087da222c 100644 --- a/openlp/core/utils/actions.py +++ b/openlp/core/utils/actions.py @@ -30,6 +30,8 @@ by the shortcuts system. """ from PyQt4 import QtCore, QtGui +from openlp.core.lib.settings import Settings + class ActionCategory(object): """ The :class:`~openlp.core.utils.ActionCategory` class encapsulates a @@ -226,7 +228,7 @@ class ActionList(object): else: self.categories[category].actions.add(action, weight) # Load the shortcut from the config. - settings = QtCore.QSettings() + settings = Settings() settings.beginGroup(u'shortcuts') shortcuts = settings.value(action.objectName(), QtCore.QVariant(action.shortcuts())).toStringList() diff --git a/openlp/core/utils/languagemanager.py b/openlp/core/utils/languagemanager.py index 929105ad2..24899fd41 100644 --- a/openlp/core/utils/languagemanager.py +++ b/openlp/core/utils/languagemanager.py @@ -35,6 +35,7 @@ from PyQt4 import QtCore, QtGui from openlp.core.utils import AppLocation from openlp.core.lib import translate +from openlp.core.lib.settings import Settings log = logging.getLogger(__name__) @@ -101,7 +102,7 @@ class LanguageManager(object): """ Retrieve a saved language to use from settings """ - settings = QtCore.QSettings() + settings = Settings() language = unicode(settings.value( u'general/language', QtCore.QVariant(u'[en]')).toString()) log.info(u'Language file: \'%s\' Loaded from conf file' % language) @@ -133,7 +134,7 @@ class LanguageManager(object): language = unicode(qm_list[action_name]) if LanguageManager.auto_language: language = u'[%s]' % language - QtCore.QSettings().setValue( + Settings().setValue( u'general/language', QtCore.QVariant(language)) log.info(u'Language file: \'%s\' written to conf file' % language) if message: diff --git a/openlp/plugins/alerts/alertsplugin.py b/openlp/plugins/alerts/alertsplugin.py index ebaabb214..1a7fe565a 100644 --- a/openlp/plugins/alerts/alertsplugin.py +++ b/openlp/plugins/alerts/alertsplugin.py @@ -32,6 +32,7 @@ from PyQt4 import QtCore from openlp.core.lib import Plugin, StringContent, build_icon, translate from openlp.core.lib.db import Manager from openlp.core.lib.ui import create_action, UiStrings +from openlp.core.lib.settings import Settings from openlp.core.lib.theme import VerticalType from openlp.core.utils.actions import ActionList from openlp.plugins.alerts.lib import AlertsManager, AlertsTab @@ -160,7 +161,7 @@ class AlertsPlugin(Plugin): def toggleAlertsState(self): self.alertsActive = not self.alertsActive - QtCore.QSettings().setValue(self.settingsSection + u'/active', + Settings().setValue(self.settingsSection + u'/active', QtCore.QVariant(self.alertsActive)) def onAlertsTrigger(self): diff --git a/openlp/plugins/alerts/forms/alertdialog.py b/openlp/plugins/alerts/forms/alertdialog.py index b211a3aa4..f4144602f 100644 --- a/openlp/plugins/alerts/forms/alertdialog.py +++ b/openlp/plugins/alerts/forms/alertdialog.py @@ -25,7 +25,7 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### -from PyQt4 import QtCore, QtGui +from PyQt4 import QtGui from openlp.core.lib import build_icon, translate from openlp.core.lib.ui import create_button, create_button_box diff --git a/openlp/plugins/alerts/lib/alertstab.py b/openlp/plugins/alerts/lib/alertstab.py index 22346b0aa..6a323eb2a 100644 --- a/openlp/plugins/alerts/lib/alertstab.py +++ b/openlp/plugins/alerts/lib/alertstab.py @@ -30,6 +30,7 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import SettingsTab, translate, Receiver from openlp.core.ui import AlertLocation from openlp.core.lib.ui import UiStrings, create_valign_selection_widgets +from openlp.core.lib.settings import Settings class AlertsTab(SettingsTab): """ @@ -152,7 +153,7 @@ class AlertsTab(SettingsTab): self.updateDisplay() def load(self): - settings = QtCore.QSettings() + settings = Settings() settings.beginGroup(self.settingsSection) self.timeout = settings.value(u'timeout', QtCore.QVariant(5)).toInt()[0] self.font_color = unicode(settings.value( @@ -180,7 +181,7 @@ class AlertsTab(SettingsTab): self.changed = False def save(self): - settings = QtCore.QSettings() + settings = Settings() settings.beginGroup(self.settingsSection) # Check value has changed as no event handles this field if settings.value(u'location', QtCore.QVariant(1)).toInt()[0] != \ diff --git a/openlp/plugins/bibles/bibleplugin.py b/openlp/plugins/bibles/bibleplugin.py index 0dddab214..e1209514c 100644 --- a/openlp/plugins/bibles/bibleplugin.py +++ b/openlp/plugins/bibles/bibleplugin.py @@ -31,6 +31,7 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import Plugin, StringContent, build_icon, translate from openlp.core.lib.ui import create_action, UiStrings +from openlp.core.lib.settings import Settings from openlp.core.utils.actions import ActionList from openlp.plugins.bibles.lib import BibleManager, BiblesTab, BibleMediaItem from openlp.plugins.bibles.forms import BibleUpgradeForm @@ -91,7 +92,7 @@ class BiblePlugin(Plugin): QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)) == QtGui.QMessageBox.Yes: self.onToolsUpgradeItemTriggered() - settings = QtCore.QSettings() + settings = Settings() settings.beginGroup(self.settingsSection) if settings.contains(u'bookname language'): settings.setValue(u'book name language', settings.value( diff --git a/openlp/plugins/bibles/forms/bibleimportform.py b/openlp/plugins/bibles/forms/bibleimportform.py index cc50fdf9b..92911c22a 100644 --- a/openlp/plugins/bibles/forms/bibleimportform.py +++ b/openlp/plugins/bibles/forms/bibleimportform.py @@ -36,6 +36,7 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import Receiver, translate from openlp.core.lib.db import delete_database from openlp.core.lib.ui import UiStrings, critical_error_message_box +from openlp.core.lib.settings import Settings from openlp.core.ui.wizard import OpenLPWizard, WizardStrings from openlp.core.utils import AppLocation from openlp.plugins.bibles.lib.manager import BibleFormat @@ -590,7 +591,7 @@ class BibleImportForm(OpenLPWizard): """ Set default values for the wizard pages. """ - settings = QtCore.QSettings() + settings = Settings() settings.beginGroup(self.plugin.settingsSection) self.restart() self.finishButton.setVisible(False) diff --git a/openlp/plugins/bibles/forms/bibleupgradeform.py b/openlp/plugins/bibles/forms/bibleupgradeform.py index 88bbd8c63..4013284e4 100644 --- a/openlp/plugins/bibles/forms/bibleupgradeform.py +++ b/openlp/plugins/bibles/forms/bibleupgradeform.py @@ -36,6 +36,7 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import Receiver, SettingsManager, translate, \ check_directory_exists from openlp.core.lib.ui import UiStrings, critical_error_message_box +from openlp.core.lib.settings import Settings from openlp.core.ui.wizard import OpenLPWizard, WizardStrings from openlp.core.utils import AppLocation, delete_file from openlp.plugins.bibles.lib.db import BibleDB, BibleMeta, OldBibleDB, \ @@ -341,7 +342,7 @@ class BibleUpgradeForm(OpenLPWizard): Set default values for the wizard pages. """ log.debug(u'BibleUpgrade setDefaults') - settings = QtCore.QSettings() + settings = Settings() settings.beginGroup(self.plugin.settingsSection) self.stop_import_flag = False self.success.clear() diff --git a/openlp/plugins/bibles/forms/languagedialog.py b/openlp/plugins/bibles/forms/languagedialog.py index f3c831410..b4a5b4d6c 100644 --- a/openlp/plugins/bibles/forms/languagedialog.py +++ b/openlp/plugins/bibles/forms/languagedialog.py @@ -24,7 +24,7 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### -from PyQt4 import QtCore, QtGui +from PyQt4 import QtGui from openlp.core.lib import translate from openlp.core.lib.ui import create_button_box diff --git a/openlp/plugins/bibles/lib/__init__.py b/openlp/plugins/bibles/lib/__init__.py index 6cd8b8d8e..d81c0f770 100644 --- a/openlp/plugins/bibles/lib/__init__.py +++ b/openlp/plugins/bibles/lib/__init__.py @@ -31,9 +31,8 @@ plugin. import logging import re -from PyQt4 import QtCore - from openlp.core.lib import translate +from openlp.core.lib.settings import Settings from openlp.plugins.bibles.lib.db import BiblesResourcesDB log = logging.getLogger(__name__) @@ -185,7 +184,7 @@ def update_reference_separators(): ':|v|V|verse|verses;;-|to;;,|and;;end', 'Double-semicolon delimited separators for parsing references. ' 'Consult the developers for further information.')).split(u';;') - settings = QtCore.QSettings() + settings = Settings() settings.beginGroup(u'bibles') custom_separators = [ unicode(settings.value(u'verse separator').toString()), diff --git a/openlp/plugins/bibles/lib/biblestab.py b/openlp/plugins/bibles/lib/biblestab.py index c352a5faf..0b4de68d9 100644 --- a/openlp/plugins/bibles/lib/biblestab.py +++ b/openlp/plugins/bibles/lib/biblestab.py @@ -31,6 +31,7 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import Receiver, SettingsTab, translate from openlp.core.lib.ui import UiStrings, find_and_set_in_combo_box +from openlp.core.lib.settings import Settings from openlp.plugins.bibles.lib import LayoutStyle, DisplayStyle, \ update_reference_separators, get_reference_separator, LanguageSelection @@ -414,7 +415,7 @@ class BiblesTab(SettingsTab): self.getGreyTextPalette(True)) def load(self): - settings = QtCore.QSettings() + settings = Settings() settings.beginGroup(self.settingsSection) self.show_new_chapters = settings.value( u'display new chapter', QtCore.QVariant(False)).toBool() @@ -488,7 +489,7 @@ class BiblesTab(SettingsTab): settings.endGroup() def save(self): - settings = QtCore.QSettings() + settings = Settings() settings.beginGroup(self.settingsSection) settings.setValue(u'display new chapter', QtCore.QVariant(self.show_new_chapters)) diff --git a/openlp/plugins/bibles/lib/csvbible.py b/openlp/plugins/bibles/lib/csvbible.py index cd4b921a1..e61ae9164 100644 --- a/openlp/plugins/bibles/lib/csvbible.py +++ b/openlp/plugins/bibles/lib/csvbible.py @@ -73,7 +73,7 @@ class CSVBible(BibleDB): def __init__(self, parent, **kwargs): """ - Loads a Bible from a set of CVS files. + Loads a Bible from a set of CSV files. This class assumes the files contain all the information and a clean bible is being loaded. """ diff --git a/openlp/plugins/bibles/lib/http.py b/openlp/plugins/bibles/lib/http.py index fb79b26e1..3bf3e5397 100644 --- a/openlp/plugins/bibles/lib/http.py +++ b/openlp/plugins/bibles/lib/http.py @@ -43,6 +43,15 @@ from openlp.plugins.bibles.lib import SearchResults from openlp.plugins.bibles.lib.db import BibleDB, BiblesResourcesDB, \ Book +UGLY_CHARS = { + u'\u2014': u' - ', + u'\u2018': u'\'', + u'\u2019': u'\'', + u'\u201c': u'"', + u'\u201d': u'"', + u' ': u' ' +} + log = logging.getLogger(__name__) class BGExtract(object): @@ -54,6 +63,103 @@ class BGExtract(object): self.proxy_url = proxy_url socket.setdefaulttimeout(30) + def _remove_elements(self, parent, tag, class_=None): + """ + Remove a particular element from the BeautifulSoup tree. + + ``parent`` + The element from which items need to be removed. + + ``tag`` + A string of the tab type, e.g. "div" + + ``class_`` + An HTML class attribute for further qualification. + """ + if class_: + all_tags = parent.findAll(tag, class_) + else: + all_tags = parent.findAll(tag) + for element in all_tags: + element.extract() + + def _extract_verse(self, tag): + """ + Extract a verse (or part of a verse) from a tag. + + ``tag`` + The BeautifulSoup Tag element with the stuff we want. + """ + if isinstance(tag, NavigableString): + return None, unicode(tag) + elif tag.get('class') == 'versenum': + verse = unicode(tag.string)\ + .replace('[', '').replace(']', '').strip() + return verse, None + elif tag.get('class') == 'chapternum': + verse = '1' + return verse, None + else: + verse, text = None, '' + for child in tag.contents: + c_verse, c_text = self._extract_verse(child) + if c_verse: + verse = c_verse + if text and c_text: + text += c_text + elif c_text is not None: + text = c_text + return verse, text + + def _clean_soup(self, tag): + """ + Remove all the rubbish from the HTML page. + + ``tag`` + The base tag within which we want to remove stuff. + """ + self._remove_elements(tag, 'sup', 'crossreference') + self._remove_elements(tag, 'sup', 'footnote') + self._remove_elements(tag, 'div', 'footnotes') + self._remove_elements(tag, 'div', 'crossrefs') + self._remove_elements(tag, 'h3') + + def _extract_verses(self, tags): + """ + Extract all the verses from a pre-prepared list of HTML tags. + + ``tags`` + A list of BeautifulSoup Tag elements. + """ + verses = [] + tags = tags[::-1] + current_text = '' + for tag in tags: + verse, text = None, '' + for child in tag.contents: + c_verse, c_text = self._extract_verse(child) + if c_verse: + verse = c_verse + if text and c_text: + text += c_text + elif c_text is not None: + text = c_text + if not verse: + current_text = text + ' ' + current_text + else: + text += ' ' + current_text + current_text = '' + if text: + for old, new in UGLY_CHARS.iteritems(): + text = text.replace(old, new) + text = u' '.join(text.split()) + if verse and text: + verses.append((int(verse.strip()), text)) + verse_list = {} + for verse, text in verses[::-1]: + verse_list[verse] = text + return verse_list + def get_bible_chapter(self, version, book_name, chapter): """ Access and decode Bibles via the BibleGateway website. @@ -80,60 +186,9 @@ class BGExtract(object): if not soup: return None Receiver.send_message(u'openlp_process_events') - footnotes = soup.findAll(u'sup', u'footnote') - if footnotes: - for footnote in footnotes: - footnote.extract() - crossrefs = soup.findAll(u'sup', u'xref') - if crossrefs: - for crossref in crossrefs: - crossref.extract() - headings = soup.findAll(u'h5') - if headings: - for heading in headings: - heading.extract() - chapter_notes = soup.findAll('div', 'footnotes') - if chapter_notes: - log.debug('Found chapter notes') - for note in chapter_notes: - note.extract() - note_comments = soup.findAll(text=u'end of footnotes') - if note_comments: - for comment in note_comments: - comment.extract() - cleanup = [(re.compile('\s+'), lambda match: ' ')] - verses = BeautifulSoup(str(soup), markupMassage=cleanup) - verse_list = {} - # Cater for inconsistent mark up in the first verse of a chapter. - first_verse = verses.find(u'versenum') - if first_verse and first_verse.contents: - verse_list[1] = unicode(first_verse.contents[0]) - for verse in verses(u'sup', u'versenum'): - raw_verse_num = verse.next - clean_verse_num = 0 - # Not all verses exist in all translations and may or may not be - # represented by a verse number. If they are not fine, if they are - # it will probably be in a format that breaks int(). We will then - # have no idea what garbage may be sucked in to the verse text so - # if we do not get a clean int() then ignore the verse completely. - try: - clean_verse_num = int(str(raw_verse_num)) - except ValueError: - log.warn(u'Illegal verse number in %s %s %s:%s', - version, book_name, chapter, unicode(raw_verse_num)) - if clean_verse_num: - verse_text = raw_verse_num.next - part = raw_verse_num.next.next - while not (isinstance(part, Tag) and part.attrMap and - part.attrMap[u'class'] == u'versenum'): - # While we are still in the same verse grab all the text. - if isinstance(part, NavigableString): - verse_text = verse_text + part - if isinstance(part.next, Tag) and part.next.name == u'div': - # Run out of verses so stop. - break - part = part.next - verse_list[clean_verse_num] = unicode(verse_text) + div = soup.find('div', 'result-text-style-normal') + self._clean_soup(div) + verse_list = self._extract_verses(div.findAll('span', 'text')) if not verse_list: log.debug(u'No content found in the BibleGateway response.') send_error_message(u'parse') diff --git a/openlp/plugins/bibles/lib/manager.py b/openlp/plugins/bibles/lib/manager.py index bfba082af..6661fad47 100644 --- a/openlp/plugins/bibles/lib/manager.py +++ b/openlp/plugins/bibles/lib/manager.py @@ -32,6 +32,7 @@ from PyQt4 import QtCore from openlp.core.lib import Receiver, SettingsManager, translate from openlp.core.utils import AppLocation, delete_file +from openlp.core.lib.settings import Settings from openlp.plugins.bibles.lib import parse_reference, \ get_reference_separator, LanguageSelection from openlp.plugins.bibles.lib.db import BibleDB, BibleMeta @@ -126,7 +127,7 @@ class BibleManager(object): self.db_cache = None self.path = AppLocation.get_section_data_path(self.settingsSection) self.proxy_name = unicode( - QtCore.QSettings().value(self.settingsSection + u'/proxy name', + Settings().value(self.settingsSection + u'/proxy name', QtCore.QVariant(u'')).toString()) self.suffix = u'.sqlite' self.import_wizard = None @@ -378,7 +379,7 @@ class BibleManager(object): except (ValueError, TypeError): language_selection = LanguageSelection.Application if language_selection is None or language_selection == -1: - language_selection = QtCore.QSettings().value( + language_selection = Settings().value( self.settingsSection + u'/bookname language', QtCore.QVariant(0)).toInt()[0] return language_selection diff --git a/openlp/plugins/bibles/lib/mediaitem.py b/openlp/plugins/bibles/lib/mediaitem.py index 288e0e2de..6ff622e9d 100644 --- a/openlp/plugins/bibles/lib/mediaitem.py +++ b/openlp/plugins/bibles/lib/mediaitem.py @@ -33,6 +33,7 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, \ translate, create_separated_list from openlp.core.lib.searchedit import SearchEdit +from openlp.core.lib.settings import Settings from openlp.core.lib.ui import UiStrings, set_case_insensitive_completer, \ create_horizontal_adjusting_combo_box, critical_error_message_box, \ find_and_set_in_combo_box, build_icon @@ -294,7 +295,7 @@ class BibleMediaItem(MediaManagerItem): def configUpdated(self): log.debug(u'configUpdated') - if QtCore.QSettings().value(self.settingsSection + u'/second bibles', + if Settings().value(self.settingsSection + u'/second bibles', QtCore.QVariant(True)).toBool(): self.advancedSecondLabel.setVisible(True) self.advancedSecondComboBox.setVisible(True) @@ -362,7 +363,7 @@ class BibleMediaItem(MediaManagerItem): translate('BiblesPlugin.MediaItem', 'Text Search'), translate('BiblesPlugin.MediaItem', 'Search Text...')) ]) - self.quickSearchEdit.setCurrentSearchType(QtCore.QSettings().value( + self.quickSearchEdit.setCurrentSearchType(Settings().value( u'%s/last search type' % self.settingsSection, QtCore.QVariant(BibleSearch.Reference)).toInt()[0]) self.configUpdated() @@ -386,7 +387,7 @@ class BibleMediaItem(MediaManagerItem): self.advancedVersionComboBox.addItems(bibles) self.advancedSecondComboBox.addItems(bibles) # set the default value - bible = QtCore.QSettings().value( + bible = Settings().value( self.settingsSection + u'/advanced bible', QtCore.QVariant(u'')).toString() if bible in bibles: @@ -394,7 +395,7 @@ class BibleMediaItem(MediaManagerItem): self.initialiseAdvancedBible(unicode(bible)) elif bibles: self.initialiseAdvancedBible(bibles[0]) - bible = QtCore.QSettings().value( + bible = Settings().value( self.settingsSection + u'/quick bible', QtCore.QVariant( self.quickVersionComboBox.currentText())).toString() find_and_set_in_combo_box(self.quickVersionComboBox, bible) @@ -497,11 +498,11 @@ class BibleMediaItem(MediaManagerItem): """ log.debug(u'updateAutoCompleter') # Save the current search type to the configuration. - QtCore.QSettings().setValue(u'%s/last search type' % + Settings().setValue(u'%s/last search type' % self.settingsSection, QtCore.QVariant(self.quickSearchEdit.currentSearchType())) # Save the current bible to the configuration. - QtCore.QSettings().setValue(self.settingsSection + u'/quick bible', + Settings().setValue(self.settingsSection + u'/quick bible', QtCore.QVariant(self.quickVersionComboBox.currentText())) books = [] # We have to do a 'Reference Search'. @@ -596,7 +597,7 @@ class BibleMediaItem(MediaManagerItem): self.advancedStyleComboBox.setCurrentIndex(self.settings.layout_style) self.settings.layoutStyleComboBox.setCurrentIndex( self.settings.layout_style) - QtCore.QSettings().setValue( + Settings().setValue( self.settingsSection + u'/verse layout style', QtCore.QVariant(self.settings.layout_style)) @@ -605,12 +606,12 @@ class BibleMediaItem(MediaManagerItem): self.quickStyleComboBox.setCurrentIndex(self.settings.layout_style) self.settings.layoutStyleComboBox.setCurrentIndex( self.settings.layout_style) - QtCore.QSettings().setValue( + Settings().setValue( self.settingsSection + u'/verse layout style', QtCore.QVariant(self.settings.layout_style)) def onAdvancedVersionComboBox(self): - QtCore.QSettings().setValue(self.settingsSection + u'/advanced bible', + Settings().setValue(self.settingsSection + u'/advanced bible', QtCore.QVariant(self.advancedVersionComboBox.currentText())) self.initialiseAdvancedBible( unicode(self.advancedVersionComboBox.currentText()), diff --git a/openlp/plugins/custom/forms/editcustomdialog.py b/openlp/plugins/custom/forms/editcustomdialog.py index bd4fb78fa..28edce0d8 100644 --- a/openlp/plugins/custom/forms/editcustomdialog.py +++ b/openlp/plugins/custom/forms/editcustomdialog.py @@ -25,7 +25,7 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### -from PyQt4 import QtCore, QtGui +from PyQt4 import QtGui from openlp.core.lib import build_icon, translate from openlp.core.lib.ui import UiStrings, create_button_box, create_button diff --git a/openlp/plugins/custom/forms/editcustomslidedialog.py b/openlp/plugins/custom/forms/editcustomslidedialog.py index 381917e8c..7bc00d4ca 100644 --- a/openlp/plugins/custom/forms/editcustomslidedialog.py +++ b/openlp/plugins/custom/forms/editcustomslidedialog.py @@ -25,7 +25,7 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### -from PyQt4 import QtCore, QtGui +from PyQt4 import QtGui from openlp.core.lib import translate, SpellTextEdit, build_icon from openlp.core.lib.ui import UiStrings, create_button, create_button_box diff --git a/openlp/plugins/custom/lib/customtab.py b/openlp/plugins/custom/lib/customtab.py index 0466cf696..bd6b854e4 100644 --- a/openlp/plugins/custom/lib/customtab.py +++ b/openlp/plugins/custom/lib/customtab.py @@ -28,6 +28,7 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import SettingsTab, translate +from openlp.core.lib.settings import Settings class CustomTab(SettingsTab): """ @@ -66,11 +67,11 @@ class CustomTab(SettingsTab): self.displayFooter = True def load(self): - self.displayFooter = QtCore.QSettings().value( + self.displayFooter = Settings().value( self.settingsSection + u'/display footer', QtCore.QVariant(True)).toBool() self.displayFooterCheckBox.setChecked(self.displayFooter) def save(self): - QtCore.QSettings().setValue(self.settingsSection + u'/display footer', + Settings().setValue(self.settingsSection + u'/display footer', QtCore.QVariant(self.displayFooter)) diff --git a/openlp/plugins/custom/lib/mediaitem.py b/openlp/plugins/custom/lib/mediaitem.py index d36cb6400..d2002deb5 100644 --- a/openlp/plugins/custom/lib/mediaitem.py +++ b/openlp/plugins/custom/lib/mediaitem.py @@ -34,6 +34,7 @@ from sqlalchemy.sql import or_, func from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, \ check_item_selected, translate from openlp.core.lib.ui import UiStrings +from openlp.core.lib.settings import Settings from openlp.plugins.custom.forms import EditCustomForm from openlp.plugins.custom.lib import CustomXMLParser from openlp.plugins.custom.lib.db import CustomSlide @@ -99,7 +100,7 @@ class CustomMediaItem(MediaManagerItem): ]) self.loadList(self.manager.get_all_objects( CustomSlide, order_by_ref=CustomSlide.title)) - self.searchTextEdit.setCurrentSearchType(QtCore.QSettings().value( + self.searchTextEdit.setCurrentSearchType(Settings().value( u'%s/last search type' % self.settingsSection, QtCore.QVariant(CustomSearch.Titles)).toInt()[0]) @@ -215,7 +216,7 @@ class CustomMediaItem(MediaManagerItem): service_item.title = title for slide in raw_slides: service_item.add_from_text(slide[:30], slide) - if QtCore.QSettings().value(self.settingsSection + u'/display footer', + if Settings().value(self.settingsSection + u'/display footer', QtCore.QVariant(True)).toBool() or credit: service_item.raw_footer.append(u' '.join([title, credit])) else: @@ -224,7 +225,7 @@ class CustomMediaItem(MediaManagerItem): def onSearchTextButtonClicked(self): # Save the current search type to the configuration. - QtCore.QSettings().setValue(u'%s/last search type' % + Settings().setValue(u'%s/last search type' % self.settingsSection, QtCore.QVariant(self.searchTextEdit.currentSearchType())) # Reload the list considering the new search type. diff --git a/openlp/plugins/images/imageplugin.py b/openlp/plugins/images/imageplugin.py index a72eab1af..e148f5625 100644 --- a/openlp/plugins/images/imageplugin.py +++ b/openlp/plugins/images/imageplugin.py @@ -31,6 +31,7 @@ import logging from openlp.core.lib import Plugin, StringContent, build_icon, translate, \ Receiver +from openlp.core.lib.settings import Settings from openlp.plugins.images.lib import ImageMediaItem, ImageTab log = logging.getLogger(__name__) @@ -94,6 +95,6 @@ class ImagePlugin(Plugin): image manager to require updates. Actual update is triggered by the last part of saving the config. """ - background = QtGui.QColor(QtCore.QSettings().value(self.settingsSection + background = QtGui.QColor(Settings().value(self.settingsSection + u'/background color', QtCore.QVariant(u'#000000'))) self.liveController.imageManager.updateImages(u'image', background) diff --git a/openlp/plugins/images/lib/imagetab.py b/openlp/plugins/images/lib/imagetab.py index a8188ace6..d80240005 100644 --- a/openlp/plugins/images/lib/imagetab.py +++ b/openlp/plugins/images/lib/imagetab.py @@ -28,6 +28,7 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import SettingsTab, translate, Receiver +from openlp.core.lib.settings import Settings class ImageTab(SettingsTab): """ @@ -82,7 +83,7 @@ class ImageTab(SettingsTab): u'background-color: %s' % self.bg_color) def load(self): - settings = QtCore.QSettings() + settings = Settings() settings.beginGroup(self.settingsSection) self.bg_color = unicode(settings.value( u'background color', QtCore.QVariant(u'#000000')).toString()) @@ -92,7 +93,7 @@ class ImageTab(SettingsTab): u'background-color: %s' % self.bg_color) def save(self): - settings = QtCore.QSettings() + settings = Settings() settings.beginGroup(self.settingsSection) settings.setValue(u'background color', QtCore.QVariant(self.bg_color)) settings.endGroup() diff --git a/openlp/plugins/images/lib/mediaitem.py b/openlp/plugins/images/lib/mediaitem.py index ffa67b95e..7e66ad9c0 100644 --- a/openlp/plugins/images/lib/mediaitem.py +++ b/openlp/plugins/images/lib/mediaitem.py @@ -35,6 +35,7 @@ from openlp.core.lib import MediaManagerItem, build_icon, ItemCapabilities, \ SettingsManager, translate, check_item_selected, check_directory_exists, \ Receiver, create_thumb, validate_thumb from openlp.core.lib.ui import UiStrings, critical_error_message_box +from openlp.core.lib.settings import Settings from openlp.core.utils import AppLocation, delete_file, get_images_filter log = logging.getLogger(__name__) @@ -151,7 +152,7 @@ class ImageMediaItem(MediaManagerItem): def generateSlideData(self, service_item, item=None, xmlVersion=False, remote=False): - background = QtGui.QColor(QtCore.QSettings().value(self.settingsSection + background = QtGui.QColor(Settings().value(self.settingsSection + u'/background color', QtCore.QVariant(u'#000000'))) if item: items = [item] @@ -220,7 +221,7 @@ class ImageMediaItem(MediaManagerItem): if check_item_selected(self.listView, translate('ImagePlugin.MediaItem', 'You must select an image to replace the background with.')): - background = QtGui.QColor(QtCore.QSettings().value( + background = QtGui.QColor(Settings().value( self.settingsSection + u'/background color', QtCore.QVariant(u'#000000'))) item = self.listView.selectedIndexes()[0] diff --git a/openlp/plugins/media/lib/mediatab.py b/openlp/plugins/media/lib/mediatab.py index c7ec1a61b..5a9543642 100644 --- a/openlp/plugins/media/lib/mediatab.py +++ b/openlp/plugins/media/lib/mediatab.py @@ -29,6 +29,7 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import SettingsTab, translate, Receiver from openlp.core.lib.ui import UiStrings, create_button +from openlp.core.lib.settings import Settings from openlp.core.ui.media import get_media_players, set_media_players class MediaQCheckBox(QtGui.QCheckBox): """ @@ -186,7 +187,7 @@ class MediaTab(SettingsTab): else: checkbox.setChecked(False) self.updatePlayerList() - self.overridePlayerCheckBox.setChecked(QtCore.QSettings().value( + self.overridePlayerCheckBox.setChecked(Settings().value( self.settingsSection + u'/override player', QtCore.QVariant(QtCore.Qt.Unchecked)).toInt()[0]) @@ -200,9 +201,9 @@ class MediaTab(SettingsTab): player_string_changed = True override_changed = True setting_key = self.settingsSection + u'/override player' - if QtCore.QSettings().value(setting_key).toInt()[0] != \ + if Settings().value(setting_key).toInt()[0] != \ self.overridePlayerCheckBox.checkState(): - QtCore.QSettings().setValue(setting_key, + Settings().setValue(setting_key, QtCore.QVariant(self.overridePlayerCheckBox.checkState())) override_changed = True if override_changed: diff --git a/openlp/plugins/media/mediaplugin.py b/openlp/plugins/media/mediaplugin.py index 13c636e83..08d7f1983 100644 --- a/openlp/plugins/media/mediaplugin.py +++ b/openlp/plugins/media/mediaplugin.py @@ -30,6 +30,7 @@ import logging from PyQt4 import QtCore from openlp.core.lib import Plugin, StringContent, build_icon, translate +from openlp.core.lib.settings import Settings from openlp.plugins.media.lib import MediaMediaItem, MediaTab log = logging.getLogger(__name__) @@ -126,7 +127,7 @@ class MediaPlugin(Plugin): we want to check if we have the old "Use Phonon" setting, and convert it to "enable Phonon" and "make it the first one in the list". """ - settings = QtCore.QSettings() + settings = Settings() settings.beginGroup(self.settingsSection) if settings.contains(u'use phonon'): log.info(u'Found old Phonon setting') diff --git a/openlp/plugins/presentations/lib/mediaitem.py b/openlp/plugins/presentations/lib/mediaitem.py index 68eea809b..b98c2d093 100644 --- a/openlp/plugins/presentations/lib/mediaitem.py +++ b/openlp/plugins/presentations/lib/mediaitem.py @@ -36,6 +36,7 @@ from openlp.core.lib import MediaManagerItem, build_icon, SettingsManager, \ validate_thumb from openlp.core.lib.ui import UiStrings, critical_error_message_box, \ create_horizontal_adjusting_combo_box +from openlp.core.lib.settings import Settings from openlp.plugins.presentations.lib import MessageListener log = logging.getLogger(__name__) @@ -149,7 +150,7 @@ class PresentationMediaItem(MediaManagerItem): if self.displayTypeComboBox.count() > 1: self.displayTypeComboBox.insertItem(0, self.Automatic) self.displayTypeComboBox.setCurrentIndex(0) - if QtCore.QSettings().value(self.settingsSection + u'/override app', + if Settings().value(self.settingsSection + u'/override app', QtCore.QVariant(QtCore.Qt.Unchecked)) == QtCore.Qt.Checked: self.presentationWidget.show() else: diff --git a/openlp/plugins/presentations/lib/presentationcontroller.py b/openlp/plugins/presentations/lib/presentationcontroller.py index 7702f19cd..3bda3e069 100644 --- a/openlp/plugins/presentations/lib/presentationcontroller.py +++ b/openlp/plugins/presentations/lib/presentationcontroller.py @@ -33,6 +33,7 @@ from PyQt4 import QtCore from openlp.core.lib import Receiver, check_directory_exists, create_thumb, \ validate_thumb +from openlp.core.lib.settings import Settings from openlp.core.utils import AppLocation log = logging.getLogger(__name__) @@ -392,7 +393,7 @@ class PresentationController(object): """ Return whether the controller is currently enabled """ - if QtCore.QSettings().value( + if Settings().value( self.settings_section + u'/' + self.name, QtCore.QVariant(QtCore.Qt.Checked)).toInt()[0] == \ QtCore.Qt.Checked: diff --git a/openlp/plugins/presentations/lib/presentationtab.py b/openlp/plugins/presentations/lib/presentationtab.py index 1b9fa04d9..312f2b55a 100644 --- a/openlp/plugins/presentations/lib/presentationtab.py +++ b/openlp/plugins/presentations/lib/presentationtab.py @@ -29,6 +29,7 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import Receiver, SettingsTab, translate from openlp.core.lib.ui import UiStrings +from openlp.core.lib.settings import Settings class PresentationTab(SettingsTab): """ @@ -102,10 +103,10 @@ class PresentationTab(SettingsTab): for key in self.controllers: controller = self.controllers[key] checkbox = self.PresenterCheckboxes[controller.name] - checkbox.setChecked(QtCore.QSettings().value( + checkbox.setChecked(Settings().value( self.settingsSection + u'/' + controller.name, QtCore.QVariant(QtCore.Qt.Checked)).toInt()[0]) - self.OverrideAppCheckBox.setChecked(QtCore.QSettings().value( + self.OverrideAppCheckBox.setChecked(Settings().value( self.settingsSection + u'/override app', QtCore.QVariant(QtCore.Qt.Unchecked)).toInt()[0]) @@ -123,19 +124,19 @@ class PresentationTab(SettingsTab): if controller.is_available(): checkbox = self.PresenterCheckboxes[controller.name] setting_key = self.settingsSection + u'/' + controller.name - if QtCore.QSettings().value(setting_key) != \ + if Settings().value(setting_key) != \ checkbox.checkState(): changed = True - QtCore.QSettings().setValue(setting_key, + Settings().setValue(setting_key, QtCore.QVariant(checkbox.checkState())) if checkbox.isChecked(): controller.start_process() else: controller.kill() setting_key = self.settingsSection + u'/override app' - if QtCore.QSettings().value(setting_key) != \ + if Settings().value(setting_key) != \ self.OverrideAppCheckBox.checkState(): - QtCore.QSettings().setValue(setting_key, + Settings().setValue(setting_key, QtCore.QVariant(self.OverrideAppCheckBox.checkState())) changed = True if changed: diff --git a/openlp/plugins/remotes/lib/httpserver.py b/openlp/plugins/remotes/lib/httpserver.py index 43afebb41..4bae0a901 100644 --- a/openlp/plugins/remotes/lib/httpserver.py +++ b/openlp/plugins/remotes/lib/httpserver.py @@ -122,6 +122,7 @@ from PyQt4 import QtCore, QtNetwork from mako.template import Template from openlp.core.lib import Receiver, PluginStatus, StringContent +from openlp.core.lib.settings import Settings from openlp.core.utils import AppLocation, translate log = logging.getLogger(__name__) @@ -169,10 +170,10 @@ class HttpServer(object): clients. Listen out for socket connections. """ log.debug(u'Start TCP server') - port = QtCore.QSettings().value( + port = Settings().value( self.plugin.settingsSection + u'/port', QtCore.QVariant(4316)).toInt()[0] - address = QtCore.QSettings().value( + address = Settings().value( self.plugin.settingsSection + u'/ip address', QtCore.QVariant(u'0.0.0.0')).toString() self.server = QtNetwork.QTcpServer() @@ -404,7 +405,7 @@ class HttpConnection(object): u'slide': self.parent.current_slide or 0, u'item': self.parent.current_item._uuid \ if self.parent.current_item else u'', - u'twelve':QtCore.QSettings().value( + u'twelve':Settings().value( u'remotes/twelve hour', QtCore.QVariant(True)).toBool(), u'blank': self.parent.plugin.liveController.blankScreen.\ isChecked(), diff --git a/openlp/plugins/remotes/lib/remotetab.py b/openlp/plugins/remotes/lib/remotetab.py index bae2a7090..5130ee65e 100644 --- a/openlp/plugins/remotes/lib/remotetab.py +++ b/openlp/plugins/remotes/lib/remotetab.py @@ -28,6 +28,7 @@ from PyQt4 import QtCore, QtGui, QtNetwork from openlp.core.lib import SettingsTab, translate, Receiver +from openlp.core.lib.settings import Settings ZERO_URL = u'0.0.0.0' @@ -149,12 +150,12 @@ class RemoteTab(SettingsTab): def load(self): self.portSpinBox.setValue( - QtCore.QSettings().value(self.settingsSection + u'/port', + Settings().value(self.settingsSection + u'/port', QtCore.QVariant(4316)).toInt()[0]) self.addressEdit.setText( - QtCore.QSettings().value(self.settingsSection + u'/ip address', + Settings().value(self.settingsSection + u'/ip address', QtCore.QVariant(ZERO_URL)).toString()) - self.twelveHour = QtCore.QSettings().value( + self.twelveHour = Settings().value( self.settingsSection + u'/twelve hour', QtCore.QVariant(True)).toBool() self.twelveHourCheckBox.setChecked(self.twelveHour) @@ -162,16 +163,16 @@ class RemoteTab(SettingsTab): def save(self): changed = False - if QtCore.QSettings().value(self.settingsSection + u'/ip address', + if Settings().value(self.settingsSection + u'/ip address', QtCore.QVariant(ZERO_URL).toString() != self.addressEdit.text() or - QtCore.QSettings().value(self.settingsSection + u'/port', + Settings().value(self.settingsSection + u'/port', QtCore.QVariant(4316).toInt()[0]) != self.portSpinBox.value()): changed = True - QtCore.QSettings().setValue(self.settingsSection + u'/port', + Settings().setValue(self.settingsSection + u'/port', QtCore.QVariant(self.portSpinBox.value())) - QtCore.QSettings().setValue(self.settingsSection + u'/ip address', + Settings().setValue(self.settingsSection + u'/ip address', QtCore.QVariant(self.addressEdit.text())) - QtCore.QSettings().setValue(self.settingsSection + u'/twelve hour', + Settings().setValue(self.settingsSection + u'/twelve hour', QtCore.QVariant(self.twelveHour)) if changed: Receiver.send_message(u'remotes_config_updated') diff --git a/openlp/plugins/songs/forms/authorsdialog.py b/openlp/plugins/songs/forms/authorsdialog.py index f5cc69aa5..a7e798bf8 100644 --- a/openlp/plugins/songs/forms/authorsdialog.py +++ b/openlp/plugins/songs/forms/authorsdialog.py @@ -25,7 +25,7 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### -from PyQt4 import QtCore, QtGui +from PyQt4 import QtGui from openlp.core.lib import translate from openlp.core.lib.ui import create_button_box diff --git a/openlp/plugins/songs/forms/editsongform.py b/openlp/plugins/songs/forms/editsongform.py index 5dea45625..226d8baa1 100644 --- a/openlp/plugins/songs/forms/editsongform.py +++ b/openlp/plugins/songs/forms/editsongform.py @@ -172,17 +172,14 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog): def loadThemes(self, theme_list): self.themeComboBox.clear() self.themeComboBox.addItem(u'') - self.themes = [] - for theme in theme_list: - self.themeComboBox.addItem(theme) - self.themes.append(theme) + self.themes = theme_list + self.themeComboBox.addItems(theme_list) set_case_insensitive_completer(self.themes, self.themeComboBox) def loadMediaFiles(self): self.audioAddFromMediaButton.setVisible(False) for plugin in self.parent().pluginManager.plugins: - if plugin.name == u'media' and \ - plugin.status == PluginStatus.Active: + if plugin.name == u'media' and plugin.status == PluginStatus.Active: self.audioAddFromMediaButton.setVisible(True) self.mediaForm.populateFiles( plugin.mediaItem.getList(MediaType.Audio)) diff --git a/openlp/plugins/songs/forms/songbookdialog.py b/openlp/plugins/songs/forms/songbookdialog.py index 5c62514ad..073151d1d 100644 --- a/openlp/plugins/songs/forms/songbookdialog.py +++ b/openlp/plugins/songs/forms/songbookdialog.py @@ -25,7 +25,7 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### -from PyQt4 import QtCore, QtGui +from PyQt4 import QtGui from openlp.core.lib import translate from openlp.core.lib.ui import create_button_box diff --git a/openlp/plugins/songs/forms/songimportform.py b/openlp/plugins/songs/forms/songimportform.py index 4bdabd1a2..d9dd6b56c 100644 --- a/openlp/plugins/songs/forms/songimportform.py +++ b/openlp/plugins/songs/forms/songimportform.py @@ -35,8 +35,9 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import Receiver, SettingsManager, translate from openlp.core.lib.ui import UiStrings, critical_error_message_box +from openlp.core.lib.settings import Settings from openlp.core.ui.wizard import OpenLPWizard, WizardStrings -from openlp.plugins.songs.lib.importer import SongFormat +from openlp.plugins.songs.lib.importer import SongFormat, SongFormatSelect log = logging.getLogger(__name__) @@ -65,122 +66,59 @@ class SongImportForm(OpenLPWizard): """ Set up the song wizard UI. """ + self.formatWidgets = dict([(format, {}) for format in + SongFormat.get_format_list()]) OpenLPWizard.setupUi(self, image) - self.formatStack.setCurrentIndex(0) + self.currentFormat = SongFormat.OpenLyrics + self.formatStack.setCurrentIndex(self.currentFormat) QtCore.QObject.connect(self.formatComboBox, QtCore.SIGNAL(u'currentIndexChanged(int)'), self.onCurrentIndexChanged) def onCurrentIndexChanged(self, index): """ - Called when the format combo box's index changed. We have to check if - the import is available and accordingly to disable or enable the next - button. + Called when the format combo box's index changed. """ + self.currentFormat = index self.formatStack.setCurrentIndex(index) - next_button = self.button(QtGui.QWizard.NextButton) - next_button.setEnabled(SongFormat.get_availability(index)) + self.sourcePage.emit(QtCore.SIGNAL(u'completeChanged()')) def customInit(self): """ Song wizard specific initialisation. """ - if not SongFormat.get_availability(SongFormat.OpenLP1): - self.openLP1DisabledWidget.setVisible(True) - self.openLP1ImportWidget.setVisible(False) - if not SongFormat.get_availability(SongFormat.SongsOfFellowship): - self.songsOfFellowshipDisabledWidget.setVisible(True) - self.songsOfFellowshipImportWidget.setVisible(False) - if not SongFormat.get_availability(SongFormat.Generic): - self.genericDisabledWidget.setVisible(True) - self.genericImportWidget.setVisible(False) + for format in SongFormat.get_format_list(): + if not SongFormat.get(format, u'availability'): + self.formatWidgets[format][u'disabledWidget'].setVisible(True) + self.formatWidgets[format][u'importWidget'].setVisible(False) def customSignals(self): """ Song wizard specific signals. """ - QtCore.QObject.connect(self.openLP2BrowseButton, - QtCore.SIGNAL(u'clicked()'), - self.onOpenLP2BrowseButtonClicked) - QtCore.QObject.connect(self.openLP1BrowseButton, - QtCore.SIGNAL(u'clicked()'), - self.onOpenLP1BrowseButtonClicked) - QtCore.QObject.connect(self.powerSongBrowseButton, - QtCore.SIGNAL(u'clicked()'), - self.onPowerSongBrowseButtonClicked) - QtCore.QObject.connect(self.openLyricsAddButton, - QtCore.SIGNAL(u'clicked()'), - self.onOpenLyricsAddButtonClicked) - QtCore.QObject.connect(self.openLyricsRemoveButton, - QtCore.SIGNAL(u'clicked()'), - self.onOpenLyricsRemoveButtonClicked) - QtCore.QObject.connect(self.openSongAddButton, - QtCore.SIGNAL(u'clicked()'), - self.onOpenSongAddButtonClicked) - QtCore.QObject.connect(self.openSongRemoveButton, - QtCore.SIGNAL(u'clicked()'), - self.onOpenSongRemoveButtonClicked) - QtCore.QObject.connect(self.wordsOfWorshipAddButton, - QtCore.SIGNAL(u'clicked()'), - self.onWordsOfWorshipAddButtonClicked) - QtCore.QObject.connect(self.wordsOfWorshipRemoveButton, - QtCore.SIGNAL(u'clicked()'), - self.onWordsOfWorshipRemoveButtonClicked) - QtCore.QObject.connect(self.ccliAddButton, - QtCore.SIGNAL(u'clicked()'), - self.onCCLIAddButtonClicked) - QtCore.QObject.connect(self.ccliRemoveButton, - QtCore.SIGNAL(u'clicked()'), - self.onCCLIRemoveButtonClicked) - QtCore.QObject.connect(self.dreamBeamAddButton, - QtCore.SIGNAL(u'clicked()'), - self.onDreamBeamAddButtonClicked) - QtCore.QObject.connect(self.dreamBeamRemoveButton, - QtCore.SIGNAL(u'clicked()'), - self.onDreamBeamRemoveButtonClicked) - QtCore.QObject.connect(self.songsOfFellowshipAddButton, - QtCore.SIGNAL(u'clicked()'), - self.onSongsOfFellowshipAddButtonClicked) - QtCore.QObject.connect(self.songsOfFellowshipRemoveButton, - QtCore.SIGNAL(u'clicked()'), - self.onSongsOfFellowshipRemoveButtonClicked) - QtCore.QObject.connect(self.genericAddButton, - QtCore.SIGNAL(u'clicked()'), - self.onGenericAddButtonClicked) - QtCore.QObject.connect(self.genericRemoveButton, - QtCore.SIGNAL(u'clicked()'), - self.onGenericRemoveButtonClicked) - QtCore.QObject.connect(self.easySlidesBrowseButton, - QtCore.SIGNAL(u'clicked()'), - self.onEasySlidesBrowseButtonClicked) - QtCore.QObject.connect(self.ewBrowseButton, - QtCore.SIGNAL(u'clicked()'), - self.onEWBrowseButtonClicked) - QtCore.QObject.connect(self.songBeamerAddButton, - QtCore.SIGNAL(u'clicked()'), - self.onSongBeamerAddButtonClicked) - QtCore.QObject.connect(self.songBeamerRemoveButton, - QtCore.SIGNAL(u'clicked()'), - self.onSongBeamerRemoveButtonClicked) - QtCore.QObject.connect(self.songShowPlusAddButton, - QtCore.SIGNAL(u'clicked()'), - self.onSongShowPlusAddButtonClicked) - QtCore.QObject.connect(self.songShowPlusRemoveButton, - QtCore.SIGNAL(u'clicked()'), - self.onSongShowPlusRemoveButtonClicked) - QtCore.QObject.connect(self.foilPresenterAddButton, - QtCore.SIGNAL(u'clicked()'), - self.onFoilPresenterAddButtonClicked) - QtCore.QObject.connect(self.foilPresenterRemoveButton, - QtCore.SIGNAL(u'clicked()'), - self.onFoilPresenterRemoveButtonClicked) + for format in SongFormat.get_format_list(): + select_mode = SongFormat.get(format, u'selectMode') + if select_mode == SongFormatSelect.MultipleFiles: + QtCore.QObject.connect(self.formatWidgets[format][u'addButton'], + QtCore.SIGNAL(u'clicked()'), self.onAddButtonClicked) + QtCore.QObject.connect( + self.formatWidgets[format][u'removeButton'], + QtCore.SIGNAL(u'clicked()'), self.onRemoveButtonClicked) + else: + QtCore.QObject.connect( + self.formatWidgets[format][u'browseButton'], + QtCore.SIGNAL(u'clicked()'), self.onBrowseButtonClicked) + QtCore.QObject.connect( + self.formatWidgets[format][u'filepathEdit'], + QtCore.SIGNAL(u'textChanged (const QString&)'), + self.onFilepathEditTextChanged) def addCustomPages(self): """ Add song wizard specific pages. """ # Source Page - self.sourcePage = QtGui.QWizardPage() + self.sourcePage = SongImportSourcePage() self.sourcePage.setObjectName(u'SourcePage') self.sourceLayout = QtGui.QVBoxLayout(self.sourcePage) self.sourceLayout.setObjectName(u'SourceLayout') @@ -196,42 +134,16 @@ class SongImportForm(OpenLPWizard): self.formatLayout.setItem(1, QtGui.QFormLayout.LabelRole, self.formatSpacer) self.sourceLayout.addLayout(self.formatLayout) + self.formatHSpacing = self.formatLayout.horizontalSpacing() + self.formatVSpacing = self.formatLayout.verticalSpacing() + self.formatLayout.setVerticalSpacing(0) self.stackSpacer = QtGui.QSpacerItem(10, 0, QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Expanding) self.formatStack = QtGui.QStackedLayout() self.formatStack.setObjectName(u'FormatStack') - # OpenLyrics - self.addFileSelectItem(u'openLyrics', u'OpenLyrics', True) - # OpenLP 2.0 - self.addFileSelectItem(u'openLP2', single_select=True) - # openlp.org 1.x - self.addFileSelectItem(u'openLP1', None, True, True) - # Generic Document/Presentation import - self.addFileSelectItem(u'generic', None, True) - # CCLI File import - self.addFileSelectItem(u'ccli') - # DreamBeam - self.addFileSelectItem(u'dreamBeam') - # EasySlides - self.addFileSelectItem(u'easySlides', single_select=True) - # EasyWorship - self.addFileSelectItem(u'ew', single_select=True) - # Foilpresenter - self.addFileSelectItem(u'foilPresenter') - # Open Song - self.addFileSelectItem(u'openSong', u'OpenSong') - # PowerSong - self.addFileSelectItem(u'powerSong', single_select=True) - # SongBeamer - self.addFileSelectItem(u'songBeamer') - # Song Show Plus - self.addFileSelectItem(u'songShowPlus') - # Songs of Fellowship - self.addFileSelectItem(u'songsOfFellowship', None, True) - # Words of Worship - self.addFileSelectItem(u'wordsOfWorship') -# Commented out for future use. -# self.addFileSelectItem(u'csv', u'CSV', single_select=True) + self.disablableFormats = [] + for self.currentFormat in SongFormat.get_format_list(): + self.addFileSelectItem() self.sourceLayout.addLayout(self.formatStack) self.addPage(self.sourcePage) @@ -245,113 +157,38 @@ class SongImportForm(OpenLPWizard): translate('OpenLP.Ui', 'Welcome to the Song Import Wizard')) self.informationLabel.setText( translate('SongsPlugin.ImportWizardForm', - 'This wizard will help you to import songs from a variety of ' - 'formats. Click the next button below to start the process by ' - 'selecting a format to import from.')) + 'This wizard will help you to import songs from a variety of ' + 'formats. Click the next button below to start the process by ' + 'selecting a format to import from.')) self.sourcePage.setTitle(WizardStrings.ImportSelect) self.sourcePage.setSubTitle(WizardStrings.ImportSelectLong) self.formatLabel.setText(WizardStrings.FormatLabel) - self.formatComboBox.setItemText(SongFormat.OpenLyrics, - translate('SongsPlugin.ImportWizardForm', - 'OpenLyrics or OpenLP 2.0 Exported Song')) - self.formatComboBox.setItemText(SongFormat.OpenLP2, UiStrings().OLPV2) - self.formatComboBox.setItemText(SongFormat.OpenLP1, UiStrings().OLPV1) - self.formatComboBox.setItemText(SongFormat.Generic, - translate('SongsPlugin.ImportWizardForm', - 'Generic Document/Presentation')) - self.formatComboBox.setItemText(SongFormat.CCLI, WizardStrings.CCLI) - self.formatComboBox.setItemText( - SongFormat.DreamBeam, WizardStrings.DB) - self.formatComboBox.setItemText( - SongFormat.EasySlides, WizardStrings.ES) - self.formatComboBox.setItemText( - SongFormat.EasyWorship, WizardStrings.EW) - self.formatComboBox.setItemText( - SongFormat.FoilPresenter, WizardStrings.FP) - self.formatComboBox.setItemText(SongFormat.OpenSong, WizardStrings.OS) - self.formatComboBox.setItemText( - SongFormat.PowerSong, WizardStrings.PS) - self.formatComboBox.setItemText( - SongFormat.SongBeamer, WizardStrings.SB) - self.formatComboBox.setItemText( - SongFormat.SongShowPlus, WizardStrings.SSP) - self.formatComboBox.setItemText( - SongFormat.SongsOfFellowship, WizardStrings.SoF) - self.formatComboBox.setItemText( - SongFormat.WordsOfWorship, WizardStrings.WoW) -# self.formatComboBox.setItemText(SongFormat.CSV, WizardStrings.CSV) - self.openLP2FilenameLabel.setText( - translate('SongsPlugin.ImportWizardForm', 'Filename:')) - self.openLP2BrowseButton.setText(UiStrings().Browse) - self.openLP1FilenameLabel.setText( - translate('SongsPlugin.ImportWizardForm', 'Filename:')) - self.openLP1BrowseButton.setText(UiStrings().Browse) - self.openLP1DisabledLabel.setText(WizardStrings.NoSqlite) - self.powerSongFilenameLabel.setText( - translate('SongsPlugin.ImportWizardForm', 'Folder:')) - self.powerSongBrowseButton.setText(UiStrings().Browse) - self.openLyricsAddButton.setText( - translate('SongsPlugin.ImportWizardForm', 'Add Files...')) - self.openLyricsRemoveButton.setText( - translate('SongsPlugin.ImportWizardForm', 'Remove File(s)')) - self.openLyricsDisabledLabel.setText( - translate('SongsPlugin.ImportWizardForm', 'The OpenLyrics ' - 'importer has not yet been developed, but as you can see, we are ' - 'still intending to do so. Hopefully it will be in the next ' - 'release.')) - self.openSongAddButton.setText( - translate('SongsPlugin.ImportWizardForm', 'Add Files...')) - self.openSongRemoveButton.setText( - translate('SongsPlugin.ImportWizardForm', 'Remove File(s)')) - self.wordsOfWorshipAddButton.setText( - translate('SongsPlugin.ImportWizardForm', 'Add Files...')) - self.wordsOfWorshipRemoveButton.setText( - translate('SongsPlugin.ImportWizardForm', 'Remove File(s)')) - self.ccliAddButton.setText( - translate('SongsPlugin.ImportWizardForm', 'Add Files...')) - self.ccliRemoveButton.setText( - translate('SongsPlugin.ImportWizardForm', 'Remove File(s)')) - self.dreamBeamAddButton.setText( - translate('SongsPlugin.ImportWizardForm', 'Add Files...')) - self.dreamBeamRemoveButton.setText( - translate('SongsPlugin.ImportWizardForm', 'Remove File(s)')) - self.songsOfFellowshipAddButton.setText( - translate('SongsPlugin.ImportWizardForm', 'Add Files...')) - self.songsOfFellowshipRemoveButton.setText( - translate('SongsPlugin.ImportWizardForm', 'Remove File(s)')) - self.songsOfFellowshipDisabledLabel.setText( - translate('SongsPlugin.ImportWizardForm', 'The Songs of ' - 'Fellowship importer has been disabled because OpenLP cannot ' - 'access OpenOffice or LibreOffice.')) - self.genericAddButton.setText( - translate('SongsPlugin.ImportWizardForm', 'Add Files...')) - self.genericRemoveButton.setText( - translate('SongsPlugin.ImportWizardForm', 'Remove File(s)')) - self.genericDisabledLabel.setText( - translate('SongsPlugin.ImportWizardForm', 'The generic document/' - 'presentation importer has been disabled because OpenLP cannot ' - 'access OpenOffice or LibreOffice.')) - self.easySlidesFilenameLabel.setText( - translate('SongsPlugin.ImportWizardForm', 'Filename:')) - self.easySlidesBrowseButton.setText(UiStrings().Browse) - self.ewFilenameLabel.setText( - translate('SongsPlugin.ImportWizardForm', 'Filename:')) - self.ewBrowseButton.setText(UiStrings().Browse) - self.songBeamerAddButton.setText( - translate('SongsPlugin.ImportWizardForm', 'Add Files...')) - self.songBeamerRemoveButton.setText( - translate('SongsPlugin.ImportWizardForm', 'Remove File(s)')) - self.songShowPlusAddButton.setText( - translate('SongsPlugin.ImportWizardForm', 'Add Files...')) - self.songShowPlusRemoveButton.setText( - translate('SongsPlugin.ImportWizardForm', 'Remove File(s)')) - self.foilPresenterAddButton.setText( - translate('SongsPlugin.ImportWizardForm', 'Add Files...')) - self.foilPresenterRemoveButton.setText( - translate('SongsPlugin.ImportWizardForm', 'Remove File(s)')) -# self.csvFilenameLabel.setText( -# translate('SongsPlugin.ImportWizardForm', 'Filename:')) -# self.csvBrowseButton.setText(UiStrings().Browse) + for format in SongFormat.get_format_list(): + format_name, custom_combo_text, description_text, select_mode = \ + SongFormat.get(format, u'name', u'comboBoxText', + u'descriptionText', u'selectMode') + combo_box_text = (custom_combo_text if custom_combo_text else + format_name) + self.formatComboBox.setItemText(format, combo_box_text) + if description_text is not None: + self.formatWidgets[format][u'descriptionLabel'].setText( + description_text) + if select_mode == SongFormatSelect.MultipleFiles: + self.formatWidgets[format][u'addButton'].setText( + translate('SongsPlugin.ImportWizardForm', 'Add Files...')) + self.formatWidgets[format][u'removeButton'].setText( + translate('SongsPlugin.ImportWizardForm', 'Remove File(s)')) + else: + self.formatWidgets[format][u'browseButton'].setText( + UiStrings().Browse) + f_label = 'Filename:' + if select_mode == SongFormatSelect.SingleFolder: + f_label = 'Folder:' + self.formatWidgets[format][u'filepathLabel'].setText( + translate('SongsPlugin.ImportWizardForm', f_label)) + for format in self.disablableFormats: + self.formatWidgets[format][u'disabledLabel'].setText( + SongFormat.get(format, u'disabledLabelText')) self.progressPage.setTitle(WizardStrings.Importing) self.progressPage.setSubTitle( translate('SongsPlugin.ImportWizardForm', @@ -363,14 +200,29 @@ class SongImportForm(OpenLPWizard): self.errorSaveToButton.setText(translate('SongsPlugin.ImportWizardForm', 'Save to File')) # Align all QFormLayouts towards each other. - width = max(self.formatLabel.minimumSizeHint().width(), - self.openLP2FilenameLabel.minimumSizeHint().width()) - self.formatSpacer.changeSize(width, 0, QtGui.QSizePolicy.Fixed, - QtGui.QSizePolicy.Fixed) + formats = filter(lambda f: u'filepathLabel' in self.formatWidgets[f], + SongFormat.get_format_list()) + labels = [self.formatWidgets[f][u'filepathLabel'] for f in formats] + # Get max width of all labels + max_label_width = max(self.formatLabel.minimumSizeHint().width(), + max([label.minimumSizeHint().width() for label in labels])) + self.formatSpacer.changeSize(max_label_width, 0, + QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed) + spacers = [self.formatWidgets[f][u'filepathSpacer'] for f in formats] + for index, spacer in enumerate(spacers): + spacer.changeSize( + max_label_width - labels[index].minimumSizeHint().width(), 0, + QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed) + # Align descriptionLabels with rest of layout + for format in SongFormat.get_format_list(): + if SongFormat.get(format, u'descriptionText') is not None: + self.formatWidgets[format][u'descriptionSpacer'].changeSize( + max_label_width + self.formatHSpacing, 0, + QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed) def customPageChanged(self, pageId): """ - Called when changing to a page other than the progress page + Called when changing to a page other than the progress page. """ if self.page(pageId) == self.sourcePage: self.onCurrentIndexChanged(self.formatStack.currentIndex()) @@ -378,108 +230,32 @@ class SongImportForm(OpenLPWizard): def validateCurrentPage(self): """ Validate the current page before moving on to the next page. + Provide each song format class with a chance to validate its input by + overriding isValidSource(). """ if self.currentPage() == self.welcomePage: return True elif self.currentPage() == self.sourcePage: - source_format = self.formatComboBox.currentIndex() - QtCore.QSettings().setValue(u'songs/last import type', - source_format) - import_class = SongFormat.get_class(source_format) - if source_format == SongFormat.OpenLP2: - if self.openLP2FilenameEdit.text().isEmpty(): - critical_error_message_box(UiStrings().NFSs, - WizardStrings.YouSpecifyFile % UiStrings().OLPV2) - self.openLP2BrowseButton.setFocus() - return False - elif source_format == SongFormat.OpenLP1: - if self.openLP1FilenameEdit.text().isEmpty(): - critical_error_message_box(UiStrings().NFSs, - WizardStrings.YouSpecifyFile % UiStrings().OLPV1) - self.openLP1BrowseButton.setFocus() - return False - elif source_format == SongFormat.PowerSong: - if self.powerSongFilenameEdit.text().isEmpty() or \ - not import_class.isValidSource( - folder=self.powerSongFilenameEdit.text()): - critical_error_message_box(UiStrings().NFdSs, - WizardStrings.YouSpecifyFolder % WizardStrings.PS) - self.powerSongBrowseButton.setFocus() - return False - elif source_format == SongFormat.OpenLyrics: - if self.openLyricsFileListWidget.count() == 0: - critical_error_message_box(UiStrings().NFSp, - WizardStrings.YouSpecifyFile % WizardStrings.OL) - self.openLyricsAddButton.setFocus() - return False - elif source_format == SongFormat.OpenSong: - if self.openSongFileListWidget.count() == 0: - critical_error_message_box(UiStrings().NFSp, - WizardStrings.YouSpecifyFile % WizardStrings.OS) - self.openSongAddButton.setFocus() - return False - elif source_format == SongFormat.WordsOfWorship: - if self.wordsOfWorshipFileListWidget.count() == 0: - critical_error_message_box(UiStrings().NFSp, - WizardStrings.YouSpecifyFile % WizardStrings.WoW) - self.wordsOfWorshipAddButton.setFocus() - return False - elif source_format == SongFormat.CCLI: - if self.ccliFileListWidget.count() == 0: - critical_error_message_box(UiStrings().NFSp, - WizardStrings.YouSpecifyFile % WizardStrings.CCLI) - self.ccliAddButton.setFocus() - return False - elif source_format == SongFormat.DreamBeam: - if self.dreamBeamFileListWidget.count() == 0: - critical_error_message_box(UiStrings().NFSp, - WizardStrings.YouSpecifyFile % WizardStrings.DB) - self.dreamBeamAddButton.setFocus() - return False - elif source_format == SongFormat.SongsOfFellowship: - if self.songsOfFellowshipFileListWidget.count() == 0: - critical_error_message_box(UiStrings().NFSp, - WizardStrings.YouSpecifyFile % WizardStrings.SoF) - self.songsOfFellowshipAddButton.setFocus() - return False - elif source_format == SongFormat.Generic: - if self.genericFileListWidget.count() == 0: - critical_error_message_box(UiStrings().NFSp, - translate('SongsPlugin.ImportWizardForm', - 'You need to specify at least one document or ' - 'presentation file to import from.')) - self.genericAddButton.setFocus() - return False - elif source_format == SongFormat.EasySlides: - if self.easySlidesFilenameEdit.text().isEmpty(): - critical_error_message_box(UiStrings().NFSp, - WizardStrings.YouSpecifyFile % WizardStrings.ES) - self.easySlidesBrowseButton.setFocus() - return False - elif source_format == SongFormat.EasyWorship: - if self.ewFilenameEdit.text().isEmpty(): - critical_error_message_box(UiStrings().NFSs, - WizardStrings.YouSpecifyFile % WizardStrings.EW) - self.ewBrowseButton.setFocus() - return False - elif source_format == SongFormat.SongBeamer: - if self.songBeamerFileListWidget.count() == 0: - critical_error_message_box(UiStrings().NFSp, - WizardStrings.YouSpecifyFile % WizardStrings.SB) - self.songBeamerAddButton.setFocus() - return False - elif source_format == SongFormat.SongShowPlus: - if self.songShowPlusFileListWidget.count() == 0: - critical_error_message_box(UiStrings().NFSp, - WizardStrings.YouSpecifyFile % WizardStrings.SSP) - self.songShowPlusAddButton.setFocus() - return False - elif source_format == SongFormat.FoilPresenter: - if self.foilPresenterFileListWidget.count() == 0: - critical_error_message_box(UiStrings().NFSp, - WizardStrings.YouSpecifyFile % WizardStrings.FP) - self.foilPresenterAddButton.setFocus() - return False + format = self.currentFormat + Settings().setValue(u'songs/last import type', + format) + select_mode, class_, error_msg = SongFormat.get(format, + u'selectMode', u'class', u'invalidSourceMsg') + if select_mode == SongFormatSelect.MultipleFiles: + import_source = self.getListOfFiles( + self.formatWidgets[format][u'fileListWidget']) + error_title = UiStrings().IFSp + focus_button = self.formatWidgets[format][u'addButton'] + else: + import_source = \ + self.formatWidgets[format][u'filepathEdit'].text() + error_title = (UiStrings().IFSs if select_mode == + SongFormatSelect.SingleFile else UiStrings().IFdSs) + focus_button = self.formatWidgets[format][u'browseButton'] + if not class_.isValidSource(import_source): + critical_error_message_box(error_title, error_msg) + focus_button.setFocus() + return False return True elif self.currentPage() == self.progressPage: return True @@ -525,203 +301,40 @@ class SongImportForm(OpenLPWizard): item = listbox.takeItem(listbox.row(item)) del item - def onOpenLP2BrowseButtonClicked(self): - """ - Get OpenLP v2 song database file - """ - self.getFileName(WizardStrings.OpenTypeFile % UiStrings().OLPV2, - self.openLP2FilenameEdit, u'%s (*.sqlite)' - % (translate('SongsPlugin.ImportWizardForm', - 'OpenLP 2.0 Databases')) - ) + def onBrowseButtonClicked(self): + format = self.currentFormat + select_mode, format_name, filter = SongFormat.get(format, u'selectMode', + u'name', u'filter') + filepathEdit = self.formatWidgets[format][u'filepathEdit'] + if select_mode == SongFormatSelect.SingleFile: + self.getFileName(WizardStrings.OpenTypeFile % format_name, + filepathEdit, filter) + elif select_mode == SongFormatSelect.SingleFolder: + self.getFolder(WizardStrings.OpenTypeFolder % format_name, + filepathEdit) - def onOpenLP1BrowseButtonClicked(self): - """ - Get OpenLP v1 song database file - """ - self.getFileName(WizardStrings.OpenTypeFile % UiStrings().OLPV1, - self.openLP1FilenameEdit, u'%s (*.olp)' - % translate('SongsPlugin.ImportWizardForm', - 'openlp.org v1.x Databases') - ) + def onAddButtonClicked(self): + format = self.currentFormat + select_mode, format_name, filter, custom_title = SongFormat.get(format, + u'selectMode', u'name', u'filter', + u'getFilesTitle') + title = custom_title if custom_title \ + else WizardStrings.OpenTypeFile % format_name + if select_mode == SongFormatSelect.MultipleFiles: + self.getFiles(title, self.formatWidgets[format][u'fileListWidget'], + filter) + self.sourcePage.emit(QtCore.SIGNAL(u'completeChanged()')) - def onPowerSongBrowseButtonClicked(self): - """ - Get PowerSong song database folder - """ - self.getFolder(WizardStrings.OpenTypeFolder % WizardStrings.PS, - self.powerSongFilenameEdit) + def onRemoveButtonClicked(self): + self.removeSelectedItems( + self.formatWidgets[self.currentFormat][u'fileListWidget']) + self.sourcePage.emit(QtCore.SIGNAL(u'completeChanged()')) - def onOpenLyricsAddButtonClicked(self): + def onFilepathEditTextChanged(self): """ - Get OpenLyrics song database files + Called when the content of the Filename/Folder edit box changes. """ - self.getFiles(WizardStrings.OpenTypeFile % WizardStrings.OL, - self.openLyricsFileListWidget, u'%s (*.xml)' % - translate('SongsPlugin.ImportWizardForm', 'OpenLyrics Files')) - - def onOpenLyricsRemoveButtonClicked(self): - """ - Remove selected OpenLyrics files from the import list - """ - self.removeSelectedItems(self.openLyricsFileListWidget) - - def onOpenSongAddButtonClicked(self): - """ - Get OpenSong song database files - """ - self.getFiles(WizardStrings.OpenTypeFile % WizardStrings.OS, - self.openSongFileListWidget) - - def onOpenSongRemoveButtonClicked(self): - """ - Remove selected OpenSong files from the import list - """ - self.removeSelectedItems(self.openSongFileListWidget) - - def onWordsOfWorshipAddButtonClicked(self): - """ - Get Words of Worship song database files - """ - self.getFiles(WizardStrings.OpenTypeFile % WizardStrings.WoW, - self.wordsOfWorshipFileListWidget, u'%s (*.wsg *.wow-song)' - % translate('SongsPlugin.ImportWizardForm', - 'Words Of Worship Song Files') - ) - - def onWordsOfWorshipRemoveButtonClicked(self): - """ - Remove selected Words of Worship files from the import list - """ - self.removeSelectedItems(self.wordsOfWorshipFileListWidget) - - def onCCLIAddButtonClicked(self): - """ - Get CCLI song database files - """ - self.getFiles(WizardStrings.OpenTypeFile % WizardStrings.CCLI, - self.ccliFileListWidget, u'%s (*.usr *.txt)' - % translate('SongsPlugin.ImportWizardForm', - 'CCLI SongSelect Files')) - - def onCCLIRemoveButtonClicked(self): - """ - Remove selected CCLI files from the import list - """ - self.removeSelectedItems(self.ccliFileListWidget) - - def onDreamBeamAddButtonClicked(self): - """ - Get DreamBeam song database files - """ - self.getFiles(WizardStrings.OpenTypeFile % WizardStrings.DB, - self.dreamBeamFileListWidget, u'%s (*.xml)' - % translate('SongsPlugin.ImportWizardForm', - 'DreamBeam Song Files') - ) - - def onDreamBeamRemoveButtonClicked(self): - """ - Remove selected DreamBeam files from the import list - """ - self.removeSelectedItems(self.dreamBeamFileListWidget) - - def onSongsOfFellowshipAddButtonClicked(self): - """ - Get Songs of Fellowship song database files - """ - self.getFiles(WizardStrings.OpenTypeFile % WizardStrings.SoF, - self.songsOfFellowshipFileListWidget, u'%s (*.rtf)' - % translate('SongsPlugin.ImportWizardForm', - 'Songs Of Fellowship Song Files') - ) - - def onSongsOfFellowshipRemoveButtonClicked(self): - """ - Remove selected Songs of Fellowship files from the import list - """ - self.removeSelectedItems(self.songsOfFellowshipFileListWidget) - - def onGenericAddButtonClicked(self): - """ - Get song database files - """ - self.getFiles( - translate('SongsPlugin.ImportWizardForm', - 'Select Document/Presentation Files'), - self.genericFileListWidget - ) - - def onGenericRemoveButtonClicked(self): - """ - Remove selected files from the import list - """ - self.removeSelectedItems(self.genericFileListWidget) - - def onEasySlidesBrowseButtonClicked(self): - """ - Get EasySlides song database file - """ - self.getFileName(WizardStrings.OpenTypeFile % WizardStrings.ES, - self.easySlidesFilenameEdit, u'%s (*.xml)' - % translate('SongsPlugin.ImportWizardForm', - 'EasySlides XML File')) - - def onEWBrowseButtonClicked(self): - """ - Get EasyWorship song database files - """ - self.getFileName(WizardStrings.OpenTypeFile % WizardStrings.EW, - self.ewFilenameEdit, u'%s (*.db)' - % translate('SongsPlugin.ImportWizardForm', - 'EasyWorship Song Database')) - - def onSongBeamerAddButtonClicked(self): - """ - Get SongBeamer song database files - """ - self.getFiles(WizardStrings.OpenTypeFile % WizardStrings.SB, - self.songBeamerFileListWidget, u'%s (*.sng)' % - translate('SongsPlugin.ImportWizardForm', 'SongBeamer Files') - ) - - def onSongBeamerRemoveButtonClicked(self): - """ - Remove selected SongBeamer files from the import list - """ - self.removeSelectedItems(self.songBeamerFileListWidget) - - def onSongShowPlusAddButtonClicked(self): - """ - Get SongShow Plus song database files - """ - self.getFiles(WizardStrings.OpenTypeFile % WizardStrings.SSP, - self.songShowPlusFileListWidget, u'%s (*.sbsong)' - % translate('SongsPlugin.ImportWizardForm', - 'SongShow Plus Song Files') - ) - - def onSongShowPlusRemoveButtonClicked(self): - """ - Remove selected SongShow Plus files from the import list - """ - self.removeSelectedItems(self.songShowPlusFileListWidget) - - def onFoilPresenterAddButtonClicked(self): - """ - Get FoilPresenter song database files - """ - self.getFiles(WizardStrings.OpenTypeFile % WizardStrings.FP, - self.foilPresenterFileListWidget, u'%s (*.foil)' - % translate('SongsPlugin.ImportWizardForm', - 'Foilpresenter Song Files') - ) - - def onFoilPresenterRemoveButtonClicked(self): - """ - Remove selected FoilPresenter files from the import list - """ - self.removeSelectedItems(self.foilPresenterFileListWidget) + self.sourcePage.emit(QtCore.SIGNAL(u'completeChanged()')) def setDefaults(self): """ @@ -730,28 +343,18 @@ class SongImportForm(OpenLPWizard): self.restart() self.finishButton.setVisible(False) self.cancelButton.setVisible(True) - last_import_type = QtCore.QSettings().value( + last_import_type = Settings().value( u'songs/last import type').toInt()[0] if last_import_type < 0 or \ last_import_type >= self.formatComboBox.count(): last_import_type = 0 self.formatComboBox.setCurrentIndex(last_import_type) - self.openLP2FilenameEdit.setText(u'') - self.openLP1FilenameEdit.setText(u'') - self.powerSongFilenameEdit.setText(u'') - self.openLyricsFileListWidget.clear() - self.openSongFileListWidget.clear() - self.wordsOfWorshipFileListWidget.clear() - self.ccliFileListWidget.clear() - self.dreamBeamFileListWidget.clear() - self.songsOfFellowshipFileListWidget.clear() - self.genericFileListWidget.clear() - self.easySlidesFilenameEdit.setText(u'') - self.ewFilenameEdit.setText(u'') - self.songBeamerFileListWidget.clear() - self.songShowPlusFileListWidget.clear() - self.foilPresenterFileListWidget.clear() - #self.csvFilenameEdit.setText(u'') + for format in SongFormat.get_format_list(): + select_mode = SongFormat.get(format, u'selectMode') + if select_mode == SongFormatSelect.MultipleFiles: + self.formatWidgets[format][u'fileListWidget'].clear() + else: + self.formatWidgets[format][u'filepathEdit'].setText(u'') self.errorReportTextEdit.clear() self.errorReportTextEdit.setHidden(True) self.errorCopyToButton.setHidden(True) @@ -771,87 +374,18 @@ class SongImportForm(OpenLPWizard): class, and then runs the ``doImport`` method of the importer to do the actual importing. """ - source_format = self.formatComboBox.currentIndex() - importer = None - if source_format == SongFormat.OpenLP2: - # Import an OpenLP 2.0 database - importer = self.plugin.importSongs(SongFormat.OpenLP2, - filename=unicode(self.openLP2FilenameEdit.text()) - ) - elif source_format == SongFormat.OpenLP1: - # Import an openlp.org database - importer = self.plugin.importSongs(SongFormat.OpenLP1, - filename=unicode(self.openLP1FilenameEdit.text()), - plugin=self.plugin - ) - elif source_format == SongFormat.PowerSong: - # Import PowerSong folder - importer = self.plugin.importSongs(SongFormat.PowerSong, - folder=unicode(self.powerSongFilenameEdit.text()) - ) - elif source_format == SongFormat.OpenLyrics: - # Import OpenLyrics songs - importer = self.plugin.importSongs(SongFormat.OpenLyrics, - filenames=self.getListOfFiles(self.openLyricsFileListWidget) - ) - elif source_format == SongFormat.OpenSong: - # Import OpenSong songs - importer = self.plugin.importSongs(SongFormat.OpenSong, - filenames=self.getListOfFiles(self.openSongFileListWidget) - ) - elif source_format == SongFormat.WordsOfWorship: - # Import Words Of Worship songs - importer = self.plugin.importSongs(SongFormat.WordsOfWorship, + source_format = self.currentFormat + select_mode = SongFormat.get(source_format, u'selectMode') + if select_mode == SongFormatSelect.SingleFile: + importer = self.plugin.importSongs(source_format, filename=unicode( + self.formatWidgets[source_format][u'filepathEdit'].text())) + elif select_mode == SongFormatSelect.SingleFolder: + importer = self.plugin.importSongs(source_format, folder=unicode( + self.formatWidgets[source_format][u'filepathEdit'].text())) + else: + importer = self.plugin.importSongs(source_format, filenames=self.getListOfFiles( - self.wordsOfWorshipFileListWidget) - ) - elif source_format == SongFormat.CCLI: - # Import Words Of Worship songs - importer = self.plugin.importSongs(SongFormat.CCLI, - filenames=self.getListOfFiles(self.ccliFileListWidget) - ) - elif source_format == SongFormat.DreamBeam: - # Import DreamBeam songs - importer = self.plugin.importSongs(SongFormat.DreamBeam, - filenames=self.getListOfFiles( - self.dreamBeamFileListWidget) - ) - elif source_format == SongFormat.SongsOfFellowship: - # Import a Songs of Fellowship RTF file - importer = self.plugin.importSongs(SongFormat.SongsOfFellowship, - filenames=self.getListOfFiles( - self.songsOfFellowshipFileListWidget) - ) - elif source_format == SongFormat.Generic: - # Import a generic document or presentation - importer = self.plugin.importSongs(SongFormat.Generic, - filenames=self.getListOfFiles(self.genericFileListWidget) - ) - elif source_format == SongFormat.EasySlides: - # Import an EasySlides export file - importer = self.plugin.importSongs(SongFormat.EasySlides, - filename=unicode(self.easySlidesFilenameEdit.text()) - ) - elif source_format == SongFormat.EasyWorship: - # Import an EasyWorship database - importer = self.plugin.importSongs(SongFormat.EasyWorship, - filename=unicode(self.ewFilenameEdit.text()) - ) - elif source_format == SongFormat.SongBeamer: - # Import SongBeamer songs - importer = self.plugin.importSongs(SongFormat.SongBeamer, - filenames=self.getListOfFiles(self.songBeamerFileListWidget) - ) - elif source_format == SongFormat.SongShowPlus: - # Import ShongShow Plus songs - importer = self.plugin.importSongs(SongFormat.SongShowPlus, - filenames=self.getListOfFiles(self.songShowPlusFileListWidget) - ) - elif source_format == SongFormat.FoilPresenter: - # Import Foilpresenter songs - importer = self.plugin.importSongs(SongFormat.FoilPresenter, - filenames=self.getListOfFiles(self.foilPresenterFileListWidget) - ) + self.formatWidgets[source_format][u'fileListWidget'])) importer.doImport() self.progressLabel.setText(WizardStrings.FinishedImport) @@ -873,90 +407,144 @@ class SongImportForm(OpenLPWizard): report_file.write(self.errorReportTextEdit.toPlainText()) report_file.close() - def addFileSelectItem(self, prefix, obj_prefix=None, can_disable=False, - single_select=False): - if not obj_prefix: - obj_prefix = prefix + def addFileSelectItem(self): + format = self.currentFormat + prefix, can_disable, description_text, select_mode = SongFormat.get( + format, u'prefix', u'canDisable', u'descriptionText', u'selectMode') page = QtGui.QWidget() - page.setObjectName(obj_prefix + u'Page') + page.setObjectName(prefix + u'Page') if can_disable: - importWidget = self.disablableWidget(page, prefix, obj_prefix) + importWidget = self.disablableWidget(page, prefix) else: importWidget = page importLayout = QtGui.QVBoxLayout(importWidget) importLayout.setMargin(0) - importLayout.setObjectName(obj_prefix + u'ImportLayout') - if single_select: - fileLayout = QtGui.QHBoxLayout() - fileLayout.setObjectName(obj_prefix + u'FileLayout') - filenameLabel = QtGui.QLabel(importWidget) - filenameLabel.setObjectName(obj_prefix + u'FilenameLabel') - fileLayout.addWidget(filenameLabel) - filenameEdit = QtGui.QLineEdit(importWidget) - filenameEdit.setObjectName(obj_prefix + u'FilenameEdit') - fileLayout.addWidget(filenameEdit) + importLayout.setObjectName(prefix + u'ImportLayout') + if description_text is not None: + descriptionLayout = QtGui.QHBoxLayout() + descriptionLayout.setObjectName(prefix + u'DescriptionLayout') + descriptionSpacer = QtGui.QSpacerItem(0, 0, QtGui.QSizePolicy.Fixed, + QtGui.QSizePolicy.Fixed) + descriptionLayout.addSpacerItem(descriptionSpacer) + descriptionLabel = QtGui.QLabel(importWidget) + descriptionLabel.setWordWrap(True) + descriptionLabel.setOpenExternalLinks(True) + descriptionLabel.setObjectName(prefix + u'DescriptionLabel') + descriptionLayout.addWidget(descriptionLabel) + importLayout.addLayout(descriptionLayout) + self.formatWidgets[format][u'descriptionLabel'] = descriptionLabel + self.formatWidgets[format][u'descriptionSpacer'] = descriptionSpacer + if select_mode == SongFormatSelect.SingleFile or \ + select_mode == SongFormatSelect.SingleFolder: + filepathLayout = QtGui.QHBoxLayout() + filepathLayout.setObjectName(prefix + u'FilepathLayout') + filepathLayout.setContentsMargins(0, self.formatVSpacing, 0, 0) + filepathLabel = QtGui.QLabel(importWidget) + filepathLabel.setObjectName(prefix + u'FilepathLabel') + filepathLayout.addWidget(filepathLabel) + filepathSpacer = QtGui.QSpacerItem(0, 0, QtGui.QSizePolicy.Fixed, + QtGui.QSizePolicy.Fixed) + filepathLayout.addSpacerItem(filepathSpacer) + filepathEdit = QtGui.QLineEdit(importWidget) + filepathEdit.setObjectName(prefix + u'FilepathEdit') + filepathLayout.addWidget(filepathEdit) browseButton = QtGui.QToolButton(importWidget) browseButton.setIcon(self.openIcon) - browseButton.setObjectName(obj_prefix + u'BrowseButton') - fileLayout.addWidget(browseButton) - importLayout.addLayout(fileLayout) + browseButton.setObjectName(prefix + u'BrowseButton') + filepathLayout.addWidget(browseButton) + importLayout.addLayout(filepathLayout) importLayout.addSpacerItem(self.stackSpacer) - else: + self.formatWidgets[format][u'filepathLabel'] = filepathLabel + self.formatWidgets[format][u'filepathSpacer'] = filepathSpacer + self.formatWidgets[format][u'filepathLayout'] = filepathLayout + self.formatWidgets[format][u'filepathEdit'] = filepathEdit + self.formatWidgets[format][u'browseButton'] = browseButton + elif select_mode == SongFormatSelect.MultipleFiles: fileListWidget = QtGui.QListWidget(importWidget) fileListWidget.setSelectionMode( QtGui.QAbstractItemView.ExtendedSelection) - fileListWidget.setObjectName(obj_prefix + u'FileListWidget') + fileListWidget.setObjectName(prefix + u'FileListWidget') importLayout.addWidget(fileListWidget) buttonLayout = QtGui.QHBoxLayout() - buttonLayout.setObjectName(obj_prefix + u'ButtonLayout') + buttonLayout.setObjectName(prefix + u'ButtonLayout') addButton = QtGui.QPushButton(importWidget) addButton.setIcon(self.openIcon) - addButton.setObjectName(obj_prefix + u'AddButton') + addButton.setObjectName(prefix + u'AddButton') buttonLayout.addWidget(addButton) buttonLayout.addStretch() removeButton = QtGui.QPushButton(importWidget) removeButton.setIcon(self.deleteIcon) - removeButton.setObjectName(obj_prefix + u'RemoveButton') + removeButton.setObjectName(prefix + u'RemoveButton') buttonLayout.addWidget(removeButton) importLayout.addLayout(buttonLayout) + self.formatWidgets[format][u'fileListWidget'] = fileListWidget + self.formatWidgets[format][u'buttonLayout'] = buttonLayout + self.formatWidgets[format][u'addButton'] = addButton + self.formatWidgets[format][u'removeButton'] = removeButton self.formatStack.addWidget(page) - setattr(self, prefix + u'Page', page) - if single_select: - setattr(self, prefix + u'FilenameLabel', filenameLabel) - setattr(self, prefix + u'FileLayout', fileLayout) - setattr(self, prefix + u'FilenameEdit', filenameEdit) - setattr(self, prefix + u'BrowseButton', browseButton) - else: - setattr(self, prefix + u'FileListWidget', fileListWidget) - setattr(self, prefix + u'ButtonLayout', buttonLayout) - setattr(self, prefix + u'AddButton', addButton) - setattr(self, prefix + u'RemoveButton', removeButton) - setattr(self, prefix + u'ImportLayout', importLayout) + self.formatWidgets[format][u'page'] = page + self.formatWidgets[format][u'importLayout'] = importLayout self.formatComboBox.addItem(u'') - def disablableWidget(self, page, prefix, obj_prefix): + def disablableWidget(self, page, prefix): + format = self.currentFormat + self.disablableFormats.append(format) layout = QtGui.QVBoxLayout(page) layout.setMargin(0) layout.setSpacing(0) - layout.setObjectName(obj_prefix + u'Layout') + layout.setObjectName(prefix + u'Layout') disabledWidget = QtGui.QWidget(page) disabledWidget.setVisible(False) - disabledWidget.setObjectName(obj_prefix + u'DisabledWidget') + disabledWidget.setObjectName(prefix + u'DisabledWidget') disabledLayout = QtGui.QVBoxLayout(disabledWidget) disabledLayout.setMargin(0) - disabledLayout.setObjectName(obj_prefix + u'DisabledLayout') + disabledLayout.setObjectName(prefix + u'DisabledLayout') disabledLabel = QtGui.QLabel(disabledWidget) disabledLabel.setWordWrap(True) - disabledLabel.setObjectName(obj_prefix + u'DisabledLabel') + disabledLabel.setObjectName(prefix + u'DisabledLabel') disabledLayout.addWidget(disabledLabel) disabledLayout.addSpacerItem(self.stackSpacer) layout.addWidget(disabledWidget) importWidget = QtGui.QWidget(page) - importWidget.setObjectName(obj_prefix + u'ImportWidget') + importWidget.setObjectName(prefix + u'ImportWidget') layout.addWidget(importWidget) - setattr(self, prefix + u'Layout', layout) - setattr(self, prefix + u'DisabledWidget', disabledWidget) - setattr(self, prefix + u'DisabledLayout', disabledLayout) - setattr(self, prefix + u'DisabledLabel', disabledLabel) - setattr(self, prefix + u'ImportWidget', importWidget) + self.formatWidgets[format][u'layout'] = layout + self.formatWidgets[format][u'disabledWidget'] = disabledWidget + self.formatWidgets[format][u'disabledLayout'] = disabledLayout + self.formatWidgets[format][u'disabledLabel'] = disabledLabel + self.formatWidgets[format][u'importWidget'] = importWidget return importWidget + +class SongImportSourcePage(QtGui.QWizardPage): + """ + Subclass of QtGui.QWizardPage to override isComplete() for Source Page. + """ + def isComplete(self): + """ + Return True if: + + * an available format is selected, and + * if MultipleFiles mode, at least one file is selected + * or if SingleFile mode, the specified file exists + * or if SingleFolder mode, the specified folder exists + + When this method returns True, the wizard's Next button is enabled. + """ + wizard = self.wizard() + format = wizard.currentFormat + select_mode, format_available = SongFormat.get(format, u'selectMode', + u'availability') + if format_available: + if select_mode == SongFormatSelect.MultipleFiles: + if wizard.formatWidgets[format][u'fileListWidget'].count() > 0: + return True + else: + filepath = wizard.formatWidgets[format][u'filepathEdit'].text() + if not filepath.isEmpty(): + if select_mode == SongFormatSelect.SingleFile \ + and os.path.isfile(filepath): + return True + elif select_mode == SongFormatSelect.SingleFolder \ + and os.path.isdir(filepath): + return True + return False diff --git a/openlp/plugins/songs/forms/topicsdialog.py b/openlp/plugins/songs/forms/topicsdialog.py index edd8df9f9..a609478fc 100644 --- a/openlp/plugins/songs/forms/topicsdialog.py +++ b/openlp/plugins/songs/forms/topicsdialog.py @@ -25,7 +25,7 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### -from PyQt4 import QtCore, QtGui +from PyQt4 import QtGui from openlp.core.lib import translate from openlp.core.lib.ui import create_button_box diff --git a/openlp/plugins/songs/lib/importer.py b/openlp/plugins/songs/lib/importer.py index 16d943a73..19916b97d 100644 --- a/openlp/plugins/songs/lib/importer.py +++ b/openlp/plugins/songs/lib/importer.py @@ -29,6 +29,9 @@ The :mod:`importer` modules provides the general song import functionality. """ import logging +from openlp.core.lib import translate +from openlp.core.lib.ui import UiStrings +from openlp.core.ui.wizard import WizardStrings from opensongimport import OpenSongImport from easyslidesimport import EasySlidesImport from olpimport import OpenLPSongImport @@ -41,6 +44,7 @@ from ewimport import EasyWorshipSongImport from songbeamerimport import SongBeamerImport from songshowplusimport import SongShowPlusImport from foilpresenterimport import FoilPresenterImport +from zionworximport import ZionWorxImport # Imports that might fail log = logging.getLogger(__name__) try: @@ -62,13 +66,58 @@ except ImportError: log.exception('Error importing %s', 'OooImport') HAS_OOO = False +class SongFormatSelect(object): + """ + This is a special enumeration class listing available file selection modes. + """ + SingleFile = 0 + MultipleFiles = 1 + SingleFolder = 2 + class SongFormat(object): """ - This is a special enumeration class that holds the various types of songs, - plus a few helper functions to facilitate generic handling of song types - for importing. + This is a special static class that holds an enumeration of the various + song formats handled by the importer, the attributes of each song format, + and a few helper functions. + + Required attributes for each song format: + + ``u'class'`` + Import class, e.g. ``OpenLyricsImport`` + ``u'name'`` + Name of the format, e.g. ``u'OpenLyrics'`` + ``u'prefix'`` + Prefix for Qt objects. Use mixedCase, e.g. ``u'openLyrics'`` + See ``SongImportForm.addFileSelectItem()`` + + Optional attributes for each song format: + + ``u'canDisable'`` + Whether song format importer is disablable. + ``u'availability'`` + Whether song format importer is available. + ``u'selectMode'`` + Whether format accepts single file, multiple files, or single folder + (as per ``SongFormatSelect`` options). + ``u'filter'`` + File extension filter for ``QFileDialog``. + + Optional/custom text Strings for ``SongImportForm`` widgets: + + ``u'comboBoxText'`` + Combo box selector (default value is the format's ``u'name'``). + ``u'disabledLabelText'`` + Required for disablable song formats. + ``u'getFilesTitle'`` + Title for ``QFileDialog`` (default includes the format's ``u'name'``). + ``u'invalidSourceMsg'`` + Message displayed if ``isValidSource()`` returns ``False``. + ``u'descriptionText'`` + Short description (1-2 lines) about the song format. """ - _format_availability = {} + # Song formats (ordered alphabetically after Generic) + # * Numerical order of song formats is significant as it determines the + # order used by formatComboBox. Unknown = -1 OpenLyrics = 0 OpenLP2 = 1 @@ -85,50 +134,164 @@ class SongFormat(object): SongShowPlus = 12 SongsOfFellowship = 13 WordsOfWorship = 14 - #CSV = 15 + ZionWorx = 15 + #CSV = 16 + + # Set optional attribute defaults + __defaults__ = { + u'canDisable': False, + u'availability': True, + u'selectMode': SongFormatSelect.MultipleFiles, + u'filter': u'', + u'comboBoxText': None, + u'disabledLabelText': u'', + u'getFilesTitle': None, + u'invalidSourceMsg': None, + u'descriptionText': None + } + + # Set attribute values for each Song Format + __attributes__ = { + OpenLyrics: { + u'class': OpenLyricsImport, + u'name': u'OpenLyrics', + u'prefix': u'openLyrics', + u'filter': u'%s (*.xml)' % translate('SongsPlugin.ImportWizardForm', + 'OpenLyrics Files'), + u'comboBoxText': translate('SongsPlugin.ImportWizardForm', + 'OpenLyrics or OpenLP 2.0 Exported Song') + }, + OpenLP2: { + u'class': OpenLPSongImport, + u'name': UiStrings().OLPV2, + u'prefix': u'openLP2', + u'selectMode': SongFormatSelect.SingleFile, + u'filter': u'%s (*.sqlite)' % (translate( + 'SongsPlugin.ImportWizardForm', 'OpenLP 2.0 Databases')) + }, + OpenLP1: { + u'name': UiStrings().OLPV1, + u'prefix': u'openLP1', + u'canDisable': True, + u'selectMode': SongFormatSelect.SingleFile, + u'filter': u'%s (*.olp)' % translate('SongsPlugin.ImportWizardForm', + 'openlp.org v1.x Databases'), + u'disabledLabelText': WizardStrings.NoSqlite + }, + Generic: { + u'name': translate('SongsPlugin.ImportWizardForm', + 'Generic Document/Presentation'), + u'prefix': u'generic', + u'canDisable': True, + u'disabledLabelText': translate('SongsPlugin.ImportWizardForm', + 'The generic document/presentation importer has been disabled ' + 'because OpenLP cannot access OpenOffice or LibreOffice.'), + u'getFilesTitle': translate('SongsPlugin.ImportWizardForm', + 'Select Document/Presentation Files') + }, + CCLI: { + u'class': CCLIFileImport, + u'name': u'CCLI/SongSelect', + u'prefix': u'ccli', + u'filter': u'%s (*.usr *.txt)' % translate( + 'SongsPlugin.ImportWizardForm', 'CCLI SongSelect Files') + }, + DreamBeam: { + u'class': DreamBeamImport, + u'name': u'DreamBeam', + u'prefix': u'dreamBeam', + u'filter': u'%s (*.xml)' % translate('SongsPlugin.ImportWizardForm', + 'DreamBeam Song Files') + }, + EasySlides: { + u'class': EasySlidesImport, + u'name': u'EasySlides', + u'prefix': u'easySlides', + u'selectMode': SongFormatSelect.SingleFile, + u'filter': u'%s (*.xml)' % translate('SongsPlugin.ImportWizardForm', + 'EasySlides XML File') + }, + EasyWorship: { + u'class': EasyWorshipSongImport, + u'name': u'EasyWorship', + u'prefix': u'ew', + u'selectMode': SongFormatSelect.SingleFile, + u'filter': u'%s (*.db)' % translate('SongsPlugin.ImportWizardForm', + 'EasyWorship Song Database') + }, + FoilPresenter: { + u'class': FoilPresenterImport, + u'name': u'Foilpresenter', + u'prefix': u'foilPresenter', + u'filter': u'%s (*.foil)' % translate( + 'SongsPlugin.ImportWizardForm', 'Foilpresenter Song Files') + }, + OpenSong: { + u'class': OpenSongImport, + u'name': WizardStrings.OS, + u'prefix': u'openSong' + }, + PowerSong: { + u'class': PowerSongImport, + u'name': u'PowerSong 1.0', + u'prefix': u'powerSong', + u'selectMode': SongFormatSelect.SingleFolder, + u'invalidSourceMsg': translate('SongsPlugin.ImportWizardForm', + 'You need to specify a valid PowerSong 1.0 database folder.') + }, + SongBeamer: { + u'class': SongBeamerImport, + u'name': u'SongBeamer', + u'prefix': u'songBeamer', + u'filter': u'%s (*.sng)' % translate('SongsPlugin.ImportWizardForm', + 'SongBeamer Files') + }, + SongShowPlus: { + u'class': SongShowPlusImport, + u'name': u'SongShow Plus', + u'prefix': u'songShowPlus', + u'filter': u'%s (*.sbsong)' % translate( + 'SongsPlugin.ImportWizardForm', 'SongShow Plus Song Files') + }, + SongsOfFellowship: { + u'name': u'Songs of Fellowship', + u'prefix': u'songsOfFellowship', + u'canDisable': True, + u'filter': u'%s (*.rtf)' % translate('SongsPlugin.ImportWizardForm', + 'Songs Of Fellowship Song Files'), + u'disabledLabelText': translate('SongsPlugin.ImportWizardForm', + 'The Songs of Fellowship importer has been disabled because ' + 'OpenLP cannot access OpenOffice or LibreOffice.') + }, + WordsOfWorship: { + u'class': WowImport, + u'name': u'Words of Worship', + u'prefix': u'wordsOfWorship', + u'filter': u'%s (*.wsg *.wow-song)' % translate( + 'SongsPlugin.ImportWizardForm', 'Words Of Worship Song Files') + }, + ZionWorx: { + u'class': ZionWorxImport, + u'name': u'ZionWorx', + u'prefix': u'zionWorx', + u'selectMode': SongFormatSelect.SingleFile, + u'comboBoxText': translate('SongsPlugin.ImportWizardForm', + 'ZionWorx (CSV)'), + u'descriptionText': translate('SongsPlugin.ImportWizardForm', + 'First convert your ZionWorx database to a CSV text file, as ' + 'explained in the User Manual.') +# }, +# CSV: { +# u'class': CSVImport, +# u'name': WizardStrings.CSV, +# u'prefix': u'csv', +# u'selectMode': SongFormatSelect.SingleFile + } + } @staticmethod - def get_class(format): - """ - Return the appropriate implementation class. - - ``format`` - The song format. - """ - if format == SongFormat.OpenLP2: - return OpenLPSongImport - elif format == SongFormat.OpenLP1: - return OpenLP1SongImport - elif format == SongFormat.OpenLyrics: - return OpenLyricsImport - elif format == SongFormat.OpenSong: - return OpenSongImport - elif format == SongFormat.SongsOfFellowship: - return SofImport - elif format == SongFormat.WordsOfWorship: - return WowImport - elif format == SongFormat.Generic: - return OooImport - elif format == SongFormat.CCLI: - return CCLIFileImport - elif format == SongFormat.DreamBeam: - return DreamBeamImport - elif format == SongFormat.PowerSong: - return PowerSongImport - elif format == SongFormat.EasySlides: - return EasySlidesImport - elif format == SongFormat.EasyWorship: - return EasyWorshipSongImport - elif format == SongFormat.SongBeamer: - return SongBeamerImport - elif format == SongFormat.SongShowPlus: - return SongShowPlusImport - elif format == SongFormat.FoilPresenter: - return FoilPresenterImport - return None - - @staticmethod - def get_formats_list(): + def get_format_list(): """ Return a list of the supported song formats. """ @@ -138,7 +301,7 @@ class SongFormat(object): SongFormat.OpenLP1, SongFormat.Generic, SongFormat.CCLI, - SongFormat.DreamBeam, + SongFormat.DreamBeam, SongFormat.EasySlides, SongFormat.EasyWorship, SongFormat.FoilPresenter, @@ -147,26 +310,55 @@ class SongFormat(object): SongFormat.SongBeamer, SongFormat.SongShowPlus, SongFormat.SongsOfFellowship, - SongFormat.WordsOfWorship + SongFormat.WordsOfWorship, + SongFormat.ZionWorx ] + + @staticmethod + def get(format, *attributes): + """ + Return requested song format attribute(s). + + ``format`` + A song format from SongFormat. + + ``*attributes`` + Zero or more song format attributes from SongFormat. + + Return type depends on number of supplied attributes: + :0: Return dict containing all defined attributes for the format. + :1: Return the attribute value. + :>1: Return tuple of requested attribute values. + """ + if not attributes: + return SongFormat.__attributes__.get(format) + elif len(attributes) == 1: + default = SongFormat.__defaults__.get(attributes[0]) + return SongFormat.__attributes__[format].get(attributes[0], + default) + else: + values = [] + for attr in attributes: + default = SongFormat.__defaults__.get(attr) + values.append(SongFormat.__attributes__[format].get(attr, + default)) + return tuple(values) @staticmethod - def set_availability(format, available): + def set(format, attribute, value): """ - Set the availability for a given song format. + Set specified song format attribute to the supplied value. """ - SongFormat._format_availability[format] = available + SongFormat.__attributes__[format][attribute] = value - @staticmethod - def get_availability(format): - """ - Return the availability of a given song format. - """ - return SongFormat._format_availability.get(format, True) - -SongFormat.set_availability(SongFormat.OpenLP1, HAS_OPENLP1) -SongFormat.set_availability(SongFormat.SongsOfFellowship, HAS_SOF) -SongFormat.set_availability(SongFormat.Generic, HAS_OOO) - -__all__ = [u'SongFormat'] +SongFormat.set(SongFormat.OpenLP1, u'availability', HAS_OPENLP1) +if HAS_OPENLP1: + SongFormat.set(SongFormat.OpenLP1, u'class', OpenLP1SongImport) +SongFormat.set(SongFormat.SongsOfFellowship, u'availability', HAS_SOF) +if HAS_SOF: + SongFormat.set(SongFormat.SongsOfFellowship, u'class', SofImport) +SongFormat.set(SongFormat.Generic, u'availability', HAS_OOO) +if HAS_OOO: + SongFormat.set(SongFormat.Generic, u'class', OooImport) +__all__ = [u'SongFormat', u'SongFormatSelect'] diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index 51158a954..ca3c76353 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -37,6 +37,7 @@ from sqlalchemy.sql import or_ from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, \ translate, check_item_selected, PluginStatus, create_separated_list from openlp.core.lib.ui import UiStrings, create_widget_action +from openlp.core.lib.settings import Settings from openlp.core.utils import AppLocation from openlp.plugins.songs.forms import EditSongForm, SongMaintenanceForm, \ SongImportForm, SongExportForm @@ -131,13 +132,13 @@ class SongMediaItem(MediaManagerItem): self.searchTextEdit.setFocus() def configUpdated(self): - self.searchAsYouType = QtCore.QSettings().value( + self.searchAsYouType = Settings().value( self.settingsSection + u'/search as type', QtCore.QVariant(u'False')).toBool() - self.updateServiceOnEdit = QtCore.QSettings().value( + self.updateServiceOnEdit = Settings().value( self.settingsSection + u'/update service on edit', QtCore.QVariant(u'False')).toBool() - self.addSongFromService = QtCore.QSettings().value( + self.addSongFromService = Settings().value( self.settingsSection + u'/add song from service', QtCore.QVariant(u'True')).toBool() @@ -168,14 +169,14 @@ class SongMediaItem(MediaManagerItem): (SongSearch.Themes, u':/slides/slide_theme.png', UiStrings().Themes, UiStrings().SearchThemes) ]) - self.searchTextEdit.setCurrentSearchType(QtCore.QSettings().value( + self.searchTextEdit.setCurrentSearchType(Settings().value( u'%s/last search type' % self.settingsSection, QtCore.QVariant(SongSearch.Entire)).toInt()[0]) self.configUpdated() def onSearchTextButtonClicked(self): # Save the current search type to the configuration. - QtCore.QSettings().setValue(u'%s/last search type' % + Settings().setValue(u'%s/last search type' % self.settingsSection, QtCore.QVariant(self.searchTextEdit.currentSearchType())) # Reload the list considering the new search type. @@ -516,11 +517,11 @@ class SongMediaItem(MediaManagerItem): service_item.raw_footer.append(song.title) service_item.raw_footer.append(create_separated_list(author_list)) service_item.raw_footer.append(song.copyright) - if QtCore.QSettings().value(u'general/ccli number', + if Settings().value(u'general/ccli number', QtCore.QVariant(u'')).toString(): service_item.raw_footer.append(unicode( translate('SongsPlugin.MediaItem', 'CCLI License: ') + - QtCore.QSettings().value(u'general/ccli number', + Settings().value(u'general/ccli number', QtCore.QVariant(u'')).toString())) service_item.audit = [ song.title, author_list, song.copyright, unicode(song.ccli_number) diff --git a/openlp/plugins/songs/lib/powersongimport.py b/openlp/plugins/songs/lib/powersongimport.py index 9946d273d..d3ac766f9 100644 --- a/openlp/plugins/songs/lib/powersongimport.py +++ b/openlp/plugins/songs/lib/powersongimport.py @@ -33,7 +33,6 @@ import fnmatch import os from openlp.core.lib import translate -from openlp.core.ui.wizard import WizardStrings from openlp.plugins.songs.lib.songimport import SongImport log = logging.getLogger(__name__) @@ -71,26 +70,25 @@ class PowerSongImport(SongImport): * .song """ - @staticmethod - def isValidSource(**kwargs): + def isValidSource(import_source): """ Checks if source is a PowerSong 1.0 folder: * is a directory * contains at least one *.song file """ - if u'folder' in kwargs: - dir = kwargs[u'folder'] - if os.path.isdir(dir): - for file in os.listdir(dir): - if fnmatch.fnmatch(file, u'*.song'): - return True + if os.path.isdir(import_source): + for file in os.listdir(import_source): + if fnmatch.fnmatch(file, u'*.song'): + return True return False def doImport(self): """ Receive either a list of files or a folder (unicode) to import. """ + from importer import SongFormat + PS_string = SongFormat.get(SongFormat.PowerSong, u'name') if isinstance(self.importSource, unicode): if os.path.isdir(self.importSource): dir = self.importSource @@ -104,7 +102,7 @@ class PowerSongImport(SongImport): self.logError(unicode(translate('SongsPlugin.PowerSongImport', 'No songs to import.')), unicode(translate('SongsPlugin.PowerSongImport', - 'No %s files found.' % WizardStrings.PS))) + 'No %s files found.' % PS_string))) return self.importWizard.progressBar.setMaximum(len(self.importSource)) for file in self.importSource: @@ -124,7 +122,7 @@ class PowerSongImport(SongImport): self.logError(os.path.basename(file), unicode( translate('SongsPlugin.PowerSongImport', 'Invalid %s file. Unexpected byte value.' - % WizardStrings.PS))) + % PS_string))) break else: if label == u'TITLE': @@ -142,15 +140,14 @@ class PowerSongImport(SongImport): if not self.title: self.logError(os.path.basename(file), unicode( translate('SongsPlugin.PowerSongImport', - 'Invalid %s file. Missing "TITLE" header.' - % WizardStrings.PS))) + 'Invalid %s file. Missing "TITLE" header.' % PS_string))) continue # Check that file had COPYRIGHTLINE label if not found_copyright: self.logError(self.title, unicode( translate('SongsPlugin.PowerSongImport', 'Invalid %s file. Missing "COPYRIGHTLINE" ' - 'header.' % WizardStrings.PS))) + 'header.' % PS_string))) continue # Check that file had at least one verse if not self.verses: diff --git a/openlp/plugins/songs/lib/songimport.py b/openlp/plugins/songs/lib/songimport.py index ac6818184..dba86f3ab 100644 --- a/openlp/plugins/songs/lib/songimport.py +++ b/openlp/plugins/songs/lib/songimport.py @@ -51,11 +51,11 @@ class SongImport(QtCore.QObject): as necessary """ @staticmethod - def isValidSource(**kwargs): + def isValidSource(import_source): """ Override this method to validate the source prior to import. """ - pass + return True def __init__(self, manager, **kwargs): """ diff --git a/openlp/plugins/songs/lib/songstab.py b/openlp/plugins/songs/lib/songstab.py index 9d6de087f..ca646cd5f 100644 --- a/openlp/plugins/songs/lib/songstab.py +++ b/openlp/plugins/songs/lib/songstab.py @@ -28,6 +28,7 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import SettingsTab, translate +from openlp.core.lib.settings import Settings class SongsTab(SettingsTab): """ @@ -110,7 +111,7 @@ class SongsTab(SettingsTab): self.update_load = True def load(self): - settings = QtCore.QSettings() + settings = Settings() settings.beginGroup(self.settingsSection) self.song_search = settings.value( u'search as type', QtCore.QVariant(False)).toBool() @@ -127,7 +128,7 @@ class SongsTab(SettingsTab): settings.endGroup() def save(self): - settings = QtCore.QSettings() + settings = Settings() settings.beginGroup(self.settingsSection) settings.setValue(u'search as type', QtCore.QVariant(self.song_search)) settings.setValue(u'display songbar', QtCore.QVariant(self.tool_bar)) diff --git a/openlp/plugins/songs/lib/zionworximport.py b/openlp/plugins/songs/lib/zionworximport.py new file mode 100644 index 000000000..8f83c4509 --- /dev/null +++ b/openlp/plugins/songs/lib/zionworximport.py @@ -0,0 +1,142 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2012 Raoul Snyman # +# Portions copyright (c) 2008-2012 Tim Bentley, Gerald Britton, Jonathan # +# Corwin, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, # +# Armin Köhler, Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias # +# Põldaru, Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # +# --------------------------------------------------------------------------- # +# 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:`zionworximport` module provides the functionality for importing +ZionWorx songs into the OpenLP database. +""" +import csv +import logging + +from openlp.core.lib import translate +from openlp.plugins.songs.lib.songimport import SongImport + +log = logging.getLogger(__name__) + +class ZionWorxImport(SongImport): + """ + The :class:`ZionWorxImport` class provides the ability to import songs + from ZionWorx, via a dump of the ZionWorx database to a CSV file. + + ZionWorx song database fields: + + * ``SongNum`` Song ID. (Discarded by importer) + * ``Title1`` Main Title. + * ``Title2`` Alternate Title. + * ``Lyrics`` Song verses, separated by blank lines. + * ``Writer`` Song author(s). + * ``Copyright`` Copyright information + * ``Keywords`` (Discarded by importer) + * ``DefaultStyle`` (Discarded by importer) + + ZionWorx has no native export function; it uses the proprietary TurboDB + database engine. The TurboDB vendor, dataWeb, provides tools which can + export TurboDB tables to other formats, such as freeware console tool + TurboDB Data Exchange which is available for Windows and Linux. This command + exports the ZionWorx songs table to a CSV file: + + ``tdbdatax MainTable.dat songstable.csv -fsdf -s, -qd`` + + * -f Table format: ``sdf`` denotes text file. + * -s Separator character between fields. + * -q Quote character surrounding fields. ``d`` denotes double-quote. + + CSV format expected by importer: + + * Field separator character is comma ``,`` + * Fields surrounded by double-quotes ``"``. This enables fields (such as + Lyrics) to include new-lines and commas. Double-quotes within a field + are denoted by two double-quotes ``""`` + * Note: This is the default format of the Python ``csv`` module. + + """ + def doImport(self): + """ + Receive a CSV file (from a ZionWorx database dump) to import. + """ + # Used to strip control chars (10=LF, 13=CR, 127=DEL) + self.control_chars_map = dict.fromkeys( + range(10) + [11, 12] + range(14,32) + [127]) + with open(self.importSource, 'rb') as songs_file: + fieldnames = [u'SongNum', u'Title1', u'Title2', u'Lyrics', + u'Writer', u'Copyright', u'Keywords', u'DefaultStyle'] + songs_reader = csv.DictReader(songs_file, fieldnames) + try: + records = list(songs_reader) + except csv.Error, e: + self.logError(unicode(translate('SongsPlugin.ZionWorxImport', + 'Error reading CSV file.')), + unicode(translate('SongsPlugin.ZionWorxImport', + 'Line %d: %s' % (songs_reader.line_num, e)))) + return + num_records = len(records) + log.info(u'%s records found in CSV file' % num_records) + self.importWizard.progressBar.setMaximum(num_records) + for index, record in enumerate(records, 1): + if self.stopImportFlag: + return + self.setDefaults() + try: + self.title = self._decode(record[u'Title1']) + if record[u'Title2']: + self.alternateTitle = self._decode(record[u'Title2']) + self.parseAuthor(self._decode(record[u'Writer'])) + self.addCopyright(self._decode(record[u'Copyright'])) + lyrics = self._decode(record[u'Lyrics']) + except UnicodeDecodeError, e: + self.logError(unicode(translate( + 'SongsPlugin.ZionWorxImport', 'Record %d' % index)), + unicode(translate('SongsPlugin.ZionWorxImport', + 'Decoding error: %s' % e))) + continue + except TypeError, e: + self.logError(unicode(translate( + 'SongsPlugin.ZionWorxImport', 'File not valid ZionWorx ' + 'CSV format.')), u'TypeError: %s' % e) + return + verse = u'' + for line in lyrics.splitlines(): + if line and not line.isspace(): + verse += line + u'\n' + elif verse: + self.addVerse(verse) + verse = u'' + if verse: + self.addVerse(verse) + title = self.title + if not self.finish(): + self.logError(unicode(translate( + 'SongsPlugin.ZionWorxImport', 'Record %d' % index)) + + (u': "' + title + u'"' if title else u'')) + + def _decode(self, str): + """ + Decodes CSV input to unicode, stripping all control characters (except + new lines). + """ + # This encoding choice seems OK. ZionWorx has no option for setting the + # encoding for its songs, so we assume encoding is always the same. + return unicode(str, u'cp1252').translate(self.control_chars_map) diff --git a/openlp/plugins/songs/songsplugin.py b/openlp/plugins/songs/songsplugin.py index 4d59186e5..d7b36414a 100644 --- a/openlp/plugins/songs/songsplugin.py +++ b/openlp/plugins/songs/songsplugin.py @@ -194,7 +194,7 @@ class SongsPlugin(Plugin): self.manager.save_object(song) def importSongs(self, format, **kwargs): - class_ = SongFormat.get_class(format) + class_ = SongFormat.get(format, u'class') importer = class_(self.manager, **kwargs) importer.register(self.mediaItem.importWizard) return importer diff --git a/openlp/plugins/songusage/forms/songusagedetailform.py b/openlp/plugins/songusage/forms/songusagedetailform.py index 363455ea5..1ad6fceef 100644 --- a/openlp/plugins/songusage/forms/songusagedetailform.py +++ b/openlp/plugins/songusage/forms/songusagedetailform.py @@ -33,6 +33,7 @@ from sqlalchemy.sql import and_ from openlp.core.lib import SettingsManager, translate, Receiver, \ check_directory_exists +from openlp.core.lib.settings import Settings from openlp.plugins.songusage.lib.db import SongUsageItem from songusagedetaildialog import Ui_SongUsageDetailDialog @@ -59,10 +60,10 @@ class SongUsageDetailForm(QtGui.QDialog, Ui_SongUsageDetailDialog): year = QtCore.QDate().currentDate().year() if QtCore.QDate().currentDate().month() < 9: year -= 1 - toDate = QtCore.QSettings().value( + toDate = Settings().value( u'songusage/to date', QtCore.QVariant(QtCore.QDate(year, 8, 31))).toDate() - fromDate = QtCore.QSettings().value( + fromDate = Settings().value( u'songusage/from date', QtCore.QVariant(QtCore.QDate(year - 1, 9, 1))).toDate() self.fromDate.setSelectedDate(fromDate) @@ -103,9 +104,9 @@ class SongUsageDetailForm(QtGui.QDialog, Ui_SongUsageDetailDialog): 'usage_detail_%s_%s.txt')) % ( self.fromDate.selectedDate().toString(u'ddMMyyyy'), self.toDate.selectedDate().toString(u'ddMMyyyy')) - QtCore.QSettings().setValue(u'songusage/from date', + Settings().setValue(u'songusage/from date', QtCore.QVariant(self.fromDate.selectedDate())) - QtCore.QSettings().setValue(u'songusage/to date', + Settings().setValue(u'songusage/to date', QtCore.QVariant(self.toDate.selectedDate())) usage = self.plugin.manager.get_all_objects( SongUsageItem, and_( diff --git a/openlp/plugins/songusage/songusageplugin.py b/openlp/plugins/songusage/songusageplugin.py index 7746f9b28..3b6f66fe5 100644 --- a/openlp/plugins/songusage/songusageplugin.py +++ b/openlp/plugins/songusage/songusageplugin.py @@ -34,6 +34,7 @@ from openlp.core.lib import Plugin, StringContent, Receiver, build_icon, \ translate from openlp.core.lib.db import Manager from openlp.core.lib.ui import create_action +from openlp.core.lib.settings import Settings from openlp.core.utils.actions import ActionList from openlp.plugins.songusage.forms import SongUsageDetailForm, \ SongUsageDeleteForm @@ -125,7 +126,7 @@ class SongUsagePlugin(Plugin): QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'print_service_started'), self.printSongUsage) - self.songUsageActive = QtCore.QSettings().value( + self.songUsageActive = Settings().value( self.settingsSection + u'/active', QtCore.QVariant(False)).toBool() # Set the button and checkbox state @@ -168,7 +169,7 @@ class SongUsagePlugin(Plugin): the UI when necessary, """ self.songUsageActive = not self.songUsageActive - QtCore.QSettings().setValue(self.settingsSection + u'/active', + Settings().setValue(self.settingsSection + u'/active', QtCore.QVariant(self.songUsageActive)) self.setButtonState()