← Back to team overview

openlp-core team mailing list archive

[Merge] lp:~trb143/openlp/bugs-2_4b into lp:openlp

 

Tim Bentley has proposed merging lp:~trb143/openlp/bugs-2_4b into lp:openlp.

Requested reviews:
  Raoul Snyman (raoul-snyman)
Related bugs:
  Bug #913508 in OpenLP: "cannot delete a theme if it is assigned to a song."
  https://bugs.launchpad.net/openlp/+bug/913508
  Bug #1168778 in OpenLP: "Search as you type setting in wrong settings tab"
  https://bugs.launchpad.net/openlp/+bug/1168778
  Bug #1281100 in OpenLP: "Unable to distinguish between songs with the same title."
  https://bugs.launchpad.net/openlp/+bug/1281100
  Bug #1390699 in OpenLP: "Better wording for "Plugin List""
  https://bugs.launchpad.net/openlp/+bug/1390699
  Bug #1390706 in OpenLP: "Improve File menu"
  https://bugs.launchpad.net/openlp/+bug/1390706
  Bug #1413217 in OpenLP: "optparse deprecated "
  https://bugs.launchpad.net/openlp/+bug/1413217
  Bug #1420276 in OpenLP: "Remove old upgrade code"
  https://bugs.launchpad.net/openlp/+bug/1420276
  Bug #1439304 in OpenLP: "Print service change font size"
  https://bugs.launchpad.net/openlp/+bug/1439304
  Bug #1487014 in OpenLP: "Image disappearing from images list"
  https://bugs.launchpad.net/openlp/+bug/1487014

For more details, see:
https://code.launchpad.net/~trb143/openlp/bugs-2_4b/+merge/276057

First merge for 2.4.

A Number of small bug fixes which could be done in 2.2.
Clean up all the 2.0 to 2.2 migrations stuff.
Create a 2.2 to 2.4 migration for settings.
Fix problems with the Tag test so you do not need to restart a branch each time we do a release.

lp:~trb143/openlp/bugs-2_4b (revision 2578)
[SUCCESS] https//ci.openlp.io/job/Branch-01-Pull/1164/
[SUCCESS] https//ci.openlp.io/job/Branch-02-Functional-Tests/1087/
[SUCCESS] https//ci.openlp.io/job/Branch-03-Interface-Tests/1028/
[SUCCESS] https//ci.openlp.io/job/Branch-04a-Windows_Functional_Tests/875/
[SUCCESS] https//ci.openlp.io/job/Branch-04b-Windows_Interface_Tests/471/
[SUCCESS] https//ci.openlp.io/job/Branch-05a-Code_Analysis/591/
[SUCCESS] https//ci.openlp.io/job/Branch-05b-Test_Coverage/462/

-- 
Your team OpenLP Core is subscribed to branch lp:openlp.
=== modified file 'openlp/core/__init__.py'
--- openlp/core/__init__.py	2015-03-24 22:33:57 +0000
+++ openlp/core/__init__.py	2015-10-28 21:25:33 +0000
@@ -30,7 +30,7 @@
 import os
 import sys
 import logging
-from optparse import OptionParser
+import argparse
 from traceback import format_exception
 import shutil
 import time
@@ -282,17 +282,18 @@
     :return: a tuple of parsed options of type optparse.Value and a list of remaining argsZ
     """
     # Set up command line options.
-    usage = 'Usage: %prog [options] [qt-options]'
-    parser = OptionParser(usage=usage)
-    parser.add_option('-e', '--no-error-form', dest='no_error_form', action='store_true',
-                      help='Disable the error notification form.')
-    parser.add_option('-l', '--log-level', dest='loglevel', default='warning', metavar='LEVEL',
-                      help='Set logging to LEVEL level. Valid values are "debug", "info", "warning".')
-    parser.add_option('-p', '--portable', dest='portable', action='store_true',
-                      help='Specify if this should be run as a portable app, off a USB flash drive (not implemented).')
-    parser.add_option('-d', '--dev-version', dest='dev_version', action='store_true',
-                      help='Ignore the version file and pull the version directly from Bazaar')
-    parser.add_option('-s', '--style', dest='style', help='Set the Qt4 style (passed directly to Qt4).')
+    parser = argparse.ArgumentParser(prog='openlp.py')
+    parser.add_argument('-e', '--no-error-form', dest='no_error_form', action='store_true',
+                        help='Disable the error notification form.')
+    parser.add_argument('-l', '--log-level', dest='loglevel', default='warning', metavar='LEVEL',
+                        help='Set logging to LEVEL level. Valid values are "debug", "info", "warning".')
+    parser.add_argument('-p', '--portable', dest='portable', action='store_true',
+                        help='Specify if this should be run as a portable app, '
+                             'off a USB flash drive (not implemented).')
+    parser.add_argument('-d', '--dev-version', dest='dev_version', action='store_true',
+                        help='Ignore the version file and pull the version directly from Bazaar')
+    parser.add_argument('-s', '--style', dest='style', help='Set the Qt4 style (passed directly to Qt4).')
+    parser.add_argument('rargs', nargs='?', default=[])
     # Parse command line options and deal with them. Use args supplied pragmatically if possible.
     return parser.parse_args(args) if args else parser.parse_args()
 
@@ -318,18 +319,18 @@
 
     :param args: Some args
     """
-    (options, args) = parse_options(args)
+    args = parse_options(args)
     qt_args = []
-    if options.loglevel.lower() in ['d', 'debug']:
+    if args and args.loglevel.lower() in ['d', 'debug']:
         log.setLevel(logging.DEBUG)
-    elif options.loglevel.lower() in ['w', 'warning']:
+    elif args and args.loglevel.lower() in ['w', 'warning']:
         log.setLevel(logging.WARNING)
     else:
         log.setLevel(logging.INFO)
-    if options.style:
-        qt_args.extend(['-style', options.style])
+    if args and args.style:
+        qt_args.extend(['-style', args.style])
     # Throw the rest of the arguments at Qt, just in case.
-    qt_args.extend(args)
+    qt_args.extend(args.rargs)
     # Bug #1018855: Set the WM_CLASS property in X11
     if not is_win() and not is_macosx():
         qt_args.append('OpenLP')
@@ -339,7 +340,7 @@
     application = OpenLP(qt_args)
     application.setOrganizationName('OpenLP')
     application.setOrganizationDomain('openlp.org')
-    if options.portable:
+    if args and args.portable:
         application.setApplicationName('OpenLPPortable')
         Settings.setDefaultFormat(Settings.IniFormat)
         # Get location OpenLPPortable.ini
@@ -383,6 +384,6 @@
         application.installTranslator(default_translator)
     else:
         log.debug('Could not find default_translator.')
-    if not options.no_error_form:
+    if args and not args.no_error_form:
         sys.excepthook = application.hook_exception
     sys.exit(application.run(qt_args))

=== modified file 'openlp/core/common/settings.py'
--- openlp/core/common/settings.py	2015-09-08 19:13:59 +0000
+++ openlp/core/common/settings.py	2015-10-28 21:25:33 +0000
@@ -118,6 +118,7 @@
         'advanced/slide limits': SlideLimits.End,
         'advanced/single click preview': False,
         'advanced/x11 bypass wm': X11_BYPASS_DEFAULT,
+        'advanced/search as type': True,
         'crashreport/last directory': '',
         'formattingTags/html_tags': '',
         'core/audio repeat list': False,
@@ -321,48 +322,10 @@
     }
     __file_path__ = ''
     __obsolete_settings__ = [
-        # Changed during 1.9.x development.
-        ('bibles/bookname language', 'bibles/book name language', []),
-        ('general/enable slide loop', 'advanced/slide limits', [(SlideLimits.Wrap, True), (SlideLimits.End, False)]),
-        ('songs/ccli number', 'core/ccli number', []),
-        ('media/use phonon', '', []),
-        # Changed during 2.1.x development.
-        ('advanced/stylesheet fix', '', []),
-        ('bibles/last directory 1', 'bibles/last directory import', []),
-        ('media/background color', 'players/background color', []),
-        ('themes/last directory', 'themes/last directory import', []),
-        ('themes/last directory 1', 'themes/last directory export', []),
-        ('songs/last directory 1', 'songs/last directory import', []),
-        ('songusage/last directory 1', 'songusage/last directory export', []),
-        ('user interface/mainwindow splitter geometry', 'user interface/main window splitter geometry', []),
-        ('shortcuts/makeLive', 'shortcuts/make_live', []),
-        ('general/audio repeat list', 'core/audio repeat list', []),
-        ('general/auto open', 'core/auto open', []),
-        ('general/auto preview', 'core/auto preview', []),
-        ('general/audio start paused', 'core/audio start paused', []),
-        ('general/auto unblank', 'core/auto unblank', []),
-        ('general/blank warning', 'core/blank warning', []),
-        ('general/ccli number', 'core/ccli number', []),
-        ('general/has run wizard', 'core/has run wizard', []),
-        ('general/language', 'core/language', []),
-        ('general/last version test', 'core/last version test', []),
-        ('general/loop delay', 'core/loop delay', []),
-        ('general/recent files', 'core/recent files', [(recent_files_conv, None)]),
-        ('general/save prompt', 'core/save prompt', []),
-        ('general/screen blank', 'core/screen blank', []),
-        ('general/show splash', 'core/show splash', []),
-        ('general/songselect password', 'core/songselect password', []),
-        ('general/songselect username', 'core/songselect username', []),
-        ('general/update check', 'core/update check', []),
-        ('general/view mode', 'core/view mode', []),
-        ('general/display on monitor', 'core/display on monitor', []),
-        ('general/override position', 'core/override position', []),
-        ('general/x position', 'core/x position', []),
-        ('general/y position', 'core/y position', []),
-        ('general/monitor', 'core/monitor', []),
-        ('general/height', 'core/height', []),
-        ('general/monitor', 'core/monitor', []),
-        ('general/width', 'core/width', [])
+        # Changed during 2.2.x development.
+        # ('advanced/stylesheet fix', '', []),
+        # ('general/recent files', 'core/recent files', [(recent_files_conv, None)]),
+        ('songs/search as type', 'advanced/search as type', [])
     ]
 
     @staticmethod

=== modified file 'openlp/core/common/uistrings.py'
--- openlp/core/common/uistrings.py	2015-04-21 21:49:22 +0000
+++ openlp/core/common/uistrings.py	2015-10-28 21:25:33 +0000
@@ -108,8 +108,9 @@
         self.NFSp = translate('OpenLP.Ui', 'No Files Selected', 'Plural')
         self.NISs = translate('OpenLP.Ui', 'No Item Selected', 'Singular')
         self.NISp = translate('OpenLP.Ui', 'No Items Selected', 'Plural')
-        self.OLPV2 = translate('OpenLP.Ui', 'OpenLP 2')
-        self.OLPV2x = translate('OpenLP.Ui', 'OpenLP 2.2')
+        self.OLP = translate('OpenLP.Ui', 'OpenLP')
+        self.OLPV2 = "%s %s" % (self.OLP, "2")
+        self.OLPV2x = "%s %s" % (self.OLP, "2.4")
         self.OpenLPStart = translate('OpenLP.Ui', 'OpenLP is already running. Do you wish to continue?')
         self.OpenService = translate('OpenLP.Ui', 'Open service.')
         self.PlaySlidesInLoop = translate('OpenLP.Ui', 'Play Slides in Loop')

=== modified file 'openlp/core/lib/plugin.py'
--- openlp/core/lib/plugin.py	2015-01-18 13:39:21 +0000
+++ openlp/core/lib/plugin.py	2015-10-28 21:25:33 +0000
@@ -288,13 +288,7 @@
         """
         Perform tasks on application startup
         """
-        # FIXME: Remove after 2.2 release.
-        # This is needed to load the list of media/presentation from the config saved before the settings rewrite.
-        if self.media_item_class is not None and self.name != 'images':
-            loaded_list = Settings().get_files_from_config(self)
-            # Now save the list to the config using our Settings class.
-            if loaded_list:
-                Settings().setValue('%s/%s files' % (self.settings_section, self.name), loaded_list)
+        pass
 
     def uses_theme(self, theme):
         """

=== modified file 'openlp/core/lib/serviceitem.py'
--- openlp/core/lib/serviceitem.py	2015-09-08 19:13:59 +0000
+++ openlp/core/lib/serviceitem.py	2015-10-28 21:25:33 +0000
@@ -129,7 +129,7 @@
     OnLoadUpdate = 8
     AddIfNewItem = 9
     ProvidesOwnDisplay = 10
-    HasDetailedTitleDisplay = 11
+    # HasDetailedTitleDisplay = 11
     HasVariableStartTime = 12
     CanSoftBreak = 13
     CanWordSplit = 14
@@ -415,11 +415,6 @@
         self.will_auto_start = header.get('will_auto_start', False)
         self.processor = header.get('processor', None)
         self.has_original_files = True
-        # TODO: Remove me in 2,3 build phase
-        if self.is_capable(ItemCapabilities.HasDetailedTitleDisplay):
-            self.capabilities.remove(ItemCapabilities.HasDetailedTitleDisplay)
-            self.processor = self.title
-            self.title = None
         if 'background_audio' in header:
             self.background_audio = []
             for filename in header['background_audio']:

=== modified file 'openlp/core/ui/advancedtab.py'
--- openlp/core/ui/advancedtab.py	2015-01-18 13:39:21 +0000
+++ openlp/core/ui/advancedtab.py	2015-10-28 21:25:33 +0000
@@ -80,6 +80,9 @@
         self.expand_service_item_check_box = QtGui.QCheckBox(self.ui_group_box)
         self.expand_service_item_check_box.setObjectName('expand_service_item_check_box')
         self.ui_layout.addRow(self.expand_service_item_check_box)
+        self.search_as_type_check_box = QtGui.QCheckBox(self.ui_group_box)
+        self.search_as_type_check_box.setObjectName('SearchAsType_check_box')
+        self.ui_layout.addRow(self.search_as_type_check_box)
         self.enable_auto_close_check_box = QtGui.QCheckBox(self.ui_group_box)
         self.enable_auto_close_check_box.setObjectName('enable_auto_close_check_box')
         self.ui_layout.addRow(self.enable_auto_close_check_box)
@@ -251,6 +254,7 @@
         self.end_slide_radio_button.clicked.connect(self.on_end_slide_button_clicked)
         self.wrap_slide_radio_button.clicked.connect(self.on_wrap_slide_button_clicked)
         self.next_item_radio_button.clicked.connect(self.on_next_item_button_clicked)
+        self.search_as_type_check_box.stateChanged.connect(self.on_search_as_type_check_box_changed)
 
     def retranslateUi(self):
         """
@@ -319,6 +323,7 @@
         self.end_slide_radio_button.setText(translate('OpenLP.GeneralTab', '&Remain on Slide'))
         self.wrap_slide_radio_button.setText(translate('OpenLP.GeneralTab', '&Wrap around'))
         self.next_item_radio_button.setText(translate('OpenLP.GeneralTab', '&Move to next/previous service item'))
+        self.search_as_type_check_box.setText(translate('SongsPlugin.GeneralTab', 'Enable search as you type'))
 
     def load(self):
         """
@@ -349,6 +354,8 @@
         self.default_color = settings.value('default color')
         self.default_file_edit.setText(settings.value('default image'))
         self.slide_limits = settings.value('slide limits')
+        self.search_as_you_type = settings.value('search as type')
+        self.search_as_type_check_box.setChecked(self.search_as_you_type)
         # Prevent the dialog displayed by the alternate_rows_check_box to display.
         self.alternate_rows_check_box.blockSignals(True)
         self.alternate_rows_check_box.setChecked(settings.value('alternate rows'))
@@ -424,8 +431,14 @@
             settings.setValue('x11 bypass wm', self.x11_bypass_check_box.isChecked())
             self.settings_form.register_post_process('config_screen_changed')
         self.settings_form.register_post_process('slidecontroller_update_slide_limits')
+        settings.setValue('search as type', self.search_as_you_type)
         settings.endGroup()
 
+    def on_search_as_type_check_box_changed(self, check_state):
+        self.search_as_you_type = (check_state == QtCore.Qt.Checked)
+        self.settings_form.register_post_process('songs_config_updated')
+        self.settings_form.register_post_process('custom_config_updated')
+
     def cancel(self):
         """
         Dialogue was cancelled, remove any pending data path change.

=== modified file 'openlp/core/ui/mainwindow.py'
--- openlp/core/ui/mainwindow.py	2015-08-24 18:19:30 +0000
+++ openlp/core/ui/mainwindow.py	2015-10-28 21:25:33 +0000
@@ -389,7 +389,7 @@
         self.file_menu.setTitle(translate('OpenLP.MainWindow', '&File'))
         self.file_import_menu.setTitle(translate('OpenLP.MainWindow', '&Import'))
         self.file_export_menu.setTitle(translate('OpenLP.MainWindow', '&Export'))
-        self.recent_files_menu.setTitle(translate('OpenLP.MainWindow', '&Recent Files'))
+        self.recent_files_menu.setTitle(translate('OpenLP.MainWindow', '&Recent Services'))
         self.view_menu.setTitle(translate('OpenLP.MainWindow', '&View'))
         self.view_mode_menu.setTitle(translate('OpenLP.MainWindow', 'M&ode'))
         self.tools_menu.setTitle(translate('OpenLP.MainWindow', '&Tools'))
@@ -400,16 +400,16 @@
         self.service_manager_dock.setWindowTitle(translate('OpenLP.MainWindow', 'Service Manager'))
         self.theme_manager_dock.setWindowTitle(translate('OpenLP.MainWindow', 'Theme Manager'))
         self.projector_manager_dock.setWindowTitle(translate('OpenLP.MainWindow', 'Projector Manager'))
-        self.file_new_item.setText(translate('OpenLP.MainWindow', '&New'))
+        self.file_new_item.setText(translate('OpenLP.MainWindow', '&New Service'))
         self.file_new_item.setToolTip(UiStrings().NewService)
         self.file_new_item.setStatusTip(UiStrings().CreateService)
-        self.file_open_item.setText(translate('OpenLP.MainWindow', '&Open'))
+        self.file_open_item.setText(translate('OpenLP.MainWindow', '&Open Service'))
         self.file_open_item.setToolTip(UiStrings().OpenService)
         self.file_open_item.setStatusTip(translate('OpenLP.MainWindow', 'Open an existing service.'))
-        self.file_save_item.setText(translate('OpenLP.MainWindow', '&Save'))
+        self.file_save_item.setText(translate('OpenLP.MainWindow', '&Save Service'))
         self.file_save_item.setToolTip(UiStrings().SaveService)
         self.file_save_item.setStatusTip(translate('OpenLP.MainWindow', 'Save the current service to disk.'))
-        self.file_save_as_item.setText(translate('OpenLP.MainWindow', 'Save &As...'))
+        self.file_save_as_item.setText(translate('OpenLP.MainWindow', 'Save Service &As...'))
         self.file_save_as_item.setToolTip(translate('OpenLP.MainWindow', 'Save Service As'))
         self.file_save_as_item.setStatusTip(translate('OpenLP.MainWindow',
                                             'Save the current service under a new name.'))
@@ -456,7 +456,7 @@
         self.lock_panel.setText(translate('OpenLP.MainWindow', 'L&ock Panels'))
         self.lock_panel.setStatusTip(translate('OpenLP.MainWindow', 'Prevent the panels being moved.'))
         self.view_live_panel.setStatusTip(translate('OpenLP.MainWindow', 'Toggle the visibility of the live panel.'))
-        self.settings_plugin_list_item.setText(translate('OpenLP.MainWindow', '&Plugin List'))
+        self.settings_plugin_list_item.setText(translate('OpenLP.MainWindow', '&Manage Plugins'))
         self.settings_plugin_list_item.setStatusTip(translate('OpenLP.MainWindow', 'List the Plugins'))
         self.about_item.setText(translate('OpenLP.MainWindow', '&About'))
         self.about_item.setStatusTip(translate('OpenLP.MainWindow', 'More information about OpenLP'))
@@ -505,7 +505,7 @@
         super(MainWindow, self).__init__()
         Registry().register('main_window', self)
         self.clipboard = self.application.clipboard()
-        self.arguments = self.application.args
+        self.arguments = ''.join(self.application.args)
         # Set up settings sections for the main application (not for use by plugins).
         self.ui_settings_section = 'user interface'
         self.general_settings_section = 'core'
@@ -634,7 +634,7 @@
             self.live_controller.display.setFocus()
         self.activateWindow()
         if self.arguments:
-            self.open_cmd_line_files()
+            self.open_cmd_line_files(self.arguments)
         elif Settings().value(self.general_settings_section + '/auto open'):
             self.service_manager_contents.load_last_file()
         view_mode = Settings().value('%s/view mode' % self.general_settings_section)
@@ -1416,15 +1416,11 @@
             settings.remove('advanced/data path')
         self.application.set_normal_cursor()
 
-    def open_cmd_line_files(self):
+    def open_cmd_line_files(self, filename):
         """
         Open files passed in through command line arguments
         """
-        args = []
-        for a in self.arguments:
-            args.extend([a])
-        for filename in args:
-            if not isinstance(filename, str):
-                filename = str(filename, sys.getfilesystemencoding())
-            if filename.endswith(('.osz', '.oszl')):
-                self.service_manager_contents.load_file(filename)
+        if not isinstance(filename, str):
+            filename = str(filename, sys.getfilesystemencoding())
+        if filename.endswith(('.osz', '.oszl')):
+            self.service_manager_contents.load_file(filename)

=== modified file 'openlp/core/ui/plugindialog.py'
--- openlp/core/ui/plugindialog.py	2015-01-18 13:39:21 +0000
+++ openlp/core/ui/plugindialog.py	2015-10-28 21:25:33 +0000
@@ -78,7 +78,7 @@
         """
         Translate the UI on the fly
         """
-        pluginViewDialog.setWindowTitle(translate('OpenLP.PluginForm', 'Plugin List'))
+        pluginViewDialog.setWindowTitle(translate('OpenLP.PluginForm', 'Manage Plugins'))
         self.plugin_info_group_box.setTitle(translate('OpenLP.PluginForm', 'Plugin Details'))
         self.version_label.setText('%s:' % UiStrings().Version)
         self.about_label.setText('%s:' % UiStrings().About)

=== modified file 'openlp/core/ui/printserviceform.py'
--- openlp/core/ui/printserviceform.py	2015-04-11 22:13:30 +0000
+++ openlp/core/ui/printserviceform.py	2015-10-28 21:25:33 +0000
@@ -162,7 +162,7 @@
         html_data = self._add_element('html')
         self._add_element('head', parent=html_data)
         self._add_element('title', self.title_line_edit.text(), html_data.head)
-        css_path = os.path.join(AppLocation.get_data_path(), 'service_print.css')
+        css_path = os.path.join(AppLocation.get_data_path(), 'serviceprint', 'service_print.css')
         custom_css = get_text_file_string(css_path)
         if not custom_css:
             custom_css = DEFAULT_CSS

=== modified file 'openlp/core/ui/thememanager.py'
--- openlp/core/ui/thememanager.py	2015-09-08 19:13:59 +0000
+++ openlp/core/ui/thememanager.py	2015-10-28 21:25:33 +0000
@@ -755,12 +755,19 @@
                 return False
             # check for use in the system else where.
             if test_plugin:
+                plugin_usage = ""
                 for plugin in self.plugin_manager.plugins:
-                    if plugin.uses_theme(theme):
-                        critical_error_message_box(translate('OpenLP.ThemeManager', 'Validation Error'),
-                                                   translate('OpenLP.ThemeManager',
-                                                             'Theme %s is used in the %s plugin.')
-                                                   % (theme, plugin.name))
-                        return False
+                    used_count = plugin.uses_theme(theme)
+                    if used_count:
+                        plugin_usage = "%s%s" % (plugin_usage, (translate('OpenLP.ThemeManager',
+                                                                          '%s time(s) by %s') %
+                                                                (used_count, plugin.name)))
+                        plugin_usage = "%s\n" % plugin_usage
+                if plugin_usage:
+                    critical_error_message_box(translate('OpenLP.ThemeManager', 'Unable to delete theme'),
+                                               translate('OpenLP.ThemeManager', 'Theme is currently used \n\n%s') %
+                                               plugin_usage)
+
+                    return False
             return True
         return False

=== modified file 'openlp/plugins/bibles/bibleplugin.py'
--- openlp/plugins/bibles/bibleplugin.py	2015-03-10 21:33:35 +0000
+++ openlp/plugins/bibles/bibleplugin.py	2015-10-28 21:25:33 +0000
@@ -178,12 +178,14 @@
 
     def uses_theme(self, theme):
         """
-        Called to find out if the bible plugin is currently using a theme. Returns ``True`` if the theme is being used,
-        otherwise returns ``False``.
+        Called to find out if the bible plugin is currently using a theme. Returns ``1`` if the theme is being used,
+        otherwise returns ``0``.
 
         :param theme: The theme
         """
-        return str(self.settings_tab.bible_theme) == theme
+        if str(self.settings_tab.bible_theme) == theme:
+            return 1
+        return 0
 
     def rename_theme(self, old_theme, new_theme):
         """

=== modified file 'openlp/plugins/bibles/lib/db.py'
--- openlp/plugins/bibles/lib/db.py	2015-09-08 19:13:26 +0000
+++ openlp/plugins/bibles/lib/db.py	2015-10-28 21:25:33 +0000
@@ -476,16 +476,6 @@
         self.save_meta('language_id', language_id)
         return language_id
 
-    def is_old_database(self):
-        """
-        Returns ``True`` if it is a bible database, which has been created prior to 1.9.6.
-        """
-        try:
-            self.session.query(Book).all()
-        except:
-            return True
-        return False
-
     def dump_bible(self):
         """
         Utility debugging method to dump the contents of a bible.

=== modified file 'openlp/plugins/bibles/lib/manager.py'
--- openlp/plugins/bibles/lib/manager.py	2015-01-31 21:52:02 +0000
+++ openlp/plugins/bibles/lib/manager.py	2015-10-28 21:25:33 +0000
@@ -129,11 +129,6 @@
                 bible.session.close()
                 delete_file(os.path.join(self.path, filename))
                 continue
-            # Find old database versions.
-            if bible.is_old_database():
-                self.old_bible_databases.append([filename, name])
-                bible.session.close()
-                continue
             log.debug('Bible Name: "%s"', name)
             self.db_cache[name] = bible
             # Look to see if lazy load bible exists and get create getter.

=== modified file 'openlp/plugins/custom/customplugin.py'
--- openlp/plugins/custom/customplugin.py	2015-02-11 20:56:13 +0000
+++ openlp/plugins/custom/customplugin.py	2015-10-28 21:25:33 +0000
@@ -72,11 +72,9 @@
         """
         Called to find out if the custom plugin is currently using a theme.
 
-        Returns True if the theme is being used, otherwise returns False.
+        Returns count of the times the theme is used.
         """
-        if self.db_manager.get_all_objects(CustomSlide, CustomSlide.theme_name == theme):
-            return True
-        return False
+        return len(self.db_manager.get_all_objects(CustomSlide, CustomSlide.theme_name == theme))
 
     def rename_theme(self, old_theme, new_theme):
         """

=== modified file 'openlp/plugins/custom/lib/mediaitem.py'
--- openlp/plugins/custom/lib/mediaitem.py	2015-04-02 20:49:19 +0000
+++ openlp/plugins/custom/lib/mediaitem.py	2015-10-28 21:25:33 +0000
@@ -85,6 +85,7 @@
         """
         log.debug('Config loaded')
         self.add_custom_from_service = Settings().value(self.settings_section + '/add custom from service')
+        self.search_as_you_type = Settings().value('advanced/search as type')
 
     def retranslateUi(self):
         """
@@ -269,11 +270,12 @@
 
         :param text: The search text
         """
-        search_length = 2
-        if len(text) > search_length:
-            self.on_search_text_button_clicked()
-        elif not text:
-            self.on_clear_text_button_click()
+        if self.search_as_you_type:
+            search_length = 2
+            if len(text) > search_length:
+                self.on_search_text_button_clicked()
+            elif not text:
+                self.on_clear_text_button_click()
 
     def service_load(self, item):
         """

=== modified file 'openlp/plugins/images/imageplugin.py'
--- openlp/plugins/images/imageplugin.py	2015-02-11 22:15:46 +0000
+++ openlp/plugins/images/imageplugin.py	2015-10-28 21:25:33 +0000
@@ -67,36 +67,13 @@
                                'provided by the theme.')
         return about_text
 
-    def app_startup(self):
-        """
-        Perform tasks on application startup.
-        """
-        # TODO: Can be removed when the upgrade path from 2.0.x to 2.2.x is no longer needed
-        Plugin.app_startup(self)
-        # Convert old settings-based image list to the database.
-        files_from_config = Settings().get_files_from_config(self)
-        if files_from_config:
-            for file in files_from_config:
-                filename = os.path.split(file)[1]
-                thumb = os.path.join(self.media_item.service_path, filename)
-                try:
-                    os.remove(thumb)
-                except:
-                    pass
-            log.debug('Importing images list from old config: %s' % files_from_config)
-            self.media_item.save_new_images_list(files_from_config)
-
     def upgrade_settings(self, settings):
         """
         Upgrade the settings of this plugin.
 
         :param settings: The Settings object containing the old settings.
         """
-        # TODO: Can be removed when the upgrade path from 2.0.x to 2.2.x is no longer needed
-        files_from_config = settings.get_files_from_config(self)
-        if files_from_config:
-            log.debug('Importing images list from old config: %s' % files_from_config)
-            self.media_item.save_new_images_list(files_from_config)
+        pass
 
     def set_plugin_text_strings(self):
         """

=== modified file 'openlp/plugins/images/lib/mediaitem.py'
--- openlp/plugins/images/lib/mediaitem.py	2015-09-08 19:13:59 +0000
+++ openlp/plugins/images/lib/mediaitem.py	2015-10-28 21:25:33 +0000
@@ -119,14 +119,6 @@
                 icon=':/general/general_edit.png',
                 triggers=self.on_edit_click)
             create_widget_action(self.list_view, separator=True)
-        if self.has_delete_icon:
-            create_widget_action(
-                self.list_view,
-                'listView%s%sItem' % (self.plugin.name.title(), StringContent.Delete.title()),
-                text=self.plugin.get_string(StringContent.Delete)['title'],
-                icon=':/general/general_delete.png',
-                can_shortcuts=True, triggers=self.on_delete_click)
-            create_widget_action(self.list_view, separator=True)
         create_widget_action(
             self.list_view,
             'listView%s%sItem' % (self.plugin.name.title(), StringContent.Preview.title()),
@@ -155,6 +147,14 @@
                 text=translate('OpenLP.MediaManagerItem', '&Add to selected Service Item'),
                 icon=':/general/general_add.png',
                 triggers=self.on_add_edit_click)
+            create_widget_action(self.list_view, separator=True)
+        if self.has_delete_icon:
+            create_widget_action(
+                self.list_view,
+                'listView%s%sItem' % (self.plugin.name.title(), StringContent.Delete.title()),
+                text=self.plugin.get_string(StringContent.Delete)['title'],
+                icon=':/general/general_delete.png',
+                can_shortcuts=True, triggers=self.on_delete_click)
         self.add_custom_context_actions()
         # Create the context menu and add all actions from the list_view.
         self.menu = QtGui.QMenu()

=== modified file 'openlp/plugins/presentations/presentationplugin.py'
--- openlp/plugins/presentations/presentationplugin.py	2015-05-26 21:26:59 +0000
+++ openlp/plugins/presentations/presentationplugin.py	2015-10-28 21:25:33 +0000
@@ -137,22 +137,6 @@
             self.register_controllers(controller)
         return bool(self.controllers)
 
-    def app_startup(self):
-        """
-        Perform tasks on application startup.
-        """
-        # TODO: Can be removed when the upgrade path from 2.0.x to 2.2.x is no longer needed
-        super().app_startup()
-        files_from_config = Settings().value('presentations/presentations files')
-        for file in files_from_config:
-            try:
-                self.media_item.clean_up_thumbnails(file, True)
-            except AttributeError:
-                pass
-        self.media_item.list_view.clear()
-        Settings().setValue('presentations/thumbnail_scheme', 'md5')
-        self.media_item.validate_and_load(files_from_config)
-
     def about(self):
         """
         Return information about this plugin.

=== modified file 'openlp/plugins/remotes/html/openlp.js'
--- openlp/plugins/remotes/html/openlp.js	2015-01-18 13:39:21 +0000
+++ openlp/plugins/remotes/html/openlp.js	2015-10-28 21:25:33 +0000
@@ -271,9 +271,15 @@
               if (typeof value[0] !== "number"){
                 value[0] = OpenLP.escapeString(value[0])
               }
+              var txt = "";
+              if (value[2].length > 0) {
+                txt = value[1] + " ( " + value[2] + " )";
+              } else {
+                txt = value[1];
+              }
               ul.append($("<li>").append($("<a>").attr("href", "#options")
                   .attr("data-rel", "dialog").attr("value", value[0])
-                  .click(OpenLP.showOptions).text(value[1])));
+                  .click(OpenLP.showOptions).text(txt)));
             });
         }
         ul.listview("refresh");

=== modified file 'openlp/plugins/remotes/lib/httprouter.py'
--- openlp/plugins/remotes/lib/httprouter.py	2015-02-14 09:12:35 +0000
+++ openlp/plugins/remotes/lib/httprouter.py	2015-10-28 21:25:33 +0000
@@ -309,10 +309,13 @@
         """
         Translate various strings in the mobile app.
         """
+        remote = translate('RemotePlugin.Mobile', 'Remote')
+        stage = translate('RemotePlugin.Mobile', 'Stage View')
+        live = translate('RemotePlugin.Mobile', 'Live View')
         self.template_vars = {
-            'app_title': translate('RemotePlugin.Mobile', 'OpenLP 2.2 Remote'),
-            'stage_title': translate('RemotePlugin.Mobile', 'OpenLP 2.2 Stage View'),
-            'live_title': translate('RemotePlugin.Mobile', 'OpenLP 2.2 Live View'),
+            'app_title': "%s %s" % (UiStrings().OLPV2x, remote),
+            'stage_title': "%s %s" % (UiStrings().OLPV2x, stage),
+            'live_title': "%s %s" % (UiStrings().OLPV2x, live),
             'service_manager': translate('RemotePlugin.Mobile', 'Service Manager'),
             'slide_controller': translate('RemotePlugin.Mobile', 'Slide Controller'),
             'alerts': translate('RemotePlugin.Mobile', 'Alerts'),

=== modified file 'openlp/plugins/songs/forms/editsongform.py'
--- openlp/plugins/songs/forms/editsongform.py	2015-01-18 13:39:21 +0000
+++ openlp/plugins/songs/forms/editsongform.py	2015-10-28 21:25:33 +0000
@@ -178,7 +178,7 @@
         if invalid_verses:
             valid = create_separated_list(verse_names)
             if len(invalid_verses) > 1:
-                msg = translate('SongsPlugin.EditSongForm', 'There are no verses corresponding to "%(invalid)s".'
+                msg = translate('SongsPlugin.EditSongForm', 'There are no verses corresponding to "%(invalid)s". '
                                 'Valid entries are %(valid)s.\nPlease enter the verses separated by spaces.') % \
                     {'invalid': ', '.join(invalid_verses), 'valid': valid}
             else:

=== modified file 'openlp/plugins/songs/lib/mediaitem.py'
--- openlp/plugins/songs/lib/mediaitem.py	2015-01-18 13:39:21 +0000
+++ openlp/plugins/songs/lib/mediaitem.py	2015-10-28 21:25:33 +0000
@@ -115,7 +115,7 @@
         Is triggered when the songs config is updated
         """
         log.debug('config_updated')
-        self.search_as_you_type = Settings().value(self.settings_section + '/search as type')
+        self.search_as_you_type = Settings().value('advanced/search as type')
         self.update_service_on_edit = Settings().value(self.settings_section + '/update service on edit')
         self.add_song_from_service = Settings().value(self.settings_section + '/add song from service')
         self.display_songbook = Settings().value(self.settings_section + '/display songbook')
@@ -590,4 +590,4 @@
         :param show_error: Is this an error?
         """
         search_results = self.search_entire(string)
-        return [[song.id, song.title] for song in search_results]
+        return [[song.id, song.title, song.alternate_title] for song in search_results]

=== modified file 'openlp/plugins/songs/lib/openlyricsxml.py'
--- openlp/plugins/songs/lib/openlyricsxml.py	2015-09-08 19:13:59 +0000
+++ openlp/plugins/songs/lib/openlyricsxml.py	2015-10-28 21:25:33 +0000
@@ -121,17 +121,7 @@
         """
         self.song_xml = None
         verse_list = []
-        if not xml.startswith('<?xml') and not xml.startswith('<song'):
-            # This is an old style song, without XML. Let's handle it correctly by iterating through the verses, and
-            # then recreating the internal xml object as well.
-            self.song_xml = objectify.fromstring('<song version="1.0" />')
-            self.lyrics = etree.SubElement(self.song_xml, 'lyrics')
-            verses = xml.split('\n\n')
-            for count, verse in enumerate(verses):
-                verse_list.append([{'type': 'v', 'label': str(count)}, str(verse)])
-                self.add_verse_to_lyrics('v', str(count), verse)
-            return verse_list
-        elif xml.startswith('<?xml'):
+        if xml.startswith('<?xml'):
             xml = xml[38:]
         try:
             self.song_xml = objectify.fromstring(xml)

=== modified file 'openlp/plugins/songs/lib/songstab.py'
--- openlp/plugins/songs/lib/songstab.py	2015-10-10 20:50:59 +0000
+++ openlp/plugins/songs/lib/songstab.py	2015-10-28 21:25:33 +0000
@@ -41,9 +41,6 @@
         self.mode_group_box.setObjectName('mode_group_box')
         self.mode_layout = QtGui.QVBoxLayout(self.mode_group_box)
         self.mode_layout.setObjectName('mode_layout')
-        self.search_as_type_check_box = QtGui.QCheckBox(self.mode_group_box)
-        self.search_as_type_check_box.setObjectName('SearchAsType_check_box')
-        self.mode_layout.addWidget(self.search_as_type_check_box)
         self.tool_bar_active_check_box = QtGui.QCheckBox(self.mode_group_box)
         self.tool_bar_active_check_box.setObjectName('tool_bar_active_check_box')
         self.mode_layout.addWidget(self.tool_bar_active_check_box)
@@ -62,7 +59,6 @@
         self.left_layout.addWidget(self.mode_group_box)
         self.left_layout.addStretch()
         self.right_layout.addStretch()
-        self.search_as_type_check_box.stateChanged.connect(self.on_search_as_type_check_box_changed)
         self.tool_bar_active_check_box.stateChanged.connect(self.on_tool_bar_active_check_box_changed)
         self.update_on_edit_check_box.stateChanged.connect(self.on_update_on_edit_check_box_changed)
         self.add_from_service_check_box.stateChanged.connect(self.on_add_from_service_check_box_changed)
@@ -71,7 +67,6 @@
 
     def retranslateUi(self):
         self.mode_group_box.setTitle(translate('SongsPlugin.SongsTab', 'Songs Mode'))
-        self.search_as_type_check_box.setText(translate('SongsPlugin.SongsTab', 'Enable search as you type'))
         self.tool_bar_active_check_box.setText(translate('SongsPlugin.SongsTab',
                                                          'Display verses on live tool bar'))
         self.update_on_edit_check_box.setText(translate('SongsPlugin.SongsTab', 'Update service from song edit'))
@@ -103,13 +98,11 @@
     def load(self):
         settings = Settings()
         settings.beginGroup(self.settings_section)
-        self.song_search = settings.value('search as type')
         self.tool_bar = settings.value('display songbar')
         self.update_edit = settings.value('update service on edit')
         self.update_load = settings.value('add song from service')
         self.display_songbook = settings.value('display songbook')
         self.display_copyright_symbol = settings.value('display copyright symbol')
-        self.search_as_type_check_box.setChecked(self.song_search)
         self.tool_bar_active_check_box.setChecked(self.tool_bar)
         self.update_on_edit_check_box.setChecked(self.update_edit)
         self.add_from_service_check_box.setChecked(self.update_load)
@@ -120,7 +113,6 @@
     def save(self):
         settings = Settings()
         settings.beginGroup(self.settings_section)
-        settings.setValue('search as type', self.song_search)
         settings.setValue('display songbar', self.tool_bar)
         settings.setValue('update service on edit', self.update_edit)
         settings.setValue('add song from service', self.update_load)

=== modified file 'openlp/plugins/songs/songsplugin.py'
--- openlp/plugins/songs/songsplugin.py	2015-02-11 20:56:13 +0000
+++ openlp/plugins/songs/songsplugin.py	2015-10-28 21:25:33 +0000
@@ -57,7 +57,6 @@
     'songs/last search type': SongSearch.Entire,
     'songs/last import type': SongFormat.OpenLyrics,
     'songs/update service on edit': False,
-    'songs/search as type': True,
     'songs/add song from service': True,
     'songs/display songbar': True,
     'songs/display songbook': False,
@@ -226,11 +225,9 @@
         Called to find out if the song plugin is currently using a theme.
 
         :param theme: The theme to check for usage
-        :return: True if the theme is being used, otherwise returns False
+        :return: count of the number of times the theme is used.
         """
-        if self.manager.get_all_objects(Song, Song.theme_name == theme):
-            return True
-        return False
+        return len(self.manager.get_all_objects(Song, Song.theme_name == theme))
 
     def rename_theme(self, old_theme, new_theme):
         """

=== added directory 'tests/functional/openlp_core'
=== added file 'tests/functional/openlp_core/test_init.py'
--- tests/functional/openlp_core/test_init.py	1970-01-01 00:00:00 +0000
+++ tests/functional/openlp_core/test_init.py	2015-10-28 21:25:33 +0000
@@ -0,0 +1,144 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection                                      #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2015 OpenLP Developers                                   #
+# --------------------------------------------------------------------------- #
+# 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
+from unittest import TestCase
+
+from openlp.core import parse_options
+from tests.helpers.testmixin import TestMixin
+
+
+class TestInitFunctions(TestMixin, TestCase):
+
+    def parse_options_basic_test(self):
+        """
+        Test the parse options process works
+
+        """
+        # GIVEN: a a set of system arguments.
+        sys.argv[1:] = []
+        # WHEN: We we parse them to expand to options
+        args = parse_options()
+        # THEN: the following fields will have been extracted.
+        self.assertFalse(args.dev_version, 'The dev_version flag should be False')
+        self.assertEquals(args.loglevel, 'warning', 'The log level should be set to warning')
+        self.assertFalse(args.no_error_form, 'The no_error_form should be set to False')
+        self.assertFalse(args.portable, 'The portable flag should be set to false')
+        self.assertEquals(args.style,  None, 'There are no style flags to be processed')
+        self.assertEquals(args.rargs, [], 'The service file should be blank')
+
+    def parse_options_debug_test(self):
+        """
+        Test the parse options process works for debug only
+
+        """
+        # GIVEN: a a set of system arguments.
+        sys.argv[1:] = ['-l debug']
+        # WHEN: We we parse them to expand to options
+        args = parse_options()
+        # THEN: the following fields will have been extracted.
+        self.assertFalse(args.dev_version, 'The dev_version flag should be False')
+        self.assertEquals(args.loglevel, ' debug', 'The log level should be set to debug')
+        self.assertFalse(args.no_error_form, 'The no_error_form should be set to False')
+        self.assertFalse(args.portable, 'The portable flag should be set to false')
+        self.assertEquals(args.style,  None, 'There are no style flags to be processed')
+        self.assertEquals(args.rargs, [], 'The service file should be blank')
+
+    def parse_options_debug_and_portable_test(self):
+        """
+        Test the parse options process works for debug and portable
+
+        """
+        # GIVEN: a a set of system arguments.
+        sys.argv[1:] = ['--portable']
+        # WHEN: We we parse them to expand to options
+        args = parse_options()
+        # THEN: the following fields will have been extracted.
+        self.assertFalse(args.dev_version, 'The dev_version flag should be False')
+        self.assertEquals(args.loglevel, 'warning', 'The log level should be set to warning')
+        self.assertFalse(args.no_error_form, 'The no_error_form should be set to False')
+        self.assertTrue(args.portable, 'The portable flag should be set to true')
+        self.assertEquals(args.style,  None, 'There are no style flags to be processed')
+        self.assertEquals(args.rargs, [], 'The service file should be blank')
+
+    def parse_options_all_no_file_test(self):
+        """
+        Test the parse options process works with two options
+
+        """
+        # GIVEN: a a set of system arguments.
+        sys.argv[1:] = ['-l debug', '-d']
+        # WHEN: We we parse them to expand to options
+        args = parse_options()
+        # THEN: the following fields will have been extracted.
+        self.assertTrue(args.dev_version, 'The dev_version flag should be True')
+        self.assertEquals(args.loglevel, ' debug', 'The log level should be set to debug')
+        self.assertFalse(args.no_error_form, 'The no_error_form should be set to False')
+        self.assertFalse(args.portable, 'The portable flag should be set to false')
+        self.assertEquals(args.style,  None, 'There are no style flags to be processed')
+        self.assertEquals(args.rargs, [], 'The service file should be blank')
+
+    def parse_options_file_test(self):
+        """
+        Test the parse options process works with a file
+
+        """
+        # GIVEN: a a set of system arguments.
+        sys.argv[1:] = ['dummy_temp']
+        # WHEN: We we parse them to expand to options
+        args = parse_options()
+        # THEN: the following fields will have been extracted.
+        self.assertFalse(args.dev_version, 'The dev_version flag should be False')
+        self.assertEquals(args.loglevel, 'warning', 'The log level should be set to warning')
+        self.assertFalse(args.no_error_form, 'The no_error_form should be set to False')
+        self.assertFalse(args.portable, 'The portable flag should be set to false')
+        self.assertEquals(args.style,  None, 'There are no style flags to be processed')
+        self.assertEquals(args.rargs, 'dummy_temp', 'The service file should not be blank')
+
+    def parse_options_file_and_debug_test(self):
+        """
+        Test the parse options process works with a file
+
+        """
+        # GIVEN: a a set of system arguments.
+        sys.argv[1:] = ['-l debug', 'dummy_temp']
+        # WHEN: We we parse them to expand to options
+        args = parse_options()
+        # THEN: the following fields will have been extracted.
+        self.assertFalse(args.dev_version, 'The dev_version flag should be False')
+        self.assertEquals(args.loglevel, ' debug', 'The log level should be set to debug')
+        self.assertFalse(args.no_error_form, 'The no_error_form should be set to False')
+        self.assertFalse(args.portable, 'The portable flag should be set to false')
+        self.assertEquals(args.style,  None, 'There are no style flags to be processed')
+        self.assertEquals(args.rargs, 'dummy_temp', 'The service file should not be blank')
+
+    def parse_options_two_files_test(self):
+        """
+        Test the parse options process works with a file
+
+        """
+        # GIVEN: a a set of system arguments.
+        sys.argv[1:] = ['dummy_temp', 'dummy_temp2']
+        # WHEN: We we parse them to expand to options
+        args = parse_options()
+        # THEN: the following fields will have been extracted.
+        self.assertEquals(args, None, 'The args should be None')

=== added file 'tests/functional/openlp_core_ui/test_advancedtab.py'
--- tests/functional/openlp_core_ui/test_advancedtab.py	1970-01-01 00:00:00 +0000
+++ tests/functional/openlp_core_ui/test_advancedtab.py	2015-10-28 21:25:33 +0000
@@ -0,0 +1,69 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection                                      #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2015 OpenLP Developers                                   #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it     #
+# under the terms of the GNU General Public License as published by the Free  #
+# Software Foundation; version 2 of the License.                              #
+#                                                                             #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for    #
+# more details.                                                               #
+#                                                                             #
+# You should have received a copy of the GNU General Public License along     #
+# with this program; if not, write to the Free Software Foundation, Inc., 59  #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA                          #
+###############################################################################
+"""
+Package to test the openlp.core.ui.advancedtab package.
+"""
+from unittest import TestCase
+
+from openlp.core.common import Registry
+from openlp.core.ui.advancedtab import AdvancedTab
+from openlp.core.ui.settingsform import SettingsForm
+
+from tests.helpers.testmixin import TestMixin
+
+
+class TestAdvancedTab(TestCase, TestMixin):
+
+    def setUp(self):
+        """
+        Set up a few things for the tests
+        """
+        Registry.create()
+
+    def test_creation(self):
+        """
+        Test that Advanced Tab is created.
+        """
+        # GIVEN: A new Advanced Tab
+        settings_form = SettingsForm(None)
+
+        # WHEN: I create an advanced tab
+        advanced_tab = AdvancedTab(settings_form)
+
+        # THEN:
+        self.assertEqual("Advanced", advanced_tab.tab_title, 'The tab title should be Advanced')
+
+    def test_change_search_as_type(self):
+        """
+        Test that when search as type is changed custom and song configs are updated
+        """
+        # GIVEN: A new Advanced Tab
+        settings_form = SettingsForm(None)
+        advanced_tab = AdvancedTab(settings_form)
+
+        # WHEN: I change search as type check box
+        advanced_tab.on_search_as_type_check_box_changed(True)
+
+        # THEN: we should have two post save processed to run
+        self.assertEqual(2, len(settings_form.processes), 'Two post save processes should be created')
+        self.assertTrue("songs_config_updated" in settings_form.processes, 'The songs plugin should be called')
+        self.assertTrue("custom_config_updated" in settings_form.processes, 'The custom plugin should be called')

=== modified file 'tests/functional/openlp_core_ui/test_mainwindow.py'
--- tests/functional/openlp_core_ui/test_mainwindow.py	2015-01-30 21:15:03 +0000
+++ tests/functional/openlp_core_ui/test_mainwindow.py	2015-10-28 21:25:33 +0000
@@ -71,7 +71,7 @@
         with patch('openlp.core.ui.servicemanager.ServiceManager.load_file') as mocked_load_path:
 
             # WHEN the argument is processed
-            self.main_window.open_cmd_line_files()
+            self.main_window.open_cmd_line_files(service)
 
             # THEN the service from the arguments is loaded
             mocked_load_path.assert_called_with(service), 'load_path should have been called with the service\'s path'
@@ -86,7 +86,7 @@
         with patch('openlp.core.ui.servicemanager.ServiceManager.load_file') as mocked_load_path:
 
             # WHEN the argument is processed
-            self.main_window.open_cmd_line_files()
+            self.main_window.open_cmd_line_files("")
 
             # THEN the file should not be opened
             assert not mocked_load_path.called, 'load_path should not have been called'

=== modified file 'tests/functional/openlp_core_utils/test_init.py'
--- tests/functional/openlp_core_utils/test_init.py	2015-01-19 08:34:29 +0000
+++ tests/functional/openlp_core_utils/test_init.py	2015-10-28 21:25:33 +0000
@@ -25,7 +25,7 @@
 from unittest import TestCase
 
 from openlp.core.common.settings import Settings
-from openlp.core.utils import VersionThread, get_application_version, get_uno_command
+from openlp.core.utils import VersionThread, get_uno_command
 from tests.functional import MagicMock, patch
 from tests.helpers.testmixin import TestMixin
 

=== modified file 'tests/functional/test_init.py'
--- tests/functional/test_init.py	2015-04-25 19:29:39 +0000
+++ tests/functional/test_init.py	2015-10-28 21:25:33 +0000
@@ -33,7 +33,6 @@
 from tests.helpers.testmixin import TestMixin
 from tests.functional import MagicMock, patch, call
 
-
 TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'resources'))
 
 
@@ -132,60 +131,3 @@
             # THEN: It should ask if we want to create a backup
             self.assertEqual(Settings().value('core/application version'), '2.2.0', 'Version should be upgraded!')
             self.assertEqual(mocked_question.call_count, 1, 'A question should have been asked!')
-
-    @patch(u'openlp.core.OptionParser')
-    def parse_options_test(self, MockedOptionParser):
-        """
-        Test that parse_options sets up OptionParser correctly and parses the options given
-        """
-        # GIVEN: A list of valid options and a mocked out OptionParser object
-        options = ['-e', '-l', 'debug', '-pd', '-s', 'style', 'extra', 'qt', 'args']
-        mocked_parser = MagicMock()
-        MockedOptionParser.return_value = mocked_parser
-        expected_calls = [
-            call('-e', '--no-error-form', dest='no_error_form', action='store_true',
-                 help='Disable the error notification form.'),
-            call('-l', '--log-level', dest='loglevel', default='warning', metavar='LEVEL',
-                 help='Set logging to LEVEL level. Valid values are "debug", "info", "warning".'),
-            call('-p', '--portable', dest='portable', action='store_true',
-                 help='Specify if this should be run as a portable app, off a USB flash drive (not implemented).'),
-            call('-d', '--dev-version', dest='dev_version', action='store_true',
-                 help='Ignore the version file and pull the version directly from Bazaar'),
-            call('-s', '--style', dest='style', help='Set the Qt4 style (passed directly to Qt4).')
-        ]
-
-        # WHEN: Calling parse_options
-        parse_options(options)
-
-        # THEN: A tuple should be returned with the parsed options and left over options
-        MockedOptionParser.assert_called_with(usage='Usage: %prog [options] [qt-options]')
-        self.assertEquals(expected_calls, mocked_parser.add_option.call_args_list)
-        mocked_parser.parse_args.assert_called_with(options)
-
-    @patch(u'openlp.core.OptionParser')
-    def parse_options_from_sys_argv_test(self, MockedOptionParser):
-        """
-        Test that parse_options sets up OptionParser correctly and parses sys.argv
-        """
-        # GIVEN: A list of valid options and a mocked out OptionParser object
-        mocked_parser = MagicMock()
-        MockedOptionParser.return_value = mocked_parser
-        expected_calls = [
-            call('-e', '--no-error-form', dest='no_error_form', action='store_true',
-                 help='Disable the error notification form.'),
-            call('-l', '--log-level', dest='loglevel', default='warning', metavar='LEVEL',
-                 help='Set logging to LEVEL level. Valid values are "debug", "info", "warning".'),
-            call('-p', '--portable', dest='portable', action='store_true',
-                 help='Specify if this should be run as a portable app, off a USB flash drive (not implemented).'),
-            call('-d', '--dev-version', dest='dev_version', action='store_true',
-                 help='Ignore the version file and pull the version directly from Bazaar'),
-            call('-s', '--style', dest='style', help='Set the Qt4 style (passed directly to Qt4).')
-        ]
-
-        # WHEN: Calling parse_options
-        parse_options([])
-
-        # THEN: A tuple should be returned with the parsed options and left over options
-        MockedOptionParser.assert_called_with(usage='Usage: %prog [options] [qt-options]')
-        self.assertEquals(expected_calls, mocked_parser.add_option.call_args_list)
-        mocked_parser.parse_args.assert_called_with()

=== modified file 'tests/utils/test_bzr_tags.py'
--- tests/utils/test_bzr_tags.py	2015-10-17 11:18:23 +0000
+++ tests/utils/test_bzr_tags.py	2015-10-28 21:25:33 +0000
@@ -23,39 +23,13 @@
 Package to test for proper bzr tags.
 """
 import os
-import re
 from unittest import TestCase
 
 from subprocess import Popen, PIPE
 
-TAGS = [
-    ['1.9.0', '1'],
-    ['1.9.1', '775'],
-    ['1.9.2', '890'],
-    ['1.9.3', '1063'],
-    ['1.9.4', '1196'],
-    ['1.9.5', '1421'],
-    ['1.9.6', '1657'],
-    ['1.9.7', '1761'],
-    ['1.9.8', '1856'],
-    ['1.9.9', '1917'],
-    ['1.9.10', '2003'],
-    ['1.9.11', '2039'],
-    ['1.9.12', '2063'],
-    ['2.0', '2118'],
-    ['2.1.0', '2119'],
-    ['2.1.1', '2438'],
-    ['2.1.2', '2488'],
-    ['2.1.3', '2513'],
-    ['2.1.4', '2532'],
-    ['2.1.5', '2543'],
-    ['2.1.6', '2550'],
-    ['2.2', '2562']
-]
-# Depending on the repository, we sometimes have the 2.0.x tags in the repo too. They come up with a revision number of
-# "?", which I suspect is due to the fact that we're using shared repositories. This regular expression matches all
-# 2.0.x tags.
-TAG_SEARCH = re.compile('2\.0\.\d')
+TAGS1 = {'1.9.0', '1.9.1', '1.9.2', '1.9.3', '1.9.4', '1.9.5', '1.9.6', '1.9.7', '1.9.8', '1.9.9', '1.9.10',
+         '1.9.11', '1.9.12', '2.0', '2.1.0', '2.1.1', '2.1.2', '2.1.3', '2.1.4', '2.1.5', '2.1.6', '2.2'
+         }
 
 
 class TestBzrTags(TestCase):
@@ -70,8 +44,12 @@
         # WHEN getting the branches tags
         bzr = Popen(('bzr', 'tags', '--directory=' + path), stdout=PIPE)
         std_out = bzr.communicate()[0]
-        tags = [line.decode('utf-8').split() for line in std_out.splitlines()]
-        tags = [t_r for t_r in tags if t_r[1] != '?' or not (t_r[1] == '?' and TAG_SEARCH.search(t_r[0]))]
+        count = len(TAGS1)
+        tags = [line.decode('utf-8').split()[0] for line in std_out.splitlines()]
+        count1 = 0
+        for t in tags:
+            if t in TAGS1:
+                count1 += 1
 
         # THEN the tags should match the accepted tags
-        self.assertEqual(TAGS, tags, 'List of tags should match')
+        self.assertEqual(count, count1, 'List of tags should match')


Follow ups