← Back to team overview

openlp-core team mailing list archive

[Merge] lp:~meths/openlp/trivialfixes into lp:openlp

 

Jon Tibble has proposed merging lp:~meths/openlp/trivialfixes into lp:openlp.

Requested reviews:
  OpenLP Core (openlp-core)

For more details, see:
https://code.launchpad.net/~meths/openlp/trivialfixes/+merge/48574

Remove scripts now importers take their role.
Fix missing import.
More UI library component refactors.
Clean up spacer use in import forms.
More deduplication in slidecontroller.py
-- 
https://code.launchpad.net/~meths/openlp/trivialfixes/+merge/48574
Your team OpenLP Core is requested to review the proposed merge of lp:~meths/openlp/trivialfixes into lp:openlp.
=== modified file 'openlp/core/lib/dockwidget.py'
--- openlp/core/lib/dockwidget.py	2011-01-01 13:22:12 +0000
+++ openlp/core/lib/dockwidget.py	2011-02-04 03:37:59 +0000
@@ -31,6 +31,8 @@
 
 from PyQt4 import QtGui
 
+from openlp.core.lib import build_icon
+
 log = logging.getLogger(__name__)
 
 class OpenLPDockWidget(QtGui.QDockWidget):
@@ -47,4 +49,4 @@
         if name:
             self.setObjectName(name)
         if icon:
-            self.setWindowIcon(icon)
+            self.setWindowIcon(build_icon(icon))

=== modified file 'openlp/core/lib/mediamanageritem.py'
--- openlp/core/lib/mediamanageritem.py	2011-02-02 13:22:43 +0000
+++ openlp/core/lib/mediamanageritem.py	2011-02-04 03:37:59 +0000
@@ -366,33 +366,34 @@
             count += 1
         return filelist
 
-    def validate(self, file, thumb):
-        """
-        Validates to see if the file still exists or thumbnail is up to date
-        """
-        if not os.path.exists(file):
+    def validate(self, image, thumb):
+        """
+        Validates whether an image still exists and, if it does, is the
+        thumbnail representation of the image up to date.
+        """
+        if not os.path.exists(image):
             return False
         if os.path.exists(thumb):
-            filedate = os.stat(file).st_mtime
-            thumbdate = os.stat(thumb).st_mtime
-            # if file updated rebuild icon
-            if filedate > thumbdate:
-                self.iconFromFile(file, thumb)
+            imageDate = os.stat(image).st_mtime
+            thumbDate = os.stat(thumb).st_mtime
+            # If image has been updated rebuild icon
+            if imageDate > thumbDate:
+                self.iconFromFile(image, thumb)
         else:
-            self.iconFromFile(file, thumb)
+            self.iconFromFile(image, thumb)
         return True
 
-    def iconFromFile(self, file, thumb):
+    def iconFromFile(self, image, thumb):
         """
-        Create a thumbnail icon from a given file
+        Create a thumbnail icon from a given image.
 
-        ``file``
-            The file to create the icon from
+        ``image``
+            The image file to create the icon from.
 
         ``thumb``
             The filename to save the thumbnail to
         """
-        icon = build_icon(unicode(file))
+        icon = build_icon(unicode(image))
         pixmap = icon.pixmap(QtCore.QSize(88, 50))
         ext = os.path.splitext(thumb)[1].lower()
         pixmap.save(thumb, ext[1:])
@@ -403,12 +404,16 @@
             u'defined by the plugin')
 
     def onNewClick(self):
-        raise NotImplementedError(u'MediaManagerItem.onNewClick needs to be '
-            u'defined by the plugin')
+        """
+        Hook for plugins to define behaviour for adding new items.
+        """
+        pass
 
     def onEditClick(self):
-        raise NotImplementedError(u'MediaManagerItem.onEditClick needs to be '
-            u'defined by the plugin')
+        """
+        Hook for plugins to define behaviour for editing items.
+        """
+        pass
 
     def onDeleteClick(self):
         raise NotImplementedError(u'MediaManagerItem.onDeleteClick needs to '

=== modified file 'openlp/core/lib/ui.py'
--- openlp/core/lib/ui.py	2011-02-03 02:46:02 +0000
+++ openlp/core/lib/ui.py	2011-02-04 03:37:59 +0000
@@ -30,7 +30,7 @@
 
 from PyQt4 import QtCore, QtGui
 
-from openlp.core.lib import translate
+from openlp.core.lib import build_icon, Receiver, translate
 
 log = logging.getLogger(__name__)
 
@@ -108,3 +108,77 @@
     combo.setSizeAdjustPolicy(QtGui.QComboBox.AdjustToMinimumContentsLength)
     combo.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Fixed)
     return combo
+
+def delete_push_button(parent, icon=None):
+    """
+    Return a standard push button with delete label.
+    """
+    delete_button = QtGui.QPushButton(parent)
+    delete_button.setObjectName(u'deleteButton')
+    delete_icon = icon if icon else u':/general/general_delete.png'
+    delete_button.setIcon(build_icon(delete_icon))
+    delete_button.setText(translate('OpenLP.Ui', '&Delete'))
+    delete_button.setToolTip(
+        translate('OpenLP.Ui', 'Delete the selected item.'))
+    QtCore.QObject.connect(delete_button,
+        QtCore.SIGNAL(u'clicked()'), parent.onDeleteButtonClicked)
+    return delete_button
+
+def up_down_push_button_set(parent):
+    """
+    Return a standard set of two push buttons for up and down use with lists.
+    """
+    up_button = QtGui.QPushButton(parent)
+    up_button.setIcon(build_icon(u':/services/service_up.png'))
+    up_button.setObjectName(u'upButton')
+    up_button.setToolTip(
+        translate('OpenLP.Ui', 'Move selection up one position.'))
+    down_button = QtGui.QPushButton(parent)
+    down_button.setIcon(build_icon(u':/services/service_down.png'))
+    down_button.setObjectName(u'downButton')
+    down_button.setToolTip(
+        translate('OpenLP.Ui', 'Move selection down one position.'))
+    QtCore.QObject.connect(up_button,
+        QtCore.SIGNAL(u'clicked()'), parent.onUpButtonClicked)
+    QtCore.QObject.connect(down_button,
+        QtCore.SIGNAL(u'clicked()'), parent.onDownButtonClicked)
+    return up_button, down_button
+
+def base_action(parent, name):
+    """
+    Return the most basic action with the object name set.
+    """
+    action = QtGui.QAction(parent)
+    action.setObjectName(name)
+    return action
+
+def checkable_action(parent, name, checked=None):
+    """
+    Return a standard action with the checkable attribute set.
+    """
+    action = base_action(parent, name)
+    action.setCheckable(True)
+    if checked is not None:
+        action.setChecked(checked)
+    return action
+
+def icon_action(parent, name, icon, checked=None):
+    """
+    Return a standard action with an icon.
+    """
+    if checked is not None:
+        action = checkable_action(parent, name, checked)
+    else:
+        action = base_action(parent, name)
+    action.setIcon(build_icon(icon))
+    return action
+
+def shortcut_action(parent, text, shortcuts, function):
+    """
+    Return a shortcut enabled action.
+    """
+    action = QtGui.QAction(text, parent)
+    action.setShortcuts(shortcuts)
+    action.setShortcutContext(QtCore.Qt.WidgetWithChildrenShortcut)
+    QtCore.QObject.connect(action, QtCore.SIGNAL(u'triggered()'), function)
+    return action

=== modified file 'openlp/core/ui/mainwindow.py'
--- openlp/core/ui/mainwindow.py	2011-02-02 05:31:11 +0000
+++ openlp/core/ui/mainwindow.py	2011-02-04 03:37:59 +0000
@@ -28,11 +28,12 @@
 
 from PyQt4 import QtCore, QtGui
 
+from openlp.core.lib import RenderManager, build_icon, OpenLPDockWidget, \
+    SettingsManager, PluginManager, Receiver, translate
+from openlp.core.lib.ui import base_action, checkable_action, icon_action
 from openlp.core.ui import AboutForm, SettingsForm, ServiceManager, \
     ThemeManager, SlideController, PluginForm, MediaDockManager, \
     ShortcutListForm
-from openlp.core.lib import RenderManager, build_icon, OpenLPDockWidget, \
-    SettingsManager, PluginManager, Receiver, translate
 from openlp.core.utils import AppLocation, add_actions, LanguageManager, \
     ActionList
 
@@ -124,9 +125,8 @@
         self.DefaultThemeLabel.setObjectName(u'DefaultThemeLabel')
         self.StatusBar.addPermanentWidget(self.DefaultThemeLabel)
         # Create the MediaManager
-        self.MediaManagerDock = OpenLPDockWidget(
-            mainWindow, u'MediaManagerDock',
-            build_icon(u':/system/system_mediamanager.png'))
+        self.MediaManagerDock = OpenLPDockWidget(mainWindow,
+            u'MediaManagerDock', u':/system/system_mediamanager.png')
         self.MediaManagerDock.setStyleSheet(MEDIA_MANAGER_STYLE)
         self.MediaManagerDock.setMinimumWidth(
             self.settingsmanager.mainwindow_left)
@@ -137,9 +137,8 @@
         mainWindow.addDockWidget(QtCore.Qt.LeftDockWidgetArea,
             self.MediaManagerDock)
         # Create the service manager
-        self.ServiceManagerDock = OpenLPDockWidget(
-            mainWindow, u'ServiceManagerDock',
-            build_icon(u':/system/system_servicemanager.png'))
+        self.ServiceManagerDock = OpenLPDockWidget(mainWindow,
+            u'ServiceManagerDock', u':/system/system_servicemanager.png')
         self.ServiceManagerDock.setMinimumWidth(
             self.settingsmanager.mainwindow_right)
         self.ServiceManagerContents = ServiceManager(mainWindow,
@@ -148,9 +147,8 @@
         mainWindow.addDockWidget(QtCore.Qt.RightDockWidgetArea,
             self.ServiceManagerDock)
         # Create the theme manager
-        self.ThemeManagerDock = OpenLPDockWidget(
-            mainWindow, u'ThemeManagerDock',
-            build_icon(u':/system/system_thememanager.png'))
+        self.ThemeManagerDock = OpenLPDockWidget(mainWindow,
+            u'ThemeManagerDock', u':/system/system_thememanager.png')
         self.ThemeManagerDock.setMinimumWidth(
             self.settingsmanager.mainwindow_right)
         self.ThemeManagerContents = ThemeManager(mainWindow,
@@ -160,103 +158,70 @@
         mainWindow.addDockWidget(QtCore.Qt.RightDockWidgetArea,
             self.ThemeManagerDock)
         # Create the menu items
-        self.FileNewItem = QtGui.QAction(mainWindow)
-        self.FileNewItem.setIcon(build_icon(u':/general/general_new.png'))
-        self.FileNewItem.setObjectName(u'FileNewItem')
+        self.FileNewItem = icon_action(mainWindow, u'FileNewItem',
+            u':/general/general_new.png')
         mainWindow.actionList.add_action(self.FileNewItem, u'File')
-        self.FileOpenItem = QtGui.QAction(mainWindow)
-        self.FileOpenItem.setIcon(build_icon(u':/general/general_open.png'))
-        self.FileOpenItem.setObjectName(u'FileOpenItem')
+        self.FileOpenItem = icon_action(mainWindow, u'FileOpenItem',
+            u':/general/general_open.png')
         mainWindow.actionList.add_action(self.FileOpenItem, u'File')
-        self.FileSaveItem = QtGui.QAction(mainWindow)
-        self.FileSaveItem.setIcon(build_icon(u':/general/general_save.png'))
-        self.FileSaveItem.setObjectName(u'FileSaveItem')
+        self.FileSaveItem = icon_action(mainWindow, u'FileSaveItem',
+            u':/general/general_save.png')
         mainWindow.actionList.add_action(self.FileSaveItem, u'File')
-        self.FileSaveAsItem = QtGui.QAction(mainWindow)
-        self.FileSaveAsItem.setObjectName(u'FileSaveAsItem')
+        self.FileSaveAsItem = base_action(mainWindow, u'FileSaveAsItem')
         mainWindow.actionList.add_action(self.FileSaveAsItem, u'File')
-        self.printServiceOrderItem = QtGui.QAction(mainWindow) 
-        self.printServiceOrderItem.setObjectName(u'printServiceItem')
+        self.printServiceOrderItem = base_action(
+            mainWindow, u'printServiceItem')
         mainWindow.actionList.add_action(
             self.printServiceOrderItem, u'Print Service Order')
-        self.FileExitItem = QtGui.QAction(mainWindow)
-        self.FileExitItem.setIcon(build_icon(u':/system/system_exit.png'))
-        self.FileExitItem.setObjectName(u'FileExitItem')
+        self.FileExitItem = icon_action(mainWindow, u'FileExitItem',
+            u':/system/system_exit.png')
         mainWindow.actionList.add_action(self.FileExitItem, u'File')
-        self.ImportThemeItem = QtGui.QAction(mainWindow)
-        self.ImportThemeItem.setObjectName(u'ImportThemeItem')
+        self.ImportThemeItem = base_action(mainWindow, u'ImportThemeItem')
         mainWindow.actionList.add_action(self.ImportThemeItem, u'Import')
-        self.ImportLanguageItem = QtGui.QAction(mainWindow)
-        self.ImportLanguageItem.setObjectName(u'ImportLanguageItem')
+        self.ImportLanguageItem = base_action(mainWindow, u'ImportLanguageItem')
         mainWindow.actionList.add_action(self.ImportLanguageItem, u'Import')
-        self.ExportThemeItem = QtGui.QAction(mainWindow)
-        self.ExportThemeItem.setObjectName(u'ExportThemeItem')
+        self.ExportThemeItem = base_action(mainWindow, u'ExportThemeItem')
         mainWindow.actionList.add_action(self.ExportThemeItem, u'Export')
-        self.ExportLanguageItem = QtGui.QAction(mainWindow)
-        self.ExportLanguageItem.setObjectName(u'ExportLanguageItem')
+        self.ExportLanguageItem = base_action(mainWindow, u'ExportLanguageItem')
         mainWindow.actionList.add_action(self.ExportLanguageItem, u'Export')
-        self.ViewMediaManagerItem = QtGui.QAction(mainWindow)
-        self.ViewMediaManagerItem.setCheckable(True)
-        self.ViewMediaManagerItem.setChecked(self.MediaManagerDock.isVisible())
-        self.ViewMediaManagerItem.setIcon(
-            build_icon(u':/system/system_mediamanager.png'))
-        self.ViewMediaManagerItem.setObjectName(u'ViewMediaManagerItem')
-        self.ViewThemeManagerItem = QtGui.QAction(mainWindow)
-        self.ViewThemeManagerItem.setCheckable(True)
-        self.ViewThemeManagerItem.setChecked(self.ThemeManagerDock.isVisible())
-        self.ViewThemeManagerItem.setIcon(
-            build_icon(u':/system/system_thememanager.png'))
-        self.ViewThemeManagerItem.setObjectName(u'ViewThemeManagerItem')
+        self.ViewMediaManagerItem = icon_action(mainWindow,
+            u'ViewMediaManagerItem', u':/system/system_mediamanager.png',
+            self.MediaManagerDock.isVisible())
+        self.ViewThemeManagerItem = icon_action(mainWindow,
+            u'ViewThemeManagerItem', u':/system/system_thememanager.png',
+            self.ThemeManagerDock.isVisible())
         mainWindow.actionList.add_action(self.ViewMediaManagerItem, u'View')
-        self.ViewServiceManagerItem = QtGui.QAction(mainWindow)
-        self.ViewServiceManagerItem.setCheckable(True)
-        self.ViewServiceManagerItem.setChecked(
+        self.ViewServiceManagerItem = icon_action(mainWindow,
+            u'ViewServiceManagerItem', u':/system/system_servicemanager.png',
             self.ServiceManagerDock.isVisible())
-        self.ViewServiceManagerItem.setIcon(
-            build_icon(u':/system/system_servicemanager.png'))
-        self.ViewServiceManagerItem.setObjectName(u'ViewServiceManagerItem')
         mainWindow.actionList.add_action(self.ViewServiceManagerItem, u'View')
-        self.ViewPreviewPanel = QtGui.QAction(mainWindow)
-        self.ViewPreviewPanel.setCheckable(True)
-        self.ViewPreviewPanel.setChecked(previewVisible)
-        self.ViewPreviewPanel.setObjectName(u'ViewPreviewPanel')
+        self.ViewPreviewPanel = checkable_action(mainWindow,
+            u'ViewPreviewPanel', previewVisible)
         mainWindow.actionList.add_action(self.ViewPreviewPanel, u'View')
-        self.ViewLivePanel = QtGui.QAction(mainWindow)
-        self.ViewLivePanel.setCheckable(True)
-        self.ViewLivePanel.setChecked(liveVisible)
-        self.ViewLivePanel.setObjectName(u'ViewLivePanel')
+        self.ViewLivePanel = checkable_action(mainWindow, u'ViewLivePanel',
+            liveVisible)
         mainWindow.actionList.add_action(self.ViewLivePanel, u'View')
-        self.ModeDefaultItem = QtGui.QAction(mainWindow)
-        self.ModeDefaultItem.setCheckable(True)
-        self.ModeDefaultItem.setObjectName(u'ModeDefaultItem')
+        self.ModeDefaultItem = checkable_action(mainWindow, u'ModeDefaultItem')
         mainWindow.actionList.add_action(self.ModeDefaultItem, u'View Mode')
-        self.ModeSetupItem = QtGui.QAction(mainWindow)
-        self.ModeSetupItem.setCheckable(True)
-        self.ModeSetupItem.setObjectName(u'ModeLiveItem')
+        self.ModeSetupItem = checkable_action(mainWindow, u'ModeLiveItem')
         mainWindow.actionList.add_action(self.ModeSetupItem, u'View Mode')
-        self.ModeLiveItem = QtGui.QAction(mainWindow)
-        self.ModeLiveItem.setCheckable(True)
-        self.ModeLiveItem.setObjectName(u'ModeLiveItem')
+        self.ModeLiveItem = checkable_action(mainWindow, u'ModeLiveItem')
         mainWindow.actionList.add_action(self.ModeLiveItem, u'View Mode')
         self.ModeGroup = QtGui.QActionGroup(mainWindow)
         self.ModeGroup.addAction(self.ModeDefaultItem)
         self.ModeGroup.addAction(self.ModeSetupItem)
         self.ModeGroup.addAction(self.ModeLiveItem)
         self.ModeDefaultItem.setChecked(True)
-        self.ToolsAddToolItem = QtGui.QAction(mainWindow)
-        self.ToolsAddToolItem.setIcon(build_icon(u':/tools/tools_add.png'))
-        self.ToolsAddToolItem.setObjectName(u'ToolsAddToolItem')
+        self.ToolsAddToolItem = icon_action(mainWindow, u'ToolsAddToolItem',
+            u':/tools/tools_add.png')
         mainWindow.actionList.add_action(self.ToolsAddToolItem, u'Tools')
-        self.SettingsPluginListItem = QtGui.QAction(mainWindow)
-        self.SettingsPluginListItem.setIcon(
-            build_icon(u':/system/settings_plugin_list.png'))
-        self.SettingsPluginListItem.setObjectName(u'SettingsPluginListItem')
+        self.SettingsPluginListItem = icon_action(mainWindow,
+            u'SettingsPluginListItem', u':/system/settings_plugin_list.png')
         mainWindow.actionList.add_action(self.SettingsPluginListItem,
             u'Settings')
         # i18n Language Items
-        self.AutoLanguageItem = QtGui.QAction(mainWindow)
-        self.AutoLanguageItem.setObjectName(u'AutoLanguageItem')
-        self.AutoLanguageItem.setCheckable(True)
+        self.AutoLanguageItem = checkable_action(mainWindow,
+            u'AutoLanguageItem')
         mainWindow.actionList.add_action(self.AutoLanguageItem, u'Settings')
         self.LanguageGroup = QtGui.QActionGroup(mainWindow)
         self.LanguageGroup.setExclusive(True)
@@ -266,39 +231,28 @@
         qmList = LanguageManager.get_qm_list()
         savedLanguage = LanguageManager.get_language()
         for key in sorted(qmList.keys()):
-            languageItem = QtGui.QAction(mainWindow)
-            languageItem.setObjectName(key)
-            languageItem.setCheckable(True)
+            languageItem = checkable_action(mainWindow, key)
             if qmList[key] == savedLanguage:
                 languageItem.setChecked(True)
             add_actions(self.LanguageGroup, [languageItem])
-        self.SettingsShortcutsItem = QtGui.QAction(mainWindow)
-        self.SettingsShortcutsItem.setIcon(
-            build_icon(u':/system/system_configure_shortcuts.png'))
-        self.SettingsShortcutsItem.setObjectName(u'SettingsShortcutsItem')
-        self.SettingsConfigureItem = QtGui.QAction(mainWindow)
-        self.SettingsConfigureItem.setIcon(
-            build_icon(u':/system/system_settings.png'))
-        self.SettingsConfigureItem.setObjectName(u'SettingsConfigureItem')
+        self.SettingsShortcutsItem = icon_action(mainWindow,
+            u'SettingsShortcutsItem', 
+            u':/system/system_configure_shortcuts.png')
+        self.SettingsConfigureItem = icon_action(mainWindow,
+            u'SettingsConfigureItem', u':/system/system_settings.png')
         mainWindow.actionList.add_action(self.SettingsShortcutsItem,
             u'Settings')
-        self.HelpDocumentationItem = QtGui.QAction(mainWindow)
-        self.HelpDocumentationItem.setIcon(
-            build_icon(u':/system/system_help_contents.png'))
-        self.HelpDocumentationItem.setObjectName(u'HelpDocumentationItem')
+        self.HelpDocumentationItem = icon_action(mainWindow,
+            u'HelpDocumentationItem', u':/system/system_help_contents.png')
         self.HelpDocumentationItem.setEnabled(False)
         mainWindow.actionList.add_action(self.HelpDocumentationItem, u'Help')
-        self.HelpAboutItem = QtGui.QAction(mainWindow)
-        self.HelpAboutItem.setIcon(
-            build_icon(u':/system/system_about.png'))
-        self.HelpAboutItem.setObjectName(u'HelpAboutItem')
+        self.HelpAboutItem = icon_action(mainWindow, u'HelpAboutItem',
+            u':/system/system_about.png')
         mainWindow.actionList.add_action(self.HelpAboutItem, u'Help')
-        self.HelpOnlineHelpItem = QtGui.QAction(mainWindow)
-        self.HelpOnlineHelpItem.setObjectName(u'HelpOnlineHelpItem')
+        self.HelpOnlineHelpItem = base_action(mainWindow, u'HelpOnlineHelpItem')
         self.HelpOnlineHelpItem.setEnabled(False)
         mainWindow.actionList.add_action(self.HelpOnlineHelpItem, u'Help')
-        self.HelpWebSiteItem = QtGui.QAction(mainWindow)
-        self.HelpWebSiteItem.setObjectName(u'HelpWebSiteItem')
+        self.HelpWebSiteItem = base_action(mainWindow, u'HelpWebSiteItem')
         mainWindow.actionList.add_action(self.HelpWebSiteItem, u'Help')
         add_actions(self.FileImportMenu,
             (self.ImportThemeItem, self.ImportLanguageItem))
@@ -999,8 +953,8 @@
             u'advanced/recent file count', QtCore.QVariant(4)).toInt()[0]
         self.FileMenu.clear()
         add_actions(self.FileMenu, self.FileMenuActions[:-1])
-        existingRecentFiles = [file for file in self.recentFiles
-            if QtCore.QFile.exists(file)]
+        existingRecentFiles = [recentFile for recentFile in self.recentFiles
+            if QtCore.QFile.exists(recentFile)]
         recentFilesToDisplay = existingRecentFiles[0:recentFileCount]
         if recentFilesToDisplay:
             self.FileMenu.addSeparator()

=== modified file 'openlp/core/ui/serviceitemeditdialog.py'
--- openlp/core/ui/serviceitemeditdialog.py	2011-02-02 19:30:06 +0000
+++ openlp/core/ui/serviceitemeditdialog.py	2011-02-04 03:37:59 +0000
@@ -26,8 +26,9 @@
 
 from PyQt4 import QtCore, QtGui
 
-from openlp.core.lib import translate, build_icon
-from openlp.core.lib.ui import save_cancel_button_box
+from openlp.core.lib import translate
+from openlp.core.lib.ui import save_cancel_button_box, delete_push_button, \
+    up_down_push_button_set
 
 class Ui_ServiceItemEditDialog(object):
     def setupUi(self, serviceItemEditDialog):
@@ -40,17 +41,12 @@
         self.dialogLayout.addWidget(self.listWidget, 0, 0)
         self.buttonLayout = QtGui.QVBoxLayout()
         self.buttonLayout.setObjectName(u'buttonLayout')
-        self.deleteButton = QtGui.QPushButton(serviceItemEditDialog)
-        self.deleteButton.setObjectName(u'deleteButton')
+        self.deleteButton = delete_push_button(serviceItemEditDialog)
         self.buttonLayout.addWidget(self.deleteButton)
         self.buttonLayout.addStretch()
-        self.upButton = QtGui.QPushButton(serviceItemEditDialog)
-        self.upButton.setIcon(build_icon(u':/services/service_up.png'))
-        self.upButton.setObjectName(u'upButton')
+        self.upButton, self.downButton = up_down_push_button_set(
+            serviceItemEditDialog)
         self.buttonLayout.addWidget(self.upButton)
-        self.downButton = QtGui.QPushButton(serviceItemEditDialog)
-        self.downButton.setIcon(build_icon(u':/services/service_down.png'))
-        self.downButton.setObjectName(u'downButton')
         self.buttonLayout.addWidget(self.downButton)
         self.dialogLayout.addLayout(self.buttonLayout, 0, 1)
         self.dialogLayout.addWidget(
@@ -61,5 +57,3 @@
     def retranslateUi(self, serviceItemEditDialog):
         serviceItemEditDialog.setWindowTitle(
             translate('OpenLP.ServiceItemEditForm', 'Reorder Service Item'))
-        self.deleteButton.setText(translate('OpenLP.ServiceItemEditForm',
-            'Delete'))

=== modified file 'openlp/core/ui/serviceitemeditform.py'
--- openlp/core/ui/serviceitemeditform.py	2011-02-01 00:33:50 +0000
+++ openlp/core/ui/serviceitemeditform.py	2011-02-04 03:37:59 +0000
@@ -39,13 +39,6 @@
         QtGui.QDialog.__init__(self, parent)
         self.setupUi(self)
         self.itemList = []
-        # enable drop
-        QtCore.QObject.connect(self.upButton,
-            QtCore.SIGNAL(u'clicked()'), self.onItemUp)
-        QtCore.QObject.connect(self.downButton,
-            QtCore.SIGNAL(u'clicked()'), self.onItemDown)
-        QtCore.QObject.connect(self.deleteButton,
-            QtCore.SIGNAL(u'clicked()'), self.onItemDelete)
         QtCore.QObject.connect(self.listWidget,
             QtCore.SIGNAL(u'currentRowChanged(int)'), self.onCurrentRowChanged)
 
@@ -77,7 +70,7 @@
             item_name = QtGui.QListWidgetItem(frame[u'title'])
             self.listWidget.addItem(item_name)
 
-    def onItemDelete(self):
+    def onDeleteButtonClicked(self):
         """
         Delete the current row.
         """
@@ -92,13 +85,13 @@
         else:
             self.listWidget.setCurrentRow(row)
 
-    def onItemUp(self):
+    def onUpButtonClicked(self):
         """
         Move the current row up in the list.
         """
         self.__moveItem(u'up')
 
-    def onItemDown(self):
+    def onDownButtonClicked(self):
         """
         Move the current row down in the list
         """

=== modified file 'openlp/core/ui/slidecontroller.py'
--- openlp/core/ui/slidecontroller.py	2011-02-01 18:05:59 +0000
+++ openlp/core/ui/slidecontroller.py	2011-02-04 03:37:59 +0000
@@ -30,9 +30,10 @@
 from PyQt4 import QtCore, QtGui
 from PyQt4.phonon import Phonon
 
-from openlp.core.ui import HideMode, MainDisplay
 from openlp.core.lib import OpenLPToolbar, Receiver, resize_image, \
     ItemCapabilities, translate
+from openlp.core.lib.ui import shortcut_action
+from openlp.core.ui import HideMode, MainDisplay
 
 log = logging.getLogger(__name__)
 
@@ -317,18 +318,8 @@
         self.mediabar.setVisible(False)
         if self.isLive:
             self.setLiveHotkeys(self)
-            self.previewListWidget.addActions(
-                [self.previousItem,
-                self.nextItem,
-                self.previousService,
-                self.nextService,
-                self.escapeItem])
-            self.display.addActions(
-                [self.previousItem,
-                self.nextItem,
-                self.previousService,
-                self.nextService,
-                self.escapeItem])
+            self.__addActionsToWidget(self.previewListWidget)
+            self.__addActionsToWidget(self.display)
         else:
             self.setPreviewHotkeys()
             self.previewListWidget.addActions(
@@ -390,28 +381,17 @@
         self.nextItem.setShortcuts([QtCore.Qt.Key_Down, QtCore.Qt.Key_PageDown])
         self.nextItem.setShortcutContext(QtCore.Qt.WidgetWithChildrenShortcut)
         actionList.add_action(self.nextItem, u'Live')
-        self.previousService = QtGui.QAction(translate(
-            'OpenLP.SlideController', 'Previous Service'), parent)
-        self.previousService.setShortcuts([QtCore.Qt.Key_Left, 0])
-        self.previousService.setShortcutContext(
-            QtCore.Qt.WidgetWithChildrenShortcut)
-        QtCore.QObject.connect(self.previousService,
-            QtCore.SIGNAL(u'triggered()'), self.servicePrevious)
+        self.previousService = shortcut_action(parent,
+            translate('OpenLP.SlideController', 'Previous Service'),
+            [QtCore.Qt.Key_Left, 0], self.servicePrevious)
         actionList.add_action(self.previousService, u'Live')
-        self.nextService = QtGui.QAction(translate(
-            'OpenLP.SlideController', 'Next Service'), parent)
-        self.nextService.setShortcuts([QtCore.Qt.Key_Right, 0])
-        self.nextService.setShortcutContext(
-            QtCore.Qt.WidgetWithChildrenShortcut)
-        QtCore.QObject.connect(self.nextService,
-            QtCore.SIGNAL(u'triggered()'), self.serviceNext)
+        self.nextService = shortcut_action(parent,
+            translate('OpenLP.SlideController', 'Next Service'),
+            [QtCore.Qt.Key_Right, 0], self.serviceNext)
         actionList.add_action(self.nextService, u'Live')
-        self.escapeItem = QtGui.QAction(translate(
-            'OpenLP.SlideController', 'Escape Item'), parent)
-        self.escapeItem.setShortcuts([QtCore.Qt.Key_Escape, 0])
-        self.escapeItem.setShortcutContext(QtCore.Qt.WidgetWithChildrenShortcut)
-        QtCore.QObject.connect(self.escapeItem,
-            QtCore.SIGNAL(u'triggered()'), self.liveEscape)
+        self.escapeItem = shortcut_action(parent,
+            translate('OpenLP.SlideController', 'Escape Item'),
+            [QtCore.Qt.Key_Escape, 0], self.liveEscape)
         actionList.add_action(self.escapeItem, u'Live')
 
     def liveEscape(self):
@@ -435,12 +415,7 @@
         self.display.alertTab = self.alertTab
         self.display.setup()
         if self.isLive:
-            self.display.addActions(
-                [self.previousItem,
-                self.nextItem,
-                self.previousService,
-                self.nextService,
-                self.escapeItem])
+            self.__addActionsToWidget(self.display)
         # The SlidePreview's ratio.
         self.ratio = float(self.screens.current[u'size'].width()) / \
             float(self.screens.current[u'size'].height())
@@ -448,6 +423,12 @@
         if self.serviceItem:
             self.refreshServiceItem()
 
+    def __addActionsToWidget(self, widget):
+        widget.addActions([
+            self.previousItem, self.nextItem,
+            self.previousService, self.nextService,
+            self.escapeItem])
+
     def previewSizeChanged(self):
         """
         Takes care of the SlidePreview's size. Is called when one of the the
@@ -575,10 +556,7 @@
             slideno = 0
         # If service item is the same as the current on only change slide
         if item.__eq__(self.serviceItem):
-            if slideno + 1 < self.previewListWidget.rowCount():
-                self.previewListWidget.scrollToItem(
-                    self.previewListWidget.item(slideno + 1, 0))
-            self.previewListWidget.selectRow(slideno)
+            self.__checkUpdateSelectedSlide(slideno)
             self.onSlideSelected()
             return
         self._processItem(item, slideno)
@@ -677,10 +655,7 @@
             self.previewListWidget.selectRow(
                 self.previewListWidget.rowCount() - 1)
         else:
-            if slideno + 1 < self.previewListWidget.rowCount():
-                self.previewListWidget.scrollToItem(
-                    self.previewListWidget.item(slideno + 1, 0))
-            self.previewListWidget.selectRow(slideno)
+            self.__checkUpdateSelectedSlide(slideno)
 
     def onTextRequest(self):
         """
@@ -729,10 +704,7 @@
                 [self.serviceItem, self.isLive, index])
             self.updatePreview()
         else:
-            if index + 1 < self.previewListWidget.rowCount():
-                self.previewListWidget.scrollToItem(
-                    self.previewListWidget.item(index + 1, 0))
-            self.previewListWidget.selectRow(index)
+            self.__checkUpdateSelectedSlide(index)
             self.onSlideSelected()
 
     def mainDisplaySetBackground(self):
@@ -891,10 +863,7 @@
         """
         The slide has been changed. Update the slidecontroller accordingly
         """
-        if row + 1 < self.previewListWidget.rowCount():
-            self.previewListWidget.scrollToItem(
-                self.previewListWidget.item(row + 1, 0))
-        self.previewListWidget.selectRow(row)
+        self.__checkUpdateSelectedSlide(row)
         self.updatePreview()
         Receiver.send_message(u'slidecontroller_%s_changed' % self.typePrefix,
             row)
@@ -945,10 +914,7 @@
                 else:
                     Receiver.send_message('servicemanager_next_item')
                     return
-            if row + 1 < self.previewListWidget.rowCount():
-                self.previewListWidget.scrollToItem(
-                    self.previewListWidget.item(row + 1, 0))
-            self.previewListWidget.selectRow(row)
+            self.__checkUpdateSelectedSlide(row)
             self.onSlideSelected()
 
     def onSlideSelectedPreviousNoloop(self):
@@ -971,12 +937,15 @@
                     row = self.previewListWidget.rowCount() - 1
                 else:
                     row = 0
-            if row + 1 < self.previewListWidget.rowCount():
-                self.previewListWidget.scrollToItem(
-                    self.previewListWidget.item(row + 1, 0))
-            self.previewListWidget.selectRow(row)
+            self.__checkUpdateSelectedSlide(row)
             self.onSlideSelected()
 
+    def __checkUpdateSelectedSlide(self, row):
+        if row + 1 < self.previewListWidget.rowCount():
+            self.previewListWidget.scrollToItem(
+                self.previewListWidget.item(row + 1, 0))
+        self.previewListWidget.selectRow(row)
+
     def onSlideSelectedLast(self):
         """
         Go to the last slide.

=== modified file 'openlp/core/ui/themewizard.py'
--- openlp/core/ui/themewizard.py	2011-02-02 19:17:48 +0000
+++ openlp/core/ui/themewizard.py	2011-02-04 03:37:59 +0000
@@ -36,6 +36,8 @@
         themeWizard.setWizardStyle(QtGui.QWizard.ModernStyle)
         themeWizard.setOptions(QtGui.QWizard.IndependentPages |
             QtGui.QWizard.NoBackButtonOnStartPage)
+        self.spacer = QtGui.QSpacerItem(10, 0,
+            QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Minimum)
         # Welcome Page
         add_welcome_page(themeWizard, u':/wizards/wizard_createtheme.bmp')
         # Background Page
@@ -52,10 +54,8 @@
         self.backgroundComboBox.setObjectName(u'BackgroundComboBox')
         self.backgroundTypeLayout.addRow(self.backgroundLabel,
             self.backgroundComboBox)
-        self.backgroundTypeSpacer = QtGui.QSpacerItem(10, 0,
-            QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Minimum)
         self.backgroundTypeLayout.setItem(1, QtGui.QFormLayout.LabelRole,
-            self.backgroundTypeSpacer)
+            self.spacer)
         self.backgroundLayout.addLayout(self.backgroundTypeLayout)
         self.backgroundStack = QtGui.QStackedLayout()
         self.backgroundStack.setObjectName(u'BackgroundStack')
@@ -69,10 +69,7 @@
         self.colorButton = QtGui.QPushButton(self.colorWidget)
         self.colorButton.setObjectName(u'ColorButton')
         self.colorLayout.addRow(self.colorLabel, self.colorButton)
-        self.colorSpacer = QtGui.QSpacerItem(10, 0, QtGui.QSizePolicy.Fixed,
-            QtGui.QSizePolicy.Minimum)
-        self.colorLayout.setItem(1, QtGui.QFormLayout.LabelRole,
-            self.colorSpacer)
+        self.colorLayout.setItem(1, QtGui.QFormLayout.LabelRole, self.spacer)
         self.backgroundStack.addWidget(self.colorWidget)
         self.gradientWidget = QtGui.QWidget(self.backgroundPage)
         self.gradientWidget.setObjectName(u'GradientWidget')
@@ -98,10 +95,7 @@
         self.gradientComboBox.addItems([u'', u'', u'', u'', u''])
         self.gradientLayout.addRow(self.gradientTypeLabel,
             self.gradientComboBox)
-        self.gradientSpacer = QtGui.QSpacerItem(10, 0, QtGui.QSizePolicy.Fixed,
-            QtGui.QSizePolicy.Minimum)
-        self.gradientLayout.setItem(3, QtGui.QFormLayout.LabelRole,
-            self.gradientSpacer)
+        self.gradientLayout.setItem(3, QtGui.QFormLayout.LabelRole, self.spacer)
         self.backgroundStack.addWidget(self.gradientWidget)
         self.imageWidget = QtGui.QWidget(self.backgroundPage)
         self.imageWidget.setObjectName(u'ImageWidget')
@@ -121,10 +115,7 @@
             build_icon(u':/general/general_open.png'))
         self.imageFileLayout.addWidget(self.imageBrowseButton)
         self.imageLayout.addRow(self.imageLabel, self.imageFileLayout)
-        self.imageSpacer = QtGui.QSpacerItem(10, 0, QtGui.QSizePolicy.Fixed,
-            QtGui.QSizePolicy.Minimum)
-        self.imageLayout.setItem(1, QtGui.QFormLayout.LabelRole,
-            self.imageSpacer)
+        self.imageLayout.setItem(1, QtGui.QFormLayout.LabelRole, self.spacer)
         self.backgroundStack.addWidget(self.imageWidget)
         self.backgroundLayout.addLayout(self.backgroundStack)
         themeWizard.addPage(self.backgroundPage)
@@ -236,6 +227,8 @@
         self.footerSizeSpinBox.setObjectName(u'FooterSizeSpinBox')
         self.footerAreaLayout.addRow(self.footerSizeLabel,
             self.footerSizeSpinBox)
+        self.footerAreaLayout.setItem(3, QtGui.QFormLayout.LabelRole,
+            self.spacer)
         themeWizard.addPage(self.footerAreaPage)
         # Alignment Page
         self.alignmentPage = QtGui.QWizardPage()
@@ -261,6 +254,8 @@
         self.transitionsCheckBox.setObjectName(u'TransitionsCheckBox')
         self.alignmentLayout.addRow(self.transitionsLabel,
             self.transitionsCheckBox)
+        self.alignmentLayout.setItem(3, QtGui.QFormLayout.LabelRole,
+            self.spacer)
         themeWizard.addPage(self.alignmentPage)
         # Area Position Page
         self.areaPositionPage = QtGui.QWizardPage()
@@ -552,16 +547,6 @@
             translate('OpenLP.ThemeWizard', 'Theme name:'))
         # Align all QFormLayouts towards each other.
         labelWidth = max(self.backgroundLabel.minimumSizeHint().width(),
-            self.colorLabel.minimumSizeHint().width(),
-            self.gradientStartLabel.minimumSizeHint().width(),
-            self.gradientEndLabel.minimumSizeHint().width(),
-            self.gradientTypeLabel.minimumSizeHint().width(),
-            self.imageLabel.minimumSizeHint().width())
-        self.backgroundTypeSpacer.changeSize(labelWidth, 0,
-            QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
-        self.colorSpacer.changeSize(labelWidth, 0,
-            QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
-        self.gradientSpacer.changeSize(labelWidth, 0,
-            QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
-        self.imageSpacer.changeSize(labelWidth, 0,
+            self.horizontalLabel.minimumSizeHint().width())
+        self.spacer.changeSize(labelWidth, 0,
             QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)

=== modified file 'openlp/plugins/alerts/forms/alertdialog.py'
--- openlp/plugins/alerts/forms/alertdialog.py	2011-02-03 19:11:27 +0000
+++ openlp/plugins/alerts/forms/alertdialog.py	2011-02-04 03:37:59 +0000
@@ -27,6 +27,7 @@
 from PyQt4 import QtCore, QtGui
 
 from openlp.core.lib import build_icon, translate
+from openlp.core.lib.ui import delete_push_button
 
 class Ui_AlertDialog(object):
     def setupUi(self, alertDialog):
@@ -65,10 +66,8 @@
         self.saveButton.setIcon(build_icon(u':/general/general_save.png'))
         self.saveButton.setObjectName(u'saveButton')
         self.manageButtonLayout.addWidget(self.saveButton)
-        self.deleteButton = QtGui.QPushButton(alertDialog)
+        self.deleteButton = delete_push_button(alertDialog)
         self.deleteButton.setEnabled(False)
-        self.deleteButton.setIcon(build_icon(u':/general/general_delete.png'))
-        self.deleteButton.setObjectName(u'deleteButton')
         self.manageButtonLayout.addWidget(self.deleteButton)
         self.manageButtonLayout.addStretch()
         self.alertDialogLayout.addLayout(self.manageButtonLayout, 1, 1)
@@ -104,8 +103,6 @@
             translate('AlertsPlugin.AlertForm', '&New'))
         self.saveButton.setText(
             translate('AlertsPlugin.AlertForm', '&Save'))
-        self.deleteButton.setText(
-            translate('AlertsPlugin.AlertForm', '&Delete'))
         self.displayButton.setText(
             translate('AlertsPlugin.AlertForm', 'Displ&ay'))
         self.displayCloseButton.setText(

=== modified file 'openlp/plugins/alerts/forms/alertform.py'
--- openlp/plugins/alerts/forms/alertform.py	2011-02-03 19:33:48 +0000
+++ openlp/plugins/alerts/forms/alertform.py	2011-02-04 03:37:59 +0000
@@ -52,8 +52,6 @@
             QtCore.SIGNAL(u'textChanged(const QString&)'), self.onTextChanged)
         QtCore.QObject.connect(self.newButton,
             QtCore.SIGNAL(u'clicked()'), self.onNewClick)
-        QtCore.QObject.connect(self.deleteButton,
-            QtCore.SIGNAL(u'clicked()'), self.onDeleteClick)
         QtCore.QObject.connect(self.saveButton,
             QtCore.SIGNAL(u'clicked()'), self.onSaveClick)
         QtCore.QObject.connect(self.alertListWidget,
@@ -82,7 +80,7 @@
         if self.triggerAlert(unicode(self.alertTextEdit.text())):
             self.close()
 
-    def onDeleteClick(self):
+    def onDeleteButtonClicked(self):
         """
         Deletes the selected item.
         """

=== modified file 'openlp/plugins/bibles/forms/bibleimportform.py'
--- openlp/plugins/bibles/forms/bibleimportform.py	2011-02-02 23:12:31 +0000
+++ openlp/plugins/bibles/forms/bibleimportform.py	2011-02-04 03:37:59 +0000
@@ -157,10 +157,9 @@
         self.formatComboBox.addItems([u'', u'', u'', u'', u''])
         self.formatComboBox.setObjectName(u'FormatComboBox')
         self.formatLayout.addRow(self.formatLabel, self.formatComboBox)
-        self.formatSpacer = QtGui.QSpacerItem(10, 0, QtGui.QSizePolicy.Fixed,
+        self.spacer = QtGui.QSpacerItem(10, 0, QtGui.QSizePolicy.Fixed,
             QtGui.QSizePolicy.Minimum)
-        self.formatLayout.setItem(1, QtGui.QFormLayout.LabelRole,
-            self.formatSpacer)
+        self.formatLayout.setItem(1, QtGui.QFormLayout.LabelRole, self.spacer)
         self.selectPageLayout.addLayout(self.formatLayout)
         self.selectStack = QtGui.QStackedLayout()
         self.selectStack.setObjectName(u'SelectStack')
@@ -181,9 +180,7 @@
         self.osisBrowseButton.setObjectName(u'OsisBrowseButton')
         self.osisFileLayout.addWidget(self.osisBrowseButton)
         self.osisLayout.addRow(self.osisFileLabel, self.osisFileLayout)
-        self.osisSpacer = QtGui.QSpacerItem(10, 0, QtGui.QSizePolicy.Fixed,
-            QtGui.QSizePolicy.Minimum)
-        self.osisLayout.setItem(1, QtGui.QFormLayout.LabelRole, self.osisSpacer)
+        self.osisLayout.setItem(1, QtGui.QFormLayout.LabelRole, self.spacer)
         self.selectStack.addWidget(self.osisWidget)
         self.csvWidget = QtGui.QWidget(self.selectPage)
         self.csvWidget.setObjectName(u'CsvWidget')
@@ -226,9 +223,7 @@
         self.csvVersesButton.setObjectName(u'CsvVersesButton')
         self.csvVersesLayout.addWidget(self.csvVersesButton)
         self.csvLayout.addRow(self.csvVersesLabel, self.csvVersesLayout)
-        self.csvSpacer = QtGui.QSpacerItem(10, 0, QtGui.QSizePolicy.Fixed,
-            QtGui.QSizePolicy.Minimum)
-        self.csvLayout.setItem(3, QtGui.QFormLayout.LabelRole, self.csvSpacer)
+        self.csvLayout.setItem(3, QtGui.QFormLayout.LabelRole, self.spacer)
         self.selectStack.addWidget(self.csvWidget)
         self.openSongWidget = QtGui.QWidget(self.selectPage)
         self.openSongWidget.setObjectName(u'OpenSongWidget')
@@ -248,10 +243,7 @@
         self.openSongFileLayout.addWidget(self.openSongBrowseButton)
         self.openSongLayout.addRow(self.openSongFileLabel,
             self.openSongFileLayout)
-        self.openSongSpacer = QtGui.QSpacerItem(10, 0, QtGui.QSizePolicy.Fixed,
-            QtGui.QSizePolicy.Minimum)
-        self.openSongLayout.setItem(1, QtGui.QFormLayout.LabelRole,
-            self.openSongSpacer)
+        self.openSongLayout.setItem(1, QtGui.QFormLayout.LabelRole, self.spacer)
         self.selectStack.addWidget(self.openSongWidget)
         self.webTabWidget = QtGui.QTabWidget(self.selectPage)
         self.webTabWidget.setObjectName(u'WebTabWidget')
@@ -330,10 +322,7 @@
         self.openlp1DisabledLabel.setWordWrap(True)
         self.openlp1DisabledLabel.setObjectName(u'Openlp1DisabledLabel')
         self.openlp1Layout.addRow(self.openlp1DisabledLabel)
-        self.openlp1Spacer = QtGui.QSpacerItem(10, 0, QtGui.QSizePolicy.Fixed,
-            QtGui.QSizePolicy.Minimum)
-        self.openlp1Layout.setItem(1, QtGui.QFormLayout.LabelRole,
-            self.openlp1Spacer)
+        self.openlp1Layout.setItem(1, QtGui.QFormLayout.LabelRole, self.spacer)
         self.selectStack.addWidget(self.openlp1Widget)
         self.selectPageLayout.addLayout(self.selectStack)
         self.addPage(self.selectPage)
@@ -401,17 +390,17 @@
         self.formatComboBox.setItemText(4,
             translate('BiblesPlugin.ImportWizardForm', 'openlp.org 1.x'))
         self.openlp1FileLabel.setText(
-            translate('BiblesPlugin.ImportWizardForm', 'File location:'))
+            translate('BiblesPlugin.ImportWizardForm', 'Bible file:'))
         self.osisFileLabel.setText(
-            translate('BiblesPlugin.ImportWizardForm', 'File location:'))
+            translate('BiblesPlugin.ImportWizardForm', 'Bible file:'))
         self.csvTestamentsLabel.setText(
-            translate('BiblesPlugin.ImportWizardForm', 'Testaments location:'))
+            translate('BiblesPlugin.ImportWizardForm', 'Testaments file:'))
         self.csvBooksLabel.setText(
-            translate('BiblesPlugin.ImportWizardForm', 'Books location:'))
+            translate('BiblesPlugin.ImportWizardForm', 'Books file:'))
         self.csvVersesLabel.setText(
-            translate('BiblesPlugin.ImportWizardForm', 'Verse location:'))
+            translate('BiblesPlugin.ImportWizardForm', 'Verses file:'))
         self.openSongFileLabel.setText(
-            translate('BiblesPlugin.ImportWizardForm', 'Bible filename:'))
+            translate('BiblesPlugin.ImportWizardForm', 'Bible file:'))
         self.webSourceLabel.setText(
             translate('BiblesPlugin.ImportWizardForm', 'Location:'))
         self.webSourceComboBox.setItemText(0,
@@ -462,19 +451,12 @@
         # Align all QFormLayouts towards each other.
         labelWidth = max(self.formatLabel.minimumSizeHint().width(),
             self.osisFileLabel.minimumSizeHint().width(),
+            self.csvTestamentsLabel.minimumSizeHint().width(),
             self.csvBooksLabel.minimumSizeHint().width(),
             self.csvVersesLabel.minimumSizeHint().width(),
             self.openSongFileLabel.minimumSizeHint().width(),
             self.openlp1FileLabel.minimumSizeHint().width())
-        self.formatSpacer.changeSize(labelWidth, 0,
-            QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
-        self.osisSpacer.changeSize(labelWidth, 0,
-            QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
-        self.csvSpacer.changeSize(labelWidth, 0,
-            QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
-        self.openSongSpacer.changeSize(labelWidth, 0,
-            QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
-        self.openlp1Spacer.changeSize(labelWidth, 0,
+        self.spacer.changeSize(labelWidth, 0,
             QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
 
     def validateCurrentPage(self):

=== modified file 'openlp/plugins/custom/forms/editcustomdialog.py'
--- openlp/plugins/custom/forms/editcustomdialog.py	2011-02-02 19:30:06 +0000
+++ openlp/plugins/custom/forms/editcustomdialog.py	2011-02-04 03:37:59 +0000
@@ -27,7 +27,8 @@
 from PyQt4 import QtCore, QtGui
 
 from openlp.core.lib import build_icon, translate
-from openlp.core.lib.ui import save_cancel_button_box
+from openlp.core.lib.ui import save_cancel_button_box, delete_push_button, \
+    up_down_push_button_set
 
 class Ui_CustomEditDialog(object):
     def setupUi(self, customEditDialog):
@@ -64,17 +65,12 @@
         self.editAllButton = QtGui.QPushButton(customEditDialog)
         self.editAllButton.setObjectName(u'editAllButton')
         self.buttonLayout.addWidget(self.editAllButton)
-        self.deleteButton = QtGui.QPushButton(customEditDialog)
-        self.deleteButton.setObjectName(u'deleteButton')
+        self.deleteButton = delete_push_button(customEditDialog)
         self.buttonLayout.addWidget(self.deleteButton)
         self.buttonLayout.addStretch()
-        self.upButton = QtGui.QPushButton(customEditDialog)
-        self.upButton.setIcon(build_icon(u':/services/service_up.png'))
-        self.upButton.setObjectName(u'upButton')
+        self.upButton, self.downButton = up_down_push_button_set(
+            customEditDialog)
         self.buttonLayout.addWidget(self.upButton)
-        self.downButton = QtGui.QPushButton(customEditDialog)
-        self.downButton.setIcon(build_icon(u':/services/service_down.png'))
-        self.downButton.setObjectName(u'downButton')
         self.buttonLayout.addWidget(self.downButton)
         self.centralLayout.addLayout(self.buttonLayout)
         self.dialogLayout.addLayout(self.centralLayout)
@@ -102,12 +98,6 @@
     def retranslateUi(self, customEditDialog):
         customEditDialog.setWindowTitle(
             translate('CustomPlugin.EditCustomForm', 'Edit Custom Slides'))
-        self.upButton.setToolTip(
-            translate('CustomPlugin.EditCustomForm', 'Move slide up one '
-            'position.'))
-        self.downButton.setToolTip(
-            translate('CustomPlugin.EditCustomForm', 'Move slide down one '
-            'position.'))
         self.titleLabel.setText(
             translate('CustomPlugin.EditCustomForm', '&Title:'))
         self.addButton.setText(
@@ -125,11 +115,6 @@
         self.editAllButton.setToolTip(
             translate('CustomPlugin.EditCustomForm', 'Edit all the slides at '
             'once.'))
-        self.deleteButton.setText(
-            translate('CustomPlugin.EditCustomForm', '&Delete'))
-        self.deleteButton.setToolTip(
-            translate('CustomPlugin.EditCustomForm', 'Delete the selected '
-            'slide.'))
         self.themeLabel.setText(
             translate('CustomPlugin.EditCustomForm', 'The&me:'))
         self.creditLabel.setText(

=== modified file 'openlp/plugins/custom/forms/editcustomform.py'
--- openlp/plugins/custom/forms/editcustomform.py	2011-02-02 23:12:31 +0000
+++ openlp/plugins/custom/forms/editcustomform.py	2011-02-04 03:37:59 +0000
@@ -62,12 +62,6 @@
             QtCore.SIGNAL(u'pressed()'), self.onEditButtonPressed)
         QtCore.QObject.connect(self.editAllButton,
             QtCore.SIGNAL(u'pressed()'), self.onEditAllButtonPressed)
-        QtCore.QObject.connect(self.deleteButton,
-            QtCore.SIGNAL(u'pressed()'), self.onDeleteButtonPressed)
-        QtCore.QObject.connect(self.upButton,
-            QtCore.SIGNAL(u'pressed()'), self.onUpButtonPressed)
-        QtCore.QObject.connect(self.downButton,
-            QtCore.SIGNAL(u'pressed()'), self.onDownButtonPressed)
         QtCore.QObject.connect(self.slideListView,
             QtCore.SIGNAL(u'itemClicked(QListWidgetItem*)'),
             self.onSlideListViewPressed)
@@ -168,14 +162,14 @@
         self.customSlide.theme_name = unicode(self.themeComboBox.currentText())
         return self.manager.save_object(self.customSlide)
 
-    def onUpButtonPressed(self):
+    def onUpButtonClicked(self):
         selectedRow = self.slideListView.currentRow()
         if selectedRow != 0:
             qw = self.slideListView.takeItem(selectedRow)
             self.slideListView.insertItem(selectedRow - 1, qw)
             self.slideListView.setCurrentRow(selectedRow - 1)
 
-    def onDownButtonPressed(self):
+    def onDownButtonClicked(self):
         selectedRow = self.slideListView.currentRow()
         # zero base arrays
         if selectedRow != self.slideListView.count() - 1:
@@ -243,7 +237,7 @@
                 self.slideListView.addItem(slide)
         self.slideListView.repaint()
 
-    def onDeleteButtonPressed(self):
+    def onDeleteButtonClicked(self):
         self.slideListView.takeItem(self.slideListView.currentRow())
         self.editButton.setEnabled(True)
         self.editAllButton.setEnabled(True)

=== modified file 'openlp/plugins/images/lib/mediaitem.py'
--- openlp/plugins/images/lib/mediaitem.py	2011-02-02 23:12:31 +0000
+++ openlp/plugins/images/lib/mediaitem.py	2011-02-04 03:37:59 +0000
@@ -123,19 +123,19 @@
                 self.settingsSection, self.getFileList())
 
     def loadList(self, list):
-        for file in list:
-            filename = os.path.split(unicode(file))[1]
+        for imageFile in list:
+            filename = os.path.split(unicode(imageFile))[1]
             thumb = os.path.join(self.servicePath, filename)
             if os.path.exists(thumb):
-                if self.validate(file, thumb):
+                if self.validate(imageFile, thumb):
                     icon = build_icon(thumb)
                 else:
                     icon = build_icon(u':/general/general_delete.png')
             else:
-                icon = self.iconFromFile(file, thumb)
+                icon = self.iconFromFile(imageFile, thumb)
             item_name = QtGui.QListWidgetItem(filename)
             item_name.setIcon(icon)
-            item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(file))
+            item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(imageFile))
             self.listView.addItem(item_name)
 
     def generateSlideData(self, service_item, item=None, xmlVersion=False):

=== modified file 'openlp/plugins/songs/forms/songimportform.py'
--- openlp/plugins/songs/forms/songimportform.py	2011-02-02 23:12:31 +0000
+++ openlp/plugins/songs/forms/songimportform.py	2011-02-04 03:37:59 +0000
@@ -162,6 +162,8 @@
         self.formatLayout.setItem(1, QtGui.QFormLayout.LabelRole,
             self.formatSpacer)
         self.sourceLayout.addLayout(self.formatLayout)
+        self.stackSpacer = QtGui.QSpacerItem(10, 0, QtGui.QSizePolicy.Fixed,
+            QtGui.QSizePolicy.Expanding)
         self.formatStack = QtGui.QStackedLayout()
         self.formatStack.setObjectName(u'FormatStack')
         # OpenLP 2.0
@@ -807,10 +809,8 @@
             browseButton.setIcon(self.openIcon)
             browseButton.setObjectName(obj_prefix + u'BrowseButton')
             fileLayout.addWidget(browseButton)
-            formSpacer = QtGui.QSpacerItem(10, 0, QtGui.QSizePolicy.Fixed,
-                QtGui.QSizePolicy.Expanding)
             importLayout.addLayout(fileLayout)
-            importLayout.addSpacerItem(formSpacer)
+            importLayout.addSpacerItem(self.stackSpacer)
         else:
             fileListWidget = QtGui.QListWidget(importWidget)
             fileListWidget.setSelectionMode(
@@ -859,6 +859,7 @@
         disabledLabel.setWordWrap(True)
         disabledLabel.setObjectName(obj_prefix + u'DisabledLabel')
         disabledLayout.addWidget(disabledLabel)
+        disabledLayout.addSpacerItem(self.stackSpacer)
         layout.addWidget(disabledWidget)
         importWidget = QtGui.QWidget(page)
         importWidget.setObjectName(obj_prefix + u'ImportWidget')

=== removed file 'scripts/bible-1to2-converter.py'
--- scripts/bible-1to2-converter.py	2010-09-18 16:11:37 +0000
+++ scripts/bible-1to2-converter.py	1970-01-01 00:00:00 +0000
@@ -1,308 +0,0 @@
-#!/usr/bin/env python
-# -*- 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                          #
-###############################################################################
-
-import sys
-import os
-import sqlite
-import sqlite3
-
-from optparse import OptionParser
-from traceback import format_tb as get_traceback
-
-# Some global options to be used throughout the import process
-verbose = False
-debug = False
-old_cursor = None
-new_cursor = None
-
-# SQL create statments
-create_statements = [
-    (u'table "book"', u"""CREATE TABLE book (
-        id INTEGER NOT NULL,
-        testament_id INTEGER,
-        name VARCHAR(30),
-        abbreviation VARCHAR(5),
-        PRIMARY KEY (id),
-        FOREIGN KEY(testament_id) REFERENCES testament (id)
-)"""),
-    (u'table "metadata"', u"""CREATE TABLE metadata (
-        "key" VARCHAR(255) NOT NULL,
-        value VARCHAR(255),
-        PRIMARY KEY ("key")
-)"""),
-    (u'table "testament"', u"""CREATE TABLE testament (
-        id INTEGER NOT NULL,
-        name VARCHAR(30),
-        PRIMARY KEY (id)
-)"""),
-    (u'table "verse"', u"""CREATE TABLE verse (
-        id INTEGER NOT NULL,
-        book_id INTEGER,
-        chapter INTEGER,
-        verse INTEGER,
-        text TEXT,
-        PRIMARY KEY (id),
-        FOREIGN KEY(book_id) REFERENCES book (id)
-)"""),
-    (u'index "idx_abbrev"',
-        u"""CREATE INDEX idx_abbrev ON book (abbreviation, id)"""),
-    (u'index "idx_chapter_verse_book',
-        u"""CREATE INDEX idx_chapter_verse_book ON verse (chapter, verse, book_id, id)"""),
-    (u'index "idx_chapter_verse_text"',
-        u"""CREATE INDEX idx_chapter_verse_text ON verse (text, verse, book_id, id)"""),
-    (u'index "idx_name"',
-        u"""CREATE INDEX idx_name ON book (name, id)""")
-]
-
-def display_sql(sql, params):
-    prepared_params = []
-    for param in params:
-        if isinstance(param, basestring):
-            prepared_params.append(u'"%s"' % param)
-        elif isinstance(param, (int, long)):
-            prepared_params.append(u'%d' % param)
-        elif isinstance(param, (float, complex)):
-            prepared_params.append(u'%f' % param)
-        else:
-            prepared_params.append(u'"%s"' % str(param))
-    for prepared_param in prepared_params:
-        sql = sql.replace(u'?', prepared_param, 1)
-    return sql
-
-def create_database():
-    global new_cursor, create_statements
-    if debug or verbose:
-        print 'Creating new database:'
-    else:
-        print 'Creating new database...',
-    for statement_type, sql_create in create_statements:
-        if debug:
-            print '... ', sql_create.replace('\n', ' ').replace('         ', ' ')
-        elif verbose:
-            print '... creating %s...' % statement_type,
-        new_cursor.execute(sql_create)
-        if verbose and not debug:
-            print 'done.'
-    if not verbose and not debug:
-        print 'done.'
-
-def import_bible():
-    global old_cursor, new_cursor, debug, verbose
-    if debug or verbose:
-        print 'Importing metadata:'
-    else:
-        print 'Importing metadata...',
-    if debug:
-        print '... SELECT "key", "value" FROM metadata'
-    elif verbose:
-        print '... fetching metadata from old database...',
-    old_cursor.execute(u'SELECT "key", "value" FROM metadata')
-    rows = old_cursor.fetchall()
-    if not debug and verbose:
-        print 'done.'
-    for row in rows:
-        key = unicode(row[0], u'cp1252')
-        value = unicode(row[1], u'cp1252')
-        if key == u'Permission':
-            key = u'Permissions'
-        sql_insert = u'INSERT INTO metadata '\
-            '("key", "value") '\
-            'VALUES (?, ?)'
-        sql_params = (key, value)
-        if debug:
-            print '...', display_sql(sql_insert, sql_params)
-        elif verbose:
-            print '... importing "%s"' % key
-        new_cursor.execute(sql_insert, sql_params)
-    if not verbose and not debug:
-        print 'done.'
-    if debug or verbose:
-        print 'Importing testaments:'
-    else:
-        print 'Importing testaments...',
-    if debug:
-        print '... SELECT id, name FROM testament'
-    elif verbose:
-        print '... fetching testaments from old database...',
-    old_cursor.execute(u'SELECT id, name FROM testament')
-    rows = old_cursor.fetchall()
-    if not debug and verbose:
-        print 'done.'
-    for row in rows:
-        id = int(row[0])
-        name = unicode(row[1], u'cp1252')
-        sql_insert = u'INSERT INTO testament '\
-            '(id, name) '\
-            'VALUES (?, ?)'
-        sql_params = (id, name)
-        if debug:
-            print '...', display_sql(sql_insert, sql_params)
-        elif verbose:
-            print '... importing "%s"' % name
-        new_cursor.execute(sql_insert, sql_params)
-    if not verbose and not debug:
-        print 'done.'
-    if debug or verbose:
-        print 'Importing books:'
-    else:
-        print 'Importing books...',
-    if debug:
-        print '... SELECT id, testament_id, name, abbreviation FROM book'
-    elif verbose:
-        print '... fetching books from old database...',
-    old_cursor.execute(u'SELECT id, testament_id, name, abbreviation FROM book')
-    rows = old_cursor.fetchall()
-    if not debug and verbose:
-        print 'done.'
-    book_map = {}
-    for row in rows:
-        testament_id = int(row[1])
-        name = unicode(row[2], u'cp1252')
-        abbreviation = unicode(row[3], u'cp1252')
-        sql_insert = u'INSERT INTO book '\
-            '(id, testament_id, name, abbreviation) '\
-            'VALUES (NULL, ?, ?, ?)'
-        sql_params = (testament_id, name, abbreviation)
-        if debug:
-            print '...', display_sql(sql_insert, sql_params)
-        elif verbose:
-            print '... importing "%s"' % name
-        new_cursor.execute(sql_insert, sql_params)
-        book_map[row[0]] = new_cursor.lastrowid
-        if debug:
-            print '    >>> (old) books.id =', row[0], ' (new) books.id =', book_map[row[0]]
-    if not verbose and not debug:
-        print 'done.'
-    if debug or verbose:
-        print 'Importing verses:'
-    else:
-        print 'Importing verses...',
-    if debug:
-        print '... SELECT id, book_id, chapter, verse, text || \'\' AS text FROM verse...',
-    elif verbose:
-        print '... fetching verses from old database...',
-    old_cursor.execute(u'SELECT id, book_id, chapter, verse, text || \'\' AS text FROM verse')
-    rows = old_cursor.fetchall()
-    if debug or verbose:
-        print 'done.'
-    for row in rows:
-        book_id = int(row[1])
-        chapter = int(row[2])
-        verse = int(row[3])
-        text = unicode(row[4], u'cp1252')
-        sql_insert = u'INSERT INTO verse '\
-            '(id, book_id, chapter, verse, text) '\
-            'VALUES (NULL, ?, ?, ?, ?)'
-        sql_params = (book_map[book_id], chapter, verse, text)
-        if debug:
-            print '...', display_sql(sql_insert, sql_params)
-        elif verbose:
-            print '... importing "%s..."' % text[:17]
-        new_cursor.execute(sql_insert, sql_params)
-    if not verbose and not debug:
-        print 'done.'
-
-def main(old_db, new_db):
-    global old_cursor, new_cursor, debug
-    old_connection = None
-    new_connection = None
-    try:
-        old_connection = sqlite.connect(old_db)
-    except:
-        if debug:
-            errormsg = '\n' + ''.join(get_traceback(sys.exc_info()[2]))\
-                + str(sys.exc_info()[1])
-        else:
-            errormsg = sys.exc_info()[1]
-        print 'There was a problem connecting to the old database:', errormsg
-        return 1
-    try:
-        new_connection = sqlite3.connect(new_db)
-    except:
-        if debug:
-            errormsg = '\n' + ''.join(get_traceback(sys.exc_info()[2]))\
-                + str(sys.exc_info()[1])
-        else:
-            errormsg = sys.exc_info()[1]
-        print 'There was a problem creating the new database:', errormsg
-        return 1
-    old_cursor = old_connection.cursor()
-    new_cursor = new_connection.cursor()
-    try:
-        create_database()
-    except:
-        if debug:
-            errormsg = '\n' + ''.join(get_traceback(sys.exc_info()[2]))\
-                + str(sys.exc_info()[1])
-        else:
-            errormsg = sys.exc_info()[1]
-        print 'There was a problem creating the database:', errormsg
-        return 1
-    try:
-        import_bible()
-        new_connection.commit()
-    except:
-        new_connection.rollback()
-        if debug:
-            errormsg = '\n' + ''.join(get_traceback(sys.exc_info()[2]))\
-                + str(sys.exc_info()[1])
-        else:
-            errormsg = sys.exc_info()[1]
-        print 'There was a problem importing songs:', errormsg
-        return 1
-    print 'Import complete.'
-
-if __name__ == u'__main__':
-    option_parser = OptionParser(usage='Usage: %prog [options] OLDDATABASE NEWDATABASE')
-    option_parser.add_option('-o', '--overwrite', dest='overwrite', default=False,
-        action=u'store_true', help='Overwrite database file if it already exists.')
-    option_parser.add_option('-v', '--verbose', dest='verbose', default=False,
-        action=u'store_true', help='Outputs additional progress data.')
-    option_parser.add_option('-d', '--debug', dest='debug', default=False,
-        action=u'store_true', help='Outputs raw SQL statements (overrides verbose).')
-    options, arguments = option_parser.parse_args()
-    if len(arguments) < 2:
-        if len(arguments) == 0:
-            option_parser.error('Please specify an old database and a new database.')
-        else:
-            option_parser.error('Please specify a new database.')
-    old_db = os.path.abspath(arguments[0])
-    new_db = os.path.abspath(arguments[1])
-    if not os.path.isfile(old_db):
-        option_parser.error('Old database file ("%s") is not a file.' % old_db)
-    if not os.path.exists(old_db):
-        option_parser.error('Old database file ("%s") does not exist.' % old_db)
-    if os.path.exists(new_db):
-        if not options.overwrite:
-            option_parser.error('New database file ("%s") exists. If you want to overwrite it, specify the --overwrite option.' % new_db)
-        else:
-            if not os.path.isfile(new_db):
-                option_parser.error('New database file ("%s") is not a file.' % new_db)
-            os.unlink(new_db)
-    verbose = options.verbose
-    debug = options.debug
-    main(old_db, new_db)

=== removed file 'scripts/openlp-1to2-converter.py'
--- scripts/openlp-1to2-converter.py	2010-07-27 09:32:52 +0000
+++ scripts/openlp-1to2-converter.py	1970-01-01 00:00:00 +0000
@@ -1,323 +0,0 @@
-#!/usr/bin/env python
-# -*- 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                          #
-###############################################################################
-
-import sys
-import os
-import sqlite
-import sqlite3
-import re
-from optparse import OptionParser
-from traceback import format_tb as get_traceback
-
-# Some global options to be used throughout the import process
-dirty_chars = re.compile(r'\W ', re.UNICODE)
-verbose = False
-debug = False
-old_cursor = None
-new_cursor = None
-
-# SQL create statments
-create_statements = [
-    (u'table "authors"', u"""CREATE TABLE authors (
-        id INTEGER NOT NULL,
-        first_name VARCHAR(128),
-        last_name VARCHAR(128),
-        display_name VARCHAR(255) NOT NULL,
-        PRIMARY KEY (id)
-)"""),
-    (u'table "song_books"', u"""CREATE TABLE song_books (
-        id INTEGER NOT NULL,
-        name VARCHAR(128) NOT NULL,
-        publisher VARCHAR(128),
-        PRIMARY KEY (id)
-)"""),
-    (u'table "songs"', u"""CREATE TABLE songs (
-        id INTEGER NOT NULL,
-        song_book_id INTEGER,
-        title VARCHAR(255) NOT NULL,
-        alternate_title VARCHAR(255),
-        lyrics TEXT NOT NULL,
-        verse_order VARCHAR(128),
-        copyright VARCHAR(255),
-        comments TEXT,
-        ccli_number VARCHAR(64),
-        song_number VARCHAR(64),
-        theme_name VARCHAR(128),
-        search_title VARCHAR(255) NOT NULL,
-        search_lyrics TEXT NOT NULL,
-        PRIMARY KEY (id),
-         FOREIGN KEY(song_book_id) REFERENCES song_books (id)
-)"""),
-    (u'table "topics"', u"""CREATE TABLE topics (
-        id INTEGER NOT NULL,
-        name VARCHAR(128) NOT NULL,
-        PRIMARY KEY (id)
-)"""),
-    (u'index "ix_songs_search_lyrics"',
-        u"""CREATE INDEX ix_songs_search_lyrics ON songs (search_lyrics)"""),
-    (u'index "ix_songs_search_title',
-        u"""CREATE INDEX ix_songs_search_title ON songs (search_title)"""),
-    (u'table "authors_songs"', u"""CREATE TABLE authors_songs (
-        author_id INTEGER NOT NULL,
-        song_id INTEGER NOT NULL,
-        PRIMARY KEY (author_id, song_id),
-         FOREIGN KEY(author_id) REFERENCES authors (id),
-         FOREIGN KEY(song_id) REFERENCES songs (id)
-)"""),
-    (u'table "songs_topics"', u"""CREATE TABLE songs_topics (
-        song_id INTEGER NOT NULL,
-        topic_id INTEGER NOT NULL,
-        PRIMARY KEY (song_id, topic_id),
-         FOREIGN KEY(song_id) REFERENCES songs (id),
-         FOREIGN KEY(topic_id) REFERENCES topics (id)
-)""")
-]
-
-def prepare_string(dirty):
-    return dirty_chars.sub(u'', dirty.replace(u'\r\n', u' ').replace(u'\n', u' '))
-
-def display_sql(sql, params):
-    prepared_params = []
-    for param in params:
-        if isinstance(param, basestring):
-            prepared_params.append(u'"%s"' % param)
-        elif isinstance(param, (int, long)):
-            prepared_params.append(u'%d' % param)
-        elif isinstance(param, (float, complex)):
-            prepared_params.append(u'%f' % param)
-        else:
-            prepared_params.append(u'"%s"' % str(param))
-    for prepared_param in prepared_params:
-        sql = sql.replace(u'?', prepared_param, 1)
-    return sql
-
-def create_database():
-    global new_cursor, create_statements
-    if debug or verbose:
-        print 'Creating new database:'
-    else:
-        print 'Creating new database...',
-    for statement_type, sql_create in create_statements:
-        if debug:
-            print '... ', sql_create.replace('\n', ' ').replace('         ', ' ')
-        elif verbose:
-            print '... creating %s...' % statement_type,
-        new_cursor.execute(sql_create)
-        if verbose and not debug:
-            print 'done.'
-    if not verbose and not debug:
-        print 'done.'
-
-def import_songs():
-    global old_cursor, new_cursor, debug, verbose
-    if debug or verbose:
-        print 'Importing authors:'
-    else:
-        print 'Importing authors...',
-    if debug:
-        print '... SELECT authorid AS id, authorname AS displayname FROM authors'
-    elif verbose:
-        print '... fetching authors from old database...',
-    old_cursor.execute(u'SELECT authorid AS id, authorname AS displayname FROM authors')
-    rows = old_cursor.fetchall()
-    if not debug and verbose:
-        print 'done.'
-    author_map = {}
-    for row in rows:
-        display_name = unicode(row[1], u'cp1252')
-        names = display_name.split(u' ')
-        first_name = names[0]
-        last_name = u' '.join(names[1:])
-        if last_name is None:
-            last_name = u''
-        sql_insert = u'INSERT INTO authors '\
-            '(id, first_name, last_name, display_name) '\
-            'VALUES (NULL, ?, ?, ?)'
-        sql_params = (first_name, last_name, display_name)
-        if debug:
-            print '...', display_sql(sql_insert, sql_params)
-        elif verbose:
-            print '... importing "%s"' % display_name
-        new_cursor.execute(sql_insert, sql_params)
-        author_map[row[0]] = new_cursor.lastrowid
-        if debug:
-            print '    >>> authors.authorid =', row[0], 'authors.id =', author_map[row[0]]
-    if not verbose and not debug:
-        print 'done.'
-    if debug or verbose:
-        print 'Importing songs:'
-    else:
-        print 'Importing songs...',
-    if debug:
-        print '... SELECT songid AS id, songtitle AS title, lyrics || \'\' AS lyrics, copyrightinfo AS copyright FROM songs...',
-    elif verbose:
-        print '... fetching songs from old database...',
-    old_cursor.execute(u'SELECT songid AS id, songtitle AS title, lyrics || \'\' AS lyrics, copyrightinfo AS copyright FROM songs')
-    rows = old_cursor.fetchall()
-    if debug or verbose:
-        print 'done.'
-    song_map = {}
-    xml_lyrics_template = u'<?xml version="1.0" encoding="utf-8"?><song version="1.0"><lyrics language="en">%s</lyrics></song>'
-    xml_verse_template = u'<verse label="%d" type="Verse"><![CDATA[%s]]></verse>'
-    for row in rows:
-        clean_title = unicode(row[1], u'cp1252')
-        clean_lyrics = unicode(row[2], u'cp1252').replace(u'\r\n', u'\n')
-        clean_copyright = unicode(row[3], u'cp1252')
-        verse_order = u''
-        text_lyrics = clean_lyrics.split(u'\n\n')
-        xml_verse = u''
-        verses = []
-        for line, verse in enumerate(text_lyrics):
-            if not verse:
-                continue
-            xml_verse += (xml_verse_template % (line + 1, verse))
-            verses.append(u'V%d' % (line + 1))
-        verse_order = u' '.join(verses)
-        xml_lyrics = xml_lyrics_template % xml_verse
-        search_title = prepare_string(clean_title)
-        search_lyrics = prepare_string(clean_lyrics)
-        sql_insert = u'INSERT INTO songs '\
-            '(id, song_book_id, title, lyrics, verse_order, copyright, search_title, search_lyrics) '\
-            'VALUES (NULL, 0, ?, ?, ?, ?, ?, ?)'
-        sql_params = (clean_title, xml_lyrics, verse_order, clean_copyright, search_title, search_lyrics)
-        if debug:
-            print '...', display_sql(sql_insert, (sql_params[0], u'%s...' % clean_lyrics[:7], sql_params[2], sql_params[3], sql_params[4], u'%s...' % search_lyrics[:7]))
-        elif verbose:
-            print '... importing "%s"' % clean_title
-        new_cursor.execute(sql_insert, sql_params)
-        song_map[row[0]] = new_cursor.lastrowid
-        if debug:
-            print '    >>> songs.songid =', row[0], 'songs.id =', song_map[row[0]]
-    if not verbose and not debug:
-        print 'done.'
-    if debug or verbose:
-        print 'Importing song-to-author mapping:'
-    else:
-        print 'Importing song-to-author mapping...',
-    if debug:
-        print '... SELECT authorid AS author_id, songid AS song_id FROM songauthors'
-    elif verbose:
-        print '... fetching song-to-author mapping from old database...',
-    old_cursor.execute(u'SELECT authorid AS author_id, songid AS song_id FROM songauthors')
-    rows = old_cursor.fetchall()
-    if not debug and verbose:
-        print 'done.'
-    for row in rows:
-        sql_insert = u'INSERT INTO authors_songs '\
-            '(author_id, song_id) '\
-            'VALUES (?, ?)'
-        sql_params = (author_map[row[0]], song_map[row[1]])
-        if debug:
-            print '... ', display_sql(sql_insert, sql_params)
-        elif verbose:
-            print '... Author %d (was %d) => Song %d (was %d)'\
-                % (int(row[0]), author_map[row[0]],
-                   int(row[1]), song_map[row[1]])
-        new_cursor.execute(sql_insert, sql_params)
-    if not verbose and not debug:
-        print 'done.'
-
-def main(old_db, new_db):
-    global old_cursor, new_cursor, debug
-    old_connection = None
-    new_connection = None
-    try:
-        old_connection = sqlite.connect(old_db)
-    except:
-        if debug:
-            errormsg = '\n' + ''.join(get_traceback(sys.exc_info()[2]))\
-                + str(sys.exc_info()[1])
-        else:
-            errormsg = sys.exc_info()[1]
-        print 'There was a problem connecting to the old database:', errormsg
-        return 1
-    try:
-        new_connection = sqlite3.connect(new_db)
-    except:
-        if debug:
-            errormsg = '\n' + ''.join(get_traceback(sys.exc_info()[2]))\
-                + str(sys.exc_info()[1])
-        else:
-            errormsg = sys.exc_info()[1]
-        print 'There was a problem creating the new database:', errormsg
-        return 1
-    old_cursor = old_connection.cursor()
-    new_cursor = new_connection.cursor()
-    try:
-        create_database()
-    except:
-        if debug:
-            errormsg = '\n' + ''.join(get_traceback(sys.exc_info()[2]))\
-                + str(sys.exc_info()[1])
-        else:
-            errormsg = sys.exc_info()[1]
-        print 'There was a problem creating the database:', errormsg
-        return 1
-    try:
-        import_songs()
-        new_connection.commit()
-    except:
-        new_connection.rollback()
-        if debug:
-            errormsg = '\n' + ''.join(get_traceback(sys.exc_info()[2]))\
-                + str(sys.exc_info()[1])
-        else:
-            errormsg = sys.exc_info()[1]
-        print 'There was a problem importing songs:', errormsg
-        return 1
-    print 'Import complete.'
-
-if __name__ == u'__main__':
-    option_parser = OptionParser(usage='Usage: %prog [options] OLDDATABASE NEWDATABASE')
-    option_parser.add_option('-o', '--overwrite', dest='overwrite', default=False,
-        action=u'store_true', help='Overwrite database file if it already exists.')
-    option_parser.add_option('-v', '--verbose', dest='verbose', default=False,
-        action=u'store_true', help='Outputs additional progress data.')
-    option_parser.add_option('-d', '--debug', dest='debug', default=False,
-        action=u'store_true', help='Outputs raw SQL statements (overrides verbose).')
-    options, arguments = option_parser.parse_args()
-    if len(arguments) < 2:
-        if len(arguments) == 0:
-            option_parser.error('Please specify an old database and a new database.')
-        else:
-            option_parser.error('Please specify a new database.')
-    old_db = os.path.abspath(arguments[0])
-    new_db = os.path.abspath(arguments[1])
-    if not os.path.isfile(old_db):
-        option_parser.error('Old database file ("%s") is not a file.' % old_db)
-    if not os.path.exists(old_db):
-        option_parser.error('Old database file ("%s") does not exist.' % old_db)
-    if os.path.exists(new_db):
-        if not options.overwrite:
-            option_parser.error('New database file ("%s") exists. If you want to overwrite it, specify the --overwrite option.' % new_db)
-        else:
-            if not os.path.isfile(new_db):
-                option_parser.error('New database file ("%s") is not a file.' % new_db)
-            os.unlink(new_db)
-    verbose = options.verbose
-    debug = options.debug
-    main(old_db, new_db)


Follow ups