← Back to team overview

openlp-core team mailing list archive

[Merge] lp:~trb143/openlp/refactor1 into lp:openlp

 

Tim Bentley has proposed merging lp:~trb143/openlp/refactor1 into lp:openlp.

Requested reviews:
  OpenLP Core (openlp-core)

For more details, see:
https://code.launchpad.net/~trb143/openlp/refactor1/+merge/199046

Move Registry from lib to common

Move de_hump to common from theme

add logging mixin and clean up pluginmanager to use this.

add Registry minix and clean up slide controller.
-- 
https://code.launchpad.net/~trb143/openlp/refactor1/+merge/199046
Your team OpenLP Core is requested to review the proposed merge of lp:~trb143/openlp/refactor1 into lp:openlp.
=== modified file 'openlp/core/__init__.py'
--- openlp/core/__init__.py	2013-10-30 20:34:23 +0000
+++ openlp/core/__init__.py	2013-12-15 16:51:10 +0000
@@ -43,8 +43,8 @@
 
 from PyQt4 import QtCore, QtGui
 
-from openlp.core.common import AppLocation, Settings, UiStrings, check_directory_exists
-from openlp.core.lib import ScreenList, Registry
+from openlp.core.common import Registry, AppLocation, Settings, UiStrings, check_directory_exists
+from openlp.core.lib import ScreenList
 from openlp.core.resources import qInitResources
 from openlp.core.ui.mainwindow import MainWindow
 from openlp.core.ui.firsttimelanguageform import FirstTimeLanguageForm
@@ -162,7 +162,8 @@
         self.shared_memory = QtCore.QSharedMemory('OpenLP')
         if self.shared_memory.attach():
             status = QtGui.QMessageBox.critical(None, UiStrings().Error, UiStrings().OpenLPStart,
-                QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No))
+                                                QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes |
+                                                                                  QtGui.QMessageBox.No))
             if status == QtGui.QMessageBox.No:
                 return True
             return False
@@ -248,16 +249,16 @@
     usage = 'Usage: %prog [options] [qt-options]'
     parser = OptionParser(usage=usage)
     parser.add_option('-e', '--no-error-form', dest='no_error_form', action='store_true',
-        help='Disable the error notification form.')
+                      help='Disable the error notification form.')
     parser.add_option('-l', '--log-level', dest='loglevel', default='warning', metavar='LEVEL',
-        help='Set logging to LEVEL level. Valid values are "debug", "info", "warning".')
+                      help='Set logging to LEVEL level. Valid values are "debug", "info", "warning".')
     parser.add_option('-p', '--portable', dest='portable', action='store_true',
-        help='Specify if this should be run as a portable app, off a USB flash drive (not implemented).')
+                      help='Specify if this should be run as a portable app, off a USB flash drive (not implemented).')
     parser.add_option('-d', '--dev-version', dest='dev_version', action='store_true',
-        help='Ignore the version file and pull the version directly from Bazaar')
+                      help='Ignore the version file and pull the version directly from Bazaar')
     parser.add_option('-s', '--style', dest='style', help='Set the Qt4 style (passed directly to Qt4).')
     # Parse command line options and deal with them.
-    # Use args supplied programatically if possible.
+    # Use args supplied pragmatically if possible.
     (options, args) = parser.parse_args(args) if args else parser.parse_args()
     qt_args = []
     if options.loglevel.lower() in ['d', 'debug']:
@@ -326,4 +327,3 @@
     if not options.no_error_form:
         sys.excepthook = application.hook_exception
     sys.exit(application.run(qt_args))
-

=== modified file 'openlp/core/common/__init__.py'
--- openlp/core/common/__init__.py	2013-10-13 20:36:42 +0000
+++ openlp/core/common/__init__.py	2013-12-15 16:51:10 +0000
@@ -30,15 +30,32 @@
 The :mod:`common` module contains most of the components and libraries that make
 OpenLP work.
 """
+import re
 import os
 import logging
 import sys
+import traceback
 
 from PyQt4 import QtCore
 
 log = logging.getLogger(__name__)
 
 
+FIRST_CAMEL_REGEX = re.compile('(.)([A-Z][a-z]+)')
+SECOND_CAMEL_REGEX = re.compile('([a-z0-9])([A-Z])')
+
+
+def trace_error_handler(logger):
+    """
+    Log the calling path of an exception
+
+    'logger'
+    Logger to use so traceback is logged to correct class
+    """
+    for tb in traceback.extract_stack():
+        logger.error('Called by ' + tb[3] + ' at line ' + str(tb[1]) + ' in ' + tb[0])
+
+
 def check_directory_exists(directory, do_not_log=False):
     """
     Check a theme directory exists and if not create it
@@ -103,6 +120,17 @@
     Wrap = 2
     Next = 3
 
+
+def de_hump(name):
+    """
+    Change any Camel Case string to python string
+    """
+    sub_name = FIRST_CAMEL_REGEX.sub(r'\1_\2', name)
+    return SECOND_CAMEL_REGEX.sub(r'\1_\2', sub_name).lower()
+
+from .openlpmixin import OpenLPMixin
+from .registry import Registry
+from .registrymixin import RegistryMixin
 from .uistrings import UiStrings
 from .settings import Settings
 from .applocation import AppLocation

=== added file 'openlp/core/common/openlpmixin.py'
--- openlp/core/common/openlpmixin.py	1970-01-01 00:00:00 +0000
+++ openlp/core/common/openlpmixin.py	2013-12-15 16:51:10 +0000
@@ -0,0 +1,90 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection                                      #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2013 Raoul Snyman                                        #
+# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan      #
+# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub,      #
+# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer.   #
+# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru,          #
+# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith,             #
+# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock,              #
+# Frode Woldsund, Martin Zibricky, Patrick Zimmermann                         #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it     #
+# under the terms of the GNU General Public License as published by the Free  #
+# Software Foundation; version 2 of the License.                              #
+#                                                                             #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for    #
+# more details.                                                               #
+#                                                                             #
+# You should have received a copy of the GNU General Public License along     #
+# with this program; if not, write to the Free Software Foundation, Inc., 59  #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA                          #
+###############################################################################
+"""
+Provide Error Handling and login Services
+"""
+import logging
+import inspect
+
+from openlp.core.common import trace_error_handler
+DO_NOT_TRACE_EVENTS = ['timerEvent', 'paintEvent']
+
+
+class OpenLPMixin(object):
+    """
+    Base Calling object for OpenLP classes.
+    """
+    def __init__(self):
+        super().__init__()
+        self.logger = logging.getLogger(self.__module__)
+        for name, m in inspect.getmembers(self, inspect.ismethod):
+            if name not in DO_NOT_TRACE_EVENTS:
+                if not name.startswith("_") and not name.startswith("log_"):
+                    setattr(self, name, self.logging_wrapper(m, self))
+
+    def logging_wrapper(self, func, parent):
+        """
+        Code to added debug wrapper to work on called functions within a decorated class.
+        """
+        def wrapped(*args, **kwargs):
+            if parent.logger.getEffectiveLevel() == logging.DEBUG:
+                parent.logger.debug("Entering %s" % func.__name__)
+            try:
+                return func(*args, **kwargs)
+            except Exception as e:
+                if parent.logger.getEffectiveLevel() <= logging.ERROR:
+                    parent.logger.error('Exception in %s : %s' % (func.__name__, e))
+                raise e
+        return wrapped
+
+    def log_debug(self, message):
+        """
+        Common log debug handler which prints the calling path
+        """
+        self.logger.debug(message)
+
+    def log_info(self, message):
+        """
+        Common log info handler which prints the calling path
+        """
+        self.logger.info(message)
+
+    def log_error(self, message):
+        """
+        Common log error handler which prints the calling path
+        """
+        trace_error_handler(self.logger)
+        self.logger.error(message)
+
+    def log_exception(self, message):
+        """
+        Common log exception handler which prints the calling path
+        """
+        trace_error_handler(self.logger)
+        self.logger.exception(message)
\ No newline at end of file

=== added file 'openlp/core/common/registry.py'
--- openlp/core/common/registry.py	1970-01-01 00:00:00 +0000
+++ openlp/core/common/registry.py	2013-12-15 16:51:10 +0000
@@ -0,0 +1,174 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection                                      #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2013 Raoul Snyman                                        #
+# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan      #
+# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub,      #
+# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer.   #
+# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru,          #
+# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith,             #
+# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock,              #
+# Frode Woldsund, Martin Zibricky, Patrick Zimmermann                         #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it     #
+# under the terms of the GNU General Public License as published by the Free  #
+# Software Foundation; version 2 of the License.                              #
+#                                                                             #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for    #
+# more details.                                                               #
+#                                                                             #
+# You should have received a copy of the GNU General Public License along     #
+# with this program; if not, write to the Free Software Foundation, Inc., 59  #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA                          #
+###############################################################################
+"""
+Provide Registry Services
+"""
+import logging
+import sys
+
+from openlp.core.common import trace_error_handler
+
+log = logging.getLogger(__name__)
+
+
+class Registry(object):
+    """
+    This is the Component Registry.  It is a singleton object and is used to provide a look up service for common
+    objects.
+    """
+    log.info('Registry loaded')
+    __instance__ = None
+
+    def __new__(cls):
+        """
+        Re-implement the __new__ method to make sure we create a true singleton.
+        """
+        if not cls.__instance__:
+            cls.__instance__ = object.__new__(cls)
+        return cls.__instance__
+
+    @classmethod
+    def create(cls):
+        """
+        The constructor for the component registry providing a single registry of objects.
+        """
+        log.info('Registry Initialising')
+        registry = cls()
+        registry.service_list = {}
+        registry.functions_list = {}
+        registry.running_under_test = False
+        # Allow the tests to remove Registry entries but not the live system
+        if 'nose' in sys.argv[0]:
+            registry.running_under_test = True
+        return registry
+
+    def get(self, key):
+        """
+        Extracts the registry value from the list based on the key passed in
+
+        ``key``
+            The service to be retrieved.
+        """
+        if key in self.service_list:
+            return self.service_list[key]
+        else:
+            trace_error_handler(log)
+            log.error('Service %s not found in list' % key)
+            raise KeyError('Service %s not found in list' % key)
+
+    def register(self, key, reference):
+        """
+        Registers a component against a key.
+
+        ``key``
+            The service to be created this is usually a major class like "renderer" or "main_window" .
+
+        ``reference``
+            The service address to be saved.
+        """
+        if key in self.service_list:
+            trace_error_handler(log)
+            log.error('Duplicate service exception %s' % key)
+            raise KeyError('Duplicate service exception %s' % key)
+        else:
+            self.service_list[key] = reference
+
+    def remove(self, key):
+        """
+        Removes the registry value from the list based on the key passed in (Only valid and active for testing
+        framework).
+
+        ``key``
+            The service to be deleted.
+        """
+        if key in self.service_list:
+            del self.service_list[key]
+
+    def register_function(self, event, function):
+        """
+        Register an event and associated function to be called
+
+        ``event``
+            The function description like "live_display_hide" where a number of places in the code
+            will/may need to respond to a single action and the caller does not need to understand or know about the
+            recipients.
+
+        ``function``
+            The function to be called when the event happens.
+        """
+        if event in self.functions_list:
+            self.functions_list[event].append(function)
+        else:
+            self.functions_list[event] = [function]
+
+    def remove_function(self, event, function):
+        """
+        Remove an event and associated handler
+
+        ``event``
+            The function description..
+
+        ``function``
+            The function to be called when the event happens.
+        """
+        if self.running_under_test is False:
+            trace_error_handler(log)
+            log.error('Invalid Method call for key %s' % event)
+            raise KeyError('Invalid Method call for key %s' % event)
+        if event in self.functions_list:
+            self.functions_list[event].remove(function)
+
+    def execute(self, event, *args, **kwargs):
+        """
+        Execute all the handlers associated with the event and return an array of results.
+
+        ``event``
+            The function to be processed
+
+        ``*args``
+            Parameters to be passed to the function.
+
+        ``*kwargs``
+            Parameters to be passed to the function.
+        """
+        results = []
+        if event in self.functions_list:
+            for function in self.functions_list[event]:
+                try:
+                    result = function(*args, **kwargs)
+                    if result:
+                        results.append(result)
+                except TypeError:
+                    # Who has called me can help in debugging
+                    trace_error_handler(log)
+                    log.exception('Exception for function %s', function)
+        else:
+            trace_error_handler(log)
+            log.error("Event %s not called by not registered" % event)
+        return results

=== added file 'openlp/core/common/registrymixin.py'
--- openlp/core/common/registrymixin.py	1970-01-01 00:00:00 +0000
+++ openlp/core/common/registrymixin.py	2013-12-15 16:51:10 +0000
@@ -0,0 +1,60 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection                                      #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2013 Raoul Snyman                                        #
+# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan      #
+# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub,      #
+# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer.   #
+# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru,          #
+# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith,             #
+# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock,              #
+# Frode Woldsund, Martin Zibricky, Patrick Zimmermann                         #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it     #
+# under the terms of the GNU General Public License as published by the Free  #
+# Software Foundation; version 2 of the License.                              #
+#                                                                             #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for    #
+# more details.                                                               #
+#                                                                             #
+# You should have received a copy of the GNU General Public License along     #
+# with this program; if not, write to the Free Software Foundation, Inc., 59  #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA                          #
+###############################################################################
+"""
+Provide Registry Services
+"""
+
+
+from openlp.core.common import Registry, de_hump
+
+
+class RegistryMixin(object):
+    """
+    This adds registry components to classes to use at run time.
+    """
+    def __init__(self):
+        """
+        Register the class and bootstrap hooks.
+        """
+        Registry().register(de_hump(self.__class__.__name__), self)
+        Registry().register_function('bootstrap_initialise', self.bootstrap_initialise)
+        Registry().register_function('bootstrap_post_set_up', self.bootstrap_post_set_up)
+        super().__init__()
+
+    def bootstrap_initialise(self):
+        """
+        Dummy method to be overridden
+        """
+        pass
+
+    def bootstrap_post_set_up(self):
+        """
+        Dummy method to be overridden
+        """
+        pass

=== modified file 'openlp/core/lib/__init__.py'
--- openlp/core/lib/__init__.py	2013-11-16 20:32:50 +0000
+++ openlp/core/lib/__init__.py	2013-12-15 16:51:10 +0000
@@ -329,7 +329,6 @@
         return translate('OpenLP.core.lib', '%s, %s', 'Locale list separator: start') % (string_list[0], merged)
 
 
-from .registry import Registry
 from .filedialog import FileDialog
 from .screen import ScreenList
 from .listwidgetwithdnd import ListWidgetWithDnD

=== modified file 'openlp/core/lib/imagemanager.py'
--- openlp/core/lib/imagemanager.py	2013-08-31 18:17:38 +0000
+++ openlp/core/lib/imagemanager.py	2013-12-15 16:51:10 +0000
@@ -39,7 +39,8 @@
 
 from PyQt4 import QtCore
 
-from openlp.core.lib import Registry, ScreenList, resize_image, image_to_byte
+from openlp.core.common import Registry
+from openlp.core.lib import ScreenList, resize_image, image_to_byte
 
 log = logging.getLogger(__name__)
 

=== modified file 'openlp/core/lib/listwidgetwithdnd.py'
--- openlp/core/lib/listwidgetwithdnd.py	2013-08-31 18:17:38 +0000
+++ openlp/core/lib/listwidgetwithdnd.py	2013-12-15 16:51:10 +0000
@@ -33,7 +33,7 @@
 
 from PyQt4 import QtCore, QtGui
 
-from openlp.core.lib import Registry
+from openlp.core.common import Registry
 
 
 class ListWidgetWithDnD(QtGui.QListWidget):

=== modified file 'openlp/core/lib/mediamanageritem.py'
--- openlp/core/lib/mediamanageritem.py	2013-11-16 20:32:50 +0000
+++ openlp/core/lib/mediamanageritem.py	2013-12-15 16:51:10 +0000
@@ -35,9 +35,9 @@
 
 from PyQt4 import QtCore, QtGui
 
-from openlp.core.common import Settings, UiStrings, translate
+from openlp.core.common import Registry, Settings, UiStrings, translate
 from openlp.core.lib import FileDialog, OpenLPToolbar, ServiceItem, StringContent, ListWidgetWithDnD, \
-    ServiceItemContext, Registry
+    ServiceItemContext
 from openlp.core.lib.searchedit import SearchEdit
 from openlp.core.lib.ui import create_widget_action, critical_error_message_box
 

=== modified file 'openlp/core/lib/plugin.py'
--- openlp/core/lib/plugin.py	2013-10-13 20:36:42 +0000
+++ openlp/core/lib/plugin.py	2013-12-15 16:51:10 +0000
@@ -34,8 +34,7 @@
 
 from PyQt4 import QtCore
 
-from openlp.core.common import Settings, UiStrings
-from openlp.core.lib import Registry
+from openlp.core.common import Registry, Settings, UiStrings
 from openlp.core.utils import get_application_version
 
 log = logging.getLogger(__name__)

=== modified file 'openlp/core/lib/pluginmanager.py'
--- openlp/core/lib/pluginmanager.py	2013-10-13 13:51:13 +0000
+++ openlp/core/lib/pluginmanager.py	2013-12-15 16:51:10 +0000
@@ -31,68 +31,56 @@
 """
 import os
 import sys
-import logging
 import imp
 
-from openlp.core.lib import Plugin, PluginStatus, Registry
-from openlp.core.common import AppLocation
-
-log = logging.getLogger(__name__)
-
-
-class PluginManager(object):
+from openlp.core.lib import Plugin, PluginStatus
+from openlp.core.common import AppLocation, Registry, OpenLPMixin, RegistryMixin
+
+
+class PluginManager(OpenLPMixin, RegistryMixin):
     """
     This is the Plugin manager, which loads all the plugins,
     and executes all the hooks, as and when necessary.
     """
-    log.info('Plugin manager loaded')
-
     def __init__(self):
         """
         The constructor for the plugin manager. Passes the controllers on to
         the plugins for them to interact with via their ServiceItems.
         """
-        log.info('Plugin manager Initialising')
-        Registry().register('plugin_manager', self)
-        Registry().register_function('bootstrap_initialise', self.bootstrap_initialise)
+        super(PluginManager, self).__init__()
+        self.log_info('Plugin manager Initialising')
         self.base_path = os.path.abspath(AppLocation.get_directory(AppLocation.PluginsDir))
-        log.debug('Base path %s ', self.base_path)
+        self.log_debug('Base path %s ' % self.base_path)
         self.plugins = []
-        log.info('Plugin manager Initialised')
+        self.log_info('Plugin manager Initialised')
 
     def bootstrap_initialise(self):
         """
         Bootstrap all the plugin manager functions
         """
-        log.info('bootstrap_initialise')
         self.find_plugins()
         # hook methods have to happen after find_plugins. Find plugins needs
         # the controllers hence the hooks have moved from setupUI() to here
         # Find and insert settings tabs
-        log.info('hook settings')
         self.hook_settings_tabs()
         # Find and insert media manager items
-        log.info('hook media')
         self.hook_media_manager()
         # Call the hook method to pull in import menus.
-        log.info('hook menus')
         self.hook_import_menu()
         # Call the hook method to pull in export menus.
         self.hook_export_menu()
         # Call the hook method to pull in tools menus.
         self.hook_tools_menu()
         # Call the initialise method to setup plugins.
-        log.info('initialise plugins')
         self.initialise_plugins()
 
     def find_plugins(self):
         """
         Scan a directory for objects inheriting from the ``Plugin`` class.
         """
-        log.info('Finding plugins')
         start_depth = len(os.path.abspath(self.base_path).split(os.sep))
         present_plugin_dir = os.path.join(self.base_path, 'presentations')
-        log.debug('finding plugins in %s at depth %d', str(self.base_path), start_depth)
+        self.log_debug('finding plugins in %s at depth %d' % (self.base_path, start_depth))
         for root, dirs, files in os.walk(self.base_path):
             if sys.platform == 'darwin' and root.startswith(present_plugin_dir):
                 # TODO Presentation plugin is not yet working on Mac OS X.
@@ -108,7 +96,7 @@
                         break
                     module_name = name[:-3]
                     # import the modules
-                    log.debug('Importing %s from %s. Depth %d', module_name, root, this_depth)
+                    self.log_debug('Importing %s from %s. Depth %d' % (module_name, root, this_depth))
                     try:
                         # Use the "imp" library to try to get around a problem with the PyUNO library which
                         # monkey-patches the __import__ function to do some magic. This causes issues with our tests.
@@ -117,20 +105,21 @@
                         # Then load the module (do the actual import) using the details from find_module()
                         imp.load_module(module_name, fp, path_name, description)
                     except ImportError as e:
-                        log.exception('Failed to import module %s on path %s: %s', module_name, path, e.args[0])
+                        self.log_exception('Failed to import module %s on path %s: %s'
+                                           % (module_name, path, e.args[0]))
         plugin_classes = Plugin.__subclasses__()
         plugin_objects = []
         for p in plugin_classes:
             try:
                 plugin = p()
-                log.debug('Loaded plugin %s', str(p))
+                self.log_debug('Loaded plugin %s' % str(p))
                 plugin_objects.append(plugin)
             except TypeError:
-                log.exception('Failed to load plugin %s', str(p))
+                self.log_exception('Failed to load plugin %s' % str(p))
         plugins_list = sorted(plugin_objects, key=lambda plugin: plugin.weight)
         for plugin in plugins_list:
             if plugin.check_pre_conditions():
-                log.debug('Plugin %s active', str(plugin.name))
+                self.log_debug('Plugin %s active' % str(plugin.name))
                 plugin.set_status()
             else:
                 plugin.status = PluginStatus.Disabled
@@ -199,24 +188,21 @@
         Loop through all the plugins and give them an opportunity to
         initialise themselves.
         """
-        log.info('Initialise Plugins - Started')
         for plugin in self.plugins:
-            log.info('initialising plugins %s in a %s state' % (plugin.name, plugin.is_active()))
+            self.log_info('initialising plugins %s in a %s state' % (plugin.name, plugin.is_active()))
             if plugin.is_active():
                 plugin.initialise()
-                log.info('Initialisation Complete for %s ' % plugin.name)
-        log.info('Initialise Plugins - Finished')
+                self.log_info('Initialisation Complete for %s ' % plugin.name)
 
     def finalise_plugins(self):
         """
         Loop through all the plugins and give them an opportunity to
         clean themselves up
         """
-        log.info('finalising plugins')
         for plugin in self.plugins:
             if plugin.is_active():
                 plugin.finalise()
-                log.info('Finalisation Complete for %s ' % plugin.name)
+                self.log_info('Finalisation Complete for %s ' % plugin.name)
 
     def get_plugin_by_name(self, name):
         """
@@ -231,7 +217,6 @@
         """
         Loop through all the plugins and give them an opportunity to handle a new service
         """
-        log.info('plugins - new service created')
         for plugin in self.plugins:
             if plugin.is_active():
                 plugin.new_service_created()
@@ -255,4 +240,3 @@
         return self._main_window
 
     main_window = property(_get_main_window)
-

=== removed file 'openlp/core/lib/registry.py'
--- openlp/core/lib/registry.py	2013-08-31 18:17:38 +0000
+++ openlp/core/lib/registry.py	1970-01-01 00:00:00 +0000
@@ -1,167 +0,0 @@
-# -*- coding: utf-8 -*-
-# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
-
-###############################################################################
-# OpenLP - Open Source Lyrics Projection                                      #
-# --------------------------------------------------------------------------- #
-# Copyright (c) 2008-2013 Raoul Snyman                                        #
-# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan      #
-# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub,      #
-# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer.   #
-# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru,          #
-# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith,             #
-# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock,              #
-# Frode Woldsund, Martin Zibricky, Patrick Zimmermann                         #
-# --------------------------------------------------------------------------- #
-# This program is free software; you can redistribute it and/or modify it     #
-# under the terms of the GNU General Public License as published by the Free  #
-# Software Foundation; version 2 of the License.                              #
-#                                                                             #
-# This program is distributed in the hope that it will be useful, but WITHOUT #
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       #
-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for    #
-# more details.                                                               #
-#                                                                             #
-# You should have received a copy of the GNU General Public License along     #
-# with this program; if not, write to the Free Software Foundation, Inc., 59  #
-# Temple Place, Suite 330, Boston, MA 02111-1307 USA                          #
-###############################################################################
-"""
-Provide Registry Services
-"""
-import logging
-import sys
-
-log = logging.getLogger(__name__)
-
-
-class Registry(object):
-    """
-    This is the Component Registry.  It is a singleton object and is used to provide a look up service for common
-    objects.
-    """
-    log.info('Registry loaded')
-    __instance__ = None
-
-    def __new__(cls):
-        """
-        Re-implement the __new__ method to make sure we create a true singleton.
-        """
-        if not cls.__instance__:
-            cls.__instance__ = object.__new__(cls)
-        return cls.__instance__
-
-    @classmethod
-    def create(cls):
-        """
-        The constructor for the component registry providing a single registry of objects.
-        """
-        log.info('Registry Initialising')
-        registry = cls()
-        registry.service_list = {}
-        registry.functions_list = {}
-        registry.running_under_test = False
-        # Allow the tests to remove Registry entries but not the live system
-        if 'nose' in sys.argv[0]:
-            registry.running_under_test = True
-        return registry
-
-    def get(self, key):
-        """
-        Extracts the registry value from the list based on the key passed in
-
-        ``key``
-            The service to be retrieved.
-        """
-        if key in self.service_list:
-            return self.service_list[key]
-        else:
-            log.error('Service %s not found in list' % key)
-            raise KeyError('Service %s not found in list' % key)
-
-    def register(self, key, reference):
-        """
-        Registers a component against a key.
-
-        ``key``
-            The service to be created this is usually a major class like "renderer" or "main_window" .
-
-        ``reference``
-            The service address to be saved.
-        """
-        if key in self.service_list:
-            log.error('Duplicate service exception %s' % key)
-            raise KeyError('Duplicate service exception %s' % key)
-        else:
-            self.service_list[key] = reference
-
-    def remove(self, key):
-        """
-        Removes the registry value from the list based on the key passed in (Only valid and active for testing
-        framework).
-
-        ``key``
-            The service to be deleted.
-        """
-        if key in self.service_list:
-            del self.service_list[key]
-
-    def register_function(self, event, function):
-        """
-        Register an event and associated function to be called
-
-        ``event``
-            The function description like "live_display_hide" where a number of places in the code
-            will/may need to respond to a single action and the caller does not need to understand or know about the
-            recipients.
-
-        ``function``
-            The function to be called when the event happens.
-        """
-        if event in self.functions_list:
-            self.functions_list[event].append(function)
-        else:
-            self.functions_list[event] = [function]
-
-    def remove_function(self, event, function):
-        """
-        Remove an event and associated handler
-
-        ``event``
-            The function description..
-
-        ``function``
-            The function to be called when the event happens.
-        """
-        if self.running_under_test is False:
-            log.error('Invalid Method call for key %s' % event)
-            raise KeyError('Invalid Method call for key %s' % event)
-        if event in self.functions_list:
-            self.functions_list[event].remove(function)
-
-    def execute(self, event, *args, **kwargs):
-        """
-        Execute all the handlers associated with the event and return an array of results.
-
-        ``event``
-            The function to be processed
-
-        ``*args``
-            Parameters to be passed to the function.
-
-        ``*kwargs``
-            Parameters to be passed to the function.
-        """
-        results = []
-        if event in self.functions_list:
-            for function in self.functions_list[event]:
-                try:
-                    result = function(*args, **kwargs)
-                    if result:
-                        results.append(result)
-                except TypeError:
-                    # Who has called me can help in debugging
-                    import inspect
-                    log.debug(inspect.currentframe().f_back.f_locals)
-                    log.exception('Exception for function %s', function)
-        return results

=== modified file 'openlp/core/lib/renderer.py'
--- openlp/core/lib/renderer.py	2013-10-13 20:36:42 +0000
+++ openlp/core/lib/renderer.py	2013-12-15 16:51:10 +0000
@@ -31,9 +31,9 @@
 
 from PyQt4 import QtGui, QtCore, QtWebKit
 
-from openlp.core.common import Settings
-from openlp.core.lib import FormattingTags, ImageSource, ItemCapabilities, Registry, ScreenList, \
-    ServiceItem, expand_tags, build_lyrics_format_css, build_lyrics_outline_css
+from openlp.core.common import Registry, Settings
+from openlp.core.lib import FormattingTags, ImageSource, ItemCapabilities, ScreenList, ServiceItem, expand_tags, \
+    build_lyrics_format_css, build_lyrics_outline_css
 from openlp.core.common import ThemeLevel
 from openlp.core.ui import MainDisplay
 

=== modified file 'openlp/core/lib/screen.py'
--- openlp/core/lib/screen.py	2013-10-13 20:36:42 +0000
+++ openlp/core/lib/screen.py	2013-12-15 16:51:10 +0000
@@ -36,8 +36,7 @@
 
 from PyQt4 import QtCore
 
-from openlp.core.common import Settings, translate
-from openlp.core.lib import Registry
+from openlp.core.common import Registry, Settings, translate
 
 log = logging.getLogger(__name__)
 

=== modified file 'openlp/core/lib/serviceitem.py'
--- openlp/core/lib/serviceitem.py	2013-10-13 21:07:28 +0000
+++ openlp/core/lib/serviceitem.py	2013-12-15 16:51:10 +0000
@@ -39,8 +39,8 @@
 
 from PyQt4 import QtGui
 
-from openlp.core.common import Settings, translate
-from openlp.core.lib import ImageSource, Registry, build_icon, clean_tags, expand_tags
+from openlp.core.common import Registry, Settings, translate
+from openlp.core.lib import ImageSource, build_icon, clean_tags, expand_tags
 
 log = logging.getLogger(__name__)
 

=== modified file 'openlp/core/lib/settingstab.py'
--- openlp/core/lib/settingstab.py	2013-08-31 18:17:38 +0000
+++ openlp/core/lib/settingstab.py	2013-12-15 16:51:10 +0000
@@ -35,7 +35,7 @@
 from PyQt4 import QtGui
 
 
-from openlp.core.lib import Registry
+from openlp.core.common import Registry
 
 
 class SettingsTab(QtGui.QWidget):

=== modified file 'openlp/core/lib/theme.py'
--- openlp/core/lib/theme.py	2013-10-18 18:10:47 +0000
+++ openlp/core/lib/theme.py	2013-12-15 16:51:10 +0000
@@ -36,7 +36,7 @@
 
 from xml.dom.minidom import Document
 from lxml import etree, objectify
-from openlp.core.common import AppLocation
+from openlp.core.common import AppLocation, de_hump
 
 from openlp.core.lib import str_to_bool, ScreenList, get_text_file_string
 
@@ -157,9 +157,6 @@
     """
     A class to encapsulate the Theme XML.
     """
-    FIRST_CAMEL_REGEX = re.compile('(.)([A-Z][a-z]+)')
-    SECOND_CAMEL_REGEX = re.compile('([a-z0-9])([A-Z])')
-
     def __init__(self):
         """
         Initialise the theme object.
@@ -532,7 +529,7 @@
         reject, master, element, value = self._translate_tags(master, element, value)
         if reject:
             return
-        field = self._de_hump(element)
+        field = de_hump(element)
         tag = master + '_' + field
         if field in BOOLEAN_LIST:
             setattr(self, tag, str_to_bool(value))
@@ -557,13 +554,6 @@
                 theme_strings.append('%30s: %s' % (key, getattr(self, key)))
         return '\n'.join(theme_strings)
 
-    def _de_hump(self, name):
-        """
-        Change Camel Case string to python string
-        """
-        sub_name = ThemeXML.FIRST_CAMEL_REGEX.sub(r'\1_\2', name)
-        return ThemeXML.SECOND_CAMEL_REGEX.sub(r'\1_\2', sub_name).lower()
-
     def _build_xml_from_attrs(self):
         """
         Build the XML from the varables in the object

=== modified file 'openlp/core/lib/treewidgetwithdnd.py'
--- openlp/core/lib/treewidgetwithdnd.py	2013-08-31 18:17:38 +0000
+++ openlp/core/lib/treewidgetwithdnd.py	2013-12-15 16:51:10 +0000
@@ -33,7 +33,7 @@
 
 from PyQt4 import QtCore, QtGui
 
-from openlp.core.lib import Registry
+from openlp.core.common import Registry
 
 
 class TreeWidgetWithDnD(QtGui.QTreeWidget):

=== modified file 'openlp/core/lib/ui.py'
--- openlp/core/lib/ui.py	2013-10-13 20:36:42 +0000
+++ openlp/core/lib/ui.py	2013-12-15 16:51:10 +0000
@@ -33,8 +33,8 @@
 
 from PyQt4 import QtCore, QtGui
 
-from openlp.core.common import UiStrings, translate
-from openlp.core.lib import Registry, build_icon
+from openlp.core.common import Registry, UiStrings, translate
+from openlp.core.lib import build_icon
 from openlp.core.utils.actions import ActionList
 
 

=== modified file 'openlp/core/ui/exceptionform.py'
--- openlp/core/ui/exceptionform.py	2013-10-30 20:34:23 +0000
+++ openlp/core/ui/exceptionform.py	2013-12-15 16:51:10 +0000
@@ -38,7 +38,7 @@
 import sqlalchemy
 from lxml import etree
 
-from openlp.core.lib import Registry
+from openlp.core.common import Registry
 
 from PyQt4 import Qt, QtCore, QtGui, QtWebKit
 

=== modified file 'openlp/core/ui/filerenameform.py'
--- openlp/core/ui/filerenameform.py	2013-10-13 21:07:28 +0000
+++ openlp/core/ui/filerenameform.py	2013-12-15 16:51:10 +0000
@@ -34,8 +34,7 @@
 
 from .filerenamedialog import Ui_FileRenameDialog
 
-from openlp.core.common import translate
-from openlp.core.lib import Registry
+from openlp.core.common import Registry, translate
 
 
 class FileRenameForm(QtGui.QDialog, Ui_FileRenameDialog):

=== modified file 'openlp/core/ui/firsttimeform.py'
--- openlp/core/ui/firsttimeform.py	2013-10-13 21:07:28 +0000
+++ openlp/core/ui/firsttimeform.py	2013-12-15 16:51:10 +0000
@@ -41,8 +41,8 @@
 
 from PyQt4 import QtCore, QtGui
 
-from openlp.core.common import AppLocation, Settings, check_directory_exists, translate
-from openlp.core.lib import PluginStatus, Registry, build_icon
+from openlp.core.common import Registry, AppLocation, Settings, check_directory_exists, translate
+from openlp.core.lib import PluginStatus, build_icon
 from openlp.core.utils import get_web_page
 from .firsttimewizard import Ui_FirstTimeWizard, FirstTimePage
 

=== modified file 'openlp/core/ui/generaltab.py'
--- openlp/core/ui/generaltab.py	2013-10-13 20:36:42 +0000
+++ openlp/core/ui/generaltab.py	2013-12-15 16:51:10 +0000
@@ -33,8 +33,8 @@
 
 from PyQt4 import QtCore, QtGui
 
-from openlp.core.common import Settings, UiStrings, translate
-from openlp.core.lib import Registry, SettingsTab, ScreenList
+from openlp.core.common import Registry, Settings, UiStrings, translate
+from openlp.core.lib import SettingsTab, ScreenList
 
 log = logging.getLogger(__name__)
 

=== modified file 'openlp/core/ui/listpreviewwidget.py'
--- openlp/core/ui/listpreviewwidget.py	2013-08-31 18:17:38 +0000
+++ openlp/core/ui/listpreviewwidget.py	2013-12-15 16:51:10 +0000
@@ -33,7 +33,8 @@
 
 from PyQt4 import QtCore, QtGui
 
-from openlp.core.lib import ImageSource, Registry, ServiceItem
+from openlp.core.common import Registry
+from openlp.core.lib import ImageSource, ServiceItem
 
 
 class ListPreviewWidget(QtGui.QTableWidget):

=== modified file 'openlp/core/ui/maindisplay.py'
--- openlp/core/ui/maindisplay.py	2013-10-23 18:49:39 +0000
+++ openlp/core/ui/maindisplay.py	2013-12-15 16:51:10 +0000
@@ -44,8 +44,8 @@
 from PyQt4 import QtCore, QtGui, QtWebKit, QtOpenGL
 from PyQt4.phonon import Phonon
 
-from openlp.core.common import Settings, translate
-from openlp.core.lib import ServiceItem, ImageSource, Registry, build_html, expand_tags, image_to_byte
+from openlp.core.common import Registry, Settings, translate
+from openlp.core.lib import ServiceItem, ImageSource, build_html, expand_tags, image_to_byte
 from openlp.core.lib.theme import BackgroundType
 
 from openlp.core.lib import ScreenList

=== modified file 'openlp/core/ui/mainwindow.py'
--- openlp/core/ui/mainwindow.py	2013-10-13 21:07:28 +0000
+++ openlp/core/ui/mainwindow.py	2013-12-15 16:51:10 +0000
@@ -41,13 +41,13 @@
 
 from PyQt4 import QtCore, QtGui
 
-from openlp.core.lib import Renderer, OpenLPDockWidget, PluginManager, ImageManager, PluginStatus, Registry, \
-    ScreenList, build_icon
+from openlp.core.common import Registry, AppLocation, Settings, check_directory_exists, translate
+from openlp.core.lib import Renderer, OpenLPDockWidget, PluginManager, ImageManager, PluginStatus, ScreenList, \
+    build_icon
 from openlp.core.lib.ui import UiStrings, create_action
 from openlp.core.ui import AboutForm, SettingsForm, ServiceManager, ThemeManager, SlideController, PluginForm, \
     MediaDockManager, ShortcutListForm, FormattingTagForm
 
-from openlp.core.common import AppLocation, Settings, check_directory_exists, translate
 from openlp.core.ui.media import MediaController
 from openlp.core.utils import LanguageManager, add_actions, get_application_version
 from openlp.core.utils.actions import ActionList, CategoryOrder

=== modified file 'openlp/core/ui/media/mediacontroller.py'
--- openlp/core/ui/media/mediacontroller.py	2013-10-13 20:36:42 +0000
+++ openlp/core/ui/media/mediacontroller.py	2013-12-15 16:51:10 +0000
@@ -35,8 +35,8 @@
 import datetime
 from PyQt4 import QtCore, QtGui
 
-from openlp.core.common import Settings, UiStrings, translate
-from openlp.core.lib import OpenLPToolbar, Registry
+from openlp.core.common import Registry, Settings, UiStrings, translate
+from openlp.core.lib import OpenLPToolbar
 from openlp.core.lib.ui import critical_error_message_box
 from openlp.core.ui.media import MediaState, MediaInfo, MediaType, get_media_players, set_media_players
 from openlp.core.ui.media.mediaplayer import MediaPlayer

=== modified file 'openlp/core/ui/media/mediaplayer.py'
--- openlp/core/ui/media/mediaplayer.py	2013-08-31 18:17:38 +0000
+++ openlp/core/ui/media/mediaplayer.py	2013-12-15 16:51:10 +0000
@@ -31,7 +31,7 @@
 """
 import os
 
-from openlp.core.lib import Registry
+from openlp.core.common import Registry
 from openlp.core.ui.media import MediaState
 
 

=== modified file 'openlp/core/ui/media/playertab.py'
--- openlp/core/ui/media/playertab.py	2013-10-13 20:36:42 +0000
+++ openlp/core/ui/media/playertab.py	2013-12-15 16:51:10 +0000
@@ -31,8 +31,8 @@
 """
 from PyQt4 import QtCore, QtGui
 
-from openlp.core.common import Settings, UiStrings, translate
-from openlp.core.lib import Registry, SettingsTab
+from openlp.core.common import Registry, Settings, UiStrings, translate
+from openlp.core.lib import SettingsTab
 from openlp.core.lib.ui import create_button
 from openlp.core.ui.media import get_media_players, set_media_players
 

=== modified file 'openlp/core/ui/pluginform.py'
--- openlp/core/ui/pluginform.py	2013-10-13 21:07:28 +0000
+++ openlp/core/ui/pluginform.py	2013-12-15 16:51:10 +0000
@@ -34,8 +34,8 @@
 
 from PyQt4 import QtGui
 
-from openlp.core.common import translate
-from openlp.core.lib import PluginStatus, Registry
+from openlp.core.common import Registry, translate
+from openlp.core.lib import PluginStatus
 from .plugindialog import Ui_PluginViewDialog
 
 log = logging.getLogger(__name__)

=== modified file 'openlp/core/ui/printserviceform.py'
--- openlp/core/ui/printserviceform.py	2013-10-13 20:36:42 +0000
+++ openlp/core/ui/printserviceform.py	2013-12-15 16:51:10 +0000
@@ -36,8 +36,8 @@
 from PyQt4 import QtCore, QtGui
 from lxml import html
 
-from openlp.core.common import Settings, UiStrings, translate
-from openlp.core.lib import Registry, get_text_file_string
+from openlp.core.common import Registry, Settings, UiStrings, translate
+from openlp.core.lib import get_text_file_string
 from openlp.core.ui.printservicedialog import Ui_PrintServiceDialog, ZoomSize
 from openlp.core.common import AppLocation
 

=== modified file 'openlp/core/ui/serviceitemeditform.py'
--- openlp/core/ui/serviceitemeditform.py	2013-10-13 21:07:28 +0000
+++ openlp/core/ui/serviceitemeditform.py	2013-12-15 16:51:10 +0000
@@ -30,7 +30,7 @@
 The service item edit dialog
 """
 from PyQt4 import QtGui
-from openlp.core.lib import Registry
+from openlp.core.common import Registry
 
 from .serviceitemeditdialog import Ui_ServiceItemEditDialog
 

=== modified file 'openlp/core/ui/servicemanager.py'
--- openlp/core/ui/servicemanager.py	2013-10-13 21:07:28 +0000
+++ openlp/core/ui/servicemanager.py	2013-12-15 16:51:10 +0000
@@ -42,8 +42,8 @@
 
 from PyQt4 import QtCore, QtGui
 
-from openlp.core.common import AppLocation, Settings, ThemeLevel, check_directory_exists, UiStrings, translate
-from openlp.core.lib import OpenLPToolbar, ServiceItem, ItemCapabilities, PluginStatus, Registry, build_icon
+from openlp.core.common import Registry, AppLocation, Settings, ThemeLevel, check_directory_exists, UiStrings, translate
+from openlp.core.lib import OpenLPToolbar, ServiceItem, ItemCapabilities, PluginStatus, build_icon
 from openlp.core.lib.ui import critical_error_message_box, create_widget_action, find_and_set_in_combo_box
 from openlp.core.ui import ServiceNoteForm, ServiceItemEditForm, StartTimeForm
 from openlp.core.ui.printserviceform import PrintServiceForm
@@ -730,7 +730,7 @@
                 Settings().setValue('servicemanager/last file', file_name)
             else:
                 critical_error_message_box(message=translate('OpenLP.ServiceManager', 'File is not a valid service.'))
-                log.exception('File contains no service data')
+                log.error('File contains no service data')
         except (IOError, NameError, zipfile.BadZipfile):
             log.exception('Problem loading service file %s' % file_name)
             critical_error_message_box(message=translate('OpenLP.ServiceManager',
@@ -741,7 +741,7 @@
                 QtGui.QMessageBox.information(self, translate('OpenLP.ServiceManager', 'Empty File'),
                     translate('OpenLP.ServiceManager', 'This service file does not contain any data.'))
             else:
-                log.exception('Service file is cannot be extracted as zip: '
+                log.error('Service file is cannot be extracted as zip: '
                     '%s' % file_name)
                 QtGui.QMessageBox.information(self, translate('OpenLP.ServiceManager', 'Corrupt File'),
                     translate('OpenLP.ServiceManager',

=== modified file 'openlp/core/ui/servicenoteform.py'
--- openlp/core/ui/servicenoteform.py	2013-10-13 21:07:28 +0000
+++ openlp/core/ui/servicenoteform.py	2013-12-15 16:51:10 +0000
@@ -31,8 +31,8 @@
 """
 from PyQt4 import QtGui
 
-from openlp.core.common import translate
-from openlp.core.lib import SpellTextEdit, Registry
+from openlp.core.common import Registry, translate
+from openlp.core.lib import SpellTextEdit
 from openlp.core.lib.ui import create_button_box
 
 

=== modified file 'openlp/core/ui/settingsform.py'
--- openlp/core/ui/settingsform.py	2013-08-31 18:17:38 +0000
+++ openlp/core/ui/settingsform.py	2013-12-15 16:51:10 +0000
@@ -33,7 +33,8 @@
 
 from PyQt4 import QtGui
 
-from openlp.core.lib import PluginStatus, Registry, build_icon
+from openlp.core.common import Registry
+from openlp.core.lib import PluginStatus, build_icon
 from openlp.core.ui import AdvancedTab, GeneralTab, ThemesTab
 from openlp.core.ui.media import PlayerTab
 from .settingsdialog import Ui_SettingsDialog

=== modified file 'openlp/core/ui/shortcutlistform.py'
--- openlp/core/ui/shortcutlistform.py	2013-12-09 02:05:52 +0000
+++ openlp/core/ui/shortcutlistform.py	2013-12-15 16:51:10 +0000
@@ -33,8 +33,7 @@
 
 from PyQt4 import QtCore, QtGui
 
-from openlp.core.lib import Registry
-from openlp.core.common import Settings, translate
+from openlp.core.common import Registry, Settings, translate
 from openlp.core.utils.actions import ActionList
 from .shortcutlistdialog import Ui_ShortcutListDialog
 

=== modified file 'openlp/core/ui/slidecontroller.py'
--- openlp/core/ui/slidecontroller.py	2013-10-13 21:07:28 +0000
+++ openlp/core/ui/slidecontroller.py	2013-12-15 16:51:10 +0000
@@ -37,8 +37,8 @@
 
 from PyQt4 import QtCore, QtGui
 
-from openlp.core.common import Settings, SlideLimits, UiStrings, translate
-from openlp.core.lib import OpenLPToolbar, ItemCapabilities, ServiceItem, ImageSource, ServiceItemAction, Registry, \
+from openlp.core.common import Registry, Settings, SlideLimits, UiStrings, translate, RegistryMixin, OpenLPMixin
+from openlp.core.lib import OpenLPToolbar, ItemCapabilities, ServiceItem, ImageSource, ServiceItemAction, \
     ScreenList, build_icon, build_html
 from openlp.core.ui import HideMode, MainDisplay, Display, DisplayControllerType
 from openlp.core.lib.ui import create_action
@@ -48,7 +48,7 @@
 log = logging.getLogger(__name__)
 
 # Threshold which has to be trespassed to toggle.
-HIDE_MENU_THRESHOLD  = 27
+HIDE_MENU_THRESHOLD = 27
 AUDIO_TIME_LABEL_STYLESHEET = 'background-color: palette(background); ' \
     'border-top-color: palette(shadow); ' \
     'border-left-color: palette(shadow); ' \
@@ -57,6 +57,24 @@
     'border-radius: 3px; border-style: inset; ' \
     'border-width: 1; font-family: monospace; margin: 2px;'
 
+NARROW_MENU = [
+    'hide_menu'
+]
+LOOP_LIST = [
+    'play_slides_menu',
+    'loop_separator',
+    'delay_spin_box'
+]
+AUDIO_LIST = [
+    'audioPauseItem',
+    'audio_time_label'
+]
+WIDE_MENU = [
+    'blank_screen_button',
+    'theme_screen_button',
+    'desktop_screen_button'
+]
+
 
 class DisplayController(QtGui.QWidget):
     """
@@ -92,30 +110,12 @@
         Set up the Slide Controller.
         """
         super(SlideController, self).__init__(parent, is_live)
-        Registry().register_function('bootstrap_post_set_up', self.screen_size_changed)
+        Registry().register_function('bootstrap_post_set_up', self.bootstrap_post_set_up)
         self.screens = ScreenList()
         try:
             self.ratio = self.screens.current['size'].width() / self.screens.current['size'].height()
         except ZeroDivisionError:
             self.ratio = 1
-        self.loop_list = [
-            'play_slides_menu',
-            'loop_separator',
-            'delay_spin_box'
-        ]
-        # audioPauseItem is also in Settings so any changes need to be paired
-        self.audio_list = [
-            'audioPauseItem',
-            'audio_time_label'
-        ]
-        self.wide_menu = [
-            'blank_screen_button',
-            'theme_screen_button',
-            'desktop_screen_button'
-        ]
-        self.narrow_menu = [
-            'hide_menu'
-        ]
         self.timer_id = 0
         self.song_edit = False
         self.selected_row = 0
@@ -123,7 +123,7 @@
         self.slide_limits = None
         self.update_slide_limits()
         self.panel = QtGui.QWidget(parent.control_splitter)
-        self.slideList = {}
+        self.slide_list = {}
         self.slide_count = 0
         self.slide_image = None
         # Layout for holding panel
@@ -172,17 +172,19 @@
         size_toolbar_policy.setHeightForWidth(self.toolbar.sizePolicy().hasHeightForWidth())
         self.toolbar.setSizePolicy(size_toolbar_policy)
         self.previous_item = create_action(self, 'previousItem_' + self.type_prefix,
-            text=translate('OpenLP.SlideController', 'Previous Slide'), icon=':/slides/slide_previous.png',
-            tooltip=translate('OpenLP.SlideController', 'Move to previous.'),
-            can_shortcuts=True, context=QtCore.Qt.WidgetWithChildrenShortcut,
-            category=self.category, triggers=self.on_slide_selected_previous)
+                                           text=translate('OpenLP.SlideController', 'Previous Slide'), 
+                                           icon=':/slides/slide_previous.png',
+                                           tooltip=translate('OpenLP.SlideController', 'Move to previous.'),
+                                           can_shortcuts=True, context=QtCore.Qt.WidgetWithChildrenShortcut,
+                                           category=self.category, triggers=self.on_slide_selected_previous)
         self.toolbar.addAction(self.previous_item)
-        self.nextItem = create_action(self, 'nextItem_' + self.type_prefix,
-            text=translate('OpenLP.SlideController', 'Next Slide'), icon=':/slides/slide_next.png',
-            tooltip=translate('OpenLP.SlideController', 'Move to next.'),
-            can_shortcuts=True, context=QtCore.Qt.WidgetWithChildrenShortcut,
-            category=self.category, triggers=self.on_slide_selected_next_action)
-        self.toolbar.addAction(self.nextItem)
+        self.next_item = create_action(self, 'nextItem_' + self.type_prefix,
+                                       text=translate('OpenLP.SlideController', 'Next Slide'), 
+                                       icon=':/slides/slide_next.png',
+                                       tooltip=translate('OpenLP.SlideController', 'Move to next.'),
+                                       can_shortcuts=True, context=QtCore.Qt.WidgetWithChildrenShortcut,
+                                       category=self.category, triggers=self.on_slide_selected_next_action)
+        self.toolbar.addAction(self.next_item)
         self.toolbar.addSeparator()
         self.controller_type = DisplayControllerType.Preview
         if self.is_live:
@@ -195,16 +197,20 @@
             self.hide_menu.setMenu(QtGui.QMenu(translate('OpenLP.SlideController', 'Hide'), self.toolbar))
             self.toolbar.add_toolbar_widget(self.hide_menu)
             self.blank_screen = create_action(self, 'blankScreen',
-                text=translate('OpenLP.SlideController', 'Blank Screen'), icon=':/slides/slide_blank.png',
-                checked=False, can_shortcuts=True, category=self.category, triggers=self.on_blank_display)
+                                              text=translate('OpenLP.SlideController', 'Blank Screen'), 
+                                              icon=':/slides/slide_blank.png',
+                                              checked=False, can_shortcuts=True, category=self.category, 
+                                              triggers=self.on_blank_display)
             self.theme_screen = create_action(self, 'themeScreen',
-                text=translate('OpenLP.SlideController', 'Blank to Theme'), icon=':/slides/slide_theme.png',
-                checked=False, can_shortcuts=True, category=self.category,
-                triggers=self.on_theme_display)
+                                              text=translate('OpenLP.SlideController', 'Blank to Theme'), 
+                                              icon=':/slides/slide_theme.png',
+                                              checked=False, can_shortcuts=True, category=self.category,
+                                              triggers=self.on_theme_display)
             self.desktop_screen = create_action(self, 'desktopScreen',
-                text=translate('OpenLP.SlideController', 'Show Desktop'), icon=':/slides/slide_desktop.png',
-                checked=False, can_shortcuts=True, category=self.category,
-                triggers=self.on_hide_display)
+                                                text=translate('OpenLP.SlideController', 'Show Desktop'), 
+                                                icon=':/slides/slide_desktop.png',
+                                                checked=False, can_shortcuts=True, category=self.category,
+                                                triggers=self.on_hide_display)
             self.hide_menu.setDefaultAction(self.blank_screen)
             self.hide_menu.menu().addAction(self.blank_screen)
             self.hide_menu.menu().addAction(self.theme_screen)
@@ -231,11 +237,11 @@
             self.play_slides_menu.setMenu(QtGui.QMenu(translate('OpenLP.SlideController', 'Play Slides'), self.toolbar))
             self.toolbar.add_toolbar_widget(self.play_slides_menu)
             self.play_slides_loop = create_action(self, 'playSlidesLoop', text=UiStrings().PlaySlidesInLoop,
-                icon=':/media/media_time.png', checked=False, can_shortcuts=True,
-                category=self.category, triggers=self.on_play_slides_loop)
+                                                  icon=':/media/media_time.png', checked=False, can_shortcuts=True,
+                                                  category=self.category, triggers=self.on_play_slides_loop)
             self.play_slides_once = create_action(self, 'playSlidesOnce', text=UiStrings().PlaySlidesToEnd,
-                icon=':/media/media_time.png', checked=False, can_shortcuts=True,
-                category=self.category, triggers=self.on_play_slides_once)
+                                                  icon=':/media/media_time.png', checked=False, can_shortcuts=True,
+                                                  category=self.category, triggers=self.on_play_slides_once)
             if Settings().value(self.main_window.advanced_settings_section + '/slide limits') == SlideLimits.Wrap:
                 self.play_slides_menu.setDefaultAction(self.play_slides_loop)
             else:
@@ -251,12 +257,15 @@
             self.toolbar.add_toolbar_widget(self.delay_spin_box)
         else:
             self.toolbar.add_toolbar_action('goLive', icon=':/general/general_live.png',
-                tooltip=translate('OpenLP.SlideController', 'Move to live.'), triggers=self.on_go_live)
+                                            tooltip=translate('OpenLP.SlideController', 'Move to live.'), 
+                                            triggers=self.on_go_live)
             self.toolbar.add_toolbar_action('addToService', icon=':/general/general_add.png',
-                tooltip=translate('OpenLP.SlideController', 'Add to Service.'), triggers=self.on_preview_add_to_service)
+                                            tooltip=translate('OpenLP.SlideController', 'Add to Service.'), 
+                                            triggers=self.on_preview_add_to_service)
             self.toolbar.addSeparator()
             self.toolbar.add_toolbar_action('editSong', icon=':/general/general_edit.png',
-                tooltip=translate('OpenLP.SlideController', 'Edit and reload song preview.'), triggers=self.on_edit_song)
+                                            tooltip=translate('OpenLP.SlideController', 'Edit and reload song preview.')
+                                            , triggers=self.on_edit_song)
         self.controller_layout.addWidget(self.toolbar)
         # Build the Media Toolbar
         self.media_controller.register_controller(self)
@@ -280,25 +289,28 @@
             self.audio_pause_item.setParent(self.toolbar)
             self.toolbar.widgetForAction(self.audio_pause_item).setPopupMode(
                 QtGui.QToolButton.MenuButtonPopup)
-            self.nextTrackItem = create_action(self, 'nextTrackItem', text=UiStrings().NextTrack,
-                icon=':/slides/media_playback_next.png',
-                tooltip=translate('OpenLP.SlideController', 'Go to next audio track.'),
-                category=self.category, can_shortcuts=True, triggers=self.on_next_track_clicked)
-            self.audio_menu.addAction(self.nextTrackItem)
-            self.trackMenu = self.audio_menu.addMenu(translate('OpenLP.SlideController', 'Tracks'))
+            self.next_track_item = create_action(self, 'nextTrackItem', text=UiStrings().NextTrack,
+                                                 icon=':/slides/media_playback_next.png',
+                                                 tooltip=translate('OpenLP.SlideController',
+                                                                   'Go to next audio track.'),
+                                                 category=self.category,
+                                                 can_shortcuts=True,
+                                                 triggers=self.on_next_track_clicked)
+            self.audio_menu.addAction(self.next_track_item)
+            self.track_menu = self.audio_menu.addMenu(translate('OpenLP.SlideController', 'Tracks'))
             self.audio_time_label = QtGui.QLabel(' 00:00 ', self.toolbar)
             self.audio_time_label.setAlignment(QtCore.Qt.AlignCenter | QtCore.Qt.AlignHCenter)
             self.audio_time_label.setStyleSheet(AUDIO_TIME_LABEL_STYLESHEET)
             self.audio_time_label.setObjectName('audio_time_label')
             self.toolbar.add_toolbar_widget(self.audio_time_label)
-            self.toolbar.set_widget_visible(self.audio_list, False)
+            self.toolbar.set_widget_visible(AUDIO_LIST, False)
             self.toolbar.set_widget_visible(['song_menu'], False)
         # Screen preview area
         self.preview_frame = QtGui.QFrame(self.splitter)
         self.preview_frame.setGeometry(QtCore.QRect(0, 0, 300, 300 * self.ratio))
         self.preview_frame.setMinimumHeight(100)
         self.preview_frame.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.Ignored, QtGui.QSizePolicy.Ignored,
-            QtGui.QSizePolicy.Label))
+                                         QtGui.QSizePolicy.Label))
         self.preview_frame.setFrameShape(QtGui.QFrame.StyledPanel)
         self.preview_frame.setFrameShadow(QtGui.QFrame.Sunken)
         self.preview_frame.setObjectName('preview_frame')
@@ -331,9 +343,9 @@
         self.grid.addLayout(self.slide_layout, 0, 0, 1, 1)
         if self.is_live:
             self.current_shortcut = ''
-            self.shortcutTimer = QtCore.QTimer()
-            self.shortcutTimer.setObjectName('shortcutTimer')
-            self.shortcutTimer.setSingleShot(True)
+            self.shortcut_timer = QtCore.QTimer()
+            self.shortcut_timer.setObjectName('shortcut_timer')
+            self.shortcut_timer.setSingleShot(True)
             shortcuts = [
                 {'key': 'V', 'configurable': True, 'text': translate('OpenLP.SlideController', 'Go to "Verse"')},
                 {'key': 'C', 'configurable': True, 'text': translate('OpenLP.SlideController', 'Go to "Chorus"')},
@@ -345,51 +357,55 @@
                 {'key': 'O', 'configurable': True, 'text': translate('OpenLP.SlideController', 'Go to "Other"')}
             ]
             shortcuts.extend([{'key': str(number)} for number in range(10)])
-            self.controller.addActions([create_action(self,
-                'shortcutAction_%s' % s['key'], text=s.get('text'),
-                can_shortcuts=True,
-                context=QtCore.Qt.WidgetWithChildrenShortcut,
-                category=self.category if s.get('configurable') else None,
-                triggers=self._slide_shortcut_activated) for s in shortcuts])
-            self.shortcutTimer.timeout.connect(self._slide_shortcut_activated)
+            self.controller.addActions([create_action(self, 'shortcutAction_%s' % s['key'], 
+                                                      text=s.get('text'),
+                                                      can_shortcuts=True,
+                                                      context=QtCore.Qt.WidgetWithChildrenShortcut,
+                                                      category=self.category if s.get('configurable') else None,
+                                                      triggers=self._slide_shortcut_activated) for s in shortcuts])
+            self.shortcut_timer.timeout.connect(self._slide_shortcut_activated)
         # Signals
         self.preview_widget.clicked.connect(self.on_slide_selected)
         if self.is_live:
             # Need to use event as called across threads and UI is updated
             QtCore.QObject.connect(self, QtCore.SIGNAL('slidecontroller_toggle_display'), self.toggle_display)
             Registry().register_function('slidecontroller_live_spin_delay', self.receive_spin_delay)
-            self.toolbar.set_widget_visible(self.loop_list, False)
-            self.toolbar.set_widget_visible(self.wide_menu, False)
+            self.toolbar.set_widget_visible(LOOP_LIST, False)
+            self.toolbar.set_widget_visible(WIDE_MENU, False)
         else:
             self.preview_widget.doubleClicked.connect(self.on_preview_add_to_service)
             self.toolbar.set_widget_visible(['editSong'], False)
         if self.is_live:
-            self.set_live_hotkeys(self)
+            self.set_live_hot_keys(self)
             self.__add_actions_to_widget(self.controller)
         else:
-            self.controller.addActions([self.nextItem, self.previous_item])
+            self.controller.addActions([self.next_item, self.previous_item])
         Registry().register_function('slidecontroller_%s_stop_loop' % self.type_prefix, self.on_stop_loop)
         Registry().register_function('slidecontroller_%s_change' % self.type_prefix, self.on_slide_change)
         Registry().register_function('slidecontroller_%s_blank' % self.type_prefix, self.on_slide_blank)
         Registry().register_function('slidecontroller_%s_unblank' % self.type_prefix, self.on_slide_unblank)
         Registry().register_function('slidecontroller_update_slide_limits', self.update_slide_limits)
         QtCore.QObject.connect(self, QtCore.SIGNAL('slidecontroller_%s_set' % self.type_prefix),
-            self.on_slide_selected_index)
+                               self.on_slide_selected_index)
         QtCore.QObject.connect(self, QtCore.SIGNAL('slidecontroller_%s_next' % self.type_prefix),
-            self.on_slide_selected_next)
+                               self.on_slide_selected_next)
         QtCore.QObject.connect(self, QtCore.SIGNAL('slidecontroller_%s_previous' % self.type_prefix),
-            self.on_slide_selected_previous)
+                               self.on_slide_selected_previous)
+
+    def bootstrap_post_set_up(self):
+        """
+        Call by bootstrap functions
+        """
+        self.screen_size_changed()
 
     def _slide_shortcut_activated(self):
         """
-        Called, when a shortcut has been activated to jump to a chorus, verse,
-        etc.
+        Called, when a shortcut has been activated to jump to a chorus, verse, etc.
 
-        **Note**: This implementation is based on shortcuts. But it rather works
-        like "key sequenes". You have to press one key after the other and
-        **not** at the same time.
-        For example to jump to "V3" you have to press "V" and afterwards but
-        within a time frame of 350ms you have to press "3".
+        **Note**: This implementation is based on shortcuts. But it rather works like "key sequenes". You have to 
+        press one key after the other and **not** at the same time.
+        For example to jump to "V3" you have to press "V" and afterwards but within a time frame of 350ms 
+        you have to press "3".
         """
         try:
             from openlp.plugins.songs.lib import VerseType
@@ -420,43 +436,45 @@
             self.current_shortcut += verse_type
         elif verse_type:
             self.current_shortcut = verse_type
-        keys = list(self.slideList.keys())
-        matches = [match for match in keys
-            if match.startswith(self.current_shortcut)]
+        keys = list(self.slide_list.keys())
+        matches = [match for match in keys if match.startswith(self.current_shortcut)]
         if len(matches) == 1:
-            self.shortcutTimer.stop()
+            self.shortcut_timer.stop()
             self.current_shortcut = ''
-            self.preview_widget.change_slide(self.slideList[matches[0]])
+            self.preview_widget.change_slide(self.slide_list[matches[0]])
             self.slide_selected()
-        elif sender_name != 'shortcutTimer':
+        elif sender_name != 'shortcut_timer':
             # Start the time as we did not have any match.
-            self.shortcutTimer.start(350)
+            self.shortcut_timer.start(350)
         else:
             # The timer timed out.
             if self.current_shortcut in keys:
                 # We had more than one match for example "V1" and "V10", but
                 # "V1" was the slide we wanted to go.
-                self.preview_widget.change_slide(self.slideList[self.current_shortcut])
+                self.preview_widget.change_slide(self.slide_list[self.current_shortcut])
                 self.slide_selected()
            # Reset the shortcut.
             self.current_shortcut = ''
 
-    def set_live_hotkeys(self, parent=None):
+    def set_live_hot_keys(self, parent=None):
         """
         Set the live hotkeys
         """
-        self.previousService = create_action(parent, 'previousService',
-            text=translate('OpenLP.SlideController', 'Previous Service'),
-            can_shortcuts=True, context=QtCore.Qt.WidgetWithChildrenShortcut, category=self.category,
-            triggers=self.service_previous)
-        self.nextService = create_action(parent, 'nextService',
-            text=translate('OpenLP.SlideController', 'Next Service'),
-            can_shortcuts=True, context=QtCore.Qt.WidgetWithChildrenShortcut, category=self.category,
-            triggers=self.service_next)
-        self.escapeItem = create_action(parent, 'escapeItem',
-            text=translate('OpenLP.SlideController', 'Escape Item'),
-            can_shortcuts=True, context=QtCore.Qt.WidgetWithChildrenShortcut, category=self.category,
-            triggers=self.live_escape)
+        self.previous_service = create_action(parent, 'previousService',
+                                              text=translate('OpenLP.SlideController', 'Previous Service'),
+                                              can_shortcuts=True, context=QtCore.Qt.WidgetWithChildrenShortcut, 
+                                              category=self.category,
+                                              triggers=self.service_previous)
+        self.next_service = create_action(parent, 'nextService',
+                                          text=translate('OpenLP.SlideController', 'Next Service'),
+                                          can_shortcuts=True, context=QtCore.Qt.WidgetWithChildrenShortcut, 
+                                          category=self.category,
+                                          triggers=self.service_next)
+        self.escape_item = create_action(parent, 'escapeItem',
+                                         text=translate('OpenLP.SlideController', 'Escape Item'),
+                                         can_shortcuts=True, context=QtCore.Qt.WidgetWithChildrenShortcut, 
+                                         category=self.category,
+                                         triggers=self.live_escape)
 
     def live_escape(self):
         """
@@ -502,10 +520,10 @@
         if self.keypress_queue:
             while len(self.keypress_queue) and not self.keypress_loop:
                 self.keypress_loop = True
-                keypressCommand = self.keypress_queue.popleft()
-                if keypressCommand == ServiceItemAction.Previous:
+                keypress_command = self.keypress_queue.popleft()
+                if keypress_command == ServiceItemAction.Previous:
                     self.service_manager.previous_item()
-                elif keypressCommand == ServiceItemAction.PreviousLastSlide:
+                elif keypress_command == ServiceItemAction.PreviousLastSlide:
                     # Go to the last slide of the previous item
                     self.service_manager.previous_item(last_slide=True)
                 else:
@@ -535,7 +553,7 @@
         self.preview_display.setup()
         service_item = ServiceItem()
         self.preview_display.web_view.setHtml(build_html(service_item, self.preview_display.screen, None, self.is_live,
-            plugins=self.plugin_manager.plugins))
+                                              plugins=self.plugin_manager.plugins))
         self.media_controller.setup_display(self.preview_display, True)
         if self.service_item:
             self.refresh_service_item()
@@ -545,9 +563,9 @@
         Add actions to the widget specified by `widget`
         """
         widget.addActions([
-            self.previous_item, self.nextItem,
-            self.previousService, self.nextService,
-            self.escapeItem])
+            self.previous_item, self.next_item,
+            self.previous_service, self.next_service,
+            self.escape_item])
 
     def preview_size_changed(self):
         """
@@ -579,19 +597,19 @@
             used_space = self.toolbar.size().width() + self.hide_menu.size().width()
             # Add the threshold to prevent flickering.
             if width > used_space + HIDE_MENU_THRESHOLD and self.hide_menu.isVisible():
-                self.toolbar.set_widget_visible(self.narrow_menu, False)
-                self.toolbar.set_widget_visible(self.wide_menu)
+                self.toolbar.set_widget_visible(NARROW_MENU, False)
+                self.toolbar.set_widget_visible(WIDE_MENU)
             # Take away a threshold to prevent flickering.
             elif width < used_space - HIDE_MENU_THRESHOLD and not self.hide_menu.isVisible():
-                self.toolbar.set_widget_visible(self.wide_menu, False)
-                self.toolbar.set_widget_visible(self.narrow_menu)
+                self.toolbar.set_widget_visible(WIDE_MENU, False)
+                self.toolbar.set_widget_visible(NARROW_MENU)
 
     def on_song_bar_handler(self):
         """
         Some song handler
         """
         request = self.sender().text()
-        slide_no = self.slideList[request]
+        slide_no = self.slide_list[request]
         width = self.main_window.control_splitter.sizes()[self.split]
         self.preview_widget.replace_service_item(self.service_item, width, slide_no)
         self.slide_selected()
@@ -626,7 +644,7 @@
         self.toolbar.hide()
         self.mediabar.hide()
         self.song_menu.hide()
-        self.toolbar.set_widget_visible(self.loop_list, False)
+        self.toolbar.set_widget_visible(LOOP_LIST, False)
         self.toolbar.set_widget_visible(['song_menu'], False)
         # Reset the button
         self.play_slides_once.setChecked(False)
@@ -634,14 +652,14 @@
         self.play_slides_loop.setChecked(False)
         self.play_slides_loop.setIcon(build_icon(':/media/media_time.png'))
         if item.is_text():
-            if Settings().value(self.main_window.songs_settings_section + '/display songbar') and self.slideList:
+            if Settings().value(self.main_window.songs_settings_section + '/display songbar') and self.slide_list:
                 self.toolbar.set_widget_visible(['song_menu'], True)
         if item.is_capable(ItemCapabilities.CanLoop) and len(item.get_frames()) > 1:
-            self.toolbar.set_widget_visible(self.loop_list)
+            self.toolbar.set_widget_visible(LOOP_LIST)
         if item.is_media():
             self.mediabar.show()
         self.previous_item.setVisible(not item.is_media())
-        self.nextItem.setVisible(not item.is_media())
+        self.next_item.setVisible(not item.is_media())
         # Work-around for OS X, hide and then show the toolbar
         # See bug #791050
         self.toolbar.show()
@@ -660,7 +678,7 @@
         elif item.is_media():
             self.mediabar.show()
         self.previous_item.setVisible(not item.is_media())
-        self.nextItem.setVisible(not item.is_media())
+        self.next_item.setVisible(not item.is_media())
         # Work-around for OS X, hide and then show the toolbar
         # See bug #791050
         self.toolbar.show()
@@ -703,15 +721,15 @@
         log.debug('add_service_manager_item live = %s' % self.is_live)
         # If no valid slide number is specified we take the first one, but we remember the initial value to see if we
         # should reload the song or not
-        slidenum = slide_no
+        slide_num = slide_no
         if slide_no == -1:
-            slidenum = 0
+            slide_num = 0
         # If service item is the same as the current one, only change slide
         if slide_no >= 0 and item == self.service_item:
-            self.preview_widget.change_slide(slidenum)
+            self.preview_widget.change_slide(slide_num)
             self.slide_selected()
         else:
-            self._process_item(item, slidenum)
+            self._process_item(item, slide_num)
             if self.is_live and item.auto_play_slides_loop and item.timed_slide_interval > 0:
                 self.play_slides_loop.setChecked(item.auto_play_slides_loop)
                 self.delay_spin_box.setValue(int(item.timed_slide_interval))
@@ -721,7 +739,7 @@
                 self.delay_spin_box.setValue(int(item.timed_slide_interval))
                 self.on_play_slides_once()
 
-    def _process_item(self, service_item, slideno):
+    def _process_item(self, service_item, slide_no):
         """
         Loads a ServiceItem into the system from ServiceManager. Display the slide number passed.
         """
@@ -733,8 +751,8 @@
         if old_item and self.is_live and old_item.is_capable(ItemCapabilities.ProvidesOwnDisplay):
             self._reset_blank()
         Registry().execute(
-            '%s_start' % service_item.name.lower(), [service_item, self.is_live, self.hide_mode(), slideno])
-        self.slideList = {}
+            '%s_start' % service_item.name.lower(), [service_item, self.is_live, self.hide_mode(), slide_no])
+        self.slide_list = {}
         if self.is_live:
             self.song_menu.menu().clear()
             self.display.audio_player.reset()
@@ -744,13 +762,13 @@
             if self.service_item.is_capable(ItemCapabilities.HasBackgroundAudio):
                 log.debug('Starting to play...')
                 self.display.audio_player.add_to_playlist(self.service_item.background_audio)
-                self.trackMenu.clear()
+                self.track_menu.clear()
                 for counter in range(len(self.service_item.background_audio)):
-                    action = self.trackMenu.addAction(os.path.basename(self.service_item.background_audio[counter]))
+                    action = self.track_menu.addAction(os.path.basename(self.service_item.background_audio[counter]))
                     action.setData(counter)
                     action.triggered.connect(self.on_track_triggered)
-                self.display.audio_player.repeat = Settings().value(
-                    self.main_window.general_settings_section + '/audio repeat list')
+                self.display.audio_player.repeat = \
+                    Settings().value(self.main_window.general_settings_section + '/audio repeat list')
                 if Settings().value(self.main_window.general_settings_section + '/audio start paused'):
                     self.audio_pause_item.setChecked(True)
                     self.display.audio_player.pause()
@@ -767,21 +785,21 @@
                     verse_def = '%s%s' % (verse_def[0], verse_def[1:])
                     two_line_def = '%s\n%s' % (verse_def[0], verse_def[1:])
                     row = two_line_def
-                    if verse_def not in self.slideList:
-                        self.slideList[verse_def] = framenumber
+                    if verse_def not in self.slide_list:
+                        self.slide_list[verse_def] = framenumber
                         if self.is_live:
                             self.song_menu.menu().addAction(verse_def, self.on_song_bar_handler)
                 else:
                     row += 1
-                    self.slideList[str(row)] = row - 1
+                    self.slide_list[str(row)] = row - 1
             else:
                 row += 1
-                self.slideList[str(row)] = row - 1
+                self.slide_list[str(row)] = row - 1
                 # If current slide set background to image
-                if not self.service_item.is_command() and framenumber == slideno:
-                    self.service_item.bg_image_bytes = self.image_manager.get_image_bytes(frame['path'],
-                        ImageSource.ImagePlugin)
-        self.preview_widget.replace_service_item(self.service_item, width, slideno)
+                if not self.service_item.is_command() and framenumber == slide_no:
+                    self.service_item.bg_image_bytes = \
+                        self.image_manager.get_image_bytes(frame['path'], ImageSource.ImagePlugin)
+        self.preview_widget.replace_service_item(self.service_item, width, slide_no)
         self.enable_tool_bar(service_item)
         # Pass to display for viewing.
         # Postpone image build, we need to do this later to avoid the theme
@@ -915,8 +933,8 @@
             if hide_mode:
                 if not self.service_item.is_command():
                     Registry().execute('live_display_hide', hide_mode)
-                Registry().execute('%s_blank' % self.service_item.name.lower(),
-                    [self.service_item, self.is_live, hide_mode])
+                Registry().execute('%s_blank' %
+                                   self.service_item.name.lower(), [self.service_item, self.is_live, hide_mode])
             else:
                 if not self.service_item.is_command():
                     Registry().execute('live_display_show')
@@ -962,8 +980,8 @@
         if -1 < row < self.preview_widget.slide_count():
             if self.service_item.is_command():
                 if self.is_live and not start:
-                    Registry().execute('%s_slide' % self.service_item.name.lower(),
-                        [self.service_item, self.is_live, row])
+                    Registry().execute('%s_slide' %
+                                       self.service_item.name.lower(), [self.service_item, self.is_live, row])
             else:
                 to_display = self.service_item.get_rendered_frame(row)
                 if self.service_item.is_text():
@@ -1142,7 +1160,7 @@
         """
         Set the visibility of the audio stuff
         """
-        self.toolbar.set_widget_visible(self.audio_list, visible)
+        self.toolbar.set_widget_visible(AUDIO_LIST, visible)
 
     def set_audio_pause_clicked(self, checked):
         """
@@ -1332,4 +1350,3 @@
         return self._main_window
 
     main_window = property(_get_main_window)
-

=== modified file 'openlp/core/ui/starttimeform.py'
--- openlp/core/ui/starttimeform.py	2013-10-13 20:36:42 +0000
+++ openlp/core/ui/starttimeform.py	2013-12-15 16:51:10 +0000
@@ -33,8 +33,7 @@
 
 from .starttimedialog import Ui_StartTimeDialog
 
-from openlp.core.common import UiStrings, translate
-from openlp.core.lib import Registry
+from openlp.core.common import Registry, UiStrings, translate
 from openlp.core.lib.ui import critical_error_message_box
 
 

=== modified file 'openlp/core/ui/themeform.py'
--- openlp/core/ui/themeform.py	2013-10-13 20:36:42 +0000
+++ openlp/core/ui/themeform.py	2013-12-15 16:51:10 +0000
@@ -34,8 +34,7 @@
 
 from PyQt4 import QtCore, QtGui
 
-from openlp.core.common import UiStrings, translate
-from openlp.core.lib import Registry
+from openlp.core.common import Registry, UiStrings, translate
 from openlp.core.lib.theme import BackgroundType, BackgroundGradientType
 from openlp.core.lib.ui import critical_error_message_box
 from openlp.core.ui import ThemeLayoutForm

=== modified file 'openlp/core/ui/thememanager.py'
--- openlp/core/ui/thememanager.py	2013-12-06 19:00:55 +0000
+++ openlp/core/ui/thememanager.py	2013-12-15 16:51:10 +0000
@@ -37,8 +37,8 @@
 from xml.etree.ElementTree import ElementTree, XML
 from PyQt4 import QtCore, QtGui
 
-from openlp.core.common import AppLocation, Settings, check_directory_exists, UiStrings, translate
-from openlp.core.lib import FileDialog, ImageSource, OpenLPToolbar, Registry, get_text_file_string, build_icon, \
+from openlp.core.common import Registry, AppLocation, Settings, check_directory_exists, UiStrings, translate
+from openlp.core.lib import FileDialog, ImageSource, OpenLPToolbar, get_text_file_string, build_icon, \
     check_item_selected, create_thumb, validate_thumb
 from openlp.core.lib.theme import ThemeXML, BackgroundType
 from openlp.core.lib.ui import critical_error_message_box, create_widget_action
@@ -490,7 +490,7 @@
             theme_zip = zipfile.ZipFile(file_name)
             xml_file = [name for name in theme_zip.namelist() if os.path.splitext(name)[1].lower() == '.xml']
             if len(xml_file) != 1:
-                log.exception('Theme contains "%s" XML files' % len(xml_file))
+                log.error('Theme contains "%s" XML files' % len(xml_file))
                 raise Exception('validation')
             xml_tree = ElementTree(element=XML(theme_zip.read(xml_file[0]))).getroot()
             theme_name = xml_tree.find('name').text.strip()
@@ -543,7 +543,7 @@
                     critical_error_message_box(
                         translate('OpenLP.ThemeManager', 'Validation Error'),
                         translate('OpenLP.ThemeManager', 'File is not a valid theme.'))
-                    log.exception('Theme file does not contain XML data %s' % file_name)
+                    log.error('Theme file does not contain XML data %s' % file_name)
 
     def check_if_theme_exists(self, theme_name):
         """

=== modified file 'openlp/core/ui/themestab.py'
--- openlp/core/ui/themestab.py	2013-10-13 20:36:42 +0000
+++ openlp/core/ui/themestab.py	2013-12-15 16:51:10 +0000
@@ -33,8 +33,8 @@
 
 from PyQt4 import QtCore, QtGui
 
-from openlp.core.common import Settings, ThemeLevel, UiStrings, translate
-from openlp.core.lib import Registry, SettingsTab
+from openlp.core.common import Registry, Settings, ThemeLevel, UiStrings, translate
+from openlp.core.lib import SettingsTab
 from openlp.core.lib.ui import find_and_set_in_combo_box
 
 

=== modified file 'openlp/core/ui/wizard.py'
--- openlp/core/ui/wizard.py	2013-10-13 20:36:42 +0000
+++ openlp/core/ui/wizard.py	2013-12-15 16:51:10 +0000
@@ -34,8 +34,8 @@
 
 from PyQt4 import QtGui
 
-from openlp.core.common import Settings, UiStrings, translate
-from openlp.core.lib import Registry, build_icon
+from openlp.core.common import Registry, Settings, UiStrings, translate
+from openlp.core.lib import build_icon
 from openlp.core.lib.ui import add_welcome_page
 
 log = logging.getLogger(__name__)

=== modified file 'openlp/core/utils/__init__.py'
--- openlp/core/utils/__init__.py	2013-10-13 21:07:28 +0000
+++ openlp/core/utils/__init__.py	2013-12-15 16:51:10 +0000
@@ -43,8 +43,7 @@
 
 from PyQt4 import QtGui, QtCore
 
-from openlp.core.common import AppLocation, Settings
-from openlp.core.lib import Registry
+from openlp.core.common import Registry, AppLocation, Settings
 
 
 if sys.platform != 'win32' and sys.platform != 'darwin':

=== modified file 'openlp/plugins/alerts/lib/alertsmanager.py'
--- openlp/plugins/alerts/lib/alertsmanager.py	2013-10-13 21:07:28 +0000
+++ openlp/plugins/alerts/lib/alertsmanager.py	2013-12-15 16:51:10 +0000
@@ -35,8 +35,7 @@
 
 from PyQt4 import QtCore
 
-from openlp.core.common import translate
-from openlp.core.lib import Registry
+from openlp.core.common import Registry, translate
 
 
 log = logging.getLogger(__name__)

=== modified file 'openlp/plugins/bibles/forms/bibleupgradeform.py'
--- openlp/plugins/bibles/forms/bibleupgradeform.py	2013-10-13 20:36:42 +0000
+++ openlp/plugins/bibles/forms/bibleupgradeform.py	2013-12-15 16:51:10 +0000
@@ -36,8 +36,7 @@
 
 from PyQt4 import QtCore, QtGui
 
-from openlp.core.common import AppLocation, UiStrings, Settings, check_directory_exists, translate
-from openlp.core.lib import Registry
+from openlp.core.common import Registry, AppLocation, UiStrings, Settings, check_directory_exists, translate
 from openlp.core.lib.ui import critical_error_message_box
 from openlp.core.ui.wizard import OpenLPWizard, WizardStrings
 from openlp.core.utils import delete_file

=== modified file 'openlp/plugins/bibles/forms/editbibleform.py'
--- openlp/plugins/bibles/forms/editbibleform.py	2013-10-13 20:36:42 +0000
+++ openlp/plugins/bibles/forms/editbibleform.py	2013-12-15 16:51:10 +0000
@@ -33,8 +33,7 @@
 
 from PyQt4 import QtGui
 
-from openlp.core.common import UiStrings, translate
-from openlp.core.lib import Registry
+from openlp.core.common import Registry, UiStrings, translate
 from openlp.core.lib.ui import critical_error_message_box
 from .editbibledialog import Ui_EditBibleDialog
 from openlp.plugins.bibles.lib import BibleStrings

=== modified file 'openlp/plugins/bibles/lib/biblestab.py'
--- openlp/plugins/bibles/lib/biblestab.py	2013-10-13 20:36:42 +0000
+++ openlp/plugins/bibles/lib/biblestab.py	2013-12-15 16:51:10 +0000
@@ -31,8 +31,8 @@
 
 from PyQt4 import QtCore, QtGui
 
-from openlp.core.common import Settings, UiStrings, translate
-from openlp.core.lib import Registry, SettingsTab
+from openlp.core.common import Registry, Settings, UiStrings, translate
+from openlp.core.lib import SettingsTab
 from openlp.core.lib.ui import find_and_set_in_combo_box
 from openlp.plugins.bibles.lib import LayoutStyle, DisplayStyle, update_reference_separators, \
     get_reference_separator, LanguageSelection

=== modified file 'openlp/plugins/bibles/lib/csvbible.py'
--- openlp/plugins/bibles/lib/csvbible.py	2013-10-13 21:07:28 +0000
+++ openlp/plugins/bibles/lib/csvbible.py	2013-12-15 16:51:10 +0000
@@ -93,7 +93,7 @@
         success = True
         language_id = self.get_language(bible_name)
         if not language_id:
-            log.exception('Importing books from "%s" failed' % self.filename)
+            log.error('Importing books from "%s" failed' % self.filename)
             return False
         books_file = None
         book_list = {}
@@ -112,7 +112,7 @@
                     str(line[2], details['encoding']))
                 book_ref_id = self.get_book_ref_id_by_name(str(line[2], details['encoding']), 67, language_id)
                 if not book_ref_id:
-                    log.exception('Importing books from "%s" failed' % self.booksfile)
+                    log.error('Importing books from "%s" failed' % self.booksfile)
                     return False
                 book_details = BiblesResourcesDB.get_book_by_id(book_ref_id)
                 self.create_book(str(line[2], details['encoding']), book_ref_id, book_details['testament_id'])

=== modified file 'openlp/plugins/bibles/lib/db.py'
--- openlp/plugins/bibles/lib/db.py	2013-10-13 21:07:28 +0000
+++ openlp/plugins/bibles/lib/db.py	2013-12-15 16:51:10 +0000
@@ -38,8 +38,7 @@
 from sqlalchemy.orm import class_mapper, mapper, relation
 from sqlalchemy.orm.exc import UnmappedClassError
 
-from openlp.core.common import AppLocation, translate
-from openlp.core.lib import Registry
+from openlp.core.common import Registry, AppLocation, translate
 from openlp.core.lib.db import BaseModel, init_db, Manager
 from openlp.core.lib.ui import critical_error_message_box
 from openlp.core.utils import clean_filename

=== modified file 'openlp/plugins/bibles/lib/http.py'
--- openlp/plugins/bibles/lib/http.py	2013-11-16 21:24:18 +0000
+++ openlp/plugins/bibles/lib/http.py	2013-12-15 16:51:10 +0000
@@ -38,8 +38,7 @@
 
 from bs4 import BeautifulSoup, NavigableString, Tag
 
-from openlp.core.common import translate
-from openlp.core.lib import Registry
+from openlp.core.common import Registry, translate
 from openlp.core.lib.ui import critical_error_message_box
 from openlp.core.utils import get_web_page
 from openlp.plugins.bibles.lib import SearchResults
@@ -553,7 +552,7 @@
             handler = BSExtract(self.proxy_server)
         books = handler.get_books_from_http(self.download_name)
         if not books:
-            log.exception('Importing books from %s - download name: "%s" '\
+            log.error('Importing books from %s - download name: "%s" '\
                 'failed' % (self.download_source, self.download_name))
             return False
         self.wizard.progress_bar.setMaximum(len(books) + 2)
@@ -565,7 +564,7 @@
         else:
             language_id = self.get_language(bible_name)
         if not language_id:
-            log.exception('Importing books from %s failed' % self.filename)
+            log.error('Importing books from %s failed' % self.filename)
             return False
         for book in books:
             if self.stop_import_flag:
@@ -574,7 +573,7 @@
                 'BiblesPlugin.HTTPBible', 'Importing %s...', 'Importing <book name>...') % book)
             book_ref_id = self.get_book_ref_id_by_name(book, len(books), language_id)
             if not book_ref_id:
-                log.exception('Importing books from %s - download name: "%s" '\
+                log.error('Importing books from %s - download name: "%s" '\
                     'failed' % (self.download_source, self.download_name))
                 return False
             book_details = BiblesResourcesDB.get_book_by_id(book_ref_id)

=== modified file 'openlp/plugins/bibles/lib/manager.py'
--- openlp/plugins/bibles/lib/manager.py	2013-10-13 21:07:28 +0000
+++ openlp/plugins/bibles/lib/manager.py	2013-12-15 16:51:10 +0000
@@ -30,8 +30,7 @@
 import logging
 import os
 
-from openlp.core.common import AppLocation, Settings, translate
-from openlp.core.lib import Registry
+from openlp.core.common import Registry, AppLocation, Settings, translate
 from openlp.core.utils import delete_file
 from openlp.plugins.bibles.lib import parse_reference, get_reference_separator, LanguageSelection
 from openlp.plugins.bibles.lib.db import BibleDB, BibleMeta

=== modified file 'openlp/plugins/bibles/lib/mediaitem.py'
--- openlp/plugins/bibles/lib/mediaitem.py	2013-10-13 21:07:28 +0000
+++ openlp/plugins/bibles/lib/mediaitem.py	2013-12-15 16:51:10 +0000
@@ -31,8 +31,8 @@
 
 from PyQt4 import QtCore, QtGui
 
-from openlp.core.common import Settings, UiStrings, translate
-from openlp.core.lib import Registry, MediaManagerItem, ItemCapabilities, ServiceItemContext, create_separated_list
+from openlp.core.common import Registry, Settings, UiStrings, translate
+from openlp.core.lib import MediaManagerItem, ItemCapabilities, ServiceItemContext, create_separated_list
 from openlp.core.lib.searchedit import SearchEdit
 from openlp.core.lib.ui import set_case_insensitive_completer, create_horizontal_adjusting_combo_box, \
     critical_error_message_box, find_and_set_in_combo_box, build_icon

=== modified file 'openlp/plugins/bibles/lib/opensong.py'
--- openlp/plugins/bibles/lib/opensong.py	2013-10-13 21:07:28 +0000
+++ openlp/plugins/bibles/lib/opensong.py	2013-12-15 16:51:10 +0000
@@ -84,14 +84,14 @@
             bible = opensong.getroot()
             language_id = self.get_language(bible_name)
             if not language_id:
-                log.exception('Importing books from "%s" failed' % self.filename)
+                log.error('Importing books from "%s" failed' % self.filename)
                 return False
             for book in bible.b:
                 if self.stop_import_flag:
                     break
                 book_ref_id = self.get_book_ref_id_by_name(str(book.attrib['n']), len(bible.b), language_id)
                 if not book_ref_id:
-                    log.exception('Importing books from "%s" failed' % self.filename)
+                    log.error('Importing books from "%s" failed' % self.filename)
                     return False
                 book_details = BiblesResourcesDB.get_book_by_id(book_ref_id)
                 db_book = self.create_book(str(book.attrib['n']), book_ref_id, book_details['testament_id'])

=== modified file 'openlp/plugins/bibles/lib/osis.py'
--- openlp/plugins/bibles/lib/osis.py	2013-10-13 21:07:28 +0000
+++ openlp/plugins/bibles/lib/osis.py	2013-12-15 16:51:10 +0000
@@ -131,7 +131,7 @@
                     if not language_id:
                         language_id = self.get_language(bible_name)
                         if not language_id:
-                            log.exception('Importing books from "%s" failed' % self.filename)
+                            log.error('Importing books from "%s" failed' % self.filename)
                             return False
                     match_count += 1
                     book = str(match.group(1))
@@ -140,7 +140,7 @@
                     verse_text = match.group(4)
                     book_ref_id = self.get_book_ref_id_by_name(book, book_count, language_id)
                     if not book_ref_id:
-                        log.exception('Importing books from "%s" failed' % self.filename)
+                        log.error('Importing books from "%s" failed' % self.filename)
                         return False
                     book_details = BiblesResourcesDB.get_book_by_id(book_ref_id)
                     if not db_book or db_book.name != book_details['name']:

=== modified file 'openlp/plugins/custom/forms/editcustomform.py'
--- openlp/plugins/custom/forms/editcustomform.py	2013-08-31 18:17:38 +0000
+++ openlp/plugins/custom/forms/editcustomform.py	2013-12-15 16:51:10 +0000
@@ -31,7 +31,7 @@
 
 from PyQt4 import QtGui
 
-from openlp.core.lib import Registry, translate
+from openlp.core.common import Registry, translate
 from openlp.core.lib.ui import critical_error_message_box, find_and_set_in_combo_box
 from openlp.plugins.custom.lib import CustomXMLBuilder, CustomXMLParser
 from openlp.plugins.custom.lib.db import CustomSlide

=== modified file 'openlp/plugins/custom/lib/mediaitem.py'
--- openlp/plugins/custom/lib/mediaitem.py	2013-10-13 20:36:42 +0000
+++ openlp/plugins/custom/lib/mediaitem.py	2013-12-15 16:51:10 +0000
@@ -32,8 +32,8 @@
 from PyQt4 import QtCore, QtGui
 from sqlalchemy.sql import or_, func, and_
 
-from openlp.core.common import Settings, UiStrings, translate
-from openlp.core.lib import Registry, MediaManagerItem, ItemCapabilities, ServiceItemContext, PluginStatus,\
+from openlp.core.common import Registry, Settings, UiStrings, translate
+from openlp.core.lib import MediaManagerItem, ItemCapabilities, ServiceItemContext, PluginStatus,\
    check_item_selected
 from openlp.plugins.custom.forms.editcustomform import EditCustomForm
 from openlp.plugins.custom.lib import CustomXMLParser, CustomXMLBuilder

=== modified file 'openlp/plugins/images/imageplugin.py'
--- openlp/plugins/images/imageplugin.py	2013-10-13 21:07:28 +0000
+++ openlp/plugins/images/imageplugin.py	2013-12-15 16:51:10 +0000
@@ -31,8 +31,8 @@
 
 import logging
 
-from openlp.core.common import Settings, translate
-from openlp.core.lib import Plugin, StringContent, Registry, ImageSource, build_icon
+from openlp.core.common import Registry, Settings, translate
+from openlp.core.lib import Plugin, StringContent, ImageSource, build_icon
 from openlp.core.lib.db import Manager
 from openlp.plugins.images.lib import ImageMediaItem, ImageTab
 from openlp.plugins.images.lib.db import init_schema

=== modified file 'openlp/plugins/images/lib/mediaitem.py'
--- openlp/plugins/images/lib/mediaitem.py	2013-10-13 21:07:28 +0000
+++ openlp/plugins/images/lib/mediaitem.py	2013-12-15 16:51:10 +0000
@@ -32,9 +32,9 @@
 
 from PyQt4 import QtCore, QtGui
 
-from openlp.core.common import AppLocation, Settings, UiStrings, check_directory_exists, translate
-from openlp.core.lib import ItemCapabilities, MediaManagerItem, Registry, ServiceItemContext, \
-    StringContent, TreeWidgetWithDnD, build_icon, check_item_selected, create_thumb, validate_thumb
+from openlp.core.common import Registry, AppLocation, Settings, UiStrings, check_directory_exists, translate
+from openlp.core.lib import ItemCapabilities, MediaManagerItem, ServiceItemContext, StringContent, TreeWidgetWithDnD,\
+    build_icon, check_item_selected, create_thumb, validate_thumb
 from openlp.core.lib.ui import create_widget_action, critical_error_message_box
 from openlp.core.utils import delete_file, get_locale_key, get_images_filter
 from openlp.plugins.images.forms import AddGroupForm, ChooseGroupForm

=== modified file 'openlp/plugins/media/lib/mediaitem.py'
--- openlp/plugins/media/lib/mediaitem.py	2013-10-13 20:36:42 +0000
+++ openlp/plugins/media/lib/mediaitem.py	2013-12-15 16:51:10 +0000
@@ -32,8 +32,8 @@
 
 from PyQt4 import QtCore, QtGui
 
-from openlp.core.common import AppLocation, Settings, check_directory_exists, UiStrings, translate
-from openlp.core.lib import ItemCapabilities, MediaManagerItem,MediaType, Registry, ServiceItem, ServiceItemContext, \
+from openlp.core.common import Registry, AppLocation, Settings, check_directory_exists, UiStrings, translate
+from openlp.core.lib import ItemCapabilities, MediaManagerItem,MediaType, ServiceItem, ServiceItemContext, \
     build_icon, check_item_selected
 from openlp.core.lib.ui import critical_error_message_box, create_horizontal_adjusting_combo_box
 from openlp.core.ui import DisplayController, Display, DisplayControllerType

=== modified file 'openlp/plugins/media/mediaplugin.py'
--- openlp/plugins/media/mediaplugin.py	2013-10-13 21:07:28 +0000
+++ openlp/plugins/media/mediaplugin.py	2013-12-15 16:51:10 +0000
@@ -31,8 +31,8 @@
 
 from PyQt4 import QtCore
 
-from openlp.core.common import translate
-from openlp.core.lib import Plugin, Registry, StringContent, build_icon
+from openlp.core.common import Registry, translate
+from openlp.core.lib import Plugin, StringContent, build_icon
 from openlp.plugins.media.lib import MediaMediaItem, MediaTab
 
 

=== modified file 'openlp/plugins/presentations/lib/mediaitem.py'
--- openlp/plugins/presentations/lib/mediaitem.py	2013-10-13 21:07:28 +0000
+++ openlp/plugins/presentations/lib/mediaitem.py	2013-12-15 16:51:10 +0000
@@ -32,8 +32,8 @@
 
 from PyQt4 import QtCore, QtGui
 
-from openlp.core.common import Settings, UiStrings, translate
-from openlp.core.lib import MediaManagerItem, Registry, ItemCapabilities, ServiceItemContext,\
+from openlp.core.common import Registry, Settings, UiStrings, translate
+from openlp.core.lib import MediaManagerItem, ItemCapabilities, ServiceItemContext,\
     build_icon, check_item_selected, create_thumb, validate_thumb
 from openlp.core.lib.ui import critical_error_message_box, create_horizontal_adjusting_combo_box
 from openlp.core.utils import get_locale_key

=== modified file 'openlp/plugins/presentations/lib/messagelistener.py'
--- openlp/plugins/presentations/lib/messagelistener.py	2013-12-07 17:35:06 +0000
+++ openlp/plugins/presentations/lib/messagelistener.py	2013-12-15 16:51:10 +0000
@@ -31,7 +31,7 @@
 
 from PyQt4 import QtCore
 
-from openlp.core.lib import Registry
+from openlp.core.common import Registry
 from openlp.core.ui import HideMode
 
 log = logging.getLogger(__name__)

=== modified file 'openlp/plugins/presentations/lib/presentationcontroller.py'
--- openlp/plugins/presentations/lib/presentationcontroller.py	2013-12-07 17:35:06 +0000
+++ openlp/plugins/presentations/lib/presentationcontroller.py	2013-12-15 16:51:10 +0000
@@ -33,8 +33,8 @@
 
 from PyQt4 import QtCore
 
-from openlp.core.common import AppLocation, Settings, check_directory_exists
-from openlp.core.lib import Registry, create_thumb, validate_thumb
+from openlp.core.common import Registry, AppLocation, Settings, check_directory_exists
+from openlp.core.lib import create_thumb, validate_thumb
 
 log = logging.getLogger(__name__)
 

=== modified file 'openlp/plugins/remotes/lib/httprouter.py'
--- openlp/plugins/remotes/lib/httprouter.py	2013-11-14 20:33:46 +0000
+++ openlp/plugins/remotes/lib/httprouter.py	2013-12-15 16:51:10 +0000
@@ -124,8 +124,8 @@
 from mako.template import Template
 from PyQt4 import QtCore
 
-from openlp.core.common import AppLocation, Settings, translate
-from openlp.core.lib import Registry, PluginStatus, StringContent, image_to_byte
+from openlp.core.common import Registry, AppLocation, Settings, translate
+from openlp.core.lib import PluginStatus, StringContent, image_to_byte
 
 log = logging.getLogger(__name__)
 FILE_TYPES = {

=== modified file 'openlp/plugins/songs/forms/duplicatesongremovalform.py'
--- openlp/plugins/songs/forms/duplicatesongremovalform.py	2013-10-13 15:52:04 +0000
+++ openlp/plugins/songs/forms/duplicatesongremovalform.py	2013-12-15 16:51:10 +0000
@@ -35,7 +35,7 @@
 
 from PyQt4 import QtCore, QtGui
 
-from openlp.core.lib import Registry, translate
+from openlp.core.common import Registry, translate
 from openlp.core.ui.wizard import OpenLPWizard, WizardStrings
 from openlp.plugins.songs.lib import delete_song
 from openlp.plugins.songs.lib.db import Song, MediaFile

=== modified file 'openlp/plugins/songs/forms/editsongform.py'
--- openlp/plugins/songs/forms/editsongform.py	2013-11-16 20:32:50 +0000
+++ openlp/plugins/songs/forms/editsongform.py	2013-12-15 16:51:10 +0000
@@ -38,8 +38,8 @@
 
 from PyQt4 import QtCore, QtGui
 
-from openlp.core.common import AppLocation, UiStrings, check_directory_exists, translate
-from openlp.core.lib import FileDialog, Registry, PluginStatus, MediaType, create_separated_list
+from openlp.core.common import Registry, AppLocation, UiStrings, check_directory_exists, translate
+from openlp.core.lib import FileDialog, PluginStatus, MediaType, create_separated_list
 from openlp.core.lib.ui import set_case_insensitive_completer, critical_error_message_box, find_and_set_in_combo_box
 from openlp.plugins.songs.lib import VerseType, clean_song
 from openlp.plugins.songs.lib.db import Book, Song, Author, Topic, MediaFile

=== modified file 'openlp/plugins/songs/forms/songexportform.py'
--- openlp/plugins/songs/forms/songexportform.py	2013-10-13 20:36:42 +0000
+++ openlp/plugins/songs/forms/songexportform.py	2013-12-15 16:51:10 +0000
@@ -34,8 +34,8 @@
 
 from PyQt4 import QtCore, QtGui
 
-from openlp.core.common import UiStrings, translate
-from openlp.core.lib import Registry,  create_separated_list, build_icon
+from openlp.core.common import Registry, UiStrings, translate
+from openlp.core.lib import create_separated_list, build_icon
 from openlp.core.lib.ui import critical_error_message_box
 from openlp.core.ui.wizard import OpenLPWizard, WizardStrings
 from openlp.plugins.songs.lib.db import Song

=== modified file 'openlp/plugins/songs/forms/songimportform.py'
--- openlp/plugins/songs/forms/songimportform.py	2013-11-16 20:32:50 +0000
+++ openlp/plugins/songs/forms/songimportform.py	2013-12-15 16:51:10 +0000
@@ -35,9 +35,8 @@
 
 from PyQt4 import QtCore, QtGui
 
-from openlp.core.common import UiStrings, translate
-from openlp.core.common import Settings
-from openlp.core.lib import FileDialog, Registry
+from openlp.core.common import Registry, Settings, UiStrings, translate
+from openlp.core.lib import FileDialog
 from openlp.core.lib.ui import critical_error_message_box
 from openlp.core.ui.wizard import OpenLPWizard, WizardStrings
 from openlp.plugins.songs.lib.importer import SongFormat, SongFormatSelect

=== modified file 'openlp/plugins/songs/forms/songmaintenanceform.py'
--- openlp/plugins/songs/forms/songmaintenanceform.py	2013-10-13 20:36:42 +0000
+++ openlp/plugins/songs/forms/songmaintenanceform.py	2013-12-15 16:51:10 +0000
@@ -32,8 +32,7 @@
 from PyQt4 import QtGui, QtCore
 from sqlalchemy.sql import and_
 
-from openlp.core.common import UiStrings, translate
-from openlp.core.lib import Registry
+from openlp.core.common import Registry, UiStrings, translate
 from openlp.core.lib.ui import critical_error_message_box
 from openlp.plugins.songs.forms.authorsform import AuthorsForm
 from openlp.plugins.songs.forms.topicsform import TopicsForm

=== modified file 'openlp/plugins/songs/lib/mediaitem.py'
--- openlp/plugins/songs/lib/mediaitem.py	2013-10-13 20:36:42 +0000
+++ openlp/plugins/songs/lib/mediaitem.py	2013-12-15 16:51:10 +0000
@@ -35,8 +35,8 @@
 from PyQt4 import QtCore, QtGui
 from sqlalchemy.sql import or_
 
-from openlp.core.common import AppLocation, Settings, check_directory_exists, UiStrings, translate
-from openlp.core.lib import Registry, MediaManagerItem, ItemCapabilities, PluginStatus, ServiceItemContext, \
+from openlp.core.common import Registry, AppLocation, Settings, check_directory_exists, UiStrings, translate
+from openlp.core.lib import MediaManagerItem, ItemCapabilities, PluginStatus, ServiceItemContext, \
      check_item_selected, create_separated_list
 from openlp.core.lib.ui import create_widget_action
 from openlp.plugins.songs.forms.editsongform import EditSongForm

=== modified file 'openlp/plugins/songs/lib/oooimport.py'
--- openlp/plugins/songs/lib/oooimport.py	2013-10-13 20:36:42 +0000
+++ openlp/plugins/songs/lib/oooimport.py	2013-12-15 16:51:10 +0000
@@ -127,7 +127,7 @@
                     manager = uno_instance.ServiceManager
                     self.desktop = manager.createInstanceWithContext("com.sun.star.frame.Desktop", uno_instance)
                     return
-            raise
+            raise Exception('Unable to start LibreOffice')
 
     def startOooProcess(self):
         try:

=== modified file 'openlp/plugins/songs/lib/openlyricsexport.py'
--- openlp/plugins/songs/lib/openlyricsexport.py	2013-10-13 20:36:42 +0000
+++ openlp/plugins/songs/lib/openlyricsexport.py	2013-12-15 16:51:10 +0000
@@ -35,8 +35,7 @@
 
 from lxml import etree
 
-from openlp.core.common import check_directory_exists, translate
-from openlp.core.lib import Registry
+from openlp.core.common import Registry, check_directory_exists, translate
 from openlp.core.utils import clean_filename
 from openlp.plugins.songs.lib.xml import OpenLyrics
 

=== modified file 'openlp/plugins/songs/lib/songimport.py'
--- openlp/plugins/songs/lib/songimport.py	2013-10-13 20:36:42 +0000
+++ openlp/plugins/songs/lib/songimport.py	2013-12-15 16:51:10 +0000
@@ -34,8 +34,7 @@
 
 from PyQt4 import QtCore
 
-from openlp.core.common import AppLocation, check_directory_exists, translate
-from openlp.core.lib import Registry
+from openlp.core.common import Registry, AppLocation, check_directory_exists, translate
 from openlp.core.ui.wizard import WizardStrings
 from openlp.plugins.songs.lib import clean_song, VerseType
 from openlp.plugins.songs.lib.db import Song, Author, Topic, Book, MediaFile

=== modified file 'openlp/plugins/songusage/forms/songusagedeleteform.py'
--- openlp/plugins/songusage/forms/songusagedeleteform.py	2013-10-13 20:36:42 +0000
+++ openlp/plugins/songusage/forms/songusagedeleteform.py	2013-12-15 16:51:10 +0000
@@ -29,8 +29,7 @@
 
 from PyQt4 import QtGui
 
-from openlp.core.common import translate
-from openlp.core.lib import Registry
+from openlp.core.common import Registry, translate
 from openlp.plugins.songusage.lib.db import SongUsageItem
 from .songusagedeletedialog import Ui_SongUsageDeleteDialog
 

=== modified file 'openlp/plugins/songusage/forms/songusagedetailform.py'
--- openlp/plugins/songusage/forms/songusagedetailform.py	2013-10-13 20:36:42 +0000
+++ openlp/plugins/songusage/forms/songusagedetailform.py	2013-12-15 16:51:10 +0000
@@ -33,8 +33,7 @@
 from PyQt4 import QtGui
 from sqlalchemy.sql import and_
 
-from openlp.core.common import Settings, check_directory_exists, translate
-from openlp.core.lib import Registry
+from openlp.core.common import Registry, Settings, check_directory_exists, translate
 from openlp.plugins.songusage.lib.db import SongUsageItem
 from .songusagedetaildialog import Ui_SongUsageDetailDialog
 

=== modified file 'openlp/plugins/songusage/songusageplugin.py'
--- openlp/plugins/songusage/songusageplugin.py	2013-10-13 20:36:42 +0000
+++ openlp/plugins/songusage/songusageplugin.py	2013-12-15 16:51:10 +0000
@@ -32,8 +32,8 @@
 
 from PyQt4 import QtCore, QtGui
 
-from openlp.core.common import Settings, translate
-from openlp.core.lib import Plugin, Registry, StringContent, build_icon
+from openlp.core.common import Registry, Settings, translate
+from openlp.core.lib import Plugin, StringContent, build_icon
 from openlp.core.lib.db import Manager
 from openlp.core.lib.ui import create_action
 from openlp.core.utils.actions import ActionList

=== added file 'tests/functional/openlp_core_common/test_init.py'
--- tests/functional/openlp_core_common/test_init.py	1970-01-01 00:00:00 +0000
+++ tests/functional/openlp_core_common/test_init.py	2013-12-15 16:51:10 +0000
@@ -0,0 +1,66 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection                                      #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2013 Raoul Snyman                                        #
+# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan      #
+# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub,      #
+# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer.   #
+# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru,          #
+# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith,             #
+# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock,              #
+# Frode Woldsund, Martin Zibricky, Patrick Zimmermann                         #
+# --------------------------------------------------------------------------- #
+# 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                          #
+###############################################################################
+"""
+Functional tests to test the AppLocation class and related methods.
+"""
+
+from unittest import TestCase
+
+from openlp.core.common import de_hump
+
+
+class TestInitFunctions(TestCase):
+    """
+    A test suite to test out various functions in the __init__ class.
+    """
+    def de_hump_conversion_test(self):
+        """
+        Test the de_hump function with a class name
+        """
+        # GIVEN: a Class name in Camel Case
+        string = "MyClass"
+
+        # WHEN: we call de_hump
+        new_string = de_hump(string)
+
+        # THEN: the new string should be converted to python format
+        self.assertTrue(new_string == "my_class", 'The class name should have been converted')
+
+    def de_hump_static_test(self):
+        """
+        Test the de_hump function with a python string
+        """
+        # GIVEN: a Class name in Camel Case
+        string = "my_class"
+
+        # WHEN: we call de_hump
+        new_string = de_hump(string)
+
+        # THEN: the new string should be converted to python format
+        self.assertTrue(new_string == "my_class", 'The class name should have been preserved')

=== added file 'tests/functional/openlp_core_common/test_registry.py'
--- tests/functional/openlp_core_common/test_registry.py	1970-01-01 00:00:00 +0000
+++ tests/functional/openlp_core_common/test_registry.py	2013-12-15 16:51:10 +0000
@@ -0,0 +1,112 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection                                      #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2013 Raoul Snyman                                        #
+# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan      #
+# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub,      #
+# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer.   #
+# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru,          #
+# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith,             #
+# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock,              #
+# Frode Woldsund, Martin Zibricky, Patrick Zimmermann                         #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it     #
+# under the terms of the GNU General Public License as published by the Free  #
+# Software Foundation; version 2 of the License.                              #
+#                                                                             #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for    #
+# more details.                                                               #
+#                                                                             #
+# You should have received a copy of the GNU General Public License along     #
+# with this program; if not, write to the Free Software Foundation, Inc., 59  #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA                          #
+###############################################################################
+"""
+Package to test the openlp.core.lib package.
+"""
+import os
+from unittest import TestCase
+
+from openlp.core.common import Registry
+from tests.functional import MagicMock
+
+TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '../', '..', 'resources'))
+
+
+class TestRegistry(TestCase):
+
+    def registry_service_test(self):
+        """
+        Test the registry creation and its usage
+        """
+        # GIVEN: A new registry
+        Registry.create()
+
+        # WHEN: I add a component it should save it
+        mock_1 = MagicMock()
+        Registry().register('test1', mock_1)
+
+        # THEN: we should be able retrieve the saved component
+        assert Registry().get('test1') == mock_1, 'The saved service can be retrieved and matches'
+
+        # WHEN: I add a component for the second time I am mad.
+        # THEN  and I will get an exception
+        with self.assertRaises(KeyError) as context:
+            Registry().register('test1', mock_1)
+        self.assertEqual(context.exception.args[0], 'Duplicate service exception test1',
+            'KeyError exception should have been thrown for duplicate service')
+
+        # WHEN I try to get back a non existent component
+        # THEN I will get an exception
+        with self.assertRaises(KeyError) as context:
+            temp = Registry().get('test2')
+        self.assertEqual(context.exception.args[0], 'Service test2 not found in list',
+            'KeyError exception should have been thrown for missing service')
+
+        # WHEN I try to replace a component I should be allowed (testing only)
+        Registry().remove('test1')
+        # THEN I will get an exception
+        with self.assertRaises(KeyError) as context:
+            temp = Registry().get('test1')
+        self.assertEqual(context.exception.args[0], 'Service test1 not found in list',
+            'KeyError exception should have been thrown for deleted service')
+
+    def registry_function_test(self):
+        """
+        Test the registry function creation and their usages
+        """
+        # GIVEN: An existing registry register a function
+        Registry.create()
+        Registry().register_function('test1', self.dummy_function_1)
+
+        # WHEN: I execute the function
+        return_value = Registry().execute('test1')
+
+        # THEN: I expect then function to have been called and a return given
+        self.assertEqual(return_value[0], 'function_1', 'A return value is provided and matches')
+
+        # WHEN: I execute the a function with the same reference and execute the function
+        Registry().register_function('test1', self.dummy_function_1)
+        return_value = Registry().execute('test1')
+
+        # THEN: I expect then function to have been called and a return given
+        self.assertEqual(return_value, ['function_1', 'function_1'], 'A return value list is provided and matches')
+
+        # WHEN: I execute the a 2nd function with the different reference and execute the function
+        Registry().register_function('test2', self.dummy_function_2)
+        return_value = Registry().execute('test2')
+
+        # THEN: I expect then function to have been called and a return given
+        self.assertEqual(return_value[0], 'function_2', 'A return value is provided and matches')
+
+    def dummy_function_1(self):
+        return "function_1"
+
+    def dummy_function_2(self):
+        return "function_2"
+

=== modified file 'tests/functional/openlp_core_lib/test_image_manager.py'
--- tests/functional/openlp_core_lib/test_image_manager.py	2013-10-11 09:48:35 +0000
+++ tests/functional/openlp_core_lib/test_image_manager.py	2013-12-15 16:51:10 +0000
@@ -34,7 +34,8 @@
 from unittest import TestCase
 from PyQt4 import QtGui
 
-from openlp.core.lib import Registry, ImageManager, ScreenList
+from openlp.core.common import Registry
+from openlp.core.lib import ImageManager, ScreenList
 
 TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', 'resources'))
 

=== modified file 'tests/functional/openlp_core_lib/test_pluginmanager.py'
--- tests/functional/openlp_core_lib/test_pluginmanager.py	2013-10-13 20:36:42 +0000
+++ tests/functional/openlp_core_lib/test_pluginmanager.py	2013-12-15 16:51:10 +0000
@@ -31,9 +31,9 @@
 """
 from unittest import TestCase
 
-from openlp.core.common import Settings
+from openlp.core.common import Registry, Settings
 from openlp.core.lib.pluginmanager import PluginManager
-from openlp.core.lib import Registry, PluginStatus
+from openlp.core.lib import PluginStatus
 from tests.functional import MagicMock
 
 

=== removed file 'tests/functional/openlp_core_lib/test_registry.py'
--- tests/functional/openlp_core_lib/test_registry.py	2013-10-02 21:37:00 +0000
+++ tests/functional/openlp_core_lib/test_registry.py	1970-01-01 00:00:00 +0000
@@ -1,112 +0,0 @@
-# -*- coding: utf-8 -*-
-# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
-
-###############################################################################
-# OpenLP - Open Source Lyrics Projection                                      #
-# --------------------------------------------------------------------------- #
-# Copyright (c) 2008-2013 Raoul Snyman                                        #
-# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan      #
-# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub,      #
-# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer.   #
-# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru,          #
-# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith,             #
-# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock,              #
-# Frode Woldsund, Martin Zibricky, Patrick Zimmermann                         #
-# --------------------------------------------------------------------------- #
-# This program is free software; you can redistribute it and/or modify it     #
-# under the terms of the GNU General Public License as published by the Free  #
-# Software Foundation; version 2 of the License.                              #
-#                                                                             #
-# This program is distributed in the hope that it will be useful, but WITHOUT #
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       #
-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for    #
-# more details.                                                               #
-#                                                                             #
-# You should have received a copy of the GNU General Public License along     #
-# with this program; if not, write to the Free Software Foundation, Inc., 59  #
-# Temple Place, Suite 330, Boston, MA 02111-1307 USA                          #
-###############################################################################
-"""
-Package to test the openlp.core.lib package.
-"""
-import os
-from unittest import TestCase
-
-from openlp.core.lib import Registry
-from tests.functional import MagicMock
-
-TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', 'resources'))
-
-
-class TestRegistry(TestCase):
-
-    def registry_service_test(self):
-        """
-        Test the registry creation and its usage
-        """
-        # GIVEN: A new registry
-        Registry.create()
-
-        # WHEN: I add a component it should save it
-        mock_1 = MagicMock()
-        Registry().register('test1', mock_1)
-
-        # THEN: we should be able retrieve the saved component
-        assert Registry().get('test1') == mock_1, 'The saved service can be retrieved and matches'
-
-        # WHEN: I add a component for the second time I am mad.
-        # THEN  and I will get an exception
-        with self.assertRaises(KeyError) as context:
-            Registry().register('test1', mock_1)
-        self.assertEqual(context.exception.args[0], 'Duplicate service exception test1',
-            'KeyError exception should have been thrown for duplicate service')
-
-        # WHEN I try to get back a non existent component
-        # THEN I will get an exception
-        with self.assertRaises(KeyError) as context:
-            temp = Registry().get('test2')
-        self.assertEqual(context.exception.args[0], 'Service test2 not found in list',
-            'KeyError exception should have been thrown for missing service')
-
-        # WHEN I try to replace a component I should be allowed (testing only)
-        Registry().remove('test1')
-        # THEN I will get an exception
-        with self.assertRaises(KeyError) as context:
-            temp = Registry().get('test1')
-        self.assertEqual(context.exception.args[0], 'Service test1 not found in list',
-            'KeyError exception should have been thrown for deleted service')
-
-    def registry_function_test(self):
-        """
-        Test the registry function creation and their usages
-        """
-        # GIVEN: An existing registry register a function
-        Registry.create()
-        Registry().register_function('test1', self.dummy_function_1)
-
-        # WHEN: I execute the function
-        return_value = Registry().execute('test1')
-
-        # THEN: I expect then function to have been called and a return given
-        self.assertEqual(return_value[0], 'function_1', 'A return value is provided and matches')
-
-        # WHEN: I execute the a function with the same reference and execute the function
-        Registry().register_function('test1', self.dummy_function_1)
-        return_value = Registry().execute('test1')
-
-        # THEN: I expect then function to have been called and a return given
-        self.assertEqual(return_value, ['function_1', 'function_1'], 'A return value list is provided and matches')
-
-        # WHEN: I execute the a 2nd function with the different reference and execute the function
-        Registry().register_function('test2', self.dummy_function_2)
-        return_value = Registry().execute('test2')
-
-        # THEN: I expect then function to have been called and a return given
-        self.assertEqual(return_value[0], 'function_2', 'A return value is provided and matches')
-
-    def dummy_function_1(self):
-        return "function_1"
-
-    def dummy_function_2(self):
-        return "function_2"
-

=== modified file 'tests/functional/openlp_core_lib/test_screen.py'
--- tests/functional/openlp_core_lib/test_screen.py	2013-10-02 21:37:00 +0000
+++ tests/functional/openlp_core_lib/test_screen.py	2013-12-15 16:51:10 +0000
@@ -33,7 +33,8 @@
 
 from PyQt4 import QtGui, QtCore
 
-from openlp.core.lib import Registry, ScreenList
+from openlp.core.common import Registry
+from openlp.core.lib import ScreenList
 from tests.functional import MagicMock
 
 SCREEN = {

=== modified file 'tests/functional/openlp_core_lib/test_serviceitem.py'
--- tests/functional/openlp_core_lib/test_serviceitem.py	2013-10-11 10:13:04 +0000
+++ tests/functional/openlp_core_lib/test_serviceitem.py	2013-12-15 16:51:10 +0000
@@ -36,7 +36,8 @@
 from tests.functional import MagicMock, patch
 from tests.utils import assert_length, convert_file_service_item
 
-from openlp.core.lib import ItemCapabilities, ServiceItem, Registry
+from openlp.core.common import Registry
+from openlp.core.lib import ItemCapabilities, ServiceItem
 
 
 VERSE = 'The Lord said to {r}Noah{/r}: \n'\

=== modified file 'tests/functional/openlp_plugins/images/test_lib.py'
--- tests/functional/openlp_plugins/images/test_lib.py	2013-10-02 21:07:20 +0000
+++ tests/functional/openlp_plugins/images/test_lib.py	2013-12-15 16:51:10 +0000
@@ -31,7 +31,7 @@
 """
 from unittest import TestCase
 
-from openlp.core.lib import Registry
+from openlp.core.common import Registry
 from openlp.plugins.images.lib.db import ImageFilenames, ImageGroups
 from openlp.plugins.images.lib.mediaitem import ImageMediaItem
 from tests.functional import MagicMock, patch

=== modified file 'tests/functional/openlp_plugins/presentations/test_mediaitem.py'
--- tests/functional/openlp_plugins/presentations/test_mediaitem.py	2013-10-02 21:07:20 +0000
+++ tests/functional/openlp_plugins/presentations/test_mediaitem.py	2013-12-15 16:51:10 +0000
@@ -33,7 +33,7 @@
 
 from PyQt4 import QtGui
 
-from openlp.core.lib import Registry
+from openlp.core.common import Registry
 from openlp.plugins.presentations.lib.mediaitem import PresentationMediaItem
 from tests.functional import patch, MagicMock
 

=== modified file 'tests/functional/openlp_plugins/songs/test_mediaitem.py'
--- tests/functional/openlp_plugins/songs/test_mediaitem.py	2013-10-13 20:36:42 +0000
+++ tests/functional/openlp_plugins/songs/test_mediaitem.py	2013-12-15 16:51:10 +0000
@@ -7,8 +7,8 @@
 
 from PyQt4 import QtCore, QtGui
 
-from openlp.core.common import Settings
-from openlp.core.lib import Registry, ServiceItem
+from openlp.core.common import Registry, Settings
+from openlp.core.lib import ServiceItem
 from openlp.plugins.songs.lib.mediaitem import SongMediaItem
 from tests.functional import patch, MagicMock
 

=== modified file 'tests/interfaces/openlp_core_lib/test_pluginmanager.py'
--- tests/interfaces/openlp_core_lib/test_pluginmanager.py	2013-10-14 04:55:20 +0000
+++ tests/interfaces/openlp_core_lib/test_pluginmanager.py	2013-12-15 16:51:10 +0000
@@ -9,9 +9,8 @@
 
 from PyQt4 import QtGui
 
-from openlp.core.common import Settings
+from openlp.core.common import Registry, Settings
 from openlp.core.lib.pluginmanager import PluginManager
-from openlp.core.lib import Registry
 from tests.interfaces import MagicMock
 
 

=== modified file 'tests/interfaces/openlp_core_ui/test_filerenamedialog.py'
--- tests/interfaces/openlp_core_ui/test_filerenamedialog.py	2013-10-04 21:45:38 +0000
+++ tests/interfaces/openlp_core_ui/test_filerenamedialog.py	2013-12-15 16:51:10 +0000
@@ -5,7 +5,7 @@
 
 from PyQt4 import QtGui, QtTest
 
-from openlp.core.lib import Registry
+from openlp.core.common import Registry
 from openlp.core.ui import filerenameform
 from tests.interfaces import MagicMock, patch
 

=== modified file 'tests/interfaces/openlp_core_ui/test_listpreviewwidget.py'
--- tests/interfaces/openlp_core_ui/test_listpreviewwidget.py	2013-10-04 21:45:38 +0000
+++ tests/interfaces/openlp_core_ui/test_listpreviewwidget.py	2013-12-15 16:51:10 +0000
@@ -6,7 +6,8 @@
 
 from PyQt4 import QtGui
 
-from openlp.core.lib import Registry, ServiceItem
+from openlp.core.common import Registry
+from openlp.core.lib import ServiceItem
 from openlp.core.ui import listpreviewwidget
 from tests.interfaces import MagicMock, patch
 from tests.utils.osdinteraction import read_service_from_file

=== modified file 'tests/interfaces/openlp_core_ui/test_mainwindow.py'
--- tests/interfaces/openlp_core_ui/test_mainwindow.py	2013-10-04 21:45:38 +0000
+++ tests/interfaces/openlp_core_ui/test_mainwindow.py	2013-12-15 16:51:10 +0000
@@ -5,7 +5,7 @@
 
 from PyQt4 import QtGui
 
-from openlp.core.lib import Registry
+from openlp.core.common import Registry
 from openlp.core.ui.mainwindow import MainWindow
 from tests.interfaces import MagicMock, patch
 

=== modified file 'tests/interfaces/openlp_core_ui/test_servicemanager.py'
--- tests/interfaces/openlp_core_ui/test_servicemanager.py	2013-10-04 21:45:38 +0000
+++ tests/interfaces/openlp_core_ui/test_servicemanager.py	2013-12-15 16:51:10 +0000
@@ -6,7 +6,8 @@
 
 from PyQt4 import QtGui
 
-from openlp.core.lib import Registry, ScreenList, ServiceItem
+from openlp.core.common import Registry
+from openlp.core.lib import ScreenList, ServiceItem
 from openlp.core.ui.mainwindow import MainWindow
 from tests.interfaces import MagicMock, patch
 

=== modified file 'tests/interfaces/openlp_core_ui/test_servicenotedialog.py'
--- tests/interfaces/openlp_core_ui/test_servicenotedialog.py	2013-10-04 21:45:38 +0000
+++ tests/interfaces/openlp_core_ui/test_servicenotedialog.py	2013-12-15 16:51:10 +0000
@@ -5,7 +5,7 @@
 
 from PyQt4 import QtCore, QtGui, QtTest
 
-from openlp.core.lib import Registry
+from openlp.core.common import Registry
 from openlp.core.ui import servicenoteform
 from tests.interfaces import patch
 

=== modified file 'tests/interfaces/openlp_core_ui/test_settings_form.py'
--- tests/interfaces/openlp_core_ui/test_settings_form.py	2013-10-04 21:45:38 +0000
+++ tests/interfaces/openlp_core_ui/test_settings_form.py	2013-12-15 16:51:10 +0000
@@ -5,8 +5,9 @@
 
 from PyQt4 import QtCore, QtTest, QtGui
 
+from openlp.core.common import Registry
 from openlp.core.ui import settingsform
-from openlp.core.lib import Registry, ScreenList
+from openlp.core.lib import ScreenList
 from tests.interfaces import MagicMock, patch
 
 

=== modified file 'tests/interfaces/openlp_core_ui/test_starttimedialog.py'
--- tests/interfaces/openlp_core_ui/test_starttimedialog.py	2013-10-04 21:45:38 +0000
+++ tests/interfaces/openlp_core_ui/test_starttimedialog.py	2013-12-15 16:51:10 +0000
@@ -5,7 +5,7 @@
 
 from PyQt4 import QtCore, QtGui, QtTest
 
-from openlp.core.lib import Registry
+from openlp.core.common import Registry
 from openlp.core.ui import starttimeform
 from tests.interfaces import MagicMock, patch
 

=== modified file 'tests/interfaces/openlp_plugins/bibles/test_lib_http.py'
--- tests/interfaces/openlp_plugins/bibles/test_lib_http.py	2013-10-04 21:45:38 +0000
+++ tests/interfaces/openlp_plugins/bibles/test_lib_http.py	2013-12-15 16:51:10 +0000
@@ -3,7 +3,7 @@
 """
 from unittest import TestCase
 
-from openlp.core.lib import Registry
+from openlp.core.common import Registry
 from openlp.plugins.bibles.lib.http import BGExtract, CWExtract
 from tests.interfaces import MagicMock
 

=== modified file 'tests/interfaces/openlp_plugins/custom/forms/test_customform.py'
--- tests/interfaces/openlp_plugins/custom/forms/test_customform.py	2013-10-04 21:45:38 +0000
+++ tests/interfaces/openlp_plugins/custom/forms/test_customform.py	2013-12-15 16:51:10 +0000
@@ -5,7 +5,7 @@
 
 from PyQt4 import QtGui, QtTest, QtCore
 
-from openlp.core.lib import Registry
+from openlp.core.common import Registry
 # Import needed due to import problems.
 from openlp.plugins.custom.lib.mediaitem import CustomMediaItem
 from openlp.plugins.custom.forms.editcustomform import EditCustomForm

=== modified file 'tests/interfaces/openlp_plugins/custom/forms/test_customslideform.py'
--- tests/interfaces/openlp_plugins/custom/forms/test_customslideform.py	2013-10-04 21:45:38 +0000
+++ tests/interfaces/openlp_plugins/custom/forms/test_customslideform.py	2013-12-15 16:51:10 +0000
@@ -5,7 +5,7 @@
 
 from PyQt4 import QtGui
 
-from openlp.core.lib import Registry
+from openlp.core.common import Registry
 from openlp.plugins.custom.forms.editcustomslideform import EditCustomSlideForm
 from tests.interfaces import MagicMock, patch
 

=== modified file 'tests/interfaces/openlp_plugins/songs/forms/test_authorsform.py'
--- tests/interfaces/openlp_plugins/songs/forms/test_authorsform.py	2013-08-31 18:17:38 +0000
+++ tests/interfaces/openlp_plugins/songs/forms/test_authorsform.py	2013-12-15 16:51:10 +0000
@@ -5,7 +5,7 @@
 
 from PyQt4 import QtGui
 
-from openlp.core.lib import Registry
+from openlp.core.common import Registry
 from openlp.plugins.songs.forms.authorsform import AuthorsForm
 
 

=== modified file 'tests/interfaces/openlp_plugins/songs/forms/test_editsongform.py'
--- tests/interfaces/openlp_plugins/songs/forms/test_editsongform.py	2013-10-21 07:38:18 +0000
+++ tests/interfaces/openlp_plugins/songs/forms/test_editsongform.py	2013-12-15 16:51:10 +0000
@@ -5,7 +5,7 @@
 
 from PyQt4 import QtGui
 
-from openlp.core.lib import Registry
+from openlp.core.common import Registry
 from openlp.plugins.songs.forms.editsongform import EditSongForm
 from tests.interfaces import MagicMock
 

=== modified file 'tests/interfaces/openlp_plugins/songs/forms/test_editverseform.py'
--- tests/interfaces/openlp_plugins/songs/forms/test_editverseform.py	2013-08-31 18:17:38 +0000
+++ tests/interfaces/openlp_plugins/songs/forms/test_editverseform.py	2013-12-15 16:51:10 +0000
@@ -5,7 +5,7 @@
 
 from PyQt4 import QtCore, QtGui, QtTest
 
-from openlp.core.lib import Registry
+from openlp.core.common import Registry
 from openlp.plugins.songs.forms.editverseform import EditVerseForm
 
 

=== modified file 'tests/interfaces/openlp_plugins/songs/forms/test_topicsform.py'
--- tests/interfaces/openlp_plugins/songs/forms/test_topicsform.py	2013-08-31 18:17:38 +0000
+++ tests/interfaces/openlp_plugins/songs/forms/test_topicsform.py	2013-12-15 16:51:10 +0000
@@ -5,7 +5,7 @@
 
 from PyQt4 import QtGui
 
-from openlp.core.lib import Registry
+from openlp.core.common import Registry
 from openlp.plugins.songs.forms.topicsform import TopicsForm
 
 


Follow ups