← Back to team overview

openlp-core team mailing list archive

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

 

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

Requested reviews:
  Jon Tibble (meths)


Start of Alpha 4 changes.
- Update theme code to allow for "Copy" and "Rename" 
- Amend Context menu to block invalid operations.
- Correct variable names in Themes
- Add Image size cache to speed up rendering.

There will be more Theme work in the coming weeks. This is just the start
-- 
https://code.launchpad.net/~trb143/openlp/alpha4/+merge/36655
Your team OpenLP Core is subscribed to branch lp:openlp.
=== modified file 'openlp/core/lib/__init__.py'
--- openlp/core/lib/__init__.py	2010-09-16 21:19:51 +0000
+++ openlp/core/lib/__init__.py	2010-09-26 12:25:58 +0000
@@ -81,6 +81,9 @@
     u'start html':u'<em>', u'end tag':u'{/it}', u'end html':u'</em>',
     u'protected':True})
 
+# Image image_cache to stop regualar image resizing
+image_cache = {}
+
 def translate(context, text, comment=None):
     """
     A special shortcut method to wrap around the Qt4 translation functions.
@@ -220,7 +223,7 @@
     ``image``
         The image to converted.
     """
-    log.debug(u'image_to_byte')    
+    log.debug(u'image_to_byte')
     byte_array = QtCore.QByteArray()
     # use buffer to store pixmap into byteArray
     buffie = QtCore.QBuffer(byte_array)
@@ -250,7 +253,7 @@
         The background colour defaults to black.
 
     """
-    log.debug(u'resize_image')    
+    log.debug(u'resize_image')
     preview = QtGui.QImage(image)
     if not preview.isNull():
         # Only resize if different size
@@ -258,6 +261,9 @@
             return preview
         preview = preview.scaled(width, height, QtCore.Qt.KeepAspectRatio,
             QtCore.Qt.SmoothTransformation)
+    image_cache_key = u'%s%s%s' % (image, unicode(width), unicode(height))
+    if image_cache_key in image_cache:
+        return image_cache[image_cache_key]
     realw = preview.width()
     realh = preview.height()
     # and move it to the centre of the preview space
@@ -266,6 +272,7 @@
     new_image.fill(background)
     painter = QtGui.QPainter(new_image)
     painter.drawImage((width - realw) / 2, (height - realh) / 2, preview)
+    image_cache[image_cache_key] = new_image
     return new_image
 
 def check_item_selected(list_widget, message):

=== modified file 'openlp/core/lib/htmlbuilder.py'
--- openlp/core/lib/htmlbuilder.py	2010-09-21 22:22:05 +0000
+++ openlp/core/lib/htmlbuilder.py	2010-09-26 12:25:58 +0000
@@ -333,7 +333,7 @@
         build_alert_css(alert, width),
         build_footer_css(item, height),
         build_lyrics_css(item, webkitvers),
-        u'true' if theme and theme.display_slideTransition and islive \
+        u'true' if theme and theme.display_slide_transition and islive \
             else u'false',
         image,
         build_lyrics_html(item, webkitvers))
@@ -370,18 +370,18 @@
                 background = \
                     u'background: ' \
                     u'-webkit-gradient(linear, left top, left bottom, ' \
-                    'from(%s), to(%s))' % (theme.background_startColor,
-                    theme.background_endColor)
+                    'from(%s), to(%s))' % (theme.background_start_color,
+                    theme.background_end_color)
             elif theme.background_direction == u'vertical':
                 background = \
                     u'background: -webkit-gradient(linear, left top, ' \
                     u'right top, from(%s), to(%s))' % \
-                    (theme.background_startColor, theme.background_endColor)
+                    (theme.background_start_color, theme.background_end_color)
             else:
                 background = \
                     u'background: -webkit-gradient(radial, %s 50%%, 100, %s ' \
                     u'50%%, %s, from(%s), to(%s))' % (width, width, width,
-                    theme.background_startColor, theme.background_endColor)
+                    theme.background_start_color, theme.background_end_color)
     return background
 
 def build_lyrics_css(item, webkitvers):
@@ -500,15 +500,15 @@
         Height of the lyrics block
 
     """
-    if theme.display_horizontalAlign == 2:
+    if theme.display_horizontal_align == 2:
         align = u'center'
-    elif theme.display_horizontalAlign == 1:
+    elif theme.display_horizontal_align == 1:
         align = u'right'
     else:
         align = u'left'
-    if theme.display_verticalAlign == 2:
+    if theme.display_vertical_align == 2:
         valign = u'bottom'
-    elif theme.display_verticalAlign == 1:
+    elif theme.display_vertical_align == 1:
         valign = u'middle'
     else:
         valign = u'top'
@@ -576,7 +576,7 @@
     font-size: %spt;
     color: %s;
     text-align: left;
-    white-space:nowrap;    
+    white-space:nowrap;
     """
     theme = item.themedata
     if not theme or not item.footer:

=== modified file 'openlp/core/lib/theme.py'
--- openlp/core/lib/theme.py	2010-09-08 21:55:24 +0000
+++ openlp/core/lib/theme.py	2010-09-26 12:25:58 +0000
@@ -27,6 +27,7 @@
 Provide the theme XML and handling functions for OpenLP v2 themes.
 """
 import os
+import re
 
 from xml.dom.minidom import Document
 from xml.etree.ElementTree import ElementTree, XML
@@ -86,6 +87,13 @@
     Service = 2
     Song = 3
 
+boolean_list = [u'italics', u'override', u'outline', u'shadow', \
+u'slide_transition']
+
+integer_list =[u'proportion', u'line_adjustment', u'x', u'height', u'y', \
+u'width', u'shadow_size', u'outline_size', u'horizontal_align', \
+u'vertical_align', u'wrap_style' ]
+
 class ThemeXML(object):
     """
     A class to encapsulate the Theme XML.
@@ -326,16 +334,14 @@
 
     def dump_xml(self):
         """
-        Dump the XML to file.
+        Dump the XML to file used for debugging
         """
-        # Debugging aid to see what we have
         return self.theme_xml.toprettyxml(indent=u'  ')
 
     def extract_xml(self):
         """
-        Pull out the XML string.
+        Print out the XML string.
         """
-        # Print our newly created XML
         return self.theme_xml.toxml(u'utf-8').decode(u'utf-8')
 
     def extract_formatted_xml(self):
@@ -372,33 +378,37 @@
             if element.getchildren():
                 master = element.tag + u'_'
             else:
-                #background transparent tags have no children so special case
+                # background transparent tags have no children so special case
                 if element.tag == u'background':
                     for e in element.attrib.iteritems():
-                        setattr(self, element.tag + u'_' + e[0], e[1])
+                        self._create_attr(element.tag , e[0], e[1])
             if element.attrib:
                 for e in element.attrib.iteritems():
                     if master == u'font_' and e[0] == u'type':
                         master += e[1] + u'_'
                     elif master == u'display_' and (element.tag == u'shadow' \
                         or element.tag == u'outline' ):
-                        et = str_to_bool(element.text)
-                        setattr(self, master + element.tag, et)
-                        setattr(self, master + element.tag + u'_'+ e[0], e[1])
+                        self._create_attr(master, element.tag, element.text)
+                        self._create_attr(master, element.tag + u'_'+ e[0], e[1])
                     else:
                         field = master + e[0]
-                        if e[1] == u'True' or e[1] == u'False':
-                            setattr(self, field, str_to_bool(e[1]))
-                        else:
-                            setattr(self, field, e[1])
+                        self._create_attr(master, e[0], e[1])
             else:
                 if element.tag:
-                    field = master + element.tag
                     element.text = element.text.strip().lstrip()
-                    if element.text == u'True' or element.text == u'False':
-                        setattr(self, field, str_to_bool(element.text))
-                    else:
-                        setattr(self, field, element.text)
+                    self._create_attr(master , element.tag, element.text)
+
+    def _create_attr(self, master , element, value):
+        """
+        Create the attributes with the correct data types and name format
+        """
+        field = self._de_hump(element)
+        if field in boolean_list:
+            setattr(self, master + field, str_to_bool(value))
+        elif field in integer_list:
+            setattr(self, master + field, int(value))
+        else:
+            setattr(self, master + field, unicode(value))
 
     def __str__(self):
         """
@@ -409,3 +419,11 @@
             if key[0:1] != u'_':
                 theme_strings.append(u'%30s: %s' % (key, getattr(self, key)))
         return u'\n'.join(theme_strings)
+
+    def _de_hump(self, name):
+        """
+        Change Camel Case string to python string
+        """
+        s1 = re.sub(u'(.)([A-Z][a-z]+)', r'\1_\2', name)
+        return re.sub(u'([a-z0-9])([A-Z])', r'\1_\2', s1).lower()
+

=== modified file 'openlp/core/ui/__init__.py'
--- openlp/core/ui/__init__.py	2010-09-04 08:12:54 +0000
+++ openlp/core/ui/__init__.py	2010-09-26 12:25:58 +0000
@@ -37,6 +37,7 @@
     Theme = 2
     Screen = 3
 
+from filerenameform import FileRenameForm
 from maindisplay import MainDisplay
 from slidecontroller import HideMode
 from servicenoteform import ServiceNoteForm

=== modified file 'openlp/core/ui/amendthemeform.py'
--- openlp/core/ui/amendthemeform.py	2010-08-21 08:24:14 +0000
+++ openlp/core/ui/amendthemeform.py	2010-09-26 12:25:58 +0000
@@ -150,8 +150,8 @@
                 unicode(self.theme.background_color))
         elif self.theme.background_type == u'gradient':
             new_theme.add_background_gradient(
-                unicode(self.theme.background_startColor),
-                unicode(self.theme.background_endColor),
+                unicode(self.theme.background_start_color),
+                unicode(self.theme.background_end_color),
                 self.theme.background_direction)
         else:
             filename = \
@@ -185,10 +185,10 @@
                 unicode(self.theme.display_shadow_color),
                 unicode(self.theme.display_outline),
                 unicode(self.theme.display_outline_color),
-                unicode(self.theme.display_horizontalAlign),
-                unicode(self.theme.display_verticalAlign),
-                unicode(self.theme.display_wrapStyle),
-                unicode(self.theme.display_slideTransition),
+                unicode(self.theme.display_horizontal_align),
+                unicode(self.theme.display_vertical_align),
+                unicode(self.theme.display_wrap_style),
+                unicode(self.theme.display_slide_transition),
                 unicode(self.theme.display_shadow_size),
                 unicode(self.theme.display_outline_size))
         theme = new_theme.extract_xml()
@@ -217,7 +217,6 @@
             self.imageLineEdit.setText(filename)
             self.theme.background_filename = filename
             self.previewTheme()
-
     #
     # Main Font Tab
     #
@@ -301,7 +300,6 @@
         if self.theme.font_main_height != self.fontMainHeightSpinBox.value():
             self.theme.font_main_height = self.fontMainHeightSpinBox.value()
             self.previewTheme()
-
     #
     # Footer Font Tab
     #
@@ -382,7 +380,6 @@
             self.theme.font_footer_height = \
                 self.fontFooterHeightSpinBox.value()
             self.previewTheme()
-
     #
     # Background Tab
     #
@@ -407,10 +404,10 @@
                 self.theme.background_direction = u'vertical'
             else:
                 self.theme.background_direction = u'circular'
-            if self.theme.background_startColor is None:
-                self.theme.background_startColor = u'#000000'
-            if self.theme.background_endColor is None:
-                self.theme.background_endColor = u'#ff0000'
+            if self.theme.background_start_color is None:
+                self.theme.background_start_color = u'#000000'
+            if self.theme.background_end_color is None:
+                self.theme.background_end_color = u'#ff0000'
             self.imageLineEdit.setText(u'')
         else:
             self.theme.background_type = u'image'
@@ -427,22 +424,21 @@
                     unicode(self.theme.background_color))
         else:
             new_color = QtGui.QColorDialog.getColor(
-                QtGui.QColor(self.theme.background_startColor), self)
+                QtGui.QColor(self.theme.background_start_color), self)
             if new_color.isValid():
-                self.theme.background_startColor = new_color.name()
+                self.theme.background_start_color = new_color.name()
                 self.color1PushButton.setStyleSheet(u'background-color: %s' %
-                    unicode(self.theme.background_startColor))
+                    unicode(self.theme.background_start_color))
         self.previewTheme()
 
     def onColor2PushButtonClicked(self):
         new_color = QtGui.QColorDialog.getColor(
-            QtGui.QColor(self.theme.background_endColor), self)
+            QtGui.QColor(self.theme.background_end_color), self)
         if new_color.isValid():
-            self.theme.background_endColor = new_color.name()
+            self.theme.background_end_color = new_color.name()
             self.color2PushButton.setStyleSheet(u'background-color: %s' %
-                unicode(self.theme.background_endColor))
+                unicode(self.theme.background_end_color))
             self.previewTheme()
-
     #
     # Other Tab
     #
@@ -483,9 +479,9 @@
 
     def onSlideTransitionCheckBoxChanged(self, value):
         if value == 2:  # checked
-            self.theme.display_slideTransition = True
+            self.theme.display_slide_transition = True
         else:
-            self.theme.display_slideTransition = False
+            self.theme.display_slide_transition = False
         self.stateChanging(self.theme)
         self.previewTheme()
 
@@ -499,15 +495,14 @@
             self.previewTheme()
 
     def onHorizontalComboBoxSelected(self, currentIndex):
-        self.theme.display_horizontalAlign = currentIndex
+        self.theme.display_horizontal_align = currentIndex
         self.stateChanging(self.theme)
         self.previewTheme()
 
     def onVerticalComboBoxSelected(self, currentIndex):
-        self.theme.display_verticalAlign = currentIndex
+        self.theme.display_vertical_align = currentIndex
         self.stateChanging(self.theme)
         self.previewTheme()
-
     #
     # Local Methods
     #
@@ -598,13 +593,13 @@
             self.shadowCheckBox.setChecked(False)
             self.shadowColorPushButton.setEnabled(False)
         self.shadowSpinBox.setValue(int(self.theme.display_shadow_size))
-        if self.theme.display_slideTransition:
+        if self.theme.display_slide_transition:
             self.slideTransitionCheckBox.setCheckState(QtCore.Qt.Checked)
         else:
             self.slideTransitionCheckBox.setCheckState(QtCore.Qt.Unchecked)
         self.horizontalComboBox.setCurrentIndex(
-            self.theme.display_horizontalAlign)
-        self.verticalComboBox.setCurrentIndex(self.theme.display_verticalAlign)
+            self.theme.display_horizontal_align)
+        self.verticalComboBox.setCurrentIndex(self.theme.display_vertical_align)
 
     def stateChanging(self, theme):
         self.backgroundTypeComboBox.setVisible(True)
@@ -625,9 +620,9 @@
             self.gradientComboBox.setVisible(False)
         elif theme.background_type == u'gradient':
             self.color1PushButton.setStyleSheet(u'background-color: %s' \
-                % unicode(theme.background_startColor))
+                % unicode(theme.background_start_color))
             self.color2PushButton.setStyleSheet(u'background-color: %s' \
-                % unicode(theme.background_endColor))
+                % unicode(theme.background_end_color))
             self.color1Label.setText(
                 translate('OpenLP.AmendThemeForm', 'First color:'))
             self.color2Label.setText(

=== modified file 'openlp/core/ui/exceptionform.py'
--- openlp/core/ui/exceptionform.py	2010-09-07 20:42:33 +0000
+++ openlp/core/ui/exceptionform.py	2010-09-26 12:25:58 +0000
@@ -27,7 +27,6 @@
 from PyQt4 import QtCore, QtGui
 
 from exceptiondialog import Ui_ExceptionDialog
-from openlp.core.lib import translate
 
 class ExceptionForm(QtGui.QDialog, Ui_ExceptionDialog):
     """

=== added file 'openlp/core/ui/filerenamedialog.py'
--- openlp/core/ui/filerenamedialog.py	1970-01-01 00:00:00 +0000
+++ openlp/core/ui/filerenamedialog.py	2010-09-26 12:25:58 +0000
@@ -0,0 +1,59 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection                                      #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2010 Raoul Snyman                                        #
+# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael      #
+# Gorven, Scott Guerrieri, Meinert Jordan, Andreas Preikschat, Christian      #
+# Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon Tibble,    #
+# Carsten Tinggaard, Frode Woldsund                                           #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it     #
+# under the terms of the GNU General Public License as published by the Free  #
+# Software Foundation; version 2 of the License.                              #
+#                                                                             #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for    #
+# more details.                                                               #
+#                                                                             #
+# You should have received a copy of the GNU General Public License along     #
+# with this program; if not, write to the Free Software Foundation, Inc., 59  #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA                          #
+###############################################################################
+
+from PyQt4 import QtCore, QtGui
+
+from openlp.core.lib import translate
+
+class Ui_FileRenameDialog(object):
+    def setupUi(self, FileRenameDialog):
+        FileRenameDialog.setObjectName("FileRenameDialog")
+        FileRenameDialog.resize(400, 87)
+        self.buttonBox = QtGui.QDialogButtonBox(FileRenameDialog)
+        self.buttonBox.setGeometry(QtCore.QRect(210, 50, 171, 25))
+        self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok)
+        self.buttonBox.setObjectName("buttonBox")
+        self.widget = QtGui.QWidget(FileRenameDialog)
+        self.widget.setGeometry(QtCore.QRect(10, 10, 381, 35))
+        self.widget.setObjectName("widget")
+        self.horizontalLayout = QtGui.QHBoxLayout(self.widget)
+        self.horizontalLayout.setObjectName("horizontalLayout")
+        self.FileRenameLabel = QtGui.QLabel(self.widget)
+        self.FileRenameLabel.setObjectName("FileRenameLabel")
+        self.horizontalLayout.addWidget(self.FileRenameLabel)
+        self.FileNameEdit = QtGui.QLineEdit(self.widget)
+        self.FileNameEdit.setObjectName("FileNameEdit")
+        self.horizontalLayout.addWidget(self.FileNameEdit)
+
+        self.retranslateUi(FileRenameDialog)
+        QtCore.QMetaObject.connectSlotsByName(FileRenameDialog)
+
+    def retranslateUi(self, FileRenameDialog):
+        FileRenameDialog.setWindowTitle(self.transitionGroupBox.setTitle(
+            translate('OpenLP.FileRenameForm', 'File Rename')))
+        self.FileRenameLabel.setText(translate('OpenLP.FileRenameForm',
+            'New File Name:'))
+

=== added file 'openlp/core/ui/filerenameform.py'
--- openlp/core/ui/filerenameform.py	1970-01-01 00:00:00 +0000
+++ openlp/core/ui/filerenameform.py	2010-09-26 12:25:58 +0000
@@ -0,0 +1,42 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection                                      #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2010 Raoul Snyman                                        #
+# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael      #
+# Gorven, Scott Guerrieri, Meinert Jordan, Andreas Preikschat, Christian      #
+# Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon Tibble,    #
+# Carsten Tinggaard, Frode Woldsund                                           #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it     #
+# under the terms of the GNU General Public License as published by the Free  #
+# Software Foundation; version 2 of the License.                              #
+#                                                                             #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for    #
+# more details.                                                               #
+#                                                                             #
+# You should have received a copy of the GNU General Public License along     #
+# with this program; if not, write to the Free Software Foundation, Inc., 59  #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA                          #
+###############################################################################
+
+from PyQt4 import QtCore, QtGui
+
+from filerenamedialog import Ui_FileRenameDialog
+from openlp.core.lib import translate
+
+class FileRenameForm(QtGui.QDialog, Ui_FileRenameDialog):
+    """
+    The exception dialog
+    """
+    def __init__(self, parent):
+        QtGui.QDialog.__init__(self, parent)
+        self.setupUi(self)
+        QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(u'accepted()'),
+            self.accept)
+        QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(u'rejected()'),
+            self.reject)

=== modified file 'openlp/core/ui/maindisplay.py'
--- openlp/core/ui/maindisplay.py	2010-09-25 06:29:03 +0000
+++ openlp/core/ui/maindisplay.py	2010-09-26 12:25:58 +0000
@@ -324,7 +324,7 @@
             # Wait for the fade to finish before geting the preview.
             # Important otherwise preview will have incorrect text if at all !
             if self.serviceItem.themedata and \
-                self.serviceItem.themedata.display_slideTransition:
+                self.serviceItem.themedata.display_slide_transition:
                 while self.frame.evaluateJavaScript(u'show_text_complete()') \
                     .toString() == u'false':
                     Receiver.send_message(u'openlp_process_events')

=== modified file 'openlp/core/ui/servicemanager.py'
--- openlp/core/ui/servicemanager.py	2010-09-23 16:45:17 +0000
+++ openlp/core/ui/servicemanager.py	2010-09-26 12:25:58 +0000
@@ -236,7 +236,7 @@
         self.addToAction = self.dndMenu.addAction(
             translate('OpenLP.ServiceManager', '&Add to Selected Item'))
         self.addToAction.setIcon(build_icon(u':/general/general_edit.png'))
-        #build the context menu
+        # build the context menu
         self.menu = QtGui.QMenu()
         self.editAction = self.menu.addAction(
             translate('OpenLP.ServiceManager', '&Edit Item'))

=== modified file 'openlp/core/ui/thememanager.py'
--- openlp/core/ui/thememanager.py	2010-09-18 15:24:39 +0000
+++ openlp/core/ui/thememanager.py	2010-09-26 12:25:58 +0000
@@ -32,7 +32,7 @@
 from xml.etree.ElementTree import ElementTree, XML
 from PyQt4 import QtCore, QtGui
 
-from openlp.core.ui import AmendThemeForm
+from openlp.core.ui import AmendThemeForm, FileRenameForm
 from openlp.core.theme import Theme
 from openlp.core.lib import OpenLPToolbar, context_menu_action, \
     ThemeXML, str_to_bool, get_text_file_string, build_icon, Receiver, \
@@ -54,6 +54,7 @@
         self.layout.setSpacing(0)
         self.layout.setMargin(0)
         self.amendThemeForm = AmendThemeForm(self)
+        self.fileRenameForm = FileRenameForm(self)
         self.toolbar = OpenLPToolbar(self)
         self.toolbar.addToolbarButton(
             translate('OpenLP.ThemeManager', 'New Theme'),
@@ -87,31 +88,32 @@
         self.themeListWidget.setAlternatingRowColors(True)
         self.themeListWidget.setIconSize(QtCore.QSize(88, 50))
         self.layout.addWidget(self.themeListWidget)
-        self.themeListWidget.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
-        self.themeListWidget.addAction(
-            context_menu_action(self.themeListWidget,
-            u':/themes/theme_edit.png',
-            translate('OpenLP.ThemeManager', '&Edit Theme'),
-            self.onEditTheme))
-        self.themeListWidget.addAction(
-            context_menu_separator(self.themeListWidget))
-        self.themeListWidget.addAction(
-            context_menu_action(self.themeListWidget,
-                u':/general/general_delete.png',
-                translate('OpenLP.ThemeManager', '&Delete Theme'),
-            self.onDeleteTheme))
-        self.themeListWidget.addAction(
-            context_menu_action(self.themeListWidget,
-                u':/general/general_export.png',
-                translate('OpenLP.ThemeManager', 'Set As &Global Default'),
-            self.changeGlobalFromScreen))
-        self.themeListWidget.addAction(
-            context_menu_action(self.themeListWidget,
-                u':/general/general_export.png',
-                translate('OpenLP.ThemeManager', 'E&xport Theme'),
-                self.onExportTheme))
-        self.themeListWidget.addAction(
-            context_menu_separator(self.themeListWidget))
+        self.themeListWidget.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
+        QtCore.QObject.connect(self.themeListWidget,
+            QtCore.SIGNAL('customContextMenuRequested(QPoint)'),
+            self.contextMenu)
+        # build the context menu
+        self.menu = QtGui.QMenu()
+        self.editAction = self.menu.addAction(
+            translate('OpenLP.ThemeManager', '&Edit Theme'))
+        self.editAction.setIcon(build_icon(u':/themes/theme_edit.png'))
+        self.copyAction = self.menu.addAction(
+            translate('OpenLP.ThemeManager', '&Copy Theme'))
+        self.copyAction.setIcon(build_icon(u':/themes/theme_edit.png'))
+        self.renameAction = self.menu.addAction(
+            translate('OpenLP.ThemeManager', '&Rename Theme'))
+        self.renameAction.setIcon(build_icon(u':/themes/theme_edit.png'))
+        self.deleteAction = self.menu.addAction(
+            translate('OpenLP.ThemeManager', '&Delete Theme'))
+        self.deleteAction.setIcon(build_icon(u':/general/general_delete.png'))
+        self.sep1 = self.menu.addAction(u'')
+        self.sep1.setSeparator(True)
+        self.globalAction = self.menu.addAction(
+            translate('OpenLP.ThemeManager', 'Set As &Global Default'))
+        self.globalAction.setIcon(build_icon(u':/general/general_export.png'))
+        self.exportAction = self.menu.addAction(
+            translate('OpenLP.ThemeManager', '&Export Theme'))
+        self.exportAction.setIcon(build_icon(u':/general/general_export.png'))
         #Signals
         QtCore.QObject.connect(self.themeListWidget,
             QtCore.SIGNAL(u'doubleClicked(QModelIndex)'),
@@ -132,6 +134,34 @@
             self.settingsSection + u'/global theme',
             QtCore.QVariant(u'')).toString())
 
+    def contextMenu(self, point):
+        item = self.themeListWidget.itemAt(point)
+        if item is None:
+            return
+        realThemeName = unicode(item.data(QtCore.Qt.UserRole).toString())
+        themeName = unicode(item.text())
+        self.deleteAction.setVisible(False)
+        self.renameAction.setVisible(False)
+        self.globalAction.setVisible(False)
+        # If default theme restrict actions
+        if realThemeName == themeName:
+            self.deleteAction.setVisible(True)
+            self.renameAction.setVisible(True)
+            self.globalAction.setVisible(True)
+        action = self.menu.exec_(self.themeListWidget.mapToGlobal(point))
+        if action == self.editAction:
+            self.onEditTheme()
+        if action == self.copyAction:
+            self.onCopyTheme()
+        if action == self.renameAction:
+            self.onRenameTheme()
+        if action == self.deleteAction:
+            self.onDeleteTheme()
+        if action == self.globalAction:
+            self.changeGlobalFromScreen()
+        if action == self.exportAction:
+            self.onExportTheme()
+
     def changeGlobalFromTab(self, themeName):
         """
         Change the global theme when it is changed through the Themes settings
@@ -189,6 +219,92 @@
         self.saveThemeName = u''
         self.amendThemeForm.exec_()
 
+    def onRenameTheme(self):
+        """
+        Renames an existing theme to a new name
+        """
+        item = self.themeListWidget.currentItem()
+        oldThemeName = unicode(item.data(QtCore.Qt.UserRole).toString())
+        self.fileRenameForm.FileNameEdit.setText(oldThemeName)
+        self.saveThemeName = u''
+        if self.fileRenameForm.exec_():
+            newThemeName =  unicode(self.fileRenameForm.FileNameEdit.text())
+            oldThemeData = self.getThemeData(oldThemeName)
+            self.deleteTheme(oldThemeName)
+            self.cloneThemeData(oldThemeData, newThemeName)
+
+    def onCopyTheme(self):
+        """
+        Copies an existing theme to a new name
+        """
+        item = self.themeListWidget.currentItem()
+        oldThemeName = unicode(item.data(QtCore.Qt.UserRole).toString())
+        self.fileRenameForm.FileNameEdit.setText(oldThemeName)
+        self.saveThemeName = u''
+        if self.fileRenameForm.exec_():
+            newThemeName =  unicode(self.fileRenameForm.FileNameEdit.text())
+            oldThemeData = self.getThemeData(oldThemeName)
+            self.cloneThemeData(oldThemeData, newThemeName)
+            self.loadThemes()
+
+    def cloneThemeData(self, oldThemeData, newThemeName):
+        """
+        """
+        log.debug(u'cloneThemeData')
+        new_theme = ThemeXML()
+        new_theme.new_document(newThemeName)
+        save_from = None
+        save_to = None
+        if oldThemeData.background_type == u'solid':
+            new_theme.add_background_solid(
+                unicode(oldThemeData.background_color))
+        elif oldThemeData.background_type == u'gradient':
+            new_theme.add_background_gradient(
+                unicode(oldThemeData.background_start_color),
+                unicode(oldThemeData.background_end_color),
+                oldThemeData.background_direction)
+        else:
+            filename = \
+                os.path.split(unicode(oldThemeData.background_filename))[1]
+            new_theme.add_background_image(filename)
+            save_to = os.path.join(self.path, theme_name, filename)
+            save_from = oldThemeData.background_filename
+        new_theme.add_font(unicode(oldThemeData.font_main_name),
+            unicode(oldThemeData.font_main_color),
+            unicode(oldThemeData.font_main_proportion),
+            unicode(oldThemeData.font_main_override), u'main',
+            unicode(oldThemeData.font_main_weight),
+            unicode(oldThemeData.font_main_italics),
+            unicode(oldThemeData.font_main_line_adjustment),
+            unicode(oldThemeData.font_main_x),
+            unicode(oldThemeData.font_main_y),
+            unicode(oldThemeData.font_main_width),
+            unicode(oldThemeData.font_main_height))
+        new_theme.add_font(unicode(oldThemeData.font_footer_name),
+            unicode(oldThemeData.font_footer_color),
+            unicode(oldThemeData.font_footer_proportion),
+            unicode(oldThemeData.font_footer_override), u'footer',
+            unicode(oldThemeData.font_footer_weight),
+            unicode(oldThemeData.font_footer_italics),
+            0, # line adjustment
+            unicode(oldThemeData.font_footer_x),
+            unicode(oldThemeData.font_footer_y),
+            unicode(oldThemeData.font_footer_width),
+            unicode(oldThemeData.font_footer_height))
+        new_theme.add_display(unicode(oldThemeData.display_shadow),
+            unicode(oldThemeData.display_shadow_color),
+            unicode(oldThemeData.display_outline),
+            unicode(oldThemeData.display_outline_color),
+            unicode(oldThemeData.display_horizontal_align),
+            unicode(oldThemeData.display_vertical_align),
+            unicode(oldThemeData.display_wrap_style),
+            unicode(oldThemeData.display_slide_transition),
+            unicode(oldThemeData.display_shadow_size),
+            unicode(oldThemeData.display_outline_size))
+        theme = new_theme.extract_xml()
+        pretty_theme = new_theme.extract_formatted_xml()
+        self.saveTheme(newThemeName, theme, pretty_theme, save_from, save_to)
+
     def onEditTheme(self):
         """
         Loads the settings for the theme that is to be edited and launches the
@@ -462,11 +578,7 @@
                                 log.exception(u'Theme XML is not UTF-8 '
                                     u'encoded.')
                                 break
-                            if self.checkVersion1(xml_data):
-                                # upgrade theme xml
-                                filexml = self.migrateVersion122(xml_data)
-                            else:
-                                filexml = xml_data
+                            filexml = self.checkVersionAndConvert(xml_data)
                             outfile = open(fullpath, u'w')
                             outfile.write(filexml.encode(u'utf-8'))
                         else:
@@ -492,20 +604,21 @@
             if outfile:
                 outfile.close()
 
-    def checkVersion1(self, xmlfile):
+    def checkVersionAndConvert(self, xml_data):
         """
         Check if a theme is from OpenLP version 1
 
-        ``xmlfile``
+        ``xml_data``
             Theme XML to check the version of
         """
         log.debug(u'checkVersion1 ')
-        theme = xmlfile.encode(u'ascii', u'xmlcharrefreplace')
+        theme = xml_data.encode(u'ascii', u'xmlcharrefreplace')
         tree = ElementTree(element=XML(theme)).getroot()
+        # look for old version 1 tags
         if tree.find(u'BackgroundType') is None:
-            return False
+            return xml_data
         else:
-            return True
+            return self.migrateVersion122(xml_data)
 
     def migrateVersion122(self, xml_data):
         """
@@ -699,61 +812,5 @@
         """
         theme = ThemeXML()
         theme.parse(theme_xml)
-        self.cleanTheme(theme)
         theme.extend_image_filename(path)
         return theme
-
-    def cleanTheme(self, theme):
-        """
-        Clean a theme loaded from an XML file by removing stray whitespace and
-        making sure parameters are the correct type for the theme object
-        attributes
-        """
-        theme.background_color = theme.background_color.strip()
-        theme.background_direction = theme.background_direction.strip()
-        theme.background_endColor = theme.background_endColor.strip()
-        if theme.background_filename:
-            theme.background_filename = theme.background_filename.strip()
-        #theme.background_mode
-        theme.background_startColor = theme.background_startColor.strip()
-        #theme.background_type
-        if theme.display_display:
-            theme.display_display = theme.display_display.strip()
-        theme.display_horizontalAlign = \
-            int(theme.display_horizontalAlign.strip())
-        theme.display_outline = str_to_bool(theme.display_outline)
-        #theme.display_outline_color
-        theme.display_shadow = str_to_bool(theme.display_shadow)
-        #theme.display_shadow_color
-        theme.display_verticalAlign = int(theme.display_verticalAlign.strip())
-        theme.display_wrapStyle = theme.display_wrapStyle.strip()
-        theme.display_slideTransition = theme.display_slideTransition
-        theme.font_footer_color = theme.font_footer_color.strip()
-        theme.font_footer_height = int(theme.font_footer_height.strip())
-        theme.font_footer_italics = str_to_bool(theme.font_footer_italics)
-        theme.font_footer_name = theme.font_footer_name.strip()
-        #theme.font_footer_override
-        theme.font_footer_proportion = \
-            int(theme.font_footer_proportion.strip())
-        theme.font_footer_weight = theme.font_footer_weight.strip()
-        theme.font_footer_width = int(theme.font_footer_width.strip())
-        theme.font_footer_x = int(theme.font_footer_x.strip())
-        theme.font_footer_y = int(theme.font_footer_y.strip())
-        theme.font_main_color = theme.font_main_color.strip()
-        theme.font_main_height = int(theme.font_main_height.strip())
-        theme.font_main_italics = str_to_bool(theme.font_main_italics)
-        theme.font_main_name = theme.font_main_name.strip()
-        #theme.font_main_override
-        theme.font_main_proportion = int(theme.font_main_proportion.strip())
-        theme.font_main_weight = theme.font_main_weight.strip()
-        theme.font_main_width = int(theme.font_main_width.strip())
-        theme.font_main_x = int(theme.font_main_x.strip())
-        theme.font_main_y = int(theme.font_main_y.strip())
-        #theme.theme_mode
-        theme.theme_name = theme.theme_name.strip()
-        #theme.theme_version
-        # Remove the Transparent settings as they are not relevent
-        if theme.background_mode == u'transparent':
-            theme.background_mode = u'opaque'
-            theme.background_type = u'solid'
-            theme.background_startColor = u'#000000'

=== modified file 'openlp/plugins/images/imageplugin.py'
--- openlp/plugins/images/imageplugin.py	2010-09-21 17:30:32 +0000
+++ openlp/plugins/images/imageplugin.py	2010-09-26 12:25:58 +0000
@@ -35,7 +35,7 @@
     log.info(u'Image Plugin loaded')
 
     def __init__(self, plugin_helpers):
-        Plugin.__init__(self, u'Images', u'1.9.3', plugin_helpers)
+        Plugin.__init__(self, u'Images', u'1.9.4', plugin_helpers)
         self.weight = -7
         self.icon_path = u':/plugins/plugin_images.png'
         self.icon = build_icon(self.icon_path)

=== modified file 'openlp/plugins/images/lib/mediaitem.py'
--- openlp/plugins/images/lib/mediaitem.py	2010-07-28 17:21:32 +0000
+++ openlp/plugins/images/lib/mediaitem.py	2010-09-26 12:25:58 +0000
@@ -187,8 +187,7 @@
             for item in items:
                 bitem = self.listView.item(item.row())
                 filename = unicode(bitem.data(QtCore.Qt.UserRole).toString())
-                frame = QtGui.QImage(unicode(filename))
-                self.parent.liveController.display.image(frame)
+                self.parent.liveController.display.image(filename)
         self.resetButton.setVisible(True)
 
     def onPreviewClick(self):

=== modified file 'openlp/plugins/songs/songsplugin.py'
--- openlp/plugins/songs/songsplugin.py	2010-09-24 20:54:52 +0000
+++ openlp/plugins/songs/songsplugin.py	2010-09-26 12:25:58 +0000
@@ -140,7 +140,7 @@
             Song.theme_name == oldTheme)
         for song in songsUsingTheme:
             song.theme_name = newTheme
-            self.custommanager.save_object(song)
+            self.manager.save_object(song)
 
     def importSongs(self, format, **kwargs):
         class_ = SongFormat.get_class(format)

=== added file 'resources/forms/filerenamedialog.ui'
--- resources/forms/filerenamedialog.ui	1970-01-01 00:00:00 +0000
+++ resources/forms/filerenamedialog.ui	2010-09-26 12:25:58 +0000
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>FileRenameDialog</class>
+ <widget class="QWidget" name="FileRenameDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>400</width>
+    <height>87</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>File Rename</string>
+  </property>
+  <widget class="QDialogButtonBox" name="buttonBox">
+   <property name="geometry">
+    <rect>
+     <x>210</x>
+     <y>50</y>
+     <width>171</width>
+     <height>25</height>
+    </rect>
+   </property>
+   <property name="standardButtons">
+    <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+   </property>
+  </widget>
+  <widget class="QWidget" name="">
+   <property name="geometry">
+    <rect>
+     <x>10</x>
+     <y>10</y>
+     <width>381</width>
+     <height>27</height>
+    </rect>
+   </property>
+   <layout class="QHBoxLayout" name="horizontalLayout">
+    <item>
+     <widget class="QLabel" name="FileRenameLabel">
+      <property name="text">
+       <string>New File Name:</string>
+      </property>
+     </widget>
+    </item>
+    <item>
+     <widget class="QLineEdit" name="FileNameEdit"/>
+    </item>
+   </layout>
+  </widget>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>

=== modified file 'resources/forms/themewizard.ui'
--- resources/forms/themewizard.ui	2008-11-27 20:14:38 +0000
+++ resources/forms/themewizard.ui	2010-09-26 12:25:58 +0000
@@ -1,95 +1,893 @@
-<ui version="4.0" >
- <class>ThemeWizard</class>
- <widget class="QWizard" name="ThemeWizard" >
-  <property name="windowModality" >
-   <enum>Qt::ApplicationModal</enum>
-  </property>
-  <property name="geometry" >
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Wizard</class>
+ <widget class="QWizard" name="Wizard">
+  <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>576</width>
-    <height>397</height>
+    <width>559</width>
+    <height>487</height>
    </rect>
   </property>
-  <property name="windowTitle" >
+  <property name="windowTitle">
    <string>Theme Wizard</string>
   </property>
-  <property name="modal" >
+  <property name="modal">
    <bool>true</bool>
   </property>
-  <property name="wizardStyle" >
+  <property name="wizardStyle">
    <enum>QWizard::ModernStyle</enum>
   </property>
-  <property name="options" >
-   <set>QWizard::DisabledBackButtonOnLastPage|QWizard::IndependentPages|QWizard::NoBackButtonOnStartPage|QWizard::NoCancelButton</set>
+  <property name="options">
+   <set>QWizard::HaveCustomButton1|QWizard::NoBackButtonOnStartPage</set>
   </property>
-  <widget class="QWizardPage" name="WelcomePage" >
-   <property name="title" >
-    <string>Welcome</string>
-   </property>
-   <property name="subTitle" >
-    <string/>
-   </property>
-   <widget class="QLabel" name="WelcomeLabel" >
-    <property name="geometry" >
-     <rect>
-      <x>20</x>
-      <y>100</y>
-      <width>341</width>
-      <height>31</height>
-     </rect>
-    </property>
-    <property name="text" >
-     <string>Welcome to the Theme Wizard. This wizard will guide you through the process of creating a new theme.</string>
-    </property>
-    <property name="wordWrap" >
-     <bool>true</bool>
-    </property>
-   </widget>
-  </widget>
-  <widget class="QWizardPage" name="NamePage" >
-   <property name="title" >
-    <string>Theme Name</string>
-   </property>
-   <property name="subTitle" >
-    <string>Choose a name for your theme</string>
-   </property>
-   <widget class="QLabel" name="NameLabel" >
-    <property name="geometry" >
-     <rect>
-      <x>100</x>
-      <y>130</y>
-      <width>91</width>
-      <height>17</height>
-     </rect>
-    </property>
-    <property name="text" >
-     <string>Theme Name:</string>
-    </property>
-   </widget>
-   <widget class="QLineEdit" name="NameEdit" >
-    <property name="geometry" >
-     <rect>
-      <x>200</x>
-      <y>127</y>
-      <width>261</width>
-      <height>22</height>
-     </rect>
-    </property>
-   </widget>
-  </widget>
-  <widget class="QWizardPage" name="BackgroundPage" >
-   <property name="title" >
-    <string>Select Background</string>
-   </property>
-   <property name="subTitle" >
-    <string>Select a background type and configure your background</string>
-   </property>
+  <widget class="QWizardPage" name="WelcomePage">
+   <property name="title">
+    <string/>
+   </property>
+   <property name="subTitle">
+    <string/>
+   </property>
+   <layout class="QHBoxLayout" name="WelcomeLayout">
+    <property name="spacing">
+     <number>8</number>
+    </property>
+    <property name="margin">
+     <number>0</number>
+    </property>
+    <item>
+     <widget class="QLabel" name="ImportBibleImage">
+      <property name="minimumSize">
+       <size>
+        <width>163</width>
+        <height>0</height>
+       </size>
+      </property>
+      <property name="maximumSize">
+       <size>
+        <width>163</width>
+        <height>16777215</height>
+       </size>
+      </property>
+      <property name="lineWidth">
+       <number>0</number>
+      </property>
+      <property name="text">
+       <string/>
+      </property>
+      <property name="pixmap">
+       <pixmap resource="../images/openlp-2.qrc">:/wizards/wizard_importbible.bmp</pixmap>
+      </property>
+      <property name="indent">
+       <number>0</number>
+      </property>
+     </widget>
+    </item>
+    <item>
+     <layout class="QVBoxLayout" name="WelcomePageLayout">
+      <property name="spacing">
+       <number>8</number>
+      </property>
+      <item>
+       <widget class="QLabel" name="TitleLabel">
+        <property name="text">
+         <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:14pt; font-weight:600;&quot;&gt;Welcome to the Theme Wizard&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <spacer name="WelcomeTopSpacer">
+        <property name="orientation">
+         <enum>Qt::Vertical</enum>
+        </property>
+        <property name="sizeType">
+         <enum>QSizePolicy::Fixed</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>20</width>
+          <height>40</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item>
+       <widget class="QLabel" name="InformationLabel">
+        <property name="text">
+         <string>This wizard will help you to maintain Themes . Click the next button below to start the process..</string>
+        </property>
+        <property name="wordWrap">
+         <bool>true</bool>
+        </property>
+        <property name="margin">
+         <number>10</number>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <spacer name="WelcomeBottomSpacer">
+        <property name="orientation">
+         <enum>Qt::Vertical</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>20</width>
+          <height>40</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+     </layout>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QWizardPage" name="BackgroundPage">
+   <property name="title">
+    <string>Select Import Source</string>
+   </property>
+   <property name="subTitle">
+    <string>Select the import format, and where to import from.</string>
+   </property>
+   <layout class="QFormLayout" name="formLayout">
+    <property name="labelAlignment">
+     <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+    </property>
+    <item row="0" column="0">
+     <layout class="QHBoxLayout" name="BackgroundlLayout">
+      <item>
+       <widget class="QLabel" name="BackgroundLabel">
+        <property name="text">
+         <string>Background:</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QComboBox" name="BackgroundComboBox">
+        <item>
+         <property name="text">
+          <string>Opaque</string>
+         </property>
+        </item>
+        <item>
+         <property name="text">
+          <string>Transparent</string>
+         </property>
+        </item>
+       </widget>
+      </item>
+     </layout>
+    </item>
+    <item row="1" column="0">
+     <layout class="QHBoxLayout" name="horizontalLayout_2">
+      <item>
+       <widget class="QLabel" name="BackgroundTypeLabel">
+        <property name="text">
+         <string>Background Type:</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QComboBox" name="BackgroundTypeComboBox">
+        <item>
+         <property name="text">
+          <string>Solid Color</string>
+         </property>
+        </item>
+        <item>
+         <property name="text">
+          <string>Gradient</string>
+         </property>
+        </item>
+        <item>
+         <property name="text">
+          <string>Image</string>
+         </property>
+        </item>
+       </widget>
+      </item>
+     </layout>
+    </item>
+    <item row="2" column="0">
+     <layout class="QHBoxLayout" name="horizontalLayout_3">
+      <item>
+       <widget class="QLabel" name="Color1Label">
+        <property name="text">
+         <string>&lt;Color1&gt;</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QPushButton" name="Color1PushButton">
+        <property name="text">
+         <string/>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </item>
+    <item row="3" column="0">
+     <layout class="QHBoxLayout" name="horizontalLayout_4">
+      <item>
+       <widget class="QLabel" name="Color2Label">
+        <property name="text">
+         <string>&lt;Color2&gt;</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QPushButton" name="Color2PushButton">
+        <property name="text">
+         <string/>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </item>
+    <item row="5" column="0">
+     <layout class="QHBoxLayout" name="GradientLayout">
+      <item>
+       <widget class="QLabel" name="GradientLabel">
+        <property name="text">
+         <string>Gradient :</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QComboBox" name="GradientComboBox">
+        <item>
+         <property name="text">
+          <string>Horizontal</string>
+         </property>
+        </item>
+        <item>
+         <property name="text">
+          <string>Vertical</string>
+         </property>
+        </item>
+        <item>
+         <property name="text">
+          <string>Circular</string>
+         </property>
+        </item>
+       </widget>
+      </item>
+     </layout>
+    </item>
+    <item row="4" column="0" colspan="2">
+     <layout class="QHBoxLayout" name="ImageLayout">
+      <item>
+       <widget class="QLabel" name="ImageLabel">
+        <property name="text">
+         <string>Image:</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QLineEdit" name="ImageLineEdit"/>
+      </item>
+      <item>
+       <widget class="QToolButton" name="ImageToolButton">
+        <property name="text">
+         <string>...</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QWizardPage" name="FontMainPage">
+   <property name="title">
+    <string>Main Area Font Details</string>
+   </property>
+   <property name="subTitle">
+    <string>Define the font and display charaistics for the Display text</string>
+   </property>
+   <layout class="QFormLayout" name="formLayout_2">
+    <item row="0" column="1">
+     <widget class="QLabel" name="FontMainlabel">
+      <property name="text">
+       <string>Font:</string>
+      </property>
+     </widget>
+    </item>
+    <item row="1" column="1">
+     <widget class="QFontComboBox" name="FontMainComboBox"/>
+    </item>
+    <item row="2" column="0">
+     <widget class="QLabel" name="FontMainColorLabel">
+      <property name="text">
+       <string>Font Color:</string>
+      </property>
+     </widget>
+    </item>
+    <item row="3" column="1">
+     <widget class="QPushButton" name="FontMainColorPushButton">
+      <property name="text">
+       <string/>
+      </property>
+     </widget>
+    </item>
+    <item row="4" column="1">
+     <widget class="QLabel" name="FontMainSize">
+      <property name="text">
+       <string>Size:</string>
+      </property>
+     </widget>
+    </item>
+    <item row="5" column="1">
+     <widget class="QSpinBox" name="FontMainSizeSpinBox">
+      <property name="sizePolicy">
+       <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+        <horstretch>0</horstretch>
+        <verstretch>0</verstretch>
+       </sizepolicy>
+      </property>
+      <property name="minimumSize">
+       <size>
+        <width>70</width>
+        <height>0</height>
+       </size>
+      </property>
+      <property name="suffix">
+       <string>pt</string>
+      </property>
+      <property name="maximum">
+       <number>999</number>
+      </property>
+      <property name="value">
+       <number>16</number>
+      </property>
+     </widget>
+    </item>
+    <item row="6" column="0">
+     <widget class="QLabel" name="FontMainWrapIndentationLabel">
+      <property name="text">
+       <string>Wrap Indentation</string>
+      </property>
+     </widget>
+    </item>
+    <item row="7" column="1">
+     <widget class="QSpinBox" name="FontMainLineSpacingSpinBox"/>
+    </item>
+    <item row="8" column="0">
+     <widget class="QLabel" name="FontMainLinesPageLabel">
+      <property name="text">
+       <string>TextLabel</string>
+      </property>
+     </widget>
+    </item>
+    <item row="9" column="0">
+     <widget class="QLabel" name="OutlineEnabledLabel_2">
+      <property name="text">
+       <string>Show Outline:</string>
+      </property>
+     </widget>
+    </item>
+    <item row="10" column="1">
+     <widget class="QCheckBox" name="OutlineCheckBox_2">
+      <property name="text">
+       <string/>
+      </property>
+     </widget>
+    </item>
+    <item row="11" column="0">
+     <widget class="QLabel" name="OutlineColorLabel_2">
+      <property name="text">
+       <string>Outline Color:</string>
+      </property>
+     </widget>
+    </item>
+    <item row="12" column="1">
+     <widget class="QPushButton" name="OutlineColorPushButton_2">
+      <property name="text">
+       <string/>
+      </property>
+     </widget>
+    </item>
+    <item row="13" column="0">
+     <widget class="QLabel" name="ShadowEnabledLabel_2">
+      <property name="text">
+       <string>Show Shadow:</string>
+      </property>
+     </widget>
+    </item>
+    <item row="14" column="1">
+     <widget class="QCheckBox" name="ShadowCheckBox_2">
+      <property name="text">
+       <string/>
+      </property>
+     </widget>
+    </item>
+    <item row="15" column="0">
+     <widget class="QLabel" name="ShadowColorLabel_2">
+      <property name="text">
+       <string>Shadow Color:</string>
+      </property>
+     </widget>
+    </item>
+    <item row="16" column="1">
+     <widget class="QPushButton" name="ShadowColorPushButton_2">
+      <property name="text">
+       <string/>
+      </property>
+     </widget>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QWizardPage" name="FontFooterPage">
+   <property name="title">
+    <string>Footer Area Font Details</string>
+   </property>
+   <property name="subTitle">
+    <string>Define the font and display charaistics for the Footer text</string>
+   </property>
+   <layout class="QFormLayout" name="formLayout_3">
+    <item row="0" column="0">
+     <widget class="QLabel" name="FontFooterLabel">
+      <property name="text">
+       <string>Font:</string>
+      </property>
+     </widget>
+    </item>
+    <item row="0" column="1">
+     <widget class="QFontComboBox" name="FontFooterComboBox"/>
+    </item>
+    <item row="1" column="0">
+     <widget class="QLabel" name="FontFooterColorLabel">
+      <property name="text">
+       <string>Font Color:</string>
+      </property>
+     </widget>
+    </item>
+    <item row="1" column="1">
+     <widget class="QPushButton" name="FontFooterColorPushButton">
+      <property name="text">
+       <string/>
+      </property>
+     </widget>
+    </item>
+    <item row="2" column="0">
+     <widget class="QLabel" name="FontFooterSizeLabel">
+      <property name="text">
+       <string>Size:</string>
+      </property>
+     </widget>
+    </item>
+    <item row="2" column="1">
+     <widget class="QSpinBox" name="FontFooterSizeSpinBox">
+      <property name="sizePolicy">
+       <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+        <horstretch>0</horstretch>
+        <verstretch>0</verstretch>
+       </sizepolicy>
+      </property>
+      <property name="minimumSize">
+       <size>
+        <width>70</width>
+        <height>0</height>
+       </size>
+      </property>
+      <property name="suffix">
+       <string>pt</string>
+      </property>
+      <property name="maximum">
+       <number>999</number>
+      </property>
+      <property name="value">
+       <number>10</number>
+      </property>
+     </widget>
+    </item>
+    <item row="3" column="0">
+     <widget class="QLabel" name="OutlineEnabledLabel">
+      <property name="text">
+       <string>Show Outline:</string>
+      </property>
+     </widget>
+    </item>
+    <item row="3" column="1">
+     <widget class="QCheckBox" name="OutlineCheckBox">
+      <property name="text">
+       <string/>
+      </property>
+     </widget>
+    </item>
+    <item row="4" column="0">
+     <widget class="QLabel" name="ShadowColorLabel">
+      <property name="text">
+       <string>Shadow Color:</string>
+      </property>
+     </widget>
+    </item>
+    <item row="4" column="1">
+     <widget class="QPushButton" name="OutlineColorPushButton">
+      <property name="text">
+       <string/>
+      </property>
+     </widget>
+    </item>
+    <item row="5" column="0">
+     <widget class="QLabel" name="ShadowEnabledLabel">
+      <property name="text">
+       <string>Show Shadow:</string>
+      </property>
+     </widget>
+    </item>
+    <item row="5" column="1">
+     <widget class="QCheckBox" name="ShadowCheckBox">
+      <property name="text">
+       <string/>
+      </property>
+     </widget>
+    </item>
+    <item row="6" column="0">
+     <widget class="QLabel" name="OutlineColorLabel">
+      <property name="text">
+       <string>Outline Color:</string>
+      </property>
+     </widget>
+    </item>
+    <item row="6" column="1">
+     <widget class="QPushButton" name="ShadowColorPushButton">
+      <property name="text">
+       <string/>
+      </property>
+     </widget>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QWizardPage" name="DisplayCharactisticsPage">
+   <property name="title">
+    <string>Text Display Layout</string>
+   </property>
+   <property name="subTitle">
+    <string>Allows you to change and move the Main and Footer areas.</string>
+   </property>
+   <layout class="QGridLayout" name="gridLayout_2">
+    <item row="0" column="0">
+     <widget class="QCheckBox" name="FontFooterDefaultCheckBox">
+      <property name="text">
+       <string/>
+      </property>
+      <property name="tristate">
+       <bool>false</bool>
+      </property>
+     </widget>
+    </item>
+    <item row="1" column="0" colspan="2">
+     <layout class="QGridLayout" name="gridLayout">
+      <item row="0" column="1" colspan="2">
+       <widget class="QLabel" name="label">
+        <property name="text">
+         <string>Main Area</string>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="3" colspan="2">
+       <widget class="QLabel" name="label_2">
+        <property name="text">
+         <string>Footer Area</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="0" colspan="2">
+       <widget class="QLabel" name="FontMainXLabel">
+        <property name="text">
+         <string>X Position:</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="2">
+       <widget class="QSpinBox" name="FontMainXSpinBox">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="minimumSize">
+         <size>
+          <width>78</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="suffix">
+         <string>px</string>
+        </property>
+        <property name="maximum">
+         <number>9999</number>
+        </property>
+        <property name="value">
+         <number>0</number>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="3">
+       <widget class="QLabel" name="FontFooterXLabel">
+        <property name="text">
+         <string>X Position:</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="4">
+       <widget class="QSpinBox" name="FontFooterXSpinBox">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="minimumSize">
+         <size>
+          <width>78</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="suffix">
+         <string>px</string>
+        </property>
+        <property name="maximum">
+         <number>9999</number>
+        </property>
+        <property name="value">
+         <number>0</number>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="0" colspan="2">
+       <widget class="QLabel" name="FontMainYLabel">
+        <property name="text">
+         <string>Y Position:</string>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="2">
+       <widget class="QSpinBox" name="FontMainYSpinBox">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="minimumSize">
+         <size>
+          <width>78</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="suffix">
+         <string>px</string>
+        </property>
+        <property name="maximum">
+         <number>9999</number>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="3">
+       <widget class="QLabel" name="FontFooterYLabel">
+        <property name="text">
+         <string>Y Position:</string>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="4">
+       <widget class="QSpinBox" name="FontFooterYSpinBox">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="minimumSize">
+         <size>
+          <width>78</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="suffix">
+         <string>px</string>
+        </property>
+        <property name="maximum">
+         <number>9999</number>
+        </property>
+        <property name="value">
+         <number>0</number>
+        </property>
+       </widget>
+      </item>
+      <item row="3" column="0">
+       <widget class="QLabel" name="FontMainWidthLabel">
+        <property name="text">
+         <string>Width:</string>
+        </property>
+       </widget>
+      </item>
+      <item row="3" column="2">
+       <widget class="QSpinBox" name="FontMainWidthSpinBox">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="minimumSize">
+         <size>
+          <width>78</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="suffix">
+         <string>px</string>
+        </property>
+        <property name="maximum">
+         <number>9999</number>
+        </property>
+       </widget>
+      </item>
+      <item row="3" column="3">
+       <widget class="QLabel" name="FontFooterWidthLabel">
+        <property name="text">
+         <string>Width:</string>
+        </property>
+       </widget>
+      </item>
+      <item row="3" column="4">
+       <widget class="QSpinBox" name="FontFooterWidthSpinBox">
+        <property name="minimumSize">
+         <size>
+          <width>78</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="suffix">
+         <string>px</string>
+        </property>
+        <property name="maximum">
+         <number>9999</number>
+        </property>
+       </widget>
+      </item>
+      <item row="4" column="0" colspan="2">
+       <widget class="QLabel" name="FontMainHeightLabel">
+        <property name="text">
+         <string>Height:</string>
+        </property>
+       </widget>
+      </item>
+      <item row="4" column="2">
+       <widget class="QSpinBox" name="FontMainHeightSpinBox">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="minimumSize">
+         <size>
+          <width>78</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="suffix">
+         <string>px</string>
+        </property>
+        <property name="maximum">
+         <number>9999</number>
+        </property>
+       </widget>
+      </item>
+      <item row="4" column="3">
+       <widget class="QLabel" name="FontFooterHeightLabel">
+        <property name="text">
+         <string>Height:</string>
+        </property>
+       </widget>
+      </item>
+      <item row="4" column="4">
+       <widget class="QSpinBox" name="FontFooterHeightSpinBox">
+        <property name="minimumSize">
+         <size>
+          <width>78</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="suffix">
+         <string>px</string>
+        </property>
+        <property name="maximum">
+         <number>9999</number>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </item>
+    <item row="0" column="1">
+     <widget class="QLabel" name="FontFooterDefaultLabel">
+      <property name="text">
+       <string>Use Default Location:</string>
+      </property>
+     </widget>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QWizardPage" name="PreviewPage">
+   <property name="title">
+    <string>Save and Preview</string>
+   </property>
+   <property name="subTitle">
+    <string>View the theme and save it replacing the current one or change the name to create a new theme</string>
+   </property>
+   <layout class="QFormLayout" name="formLayout_4">
+    <item row="0" column="0">
+     <layout class="QHBoxLayout" name="horizontalLayout">
+      <item>
+       <widget class="QLabel" name="ThemeNameLabel">
+        <property name="text">
+         <string>Theme Name:</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QLineEdit" name="lineEdit"/>
+      </item>
+     </layout>
+    </item>
+    <item row="1" column="0">
+     <layout class="QVBoxLayout" name="verticalLayout">
+      <item>
+       <widget class="QLabel" name="PreviewLabel">
+        <property name="text">
+         <string>Preview</string>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignCenter</set>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QLabel" name="ThemePreview">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="minimumSize">
+         <size>
+          <width>300</width>
+          <height>225</height>
+         </size>
+        </property>
+        <property name="frameShape">
+         <enum>QFrame::WinPanel</enum>
+        </property>
+        <property name="frameShadow">
+         <enum>QFrame::Sunken</enum>
+        </property>
+        <property name="lineWidth">
+         <number>1</number>
+        </property>
+        <property name="text">
+         <string/>
+        </property>
+        <property name="scaledContents">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </item>
+   </layout>
   </widget>
  </widget>
  <resources>
-  <include location="../images/openlp-2.qrc" />
+  <include location="../images/openlp-2.qrc"/>
  </resources>
  <connections/>
 </ui>


Follow ups