← Back to team overview

openlp-core team mailing list archive

[Merge] lp:~trb143/openlp/theme-cleanup into lp:openlp

 

Tim Bentley has proposed merging lp:~trb143/openlp/theme-cleanup into lp:openlp.

Requested reviews:
  OpenLP Core (openlp-core)

For more details, see:
https://code.launchpad.net/~trb143/openlp/theme-cleanup/+merge/190837

Start to clean up the theme code.
Add a helper 
replace the xml default code to json load and simplify it.
remove to v1 theme import code.  We will not support v1 to v2.2 direct
move applocation to a common package to allow it to be used in lib.

This is part of a series of theme cleanups which will have tests written,

Proposing to get a view on direction.

-- 
https://code.launchpad.net/~trb143/openlp/theme-cleanup/+merge/190837
Your team OpenLP Core is requested to review the proposed merge of lp:~trb143/openlp/theme-cleanup into lp:openlp.
=== modified file 'openlp/core/__init__.py'
--- openlp/core/__init__.py	2013-08-31 18:17:38 +0000
+++ openlp/core/__init__.py	2013-10-13 17:03:19 +0000
@@ -43,6 +43,7 @@
 
 from PyQt4 import QtCore, QtGui
 
+from openlp.core.common import AppLocation
 from openlp.core.lib import Settings, ScreenList, UiStrings, Registry, check_directory_exists
 from openlp.core.resources import qInitResources
 from openlp.core.ui.mainwindow import MainWindow
@@ -50,7 +51,7 @@
 from openlp.core.ui.firsttimeform import FirstTimeForm
 from openlp.core.ui.exceptionform import ExceptionForm
 from openlp.core.ui import SplashScreen
-from openlp.core.utils import AppLocation, LanguageManager, VersionThread, get_application_version
+from openlp.core.utils import LanguageManager, VersionThread, get_application_version
 
 
 __all__ = ['OpenLP', 'main']

=== added directory 'openlp/core/common'
=== added file 'openlp/core/common/__init__.py'
--- openlp/core/common/__init__.py	1970-01-01 00:00:00 +0000
+++ openlp/core/common/__init__.py	2013-10-13 17:03:19 +0000
@@ -0,0 +1,67 @@
+# -*- 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                          #
+###############################################################################
+"""
+The :mod:`common` module contains most of the components and libraries that make
+OpenLP work.
+"""
+import os
+import logging
+import sys
+
+log = logging.getLogger(__name__)
+
+
+def check_directory_exists(directory, do_not_log=False):
+    """
+    Check a theme directory exists and if not create it
+
+    ``directory``
+        The directory to make sure exists
+
+    ``do_not_log``
+        To not log anything. This is need for the start up, when the log isn't ready.
+    """
+    if not do_not_log:
+        log.debug('check_directory_exists %s' % directory)
+    try:
+        if not os.path.exists(directory):
+            os.makedirs(directory)
+    except IOError:
+        pass
+
+
+def get_frozen_path(frozen_option, non_frozen_option):
+    """
+    Return a path based on the system status.
+    """
+    if hasattr(sys, 'frozen') and sys.frozen == 1:
+        return frozen_option
+    return non_frozen_option
+
+from .applocation import AppLocation

=== added file 'openlp/core/common/applocation.py'
--- openlp/core/common/applocation.py	1970-01-01 00:00:00 +0000
+++ openlp/core/common/applocation.py	2013-10-13 17:03:19 +0000
@@ -0,0 +1,170 @@
+# -*- 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                          #
+###############################################################################
+"""
+The :mod:`openlp.core.common.applocation` module provides an utility for OpenLP receiving the data path etc.
+"""
+import logging
+import os
+import sys
+
+if sys.platform != 'win32' and sys.platform != 'darwin':
+    try:
+        from xdg import BaseDirectory
+        XDG_BASE_AVAILABLE = True
+    except ImportError:
+        XDG_BASE_AVAILABLE = False
+
+import openlp
+from openlp.core.common import check_directory_exists, get_frozen_path
+
+
+log = logging.getLogger(__name__)
+
+
+class AppLocation(object):
+    """
+    The :class:`AppLocation` class is a static class which retrieves a directory based on the directory type.
+    """
+    AppDir = 1
+    DataDir = 2
+    PluginsDir = 3
+    VersionDir = 4
+    CacheDir = 5
+    LanguageDir = 6
+
+    # Base path where data/config/cache dir is located
+    BaseDir = None
+
+    @staticmethod
+    def get_directory(dir_type=AppDir):
+        """
+        Return the appropriate directory according to the directory type.
+
+        ``dir_type``
+            The directory type you want, for instance the data directory. Default *AppLocation.AppDir*
+        """
+        if dir_type == AppLocation.AppDir:
+            return get_frozen_path(os.path.abspath(os.path.split(sys.argv[0])[0]), os.path.split(openlp.__file__)[0])
+        elif dir_type == AppLocation.PluginsDir:
+            app_path = os.path.abspath(os.path.split(sys.argv[0])[0])
+            return get_frozen_path(os.path.join(app_path, 'plugins'),
+                os.path.join(os.path.split(openlp.__file__)[0], 'plugins'))
+        elif dir_type == AppLocation.VersionDir:
+            return get_frozen_path(os.path.abspath(os.path.split(sys.argv[0])[0]), os.path.split(openlp.__file__)[0])
+        elif dir_type == AppLocation.LanguageDir:
+            app_path = get_frozen_path(os.path.abspath(os.path.split(sys.argv[0])[0]), _get_os_dir_path(dir_type))
+            return os.path.join(app_path, 'i18n')
+        elif dir_type == AppLocation.DataDir and AppLocation.BaseDir:
+            return os.path.join(AppLocation.BaseDir, 'data')
+        else:
+            return _get_os_dir_path(dir_type)
+
+    @staticmethod
+    def get_data_path():
+        """
+        Return the path OpenLP stores all its data under.
+        """
+        # Check if we have a different data location.
+        from openlp.core.lib import Settings
+        if Settings().contains('advanced/data path'):
+            path = Settings().value('advanced/data path')
+        else:
+            path = AppLocation.get_directory(AppLocation.DataDir)
+            check_directory_exists(path)
+        return os.path.normpath(path)
+
+    @staticmethod
+    def get_files(section=None, extension=None):
+        """
+        Get a list of files from the data files path.
+
+        ``section``
+            Defaults to *None*. The section of code getting the files - used to load from a section's data subdirectory.
+
+        ``extension``
+            Defaults to *None*. The extension to search for. For example::
+
+                u'.png'
+        """
+        path = AppLocation.get_data_path()
+        if section:
+            path = os.path.join(path, section)
+        try:
+            files = os.listdir(path)
+        except OSError:
+            return []
+        if extension:
+            return [filename for filename in files if extension == os.path.splitext(filename)[1]]
+        else:
+            # no filtering required
+            return files
+
+    @staticmethod
+    def get_section_data_path(section):
+        """
+        Return the path a particular module stores its data under.
+        """
+        data_path = AppLocation.get_data_path()
+        path = os.path.join(data_path, section)
+        check_directory_exists(path)
+        return path
+
+
+def _get_os_dir_path(dir_type):
+    """
+    Return a path based on which OS and environment we are running in.
+    """
+    if sys.platform == 'win32':
+        if dir_type == AppLocation.DataDir:
+            return os.path.join(str(os.getenv('APPDATA')), 'openlp', 'data')
+        elif dir_type == AppLocation.LanguageDir:
+            return os.path.split(openlp.__file__)[0]
+        return os.path.join(str(os.getenv('APPDATA')), 'openlp')
+    elif sys.platform == 'darwin':
+        if dir_type == AppLocation.DataDir:
+            return os.path.join(str(os.getenv('HOME')),
+                                'Library', 'Application Support', 'openlp', 'Data')
+        elif dir_type == AppLocation.LanguageDir:
+            return os.path.split(openlp.__file__)[0]
+        return os.path.join(str(os.getenv('HOME')), 'Library', 'Application Support', 'openlp')
+    else:
+        if dir_type == AppLocation.LanguageDir:
+            for prefix in ['/usr/local', '/usr']:
+                directory = os.path.join(prefix, 'share', 'openlp')
+                if os.path.exists(directory):
+                    return directory
+            return os.path.join('/usr', 'share', 'openlp')
+        if XDG_BASE_AVAILABLE:
+            if dir_type == AppLocation.DataDir:
+                return os.path.join(str(BaseDirectory.xdg_data_home), 'openlp')
+            elif dir_type == AppLocation.CacheDir:
+                return os.path.join(str(BaseDirectory.xdg_cache_home), 'openlp')
+        if dir_type == AppLocation.DataDir:
+            return os.path.join(str(os.getenv('HOME')), '.openlp', 'data')
+        return os.path.join(str(os.getenv('HOME')), '.openlp')

=== modified file 'openlp/core/lib/db.py'
--- openlp/core/lib/db.py	2013-08-31 18:17:38 +0000
+++ openlp/core/lib/db.py	2013-10-13 17:03:19 +0000
@@ -41,9 +41,10 @@
 from alembic.migration import MigrationContext
 from alembic.operations import Operations
 
+from openlp.core.common import AppLocation
 from openlp.core.lib import translate, Settings
 from openlp.core.lib.ui import critical_error_message_box
-from openlp.core.utils import AppLocation, delete_file
+from openlp.core.utils import delete_file
 
 log = logging.getLogger(__name__)
 

=== added directory 'openlp/core/lib/json'
=== added file 'openlp/core/lib/json/theme.json'
--- openlp/core/lib/json/theme.json	1970-01-01 00:00:00 +0000
+++ openlp/core/lib/json/theme.json	2013-10-13 17:03:19 +0000
@@ -0,0 +1,49 @@
+{
+    "background_border_color": "#000000",
+    "background_color": "#000000",
+    "background_direction": "vertical",
+    "background_end_color": "#000000",
+    "background_filename": "",
+    "background_start_color": "#000000",
+    "background_type": "solid",
+    "display_horizontal_align": 0,
+    "display_slide_transition": false,
+    "display_vertical_align": 0,
+    "font_footer_bold": false,
+    "font_footer_color": "#FFFFFF",
+    "font_footer_height": 78,
+    "font_footer_italics": false,
+    "font_footer_line_adjustment": 0,
+    "font_footer_location": "",
+    "font_footer_name": "Arial",
+    "font_footer_outline": false,
+    "font_footer_outline_color": "#000000",
+    "font_footer_outline_size": 2,
+    "font_footer_override": false,
+    "font_footer_shadow": true,
+    "font_footer_shadow_color": "#000000",
+    "font_footer_shadow_size": 5,
+    "font_footer_size": 12,
+    "font_footer_width": 1004,
+    "font_footer_x": 10,
+    "font_footer_y": 690,
+    "font_main_bold": false,
+    "font_main_color": "#FFFFFF",
+    "font_main_height": 690,
+    "font_main_italics": false,
+    "font_main_line_adjustment": 0,
+    "font_main_location": "",
+    "font_main_name": "Arial",
+    "font_main_outline": false,
+    "font_main_outline_color": "#000000",
+    "font_main_outline_size": 2,
+    "font_main_override": false,
+    "font_main_shadow": true,
+    "font_main_shadow_color": "#000000",
+    "font_main_shadow_size": 5,
+    "font_main_size": 40,
+    "font_main_width": 1004,
+    "font_main_x": 10,
+    "font_main_y": 10,
+    "theme_name": ""
+}

=== modified file 'openlp/core/lib/pluginmanager.py'
--- openlp/core/lib/pluginmanager.py	2013-08-31 18:17:38 +0000
+++ openlp/core/lib/pluginmanager.py	2013-10-13 17:03:19 +0000
@@ -35,7 +35,7 @@
 import imp
 
 from openlp.core.lib import Plugin, PluginStatus, Registry
-from openlp.core.utils import AppLocation
+from openlp.core.common import AppLocation
 
 log = logging.getLogger(__name__)
 

=== modified file 'openlp/core/lib/theme.py'
--- openlp/core/lib/theme.py	2013-08-31 18:17:38 +0000
+++ openlp/core/lib/theme.py	2013-10-13 17:03:19 +0000
@@ -32,60 +32,16 @@
 import os
 import re
 import logging
+import json
 
 from xml.dom.minidom import Document
 from lxml import etree, objectify
+from openlp.core.common import AppLocation
 
-from openlp.core.lib import str_to_bool, ScreenList
+from openlp.core.lib import str_to_bool, ScreenList, get_text_file_string
 
 log = logging.getLogger(__name__)
 
-BLANK_THEME_XML = \
-'''<?xml version="1.0" encoding="utf-8"?>
- <theme version="1.0">
-   <name> </name>
-   <background type="image">
-      <filename></filename>
-      <borderColor>#000000</borderColor>
-   </background>
-   <background type="gradient">
-      <startColor>#000000</startColor>
-      <endColor>#000000</endColor>
-      <direction>vertical</direction>
-   </background>
-   <background type="solid">
-      <color>#000000</color>
-   </background>
-   <font type="main">
-      <name>Arial</name>
-      <color>#FFFFFF</color>
-      <size>40</size>
-      <bold>False</bold>
-      <italics>False</italics>
-      <line_adjustment>0</line_adjustment>
-      <shadow shadowColor="#000000" shadowSize="5">True</shadow>
-      <outline outlineColor="#000000" outlineSize="2">False</outline>
-      <location override="False" x="10" y="10" width="1004" height="690"/>
-   </font>
-   <font type="footer">
-      <name>Arial</name>
-      <color>#FFFFFF</color>
-      <size>12</size>
-      <bold>False</bold>
-      <italics>False</italics>
-      <line_adjustment>0</line_adjustment>
-      <shadow shadowColor="#000000" shadowSize="5">True</shadow>
-      <outline outlineColor="#000000" outlineSize="2">False</outline>
-      <location override="False" x="10" y="690" width="1004" height="78"/>
-   </font>
-   <display>
-      <horizontalAlign>0</horizontalAlign>
-      <verticalAlign>0</verticalAlign>
-      <slideTransition>False</slideTransition>
-   </display>
- </theme>
-'''
-
 
 class ThemeLevel(object):
     """
@@ -217,9 +173,13 @@
         """
         Initialise the theme object.
         """
-        # Create the minidom document
-        self.theme_xml = Document()
-        self.parse_xml(BLANK_THEME_XML)
+        # basic theme object with defaults
+        json_dir = os.path.join(AppLocation.get_directory(AppLocation.AppDir), 'core', 'lib', 'json')
+        json_file = os.path.join(json_dir, 'theme.json')
+        jsn = get_text_file_string(json_file)
+        jsn = json.loads(jsn)
+        for key, value in jsn.items():
+            setattr(self, key, value)
 
     def extend_image_filename(self, path):
         """
@@ -559,6 +519,7 @@
         """
         Create the attributes with the correct data types and name format
         """
+        #print(master, element, value)
         reject, master, element, value = self._translate_tags(master, element, value)
         if reject:
             return

=== removed directory 'openlp/core/theme'
=== removed file 'openlp/core/theme/__init__.py'
--- openlp/core/theme/__init__.py	2013-02-01 19:58:18 +0000
+++ openlp/core/theme/__init__.py	1970-01-01 00:00:00 +0000
@@ -1,36 +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                          #
-###############################################################################
-"""
-The :mod:`~openlp.core.theme` module contains all the themeing functions used by
-OpenLP when displaying a song or a scripture.
-"""
-
-from openlp.core.theme.theme import Theme
-
-__all__ = ['Theme']

=== removed file 'openlp/core/theme/theme.py'
--- openlp/core/theme/theme.py	2013-08-31 18:17:38 +0000
+++ openlp/core/theme/theme.py	1970-01-01 00:00:00 +0000
@@ -1,252 +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                          #
-###############################################################################
-"""
-OpenLP version 1 theme handling
-
-Provides reference data, a default v1 XML theme and class wrapper for
-processing version 1 themes in OpenLP version 2.
-"""
-
-from xml.etree.ElementTree import ElementTree, XML
-from PyQt4 import QtGui
-
-DELPHI_COLORS = {
-    'clAqua': 0x00FFFF,
-    'clBlack': 0x000000,
-    'clBlue': 0x0000FF,
-    'clFuchsia': 0xFF00FF,
-    'clGray': 0x808080,
-    'clGreen': 0x008000,
-    'clLime': 0x00FF00,
-    'clMaroon': 0x800000,
-    'clNavy': 0x000080,
-    'clOlive': 0x808000,
-    'clPurple': 0x800080,
-    'clRed': 0xFF0000,
-    'clSilver': 0xC0C0C0,
-    'clTeal': 0x008080,
-    'clWhite': 0xFFFFFF,
-    'clYellow': 0xFFFF00
-}
-
-BLANK_STYLE_XML = \
-'''<?xml version="1.0" encoding="iso-8859-1"?>
-<Theme>
-  <Name>BlankStyle</Name>
-  <BackgroundMode>1</BackgroundMode>
-  <BackgroundType>0</BackgroundType>
-  <BackgroundParameter1>$000000</BackgroundParameter1>
-  <BackgroundParameter2/>
-  <BackgroundParameter3/>
-  <FontName>Arial</FontName>
-  <FontColor>clWhite</FontColor>
-  <FontProportion>30</FontProportion>
-  <FontUnits>pixels</FontUnits>
-  <Shadow>0</Shadow>
-  <Outline>0</Outline>
-  <HorizontalAlign>0</HorizontalAlign>
-  <VerticalAlign>0</VerticalAlign>
-  <WrapStyle>0</WrapStyle>
-</Theme>
-'''
-
-
-class Theme(object):
-    """
-    Provide a class wrapper storing data from an XML theme
-
-    ``name``
-        Theme name
-
-    ``BackgroundMode``
-        The behaviour of the background. Valid modes are:
-
-            * ``0`` - Transparent
-            * ``1`` - Opaque
-
-    ``BackgroundType``
-        The content of the background. Valid types are:
-
-            * ``0`` - solid color
-            * ``1`` - gradient color
-            * ``2`` - image
-
-    ``BackgroundParameter1``
-        Extra information about the background. The contents of this attribute
-        depend on the BackgroundType:
-
-            * ``image`` - image filename
-            * ``gradient`` - start color
-            * ``solid`` - color
-
-    ``BackgroundParameter2``
-        Extra information about the background. The contents of this attribute
-        depend on the BackgroundType:
-
-            * ``image`` - border color
-            * ``gradient`` - end color
-            * ``solid`` - N/A
-
-    ``BackgroundParameter3``
-        Extra information about the background. The contents of this attribute
-        depend on the BackgroundType:
-
-            * ``image`` - N/A
-            * ``gradient`` - The direction of the gradient. Valid entries are:
-
-                * ``0`` - vertical
-                * ``1`` - horizontal
-
-            * ``solid`` - N/A
-
-    ``FontName``
-        Name of the font to use for the main font.
-
-    ``FontColor``
-        The color for the main font
-
-    ``FontProportion``
-        The size of the main font
-
-    ``FontUnits``
-        The units for FontProportion, either <pixels> or <points>
-
-    ``Shadow``
-        The shadow type to apply to the main font.
-
-            * ``0`` - no shadow
-            * non-zero - use shadow
-
-    ``ShadowColor``
-        Color for the shadow
-
-    ``Outline``
-        The outline to apply to the main font
-
-            * ``0`` - no outline
-            * non-zero - use outline
-
-    ``OutlineColor``
-        Color for the outline (or None if Outline is 0)
-
-    ``HorizontalAlign``
-        The horizontal alignment to apply to text. Valid alignments are:
-
-            * ``0`` - left align
-            * ``1`` - right align
-            * ``2`` - centre align
-
-    ``VerticalAlign``
-        The vertical alignment to apply to the text. Valid alignments are:
-
-            * ``0`` - top align
-            * ``1`` - bottom align
-            * ``2`` - centre align
-
-    ``WrapStyle``
-        The wrap style to apply to the text. Valid styles are:
-
-            * ``0`` - normal
-            * ``1`` - lyrics
-    """
-
-    def __init__(self, xml):
-        """
-        Initialise a theme with data from xml
-
-        ``xml``
-            The data to initialise the theme with
-        """
-        # init to defaults
-        self._set_from_xml(BLANK_STYLE_XML)
-        self._set_from_xml(xml)
-
-    def _get_as_string(self):
-        """
-        Return single line string representation of a theme
-        """
-        theme_strings = []
-        keys = dir(self)
-        keys.sort()
-        for key in keys:
-            if key[0:1] != '_':
-                theme_strings.append('_%s_' % (getattr(self, key)))
-        return ''.join(theme_strings)
-
-    def _set_from_xml(self, xml):
-        """
-        Set theme class attributes with data from XML
-
-        ``xml``
-            The data to apply to the theme
-        """
-        root = ElementTree(element=XML(xml.encode('ascii', 'xmlcharrefreplace')))
-        xml_iter = root.getiterator()
-        for element in xml_iter:
-            delphi_color_change = False
-            if element.tag != 'Theme':
-                element_text = element.text
-                val = 0
-                if element_text is None:
-                    val = element_text
-                # strings need special handling to sort the colours out
-                if isinstance(element_text, str):
-                    if element_text[0] == '$':
-                        # might be a hex number
-                        try:
-                            val = int(element_text[1:], 16)
-                        except ValueError:
-                            # nope
-                            pass
-                    elif element_text in DELPHI_COLORS:
-                        val = DELPHI_COLORS[element_text]
-                        delphi_color_change = True
-                    else:
-                        try:
-                            val = int(element_text)
-                        except ValueError:
-                            val = element_text
-                if (element.tag.find('Color') > 0 or (element.tag.find('BackgroundParameter') == 0 and
-                    isinstance(val, int))):
-                    # convert to a wx.Colour
-                    if not delphi_color_change:
-                        val = QtGui.QColor(val & 0xFF, (val >> 8) & 0xFF, (val >> 16) & 0xFF)
-                    else:
-                        val = QtGui.QColor((val >> 16) & 0xFF, (val >> 8) & 0xFF, val & 0xFF)
-                setattr(self, element.tag, val)
-
-    def __str__(self):
-        """
-        Provide Python string representation for the class (multiline output)
-        """
-        theme_strings = []
-        for key in dir(self):
-            if key[0:1] != '_':
-                theme_strings.append('%30s : %s' % (key, getattr(self, key)))
-        return '\n'.join(theme_strings)

=== modified file 'openlp/core/ui/__init__.py'
--- openlp/core/ui/__init__.py	2013-09-01 06:31:09 +0000
+++ openlp/core/ui/__init__.py	2013-10-13 17:03:19 +0000
@@ -99,10 +99,11 @@
 from .shortcutlistform import ShortcutListForm
 from .mediadockmanager import MediaDockManager
 from .servicemanager import ServiceManager
+from .thememanagerhelper import ThemeManagerHelper
 from .thememanager import ThemeManager
 
 __all__ = ['SplashScreen', 'AboutForm', 'SettingsForm', 'MainDisplay', 'SlideController', 'ServiceManager',
     'ThemeManager', 'MediaDockManager', 'ServiceItemEditForm', 'FirstTimeForm', 'FirstTimeLanguageForm', 'ThemeForm',
     'ThemeLayoutForm', 'FileRenameForm', 'StartTimeForm', 'MainDisplay', 'Display', 'ServiceNoteForm',
     'SlideController', 'DisplayController', 'GeneralTab', 'ThemesTab', 'AdvancedTab', 'PluginForm',
-    'FormattingTagForm', 'ShortcutListForm', 'FormattingTagController']
+    'FormattingTagForm', 'ShortcutListForm', 'FormattingTagController', 'ThemeManagerHelper']

=== modified file 'openlp/core/ui/advancedtab.py'
--- openlp/core/ui/advancedtab.py	2013-08-31 18:17:38 +0000
+++ openlp/core/ui/advancedtab.py	2013-10-13 17:03:19 +0000
@@ -36,8 +36,9 @@
 
 from PyQt4 import QtCore, QtGui
 
+from openlp.core.common import AppLocation
 from openlp.core.lib import SettingsTab, Settings, UiStrings, translate, build_icon
-from openlp.core.utils import AppLocation, format_time, get_images_filter
+from openlp.core.utils import format_time, get_images_filter
 from openlp.core.lib import SlideLimits
 
 log = logging.getLogger(__name__)

=== modified file 'openlp/core/ui/firsttimeform.py'
--- openlp/core/ui/firsttimeform.py	2013-08-31 18:17:38 +0000
+++ openlp/core/ui/firsttimeform.py	2013-10-13 17:03:19 +0000
@@ -41,8 +41,9 @@
 
 from PyQt4 import QtCore, QtGui
 
+from openlp.core.common import AppLocation
 from openlp.core.lib import PluginStatus, Settings, Registry, build_icon, check_directory_exists, translate
-from openlp.core.utils import AppLocation, get_web_page
+from openlp.core.utils import get_web_page
 from .firsttimewizard import Ui_FirstTimeWizard, FirstTimePage
 
 log = logging.getLogger(__name__)

=== modified file 'openlp/core/ui/mainwindow.py'
--- openlp/core/ui/mainwindow.py	2013-08-31 18:17:38 +0000
+++ openlp/core/ui/mainwindow.py	2013-10-13 17:03:19 +0000
@@ -46,8 +46,10 @@
 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
 from openlp.core.ui.media import MediaController
-from openlp.core.utils import AppLocation, LanguageManager, add_actions, get_application_version
+from openlp.core.utils import LanguageManager, add_actions, get_application_version
 from openlp.core.utils.actions import ActionList, CategoryOrder
 from openlp.core.ui.firsttimeform import FirstTimeForm
 

=== modified file 'openlp/core/ui/media/mediacontroller.py'
--- openlp/core/ui/media/mediacontroller.py	2013-08-31 18:17:38 +0000
+++ openlp/core/ui/media/mediacontroller.py	2013-10-13 17:03:19 +0000
@@ -39,7 +39,7 @@
 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
-from openlp.core.utils import AppLocation
+from openlp.core.common import AppLocation
 from openlp.core.ui import DisplayControllerType
 
 log = logging.getLogger(__name__)

=== modified file 'openlp/core/ui/printserviceform.py'
--- openlp/core/ui/printserviceform.py	2013-08-31 18:17:38 +0000
+++ openlp/core/ui/printserviceform.py	2013-10-13 17:03:19 +0000
@@ -38,7 +38,7 @@
 
 from openlp.core.lib import Settings, UiStrings, Registry, translate, get_text_file_string
 from openlp.core.ui.printservicedialog import Ui_PrintServiceDialog, ZoomSize
-from openlp.core.utils import AppLocation
+from openlp.core.common import AppLocation
 
 DEFAULT_CSS = """/*
 Edit this file to customize the service order print. Note, that not all CSS

=== modified file 'openlp/core/ui/servicemanager.py'
--- openlp/core/ui/servicemanager.py	2013-09-07 07:52:52 +0000
+++ openlp/core/ui/servicemanager.py	2013-10-13 17:03:19 +0000
@@ -42,13 +42,14 @@
 
 from PyQt4 import QtCore, QtGui
 
+from openlp.core.common import AppLocation
 from openlp.core.lib import OpenLPToolbar, ServiceItem, ItemCapabilities, Settings, PluginStatus, Registry, \
     UiStrings, build_icon, translate, str_to_bool, check_directory_exists
 from openlp.core.lib.theme import ThemeLevel
 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
-from openlp.core.utils import AppLocation, delete_file, split_filename, format_time
+from openlp.core.utils import delete_file, split_filename, format_time
 from openlp.core.utils.actions import ActionList, CategoryOrder
 
 

=== modified file 'openlp/core/ui/thememanager.py'
--- openlp/core/ui/thememanager.py	2013-08-31 18:17:38 +0000
+++ openlp/core/ui/thememanager.py	2013-10-13 17:03:19 +0000
@@ -38,18 +38,18 @@
 from xml.etree.ElementTree import ElementTree, XML
 from PyQt4 import QtCore, QtGui
 
+from openlp.core.common import AppLocation
 from openlp.core.lib import ImageSource, OpenLPToolbar, Registry, Settings, UiStrings, get_text_file_string, \
     build_icon, translate, check_item_selected, check_directory_exists, create_thumb, validate_thumb
-from openlp.core.lib.theme import ThemeXML, BackgroundType, VerticalType, BackgroundGradientType
+from openlp.core.lib.theme import ThemeXML, BackgroundType
 from openlp.core.lib.ui import critical_error_message_box, create_widget_action
-from openlp.core.theme import Theme
-from openlp.core.ui import FileRenameForm, ThemeForm
-from openlp.core.utils import AppLocation, delete_file, get_locale_key, get_filesystem_encoding
+from openlp.core.ui import FileRenameForm, ThemeForm, ThemeManagerHelper
+from openlp.core.utils import delete_file, get_locale_key, get_filesystem_encoding
 
 log = logging.getLogger(__name__)
 
 
-class ThemeManager(QtGui.QWidget):
+class ThemeManager(QtGui.QWidget, ThemeManagerHelper):
     """
     Manages the orders of Theme.
     """
@@ -328,8 +328,8 @@
         try:
             encoding = get_filesystem_encoding()
             shutil.rmtree(os.path.join(self.path, theme).encode(encoding))
-        except OSError as xxx_todo_changeme1:
-            shutil.Error = xxx_todo_changeme1
+        except OSError as os_error:
+            shutil.Error = os_error
             log.exception('Error deleting theme %s', theme)
 
     def on_export_theme(self):
@@ -469,7 +469,7 @@
             log.debug('No theme data - using default theme')
             return ThemeXML()
         else:
-            return self._create_theme_fom_Xml(xml, self.path)
+            return self._create_theme_from_Xml(xml, self.path)
 
     def over_write_message_box(self, theme_name):
         """
@@ -501,35 +501,30 @@
                 log.exception('Theme contains "%s" XML files' % len(xml_file))
                 raise Exception('validation')
             xml_tree = ElementTree(element=XML(theme_zip.read(xml_file[0]))).getroot()
-            v1_background = xml_tree.find('BackgroundType')
-            if v1_background is not None:
-                theme_name, file_xml, out_file, abort_import = \
-                    self.unzip_version_122(directory, theme_zip, xml_file[0], xml_tree, v1_background, out_file)
+            theme_name = xml_tree.find('name').text.strip()
+            theme_folder = os.path.join(directory, theme_name)
+            theme_exists = os.path.exists(theme_folder)
+            if theme_exists and not self.over_write_message_box(theme_name):
+                abort_import = True
+                return
             else:
-                theme_name = xml_tree.find('name').text.strip()
-                theme_folder = os.path.join(directory, theme_name)
-                theme_exists = os.path.exists(theme_folder)
-                if theme_exists and not self.over_write_message_box(theme_name):
-                    abort_import = True
-                    return
+                abort_import = False
+            for name in theme_zip.namelist():
+                name = name.replace('/', os.path.sep)
+                split_name = name.split(os.path.sep)
+                if split_name[-1] == '' or len(split_name) == 1:
+                    # is directory or preview file
+                    continue
+                full_name = os.path.join(directory, name)
+                check_directory_exists(os.path.dirname(full_name))
+                if os.path.splitext(name)[1].lower() == '.xml':
+                    file_xml = str(theme_zip.read(name), 'utf-8')
+                    out_file = open(full_name, 'w')
+                    out_file.write(file_xml)
                 else:
-                    abort_import = False
-                for name in theme_zip.namelist():
-                    name = name.replace('/', os.path.sep)
-                    split_name = name.split(os.path.sep)
-                    if split_name[-1] == '' or len(split_name) == 1:
-                        # is directory or preview file
-                        continue
-                    full_name = os.path.join(directory, name)
-                    check_directory_exists(os.path.dirname(full_name))
-                    if os.path.splitext(name)[1].lower() == '.xml':
-                        file_xml = str(theme_zip.read(name), 'utf-8')
-                        out_file = open(full_name, 'w')
-                        out_file.write(file_xml)
-                    else:
-                        out_file = open(full_name, 'wb')
-                        out_file.write(theme_zip.read(name))
-                    out_file.close()
+                    out_file = open(full_name, 'wb')
+                    out_file.write(theme_zip.read(name))
+                out_file.close()
         except (IOError, zipfile.BadZipfile):
             log.exception('Importing theme from zip failed %s' % file_name)
             raise Exception('validation')
@@ -548,7 +543,7 @@
             if not abort_import:
                 # As all files are closed, we can create the Theme.
                 if file_xml:
-                    theme = self._create_theme_fom_Xml(file_xml, self.path)
+                    theme = self._create_theme_from_Xml(file_xml, self.path)
                     self.generate_and_save_image(directory, theme_name, theme)
                 # Only show the error message, when IOError was not raised (in
                 # this case the error message has already been shown).
@@ -558,38 +553,6 @@
                         translate('OpenLP.ThemeManager', 'File is not a valid theme.'))
                     log.exception('Theme file does not contain XML data %s' % file_name)
 
-    def unzip_version_122(self, dir_name, zip_file, xml_file, xml_tree, background, out_file):
-        """
-        Unzip openlp.org 1.2x theme file and upgrade the theme xml. When calling
-        this method, please keep in mind, that some parameters are redundant.
-        """
-        theme_name = xml_tree.find('Name').text.strip()
-        theme_name = self.bad_v1_name_chars.sub('', theme_name)
-        theme_folder = os.path.join(dir_name, theme_name)
-        theme_exists = os.path.exists(theme_folder)
-        if theme_exists and not self.over_write_message_box(theme_name):
-            return '', '', '', True
-        themedir = os.path.join(dir_name, theme_name)
-        check_directory_exists(themedir)
-        file_xml = str(zip_file.read(xml_file), 'utf-8')
-        file_xml = self._migrate_version_122(file_xml)
-        out_file = open(os.path.join(themedir, theme_name + '.xml'), 'w')
-        out_file.write(file_xml.encode('utf-8'))
-        out_file.close()
-        if background.text.strip() == '2':
-            image_name = xml_tree.find('BackgroundParameter1').text.strip()
-            # image file has same extension and is in subfolder
-            image_file = [name for name in zip_file.namelist() if os.path.splitext(name)[1].lower()
-                == os.path.splitext(image_name)[1].lower() and name.find(r'/')]
-            if len(image_file) >= 1:
-                out_file = open(os.path.join(themedir, image_name), 'wb')
-                out_file.write(zip_file.read(image_file[0]))
-                out_file.close()
-            else:
-                log.exception('Theme file does not contain image file "%s"' % image_name.decode('utf-8', 'replace'))
-                raise Exception('validation')
-        return theme_name, file_xml, out_file, False
-
     def check_if_theme_exists(self, theme_name):
         """
         Check if theme already exists and displays error message
@@ -697,7 +660,7 @@
         image = os.path.join(self.path, theme + '.png')
         return image
 
-    def _create_theme_fom_Xml(self, theme_xml, path):
+    def _create_theme_from_Xml(self, theme_xml, path):
         """
         Return a theme object using information parsed from XML
 
@@ -741,55 +704,6 @@
             return True
         return False
 
-    def _migrate_version_122(self, xml_data):
-        """
-        Convert the xml data from version 1 format to the current format.
-
-        New fields are loaded with defaults to provide a complete, working
-        theme containing all compatible customisations from the old theme.
-
-        ``xml_data``
-            Version 1 theme to convert
-        """
-        theme = Theme(xml_data)
-        new_theme = ThemeXML()
-        new_theme.theme_name = self.bad_v1_name_chars.sub('', theme.Name)
-        if theme.BackgroundType == BackgroundType.Solid:
-            new_theme.background_type = BackgroundType.to_string(BackgroundType.Solid)
-            new_theme.background_color = str(theme.BackgroundParameter1.name())
-        elif theme.BackgroundType == BackgroundType.Horizontal:
-            new_theme.background_type = BackgroundType.to_string(BackgroundType.Gradient)
-            new_theme.background_direction = BackgroundGradientType.to_string(BackgroundGradientType.Horizontal)
-            if theme.BackgroundParameter3.name() == 1:
-                new_theme.background_direction = BackgroundGradientType.to_string(BackgroundGradientType.Horizontal)
-            new_theme.background_start_color = str(theme.BackgroundParameter1.name())
-            new_theme.background_end_color = str(theme.BackgroundParameter2.name())
-        elif theme.BackgroundType == BackgroundType.Image:
-            new_theme.background_type = BackgroundType.to_string(BackgroundType.Image)
-            new_theme.background_filename = str(theme.BackgroundParameter1)
-        elif theme.BackgroundType == BackgroundType.Transparent:
-            new_theme.background_type = BackgroundType.to_string(BackgroundType.Transparent)
-        new_theme.font_main_name = theme.FontName
-        new_theme.font_main_color = str(theme.FontColor.name())
-        new_theme.font_main_size = theme.FontProportion * 3
-        new_theme.font_footer_name = theme.FontName
-        new_theme.font_footer_color = str(theme.FontColor.name())
-        new_theme.font_main_shadow = False
-        if theme.Shadow == 1:
-            new_theme.font_main_shadow = True
-            new_theme.font_main_shadow_color = str(theme.ShadowColor.name())
-        if theme.Outline == 1:
-            new_theme.font_main_outline = True
-            new_theme.font_main_outline_color = str(theme.OutlineColor.name())
-        vAlignCorrection = VerticalType.Top
-        if theme.VerticalAlign == 2:
-            vAlignCorrection = VerticalType.Middle
-        elif theme.VerticalAlign == 1:
-            vAlignCorrection = VerticalType.Bottom
-        new_theme.display_horizontal_align = theme.HorizontalAlign
-        new_theme.display_vertical_align = vAlignCorrection
-        return new_theme.extract_xml()
-
     def _get_renderer(self):
         """
         Adds the Renderer to the class dynamically

=== added file 'openlp/core/ui/thememanagerhelper.py'
--- openlp/core/ui/thememanagerhelper.py	1970-01-01 00:00:00 +0000
+++ openlp/core/ui/thememanagerhelper.py	2013-10-13 17:03:19 +0000
@@ -0,0 +1,38 @@
+# -*- 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                          #
+###############################################################################
+"""
+The Theme Controller helps manages adding, deleteing and modifying of themes.
+"""
+
+
+class ThemeManagerHelper(object):
+    """
+    Manages the non ui theme functions.
+    """
+    pass
\ No newline at end of file

=== modified file 'openlp/core/utils/__init__.py'
--- openlp/core/utils/__init__.py	2013-09-09 21:10:40 +0000
+++ openlp/core/utils/__init__.py	2013-10-13 17:03:19 +0000
@@ -37,10 +37,13 @@
 import re
 from subprocess import Popen, PIPE
 import sys
-import urllib.request, urllib.error, urllib.parse
+import urllib.request
+import urllib.error
+import urllib.parse
 
 from PyQt4 import QtGui, QtCore
 
+from openlp.core.common import AppLocation
 from openlp.core.lib import Registry, Settings
 
 
@@ -81,15 +84,6 @@
             Registry().execute('openlp_version_check', '%s' % version)
 
 
-def _get_frozen_path(frozen_option, non_frozen_option):
-    """
-    Return a path based on the system status.
-    """
-    if hasattr(sys, 'frozen') and sys.frozen == 1:
-        return frozen_option
-    return non_frozen_option
-
-
 def get_application_version():
     """
     Returns the application version of the running instance of OpenLP::
@@ -418,18 +412,17 @@
     """
     key = DIGITS_OR_NONDIGITS.findall(string)
     key = [int(part) if part.isdigit() else get_locale_key(part) for part in key]
-    # Python 3 does not support comparision of different types anymore. So make sure, that we do not compare str
+    # Python 3 does not support comparison of different types anymore. So make sure, that we do not compare str
     # and int.
     if string[0].isdigit():
         return [b''] + key
     return key
 
 
-from .applocation import AppLocation
 from .languagemanager import LanguageManager
 from .actions import ActionList
 
 
-__all__ = ['AppLocation', 'ActionList', 'LanguageManager', 'get_application_version', 'check_latest_version',
+__all__ = ['ActionList', 'LanguageManager', 'get_application_version', 'check_latest_version',
     'add_actions', 'get_filesystem_encoding', 'get_web_page', 'get_uno_command', 'get_uno_instance',
     'delete_file', 'clean_filename', 'format_time', 'get_locale_key', 'get_natural_key']

=== removed file 'openlp/core/utils/applocation.py'
--- openlp/core/utils/applocation.py	2013-08-31 18:17:38 +0000
+++ openlp/core/utils/applocation.py	1970-01-01 00:00:00 +0000
@@ -1,174 +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                          #
-###############################################################################
-"""
-The :mod:`openlp.core.utils.applocation` module provides an utility for OpenLP receiving the data path etc.
-"""
-import logging
-import os
-import sys
-
-from openlp.core.lib import Settings
-from openlp.core.utils import _get_frozen_path
-
-
-if sys.platform != 'win32' and sys.platform != 'darwin':
-    try:
-        from xdg import BaseDirectory
-        XDG_BASE_AVAILABLE = True
-    except ImportError:
-        XDG_BASE_AVAILABLE = False
-
-import openlp
-from openlp.core.lib import check_directory_exists
-
-
-log = logging.getLogger(__name__)
-
-
-class AppLocation(object):
-    """
-    The :class:`AppLocation` class is a static class which retrieves a directory based on the directory type.
-    """
-    AppDir = 1
-    DataDir = 2
-    PluginsDir = 3
-    VersionDir = 4
-    CacheDir = 5
-    LanguageDir = 6
-
-    # Base path where data/config/cache dir is located
-    BaseDir = None
-
-    @staticmethod
-    def get_directory(dir_type=AppDir):
-        """
-        Return the appropriate directory according to the directory type.
-
-        ``dir_type``
-            The directory type you want, for instance the data directory. Default *AppLocation.AppDir*
-        """
-        if dir_type == AppLocation.AppDir:
-            return _get_frozen_path(os.path.abspath(os.path.split(sys.argv[0])[0]), os.path.split(openlp.__file__)[0])
-        elif dir_type == AppLocation.PluginsDir:
-            app_path = os.path.abspath(os.path.split(sys.argv[0])[0])
-            return _get_frozen_path(os.path.join(app_path, 'plugins'),
-                os.path.join(os.path.split(openlp.__file__)[0], 'plugins'))
-        elif dir_type == AppLocation.VersionDir:
-            return _get_frozen_path(os.path.abspath(os.path.split(sys.argv[0])[0]), os.path.split(openlp.__file__)[0])
-        elif dir_type == AppLocation.LanguageDir:
-            app_path = _get_frozen_path(os.path.abspath(os.path.split(sys.argv[0])[0]), _get_os_dir_path(dir_type))
-            return os.path.join(app_path, 'i18n')
-        elif dir_type == AppLocation.DataDir and AppLocation.BaseDir:
-            return os.path.join(AppLocation.BaseDir, 'data')
-        else:
-            return _get_os_dir_path(dir_type)
-
-    @staticmethod
-    def get_data_path():
-        """
-        Return the path OpenLP stores all its data under.
-        """
-        # Check if we have a different data location.
-        if Settings().contains('advanced/data path'):
-            path = Settings().value('advanced/data path')
-        else:
-            path = AppLocation.get_directory(AppLocation.DataDir)
-            check_directory_exists(path)
-        return os.path.normpath(path)
-
-    @staticmethod
-    def get_files(section=None, extension=None):
-        """
-        Get a list of files from the data files path.
-
-        ``section``
-            Defaults to *None*. The section of code getting the files - used to load from a section's data subdirectory.
-
-        ``extension``
-            Defaults to *None*. The extension to search for. For example::
-
-                u'.png'
-        """
-        path = AppLocation.get_data_path()
-        if section:
-            path = os.path.join(path, section)
-        try:
-            files = os.listdir(path)
-        except OSError:
-            return []
-        if extension:
-            return [filename for filename in files if extension == os.path.splitext(filename)[1]]
-        else:
-            # no filtering required
-            return files
-
-    @staticmethod
-    def get_section_data_path(section):
-        """
-        Return the path a particular module stores its data under.
-        """
-        data_path = AppLocation.get_data_path()
-        path = os.path.join(data_path, section)
-        check_directory_exists(path)
-        return path
-
-
-def _get_os_dir_path(dir_type):
-    """
-    Return a path based on which OS and environment we are running in.
-    """
-    if sys.platform == 'win32':
-        if dir_type == AppLocation.DataDir:
-            return os.path.join(str(os.getenv('APPDATA')), 'openlp', 'data')
-        elif dir_type == AppLocation.LanguageDir:
-            return os.path.split(openlp.__file__)[0]
-        return os.path.join(str(os.getenv('APPDATA')), 'openlp')
-    elif sys.platform == 'darwin':
-        if dir_type == AppLocation.DataDir:
-            return os.path.join(str(os.getenv('HOME')),
-                                'Library', 'Application Support', 'openlp', 'Data')
-        elif dir_type == AppLocation.LanguageDir:
-            return os.path.split(openlp.__file__)[0]
-        return os.path.join(str(os.getenv('HOME')), 'Library', 'Application Support', 'openlp')
-    else:
-        if dir_type == AppLocation.LanguageDir:
-            for prefix in ['/usr/local', '/usr']:
-                directory = os.path.join(prefix, 'share', 'openlp')
-                if os.path.exists(directory):
-                    return directory
-            return os.path.join('/usr', 'share', 'openlp')
-        if XDG_BASE_AVAILABLE:
-            if dir_type == AppLocation.DataDir:
-                return os.path.join(str(BaseDirectory.xdg_data_home), 'openlp')
-            elif dir_type == AppLocation.CacheDir:
-                return os.path.join(str(BaseDirectory.xdg_cache_home), 'openlp')
-        if dir_type == AppLocation.DataDir:
-            return os.path.join(str(os.getenv('HOME')), '.openlp', 'data')
-        return os.path.join(str(os.getenv('HOME')), '.openlp')
-

=== modified file 'openlp/core/utils/languagemanager.py'
--- openlp/core/utils/languagemanager.py	2013-08-31 18:17:38 +0000
+++ openlp/core/utils/languagemanager.py	2013-10-13 17:03:19 +0000
@@ -35,7 +35,7 @@
 
 from PyQt4 import QtCore, QtGui
 
-from openlp.core.utils import AppLocation
+from openlp.core.common import AppLocation
 from openlp.core.lib import Settings, translate
 
 log = logging.getLogger(__name__)

=== modified file 'openlp/plugins/bibles/forms/bibleimportform.py'
--- openlp/plugins/bibles/forms/bibleimportform.py	2013-08-31 18:17:38 +0000
+++ openlp/plugins/bibles/forms/bibleimportform.py	2013-10-13 17:03:19 +0000
@@ -32,13 +32,14 @@
 import logging
 import os
 
-from PyQt4 import QtCore, QtGui
+from PyQt4 import QtGui
 
+from openlp.core.common import AppLocation
 from openlp.core.lib import Settings, UiStrings, translate
 from openlp.core.lib.db import delete_database
 from openlp.core.lib.ui import critical_error_message_box
 from openlp.core.ui.wizard import OpenLPWizard, WizardStrings
-from openlp.core.utils import AppLocation, get_locale_key
+from openlp.core.utils import get_locale_key
 from openlp.plugins.bibles.lib.manager import BibleFormat
 from openlp.plugins.bibles.lib.db import BiblesResourcesDB, clean_filename
 

=== modified file 'openlp/plugins/bibles/forms/bibleupgradeform.py'
--- openlp/plugins/bibles/forms/bibleupgradeform.py	2013-08-31 18:17:38 +0000
+++ openlp/plugins/bibles/forms/bibleupgradeform.py	2013-10-13 17:03:19 +0000
@@ -36,10 +36,11 @@
 
 from PyQt4 import QtCore, QtGui
 
+from openlp.core.common import AppLocation
 from openlp.core.lib import Registry, Settings, UiStrings, translate, check_directory_exists
 from openlp.core.lib.ui import critical_error_message_box
 from openlp.core.ui.wizard import OpenLPWizard, WizardStrings
-from openlp.core.utils import AppLocation, delete_file
+from openlp.core.utils import delete_file
 from openlp.plugins.bibles.lib.db import BibleDB, BibleMeta, OldBibleDB, BiblesResourcesDB
 from openlp.plugins.bibles.lib.http import BSExtract, BGExtract, CWExtract
 

=== modified file 'openlp/plugins/bibles/lib/db.py'
--- openlp/plugins/bibles/lib/db.py	2013-08-31 18:17:38 +0000
+++ openlp/plugins/bibles/lib/db.py	2013-10-13 17:03:19 +0000
@@ -38,10 +38,11 @@
 from sqlalchemy.orm import class_mapper, mapper, relation
 from sqlalchemy.orm.exc import UnmappedClassError
 
+from openlp.core.common import AppLocation
 from openlp.core.lib import Registry, 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 AppLocation, clean_filename
+from openlp.core.utils import clean_filename
 from . import upgrade
 
 log = logging.getLogger(__name__)

=== modified file 'openlp/plugins/bibles/lib/manager.py'
--- openlp/plugins/bibles/lib/manager.py	2013-08-31 18:17:38 +0000
+++ openlp/plugins/bibles/lib/manager.py	2013-10-13 17:03:19 +0000
@@ -30,8 +30,9 @@
 import logging
 import os
 
+from openlp.core.common import AppLocation
 from openlp.core.lib import Registry, Settings, translate
-from openlp.core.utils import AppLocation, delete_file
+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
 from .csvbible import CSVBible

=== modified file 'openlp/plugins/bibles/lib/osis.py'
--- openlp/plugins/bibles/lib/osis.py	2013-08-31 18:17:38 +0000
+++ openlp/plugins/bibles/lib/osis.py	2013-10-13 17:03:19 +0000
@@ -33,8 +33,8 @@
 import codecs
 import re
 
+from openlp.core.common import AppLocation
 from openlp.core.lib import translate
-from openlp.core.utils import AppLocation
 from openlp.plugins.bibles.lib.db import BibleDB, BiblesResourcesDB
 
 log = logging.getLogger(__name__)

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

=== modified file 'openlp/plugins/media/lib/mediaitem.py'
--- openlp/plugins/media/lib/mediaitem.py	2013-10-02 21:07:20 +0000
+++ openlp/plugins/media/lib/mediaitem.py	2013-10-13 17:03:19 +0000
@@ -32,12 +32,13 @@
 
 from PyQt4 import QtCore, QtGui
 
+from openlp.core.common import AppLocation
 from openlp.core.lib import ItemCapabilities, MediaManagerItem,MediaType, Registry, ServiceItem, ServiceItemContext, \
     Settings, UiStrings, build_icon, check_item_selected, check_directory_exists, translate
 from openlp.core.lib.ui import critical_error_message_box, create_horizontal_adjusting_combo_box
 from openlp.core.ui import DisplayController, Display, DisplayControllerType
 from openlp.core.ui.media import get_media_players, set_media_players
-from openlp.core.utils import AppLocation, get_locale_key
+from openlp.core.utils import get_locale_key
 
 
 log = logging.getLogger(__name__)

=== modified file 'openlp/plugins/presentations/lib/presentationcontroller.py'
--- openlp/plugins/presentations/lib/presentationcontroller.py	2013-08-31 18:17:38 +0000
+++ openlp/plugins/presentations/lib/presentationcontroller.py	2013-10-13 17:03:19 +0000
@@ -33,8 +33,8 @@
 
 from PyQt4 import QtCore
 
+from openlp.core.common import AppLocation
 from openlp.core.lib import Registry, Settings, check_directory_exists, create_thumb, validate_thumb
-from openlp.core.utils import AppLocation
 
 log = logging.getLogger(__name__)
 

=== modified file 'openlp/plugins/presentations/presentationplugin.py'
--- openlp/plugins/presentations/presentationplugin.py	2013-10-02 21:07:20 +0000
+++ openlp/plugins/presentations/presentationplugin.py	2013-10-13 17:03:19 +0000
@@ -35,8 +35,8 @@
 
 from PyQt4 import QtCore
 
+from openlp.core.common import AppLocation
 from openlp.core.lib import Plugin, StringContent, build_icon, translate
-from openlp.core.utils import AppLocation
 from openlp.plugins.presentations.lib import PresentationController, PresentationMediaItem, PresentationTab
 
 

=== modified file 'openlp/plugins/remotes/lib/httprouter.py'
--- openlp/plugins/remotes/lib/httprouter.py	2013-09-28 05:10:44 +0000
+++ openlp/plugins/remotes/lib/httprouter.py	2013-10-13 17:03:19 +0000
@@ -121,12 +121,12 @@
 import urllib.error
 from urllib.parse import urlparse, parse_qs
 
-
 from mako.template import Template
 from PyQt4 import QtCore
 
+from openlp.core.common import AppLocation
 from openlp.core.lib import Registry, Settings, PluginStatus, StringContent, image_to_byte
-from openlp.core.utils import AppLocation, translate
+from openlp.core.utils import translate
 
 log = logging.getLogger(__name__)
 

=== modified file 'openlp/plugins/remotes/lib/httpserver.py'
--- openlp/plugins/remotes/lib/httpserver.py	2013-09-14 21:00:58 +0000
+++ openlp/plugins/remotes/lib/httpserver.py	2013-10-13 17:03:19 +0000
@@ -37,12 +37,11 @@
 import socket
 import os
 import logging
-from urllib.parse import urlparse, parse_qs
 
 from PyQt4 import QtCore
 
+from openlp.core.common import AppLocation
 from openlp.core.lib import Settings
-from openlp.core.utils import AppLocation
 
 from openlp.plugins.remotes.lib import HttpRouter
 

=== modified file 'openlp/plugins/remotes/lib/remotetab.py'
--- openlp/plugins/remotes/lib/remotetab.py	2013-09-28 20:43:00 +0000
+++ openlp/plugins/remotes/lib/remotetab.py	2013-10-13 17:03:19 +0000
@@ -31,9 +31,8 @@
 
 from PyQt4 import QtCore, QtGui, QtNetwork
 
+from openlp.core.common import AppLocation
 from openlp.core.lib import Settings, SettingsTab, translate
-from openlp.core.utils import AppLocation
-
 
 ZERO_URL = '0.0.0.0'
 

=== modified file 'openlp/plugins/songs/forms/duplicatesongremovalform.py'
--- openlp/plugins/songs/forms/duplicatesongremovalform.py	2013-08-31 18:17:38 +0000
+++ openlp/plugins/songs/forms/duplicatesongremovalform.py	2013-10-13 17:03:19 +0000
@@ -37,7 +37,6 @@
 
 from openlp.core.lib import Registry, translate
 from openlp.core.ui.wizard import OpenLPWizard, WizardStrings
-from openlp.core.utils import AppLocation
 from openlp.plugins.songs.lib import delete_song
 from openlp.plugins.songs.lib.db import Song, MediaFile
 from openlp.plugins.songs.forms.songreviewwidget import SongReviewWidget
@@ -45,6 +44,7 @@
 
 log = logging.getLogger(__name__)
 
+
 class DuplicateSongRemovalForm(OpenLPWizard):
     """
     This is the Duplicate Song Removal Wizard. It provides functionality to

=== modified file 'openlp/plugins/songs/forms/editsongform.py'
--- openlp/plugins/songs/forms/editsongform.py	2013-09-01 20:43:22 +0000
+++ openlp/plugins/songs/forms/editsongform.py	2013-10-13 17:03:19 +0000
@@ -38,10 +38,10 @@
 
 from PyQt4 import QtCore, QtGui
 
+from openlp.core.common import AppLocation
 from openlp.core.lib import Registry, PluginStatus, MediaType, UiStrings, translate, create_separated_list, \
     check_directory_exists
 from openlp.core.lib.ui import set_case_insensitive_completer, critical_error_message_box, find_and_set_in_combo_box
-from openlp.core.utils import AppLocation
 from openlp.plugins.songs.lib import VerseType, clean_song
 from openlp.plugins.songs.lib.db import Book, Song, Author, Topic, MediaFile
 from openlp.plugins.songs.lib.ui import SongStrings

=== modified file 'openlp/plugins/songs/lib/__init__.py'
--- openlp/plugins/songs/lib/__init__.py	2013-10-05 05:30:00 +0000
+++ openlp/plugins/songs/lib/__init__.py	2013-10-13 17:03:19 +0000
@@ -36,8 +36,9 @@
 
 from PyQt4 import QtGui
 
+from openlp.core.common import AppLocation
 from openlp.core.lib import translate
-from openlp.core.utils import AppLocation, CONTROL_CHARS
+from openlp.core.utils import CONTROL_CHARS
 from openlp.plugins.songs.lib.db import MediaFile, Song
 from .db import Author
 from .ui import SongStrings

=== modified file 'openlp/plugins/songs/lib/mediaitem.py'
--- openlp/plugins/songs/lib/mediaitem.py	2013-10-02 21:07:20 +0000
+++ openlp/plugins/songs/lib/mediaitem.py	2013-10-13 17:03:19 +0000
@@ -35,10 +35,10 @@
 from PyQt4 import QtCore, QtGui
 from sqlalchemy.sql import or_
 
+from openlp.core.common import AppLocation
 from openlp.core.lib import Registry, MediaManagerItem, ItemCapabilities, PluginStatus, ServiceItemContext, Settings, \
     UiStrings, translate, check_item_selected, create_separated_list, check_directory_exists
 from openlp.core.lib.ui import create_widget_action
-from openlp.core.utils import AppLocation
 from openlp.plugins.songs.forms.editsongform import EditSongForm
 from openlp.plugins.songs.forms.songmaintenanceform import SongMaintenanceForm
 from openlp.plugins.songs.forms.songimportform import SongImportForm

=== modified file 'openlp/plugins/songs/lib/songimport.py'
--- openlp/plugins/songs/lib/songimport.py	2013-08-31 18:17:38 +0000
+++ openlp/plugins/songs/lib/songimport.py	2013-10-13 17:03:19 +0000
@@ -34,9 +34,9 @@
 
 from PyQt4 import QtCore
 
+from openlp.core.common import AppLocation
 from openlp.core.lib import Registry, translate, check_directory_exists
 from openlp.core.ui.wizard import WizardStrings
-from openlp.core.utils import AppLocation
 from openlp.plugins.songs.lib import clean_song, VerseType
 from openlp.plugins.songs.lib.db import Song, Author, Topic, Book, MediaFile
 from openlp.plugins.songs.lib.ui import SongStrings

=== added directory 'tests/functional/openlp_core_common'
=== added file 'tests/functional/openlp_core_common/__init__.py'
--- tests/functional/openlp_core_common/__init__.py	1970-01-01 00:00:00 +0000
+++ tests/functional/openlp_core_common/__init__.py	2013-10-13 17:03:19 +0000
@@ -0,0 +1,1 @@
+__author__ = 'tim'

=== renamed file 'tests/functional/openlp_core_utils/test_applocation.py' => 'tests/functional/openlp_core_common/test_applocation.py'
--- tests/functional/openlp_core_utils/test_applocation.py	2013-09-19 21:02:28 +0000
+++ tests/functional/openlp_core_common/test_applocation.py	2013-10-13 17:03:19 +0000
@@ -32,7 +32,7 @@
 import copy
 from unittest import TestCase
 
-from openlp.core.utils import AppLocation
+from openlp.core.common import AppLocation, get_frozen_path
 from tests.functional import patch
 
 FILE_LIST = ['file1', 'file2', 'file3.txt', 'file4.txt', 'file5.mp3', 'file6.mp3']
@@ -46,10 +46,10 @@
         """
         Test the AppLocation.get_data_path() method
         """
-        with patch('openlp.core.utils.applocation.Settings') as mocked_class, \
-                patch('openlp.core.utils.AppLocation.get_directory') as mocked_get_directory, \
-                patch('openlp.core.utils.applocation.check_directory_exists') as mocked_check_directory_exists, \
-                patch('openlp.core.utils.applocation.os') as mocked_os:
+        with patch('openlp.core.lib.Settings') as mocked_class, \
+                patch('openlp.core.common.AppLocation.get_directory') as mocked_get_directory, \
+                patch('openlp.core.common.applocation.check_directory_exists') as mocked_check_directory_exists, \
+                patch('openlp.core.common.applocation.os') as mocked_os:
             # GIVEN: A mocked out Settings class and a mocked out AppLocation.get_directory()
             mocked_settings = mocked_class.return_value
             mocked_settings.contains.return_value = False
@@ -70,8 +70,8 @@
         """
         Test the AppLocation.get_data_path() method when a custom location is set in the settings
         """
-        with patch('openlp.core.utils.applocation.Settings') as mocked_class,\
-                patch('openlp.core.utils.applocation.os') as mocked_os:
+        with patch('openlp.core.lib.Settings') as mocked_class,\
+                patch('openlp.core.common.applocation.os') as mocked_os:
             # GIVEN: A mocked out Settings class which returns a custom data location
             mocked_settings = mocked_class.return_value
             mocked_settings.contains.return_value = True
@@ -90,8 +90,8 @@
         """
         Test the AppLocation.get_files() method with no parameters passed.
         """
-        with patch('openlp.core.utils.AppLocation.get_data_path') as mocked_get_data_path, \
-                patch('openlp.core.utils.applocation.os.listdir') as mocked_listdir:
+        with patch('openlp.core.common.AppLocation.get_data_path') as mocked_get_data_path, \
+                patch('openlp.core.common.applocation.os.listdir') as mocked_listdir:
             # GIVEN: Our mocked modules/methods.
             mocked_get_data_path.return_value = 'test/dir'
             mocked_listdir.return_value = copy.deepcopy(FILE_LIST)
@@ -106,8 +106,8 @@
         """
         Test the AppLocation.get_files() method with all parameters passed.
         """
-        with patch('openlp.core.utils.AppLocation.get_data_path') as mocked_get_data_path, \
-                patch('openlp.core.utils.applocation.os.listdir') as mocked_listdir:
+        with patch('openlp.core.common.AppLocation.get_data_path') as mocked_get_data_path, \
+                patch('openlp.core.common.applocation.os.listdir') as mocked_listdir:
             # GIVEN: Our mocked modules/methods.
             mocked_get_data_path.return_value = 'test/dir'
             mocked_listdir.return_value = copy.deepcopy(FILE_LIST)
@@ -125,8 +125,8 @@
         """
         Test the AppLocation.get_section_data_path() method
         """
-        with patch('openlp.core.utils.AppLocation.get_data_path') as mocked_get_data_path, \
-                patch('openlp.core.utils.applocation.check_directory_exists') as mocked_check_directory_exists:
+        with patch('openlp.core.common.AppLocation.get_data_path') as mocked_get_data_path, \
+                patch('openlp.core.common.applocation.check_directory_exists') as mocked_check_directory_exists:
             # GIVEN: A mocked out AppLocation.get_data_path()
             mocked_get_data_path.return_value = 'test/dir'
             mocked_check_directory_exists.return_value = True
@@ -143,7 +143,7 @@
         Test the AppLocation.get_directory() method for AppLocation.AppDir
         """
         # GIVEN: A mocked out _get_frozen_path function
-        with patch('openlp.core.utils.applocation._get_frozen_path') as mocked_get_frozen_path:
+        with patch('openlp.core.common.applocation.get_frozen_path') as mocked_get_frozen_path:
             mocked_get_frozen_path.return_value = 'app/dir'
 
             # WHEN: We call AppLocation.get_directory
@@ -157,10 +157,10 @@
         Test the AppLocation.get_directory() method for AppLocation.PluginsDir
         """
         # GIVEN: _get_frozen_path, abspath, split and sys are mocked out
-        with patch('openlp.core.utils.applocation._get_frozen_path') as mocked_get_frozen_path, \
-                patch('openlp.core.utils.applocation.os.path.abspath') as mocked_abspath, \
-                patch('openlp.core.utils.applocation.os.path.split') as mocked_split, \
-                patch('openlp.core.utils.applocation.sys') as mocked_sys:
+        with patch('openlp.core.common.applocation.get_frozen_path') as mocked_get_frozen_path, \
+                patch('openlp.core.common.applocation.os.path.abspath') as mocked_abspath, \
+                patch('openlp.core.common.applocation.os.path.split') as mocked_split, \
+                patch('openlp.core.common.applocation.sys') as mocked_sys:
             mocked_abspath.return_value = 'plugins/dir'
             mocked_split.return_value = ['openlp']
             mocked_get_frozen_path.return_value = 'plugins/dir'
@@ -172,3 +172,31 @@
 
             # THEN: The correct directory should be returned
             self.assertEqual('plugins/dir', directory, 'Directory should be "plugins/dir"')
+
+    def get_frozen_path_in_unfrozen_app_test(self):
+        """
+        Test the _get_frozen_path() function when the application is not frozen (compiled by PyInstaller)
+        """
+        with patch('openlp.core.utils.sys') as mocked_sys:
+            # GIVEN: The sys module "without" a "frozen" attribute
+            mocked_sys.frozen = None
+
+            # WHEN: We call _get_frozen_path() with two parameters
+            frozen_path = get_frozen_path('frozen', 'not frozen')
+
+            # THEN: The non-frozen parameter is returned
+            self.assertEqual('not frozen', frozen_path, '_get_frozen_path should return "not frozen"')
+
+    def get_frozen_path_in_frozen_app_test(self):
+        """
+        Test the get_frozen_path() function when the application is frozen (compiled by PyInstaller)
+        """
+        with patch('openlp.core.common.sys') as mocked_sys:
+            # GIVEN: The sys module *with* a "frozen" attribute
+            mocked_sys.frozen = 1
+
+            # WHEN: We call _get_frozen_path() with two parameters
+            frozen_path = get_frozen_path('frozen', 'not frozen')
+
+            # THEN: The frozen parameter is returned
+            self.assertEqual('frozen', frozen_path, 'Should return "frozen"')
\ No newline at end of file

=== added file 'tests/functional/openlp_core_lib/test_theme.py'
--- tests/functional/openlp_core_lib/test_theme.py	1970-01-01 00:00:00 +0000
+++ tests/functional/openlp_core_lib/test_theme.py	2013-10-13 17:03:19 +0000
@@ -0,0 +1,65 @@
+# -*- 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.theme package.
+"""
+from tests.functional import MagicMock, patch
+from unittest import TestCase
+
+from openlp.core.lib.theme import ThemeXML
+
+
+class TestTheme(TestCase):
+    """
+    Test the functions in the Theme module
+    """
+    def setUp(self):
+        """
+        Create the UI
+        """
+        pass
+
+    def tearDown(self):
+        """
+        Delete all the C++ objects at the end so that we don't have a segfault
+        """
+        pass
+
+    def test_new_theme(self):
+        """
+        Test the theme creation - basic test
+        """
+        # GIVEN: A new theme
+
+        # WHEN: A theme is created
+        default_theme = ThemeXML()
+
+        # THEN: We should get some default behaviours
+        self.assertTrue(default_theme.background_border_color == '#000000', 'The theme should have a black border')
+        self.assertTrue(default_theme.background_type == 'solid', 'There theme should have a solid backgrounds')
\ No newline at end of file

=== modified file 'tests/functional/openlp_core_utils/test_utils.py'
--- tests/functional/openlp_core_utils/test_utils.py	2013-10-05 18:06:23 +0000
+++ tests/functional/openlp_core_utils/test_utils.py	2013-10-13 17:03:19 +0000
@@ -31,7 +31,7 @@
 """
 from unittest import TestCase
 
-from openlp.core.utils import clean_filename, get_filesystem_encoding, _get_frozen_path, get_locale_key, \
+from openlp.core.utils import clean_filename, get_filesystem_encoding, get_locale_key, \
     get_natural_key, split_filename
 from tests.functional import patch
 
@@ -75,34 +75,6 @@
             mocked_getdefaultencoding.assert_called_with()
             self.assertEqual('utf-8', result, 'The result should be "utf-8"')
 
-    def get_frozen_path_in_unfrozen_app_test(self):
-        """
-        Test the _get_frozen_path() function when the application is not frozen (compiled by PyInstaller)
-        """
-        with patch('openlp.core.utils.sys') as mocked_sys:
-            # GIVEN: The sys module "without" a "frozen" attribute
-            mocked_sys.frozen = None
-
-            # WHEN: We call _get_frozen_path() with two parameters
-            frozen_path = _get_frozen_path('frozen', 'not frozen')
-
-            # THEN: The non-frozen parameter is returned
-            self.assertEqual('not frozen', frozen_path, '_get_frozen_path should return "not frozen"')
-
-    def get_frozen_path_in_frozen_app_test(self):
-        """
-        Test the _get_frozen_path() function when the application is frozen (compiled by PyInstaller)
-        """
-        with patch('openlp.core.utils.sys') as mocked_sys:
-            # GIVEN: The sys module *with* a "frozen" attribute
-            mocked_sys.frozen = 1
-
-            # WHEN: We call _get_frozen_path() with two parameters
-            frozen_path = _get_frozen_path('frozen', 'not frozen')
-
-            # THEN: The frozen parameter is returned
-            self.assertEqual('frozen', frozen_path, 'Should return "frozen"')
-
     def split_filename_with_file_path_test(self):
         """
         Test the split_filename() function with a path to a file

=== modified file 'tests/functional/openlp_plugins/remotes/test_remotetab.py'
--- tests/functional/openlp_plugins/remotes/test_remotetab.py	2013-09-19 21:02:28 +0000
+++ tests/functional/openlp_plugins/remotes/test_remotetab.py	2013-10-13 17:03:19 +0000
@@ -105,10 +105,10 @@
         Test the set_urls function with standard defaults
         """
         # GIVEN: A mocked location
-        with patch('openlp.core.utils.applocation.Settings') as mocked_class, \
+        with patch('openlp.core.lib.Settings') as mocked_class, \
                 patch('openlp.core.utils.AppLocation.get_directory') as mocked_get_directory, \
-                patch('openlp.core.utils.applocation.check_directory_exists') as mocked_check_directory_exists, \
-                patch('openlp.core.utils.applocation.os') as mocked_os:
+                patch('openlp.core.common.applocation.check_directory_exists') as mocked_check_directory_exists, \
+                patch('openlp.core.common.applocation.os') as mocked_os:
             # GIVEN: A mocked out Settings class and a mocked out AppLocation.get_directory()
             mocked_settings = mocked_class.return_value
             mocked_settings.contains.return_value = False
@@ -133,10 +133,10 @@
         Test the set_urls function with certificate available
         """
         # GIVEN: A mocked location
-        with patch('openlp.core.utils.applocation.Settings') as mocked_class, \
+        with patch('openlp.core.lib.Settings') as mocked_class, \
                 patch('openlp.core.utils.AppLocation.get_directory') as mocked_get_directory, \
-                patch('openlp.core.utils.applocation.check_directory_exists') as mocked_check_directory_exists, \
-                patch('openlp.core.utils.applocation.os') as mocked_os:
+                patch('openlp.core.common.applocation.check_directory_exists') as mocked_check_directory_exists, \
+                patch('openlp.core.common.applocation.os') as mocked_os:
             # GIVEN: A mocked out Settings class and a mocked out AppLocation.get_directory()
             mocked_settings = mocked_class.return_value
             mocked_settings.contains.return_value = False