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/...

bzr-revno: 2566
Fixes: https://launchpad.net/bugs/913508, https://launchpad.net/bugs/1168778, https://launchpad.net/bugs/1281100, https://launchpad.net/bugs/1390699, https://launchpad.net/bugs/1390706, https://launchpad.net/bugs/1413217, https://launchpad.net/bugs/1420276, https://launchpad.net/bugs/1439304, https://launchpad.net/bugs/1487014
This commit is contained in:
tim.bentley@gmail.com 2015-11-05 19:05:19 +00:00 committed by Tim Bentley
commit 7c5add7fac
31 changed files with 351 additions and 312 deletions

View File

@ -30,7 +30,7 @@ logging and a plugin framework are contained within the openlp.core module.
import os import os
import sys import sys
import logging import logging
from optparse import OptionParser import argparse
from traceback import format_exception from traceback import format_exception
import shutil import shutil
import time import time
@ -282,17 +282,18 @@ def parse_options(args):
:return: a tuple of parsed options of type optparse.Value and a list of remaining argsZ :return: a tuple of parsed options of type optparse.Value and a list of remaining argsZ
""" """
# Set up command line options. # Set up command line options.
usage = 'Usage: %prog [options] [qt-options]' parser = argparse.ArgumentParser(prog='openlp.py')
parser = OptionParser(usage=usage) parser.add_argument('-e', '--no-error-form', dest='no_error_form', action='store_true',
parser.add_option('-e', '--no-error-form', dest='no_error_form', action='store_true', help='Disable the error notification form.')
help='Disable the error notification form.') parser.add_argument('-l', '--log-level', dest='loglevel', default='warning', metavar='LEVEL',
parser.add_option('-l', '--log-level', dest='loglevel', default='warning', metavar='LEVEL', help='Set logging to LEVEL level. Valid values are "debug", "info", "warning".')
help='Set logging to LEVEL level. Valid values are "debug", "info", "warning".') parser.add_argument('-p', '--portable', dest='portable', action='store_true',
parser.add_option('-p', '--portable', dest='portable', action='store_true', help='Specify if this should be run as a portable app, '
help='Specify if this should be run as a portable app, off a USB flash drive (not implemented).') 'off a USB flash drive (not implemented).')
parser.add_option('-d', '--dev-version', dest='dev_version', action='store_true', parser.add_argument('-d', '--dev-version', dest='dev_version', action='store_true',
help='Ignore the version file and pull the version directly from Bazaar') help='Ignore the version file and pull the version directly from Bazaar')
parser.add_option('-s', '--style', dest='style', help='Set the Qt4 style (passed directly to Qt4).') 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. # 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() return parser.parse_args(args) if args else parser.parse_args()
@ -318,18 +319,18 @@ def main(args=None):
:param args: Some args :param args: Some args
""" """
(options, args) = parse_options(args) args = parse_options(args)
qt_args = [] qt_args = []
if options.loglevel.lower() in ['d', 'debug']: if args and args.loglevel.lower() in ['d', 'debug']:
log.setLevel(logging.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) log.setLevel(logging.WARNING)
else: else:
log.setLevel(logging.INFO) log.setLevel(logging.INFO)
if options.style: if args and args.style:
qt_args.extend(['-style', options.style]) qt_args.extend(['-style', args.style])
# Throw the rest of the arguments at Qt, just in case. # 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 # Bug #1018855: Set the WM_CLASS property in X11
if not is_win() and not is_macosx(): if not is_win() and not is_macosx():
qt_args.append('OpenLP') qt_args.append('OpenLP')
@ -339,7 +340,7 @@ def main(args=None):
application = OpenLP(qt_args) application = OpenLP(qt_args)
application.setOrganizationName('OpenLP') application.setOrganizationName('OpenLP')
application.setOrganizationDomain('openlp.org') application.setOrganizationDomain('openlp.org')
if options.portable: if args and args.portable:
application.setApplicationName('OpenLPPortable') application.setApplicationName('OpenLPPortable')
Settings.setDefaultFormat(Settings.IniFormat) Settings.setDefaultFormat(Settings.IniFormat)
# Get location OpenLPPortable.ini # Get location OpenLPPortable.ini
@ -383,6 +384,6 @@ def main(args=None):
application.installTranslator(default_translator) application.installTranslator(default_translator)
else: else:
log.debug('Could not find default_translator.') 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.excepthook = application.hook_exception
sys.exit(application.run(qt_args)) sys.exit(application.run(qt_args))

View File

@ -118,6 +118,7 @@ class Settings(QtCore.QSettings):
'advanced/slide limits': SlideLimits.End, 'advanced/slide limits': SlideLimits.End,
'advanced/single click preview': False, 'advanced/single click preview': False,
'advanced/x11 bypass wm': X11_BYPASS_DEFAULT, 'advanced/x11 bypass wm': X11_BYPASS_DEFAULT,
'advanced/search as type': True,
'crashreport/last directory': '', 'crashreport/last directory': '',
'formattingTags/html_tags': '', 'formattingTags/html_tags': '',
'core/audio repeat list': False, 'core/audio repeat list': False,
@ -321,48 +322,10 @@ class Settings(QtCore.QSettings):
} }
__file_path__ = '' __file_path__ = ''
__obsolete_settings__ = [ __obsolete_settings__ = [
# Changed during 1.9.x development. # Changed during 2.2.x development.
('bibles/bookname language', 'bibles/book name language', []), # ('advanced/stylesheet fix', '', []),
('general/enable slide loop', 'advanced/slide limits', [(SlideLimits.Wrap, True), (SlideLimits.End, False)]), # ('general/recent files', 'core/recent files', [(recent_files_conv, None)]),
('songs/ccli number', 'core/ccli number', []), ('songs/search as type', 'advanced/search as type', [])
('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', [])
] ]
@staticmethod @staticmethod

View File

@ -108,8 +108,9 @@ class UiStrings(object):
self.NFSp = translate('OpenLP.Ui', 'No Files Selected', 'Plural') self.NFSp = translate('OpenLP.Ui', 'No Files Selected', 'Plural')
self.NISs = translate('OpenLP.Ui', 'No Item Selected', 'Singular') self.NISs = translate('OpenLP.Ui', 'No Item Selected', 'Singular')
self.NISp = translate('OpenLP.Ui', 'No Items Selected', 'Plural') self.NISp = translate('OpenLP.Ui', 'No Items Selected', 'Plural')
self.OLPV2 = translate('OpenLP.Ui', 'OpenLP 2') self.OLP = translate('OpenLP.Ui', 'OpenLP')
self.OLPV2x = translate('OpenLP.Ui', 'OpenLP 2.2') 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.OpenLPStart = translate('OpenLP.Ui', 'OpenLP is already running. Do you wish to continue?')
self.OpenService = translate('OpenLP.Ui', 'Open service.') self.OpenService = translate('OpenLP.Ui', 'Open service.')
self.PlaySlidesInLoop = translate('OpenLP.Ui', 'Play Slides in Loop') self.PlaySlidesInLoop = translate('OpenLP.Ui', 'Play Slides in Loop')

View File

@ -288,13 +288,7 @@ class Plugin(QtCore.QObject, RegistryProperties):
""" """
Perform tasks on application startup Perform tasks on application startup
""" """
# FIXME: Remove after 2.2 release. pass
# 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)
def uses_theme(self, theme): def uses_theme(self, theme):
""" """

View File

@ -129,7 +129,7 @@ class ItemCapabilities(object):
OnLoadUpdate = 8 OnLoadUpdate = 8
AddIfNewItem = 9 AddIfNewItem = 9
ProvidesOwnDisplay = 10 ProvidesOwnDisplay = 10
HasDetailedTitleDisplay = 11 # HasDetailedTitleDisplay = 11
HasVariableStartTime = 12 HasVariableStartTime = 12
CanSoftBreak = 13 CanSoftBreak = 13
CanWordSplit = 14 CanWordSplit = 14
@ -415,11 +415,6 @@ class ServiceItem(RegistryProperties):
self.will_auto_start = header.get('will_auto_start', False) self.will_auto_start = header.get('will_auto_start', False)
self.processor = header.get('processor', None) self.processor = header.get('processor', None)
self.has_original_files = True 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: if 'background_audio' in header:
self.background_audio = [] self.background_audio = []
for filename in header['background_audio']: for filename in header['background_audio']:

View File

@ -80,6 +80,9 @@ class AdvancedTab(SettingsTab):
self.expand_service_item_check_box = QtGui.QCheckBox(self.ui_group_box) 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.expand_service_item_check_box.setObjectName('expand_service_item_check_box')
self.ui_layout.addRow(self.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 = QtGui.QCheckBox(self.ui_group_box)
self.enable_auto_close_check_box.setObjectName('enable_auto_close_check_box') self.enable_auto_close_check_box.setObjectName('enable_auto_close_check_box')
self.ui_layout.addRow(self.enable_auto_close_check_box) self.ui_layout.addRow(self.enable_auto_close_check_box)
@ -251,6 +254,7 @@ class AdvancedTab(SettingsTab):
self.end_slide_radio_button.clicked.connect(self.on_end_slide_button_clicked) 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.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.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): def retranslateUi(self):
""" """
@ -319,6 +323,7 @@ class AdvancedTab(SettingsTab):
self.end_slide_radio_button.setText(translate('OpenLP.GeneralTab', '&Remain on Slide')) self.end_slide_radio_button.setText(translate('OpenLP.GeneralTab', '&Remain on Slide'))
self.wrap_slide_radio_button.setText(translate('OpenLP.GeneralTab', '&Wrap around')) 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.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): def load(self):
""" """
@ -349,6 +354,8 @@ class AdvancedTab(SettingsTab):
self.default_color = settings.value('default color') self.default_color = settings.value('default color')
self.default_file_edit.setText(settings.value('default image')) self.default_file_edit.setText(settings.value('default image'))
self.slide_limits = settings.value('slide limits') self.slide_limits = settings.value('slide limits')
self.is_search_as_you_type_enabled = settings.value('search as type')
self.search_as_type_check_box.setChecked(self.is_search_as_you_type_enabled)
# Prevent the dialog displayed by the alternate_rows_check_box to display. # Prevent the dialog displayed by the alternate_rows_check_box to display.
self.alternate_rows_check_box.blockSignals(True) self.alternate_rows_check_box.blockSignals(True)
self.alternate_rows_check_box.setChecked(settings.value('alternate rows')) self.alternate_rows_check_box.setChecked(settings.value('alternate rows'))
@ -424,8 +431,14 @@ class AdvancedTab(SettingsTab):
settings.setValue('x11 bypass wm', self.x11_bypass_check_box.isChecked()) 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('config_screen_changed')
self.settings_form.register_post_process('slidecontroller_update_slide_limits') self.settings_form.register_post_process('slidecontroller_update_slide_limits')
settings.setValue('search as type', self.is_search_as_you_type_enabled)
settings.endGroup() settings.endGroup()
def on_search_as_type_check_box_changed(self, check_state):
self.is_search_as_you_type_enabled = (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): def cancel(self):
""" """
Dialogue was cancelled, remove any pending data path change. Dialogue was cancelled, remove any pending data path change.

View File

@ -389,7 +389,7 @@ class Ui_MainWindow(object):
self.file_menu.setTitle(translate('OpenLP.MainWindow', '&File')) self.file_menu.setTitle(translate('OpenLP.MainWindow', '&File'))
self.file_import_menu.setTitle(translate('OpenLP.MainWindow', '&Import')) self.file_import_menu.setTitle(translate('OpenLP.MainWindow', '&Import'))
self.file_export_menu.setTitle(translate('OpenLP.MainWindow', '&Export')) 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_menu.setTitle(translate('OpenLP.MainWindow', '&View'))
self.view_mode_menu.setTitle(translate('OpenLP.MainWindow', 'M&ode')) self.view_mode_menu.setTitle(translate('OpenLP.MainWindow', 'M&ode'))
self.tools_menu.setTitle(translate('OpenLP.MainWindow', '&Tools')) self.tools_menu.setTitle(translate('OpenLP.MainWindow', '&Tools'))
@ -400,16 +400,16 @@ class Ui_MainWindow(object):
self.service_manager_dock.setWindowTitle(translate('OpenLP.MainWindow', 'Service Manager')) self.service_manager_dock.setWindowTitle(translate('OpenLP.MainWindow', 'Service Manager'))
self.theme_manager_dock.setWindowTitle(translate('OpenLP.MainWindow', 'Theme Manager')) self.theme_manager_dock.setWindowTitle(translate('OpenLP.MainWindow', 'Theme Manager'))
self.projector_manager_dock.setWindowTitle(translate('OpenLP.MainWindow', 'Projector 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.setToolTip(UiStrings().NewService)
self.file_new_item.setStatusTip(UiStrings().CreateService) 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.setToolTip(UiStrings().OpenService)
self.file_open_item.setStatusTip(translate('OpenLP.MainWindow', 'Open an existing service.')) 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.setToolTip(UiStrings().SaveService)
self.file_save_item.setStatusTip(translate('OpenLP.MainWindow', 'Save the current service to disk.')) 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.setToolTip(translate('OpenLP.MainWindow', 'Save Service As'))
self.file_save_as_item.setStatusTip(translate('OpenLP.MainWindow', self.file_save_as_item.setStatusTip(translate('OpenLP.MainWindow',
'Save the current service under a new name.')) 'Save the current service under a new name.'))
@ -456,7 +456,7 @@ class Ui_MainWindow(object):
self.lock_panel.setText(translate('OpenLP.MainWindow', 'L&ock Panels')) self.lock_panel.setText(translate('OpenLP.MainWindow', 'L&ock Panels'))
self.lock_panel.setStatusTip(translate('OpenLP.MainWindow', 'Prevent the panels being moved.')) 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.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.settings_plugin_list_item.setStatusTip(translate('OpenLP.MainWindow', 'List the Plugins'))
self.about_item.setText(translate('OpenLP.MainWindow', '&About')) self.about_item.setText(translate('OpenLP.MainWindow', '&About'))
self.about_item.setStatusTip(translate('OpenLP.MainWindow', 'More information about OpenLP')) self.about_item.setStatusTip(translate('OpenLP.MainWindow', 'More information about OpenLP'))
@ -505,7 +505,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow, RegistryProperties):
super(MainWindow, self).__init__() super(MainWindow, self).__init__()
Registry().register('main_window', self) Registry().register('main_window', self)
self.clipboard = self.application.clipboard() 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). # Set up settings sections for the main application (not for use by plugins).
self.ui_settings_section = 'user interface' self.ui_settings_section = 'user interface'
self.general_settings_section = 'core' self.general_settings_section = 'core'
@ -634,7 +634,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow, RegistryProperties):
self.live_controller.display.setFocus() self.live_controller.display.setFocus()
self.activateWindow() self.activateWindow()
if self.arguments: if self.arguments:
self.open_cmd_line_files() self.open_cmd_line_files(self.arguments)
elif Settings().value(self.general_settings_section + '/auto open'): elif Settings().value(self.general_settings_section + '/auto open'):
self.service_manager_contents.load_last_file() self.service_manager_contents.load_last_file()
view_mode = Settings().value('%s/view mode' % self.general_settings_section) view_mode = Settings().value('%s/view mode' % self.general_settings_section)
@ -1416,15 +1416,11 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow, RegistryProperties):
settings.remove('advanced/data path') settings.remove('advanced/data path')
self.application.set_normal_cursor() 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 Open files passed in through command line arguments
""" """
args = [] if not isinstance(filename, str):
for a in self.arguments: filename = str(filename, sys.getfilesystemencoding())
args.extend([a]) if filename.endswith(('.osz', '.oszl')):
for filename in args: 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)

View File

@ -33,21 +33,21 @@ class Ui_PluginViewDialog(object):
""" """
The UI of the plugin view dialog The UI of the plugin view dialog
""" """
def setupUi(self, pluginViewDialog): def setupUi(self, plugin_view_dialog):
""" """
Set up the UI Set up the UI
""" """
pluginViewDialog.setObjectName('pluginViewDialog') plugin_view_dialog.setObjectName('plugin_view_dialog')
pluginViewDialog.setWindowIcon(build_icon(u':/icon/openlp-logo.svg')) plugin_view_dialog.setWindowIcon(build_icon(u':/icon/openlp-logo.svg'))
pluginViewDialog.setWindowModality(QtCore.Qt.ApplicationModal) plugin_view_dialog.setWindowModality(QtCore.Qt.ApplicationModal)
self.plugin_layout = QtGui.QVBoxLayout(pluginViewDialog) self.plugin_layout = QtGui.QVBoxLayout(plugin_view_dialog)
self.plugin_layout.setObjectName('plugin_layout') self.plugin_layout.setObjectName('plugin_layout')
self.list_layout = QtGui.QHBoxLayout() self.list_layout = QtGui.QHBoxLayout()
self.list_layout.setObjectName('list_layout') self.list_layout.setObjectName('list_layout')
self.plugin_list_widget = QtGui.QListWidget(pluginViewDialog) self.plugin_list_widget = QtGui.QListWidget(plugin_view_dialog)
self.plugin_list_widget.setObjectName('plugin_list_widget') self.plugin_list_widget.setObjectName('plugin_list_widget')
self.list_layout.addWidget(self.plugin_list_widget) self.list_layout.addWidget(self.plugin_list_widget)
self.plugin_info_group_box = QtGui.QGroupBox(pluginViewDialog) self.plugin_info_group_box = QtGui.QGroupBox(plugin_view_dialog)
self.plugin_info_group_box.setObjectName('plugin_info_group_box') self.plugin_info_group_box.setObjectName('plugin_info_group_box')
self.plugin_info_layout = QtGui.QFormLayout(self.plugin_info_group_box) self.plugin_info_layout = QtGui.QFormLayout(self.plugin_info_group_box)
self.plugin_info_layout.setObjectName('plugin_info_layout') self.plugin_info_layout.setObjectName('plugin_info_layout')
@ -70,15 +70,15 @@ class Ui_PluginViewDialog(object):
self.plugin_info_layout.addRow(self.about_label, self.about_text_browser) self.plugin_info_layout.addRow(self.about_label, self.about_text_browser)
self.list_layout.addWidget(self.plugin_info_group_box) self.list_layout.addWidget(self.plugin_info_group_box)
self.plugin_layout.addLayout(self.list_layout) self.plugin_layout.addLayout(self.list_layout)
self.button_box = create_button_box(pluginViewDialog, 'button_box', ['ok']) self.button_box = create_button_box(plugin_view_dialog, 'button_box', ['ok'])
self.plugin_layout.addWidget(self.button_box) self.plugin_layout.addWidget(self.button_box)
self.retranslateUi(pluginViewDialog) self.retranslateUi(plugin_view_dialog)
def retranslateUi(self, pluginViewDialog): def retranslateUi(self, plugin_view_dialog):
""" """
Translate the UI on the fly Translate the UI on the fly
""" """
pluginViewDialog.setWindowTitle(translate('OpenLP.PluginForm', 'Plugin List')) plugin_view_dialog.setWindowTitle(translate('OpenLP.PluginForm', 'Manage Plugins'))
self.plugin_info_group_box.setTitle(translate('OpenLP.PluginForm', 'Plugin Details')) self.plugin_info_group_box.setTitle(translate('OpenLP.PluginForm', 'Plugin Details'))
self.version_label.setText('%s:' % UiStrings().Version) self.version_label.setText('%s:' % UiStrings().Version)
self.about_label.setText('%s:' % UiStrings().About) self.about_label.setText('%s:' % UiStrings().About)

View File

@ -162,7 +162,7 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog, RegistryProperties)
html_data = self._add_element('html') html_data = self._add_element('html')
self._add_element('head', parent=html_data) self._add_element('head', parent=html_data)
self._add_element('title', self.title_line_edit.text(), html_data.head) 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) custom_css = get_text_file_string(css_path)
if not custom_css: if not custom_css:
custom_css = DEFAULT_CSS custom_css = DEFAULT_CSS

View File

@ -755,12 +755,19 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtGui.QWidget, Ui_ThemeManager, R
return False return False
# check for use in the system else where. # check for use in the system else where.
if test_plugin: if test_plugin:
plugin_usage = ""
for plugin in self.plugin_manager.plugins: for plugin in self.plugin_manager.plugins:
if plugin.uses_theme(theme): used_count = plugin.uses_theme(theme)
critical_error_message_box(translate('OpenLP.ThemeManager', 'Validation Error'), if used_count:
translate('OpenLP.ThemeManager', plugin_usage = "%s%s" % (plugin_usage, (translate('OpenLP.ThemeManager',
'Theme %s is used in the %s plugin.') '%s time(s) by %s') %
% (theme, plugin.name)) (used_count, plugin.name)))
return False 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 True
return False return False

View File

@ -178,12 +178,14 @@ class BiblePlugin(Plugin):
def uses_theme(self, theme): 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, Called to find out if the bible plugin is currently using a theme. Returns ``1`` if the theme is being used,
otherwise returns ``False``. otherwise returns ``0``.
:param theme: The theme :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): def rename_theme(self, old_theme, new_theme):
""" """

View File

@ -476,16 +476,6 @@ class BibleDB(QtCore.QObject, Manager, RegistryProperties):
self.save_meta('language_id', language_id) self.save_meta('language_id', language_id)
return 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): def dump_bible(self):
""" """
Utility debugging method to dump the contents of a bible. Utility debugging method to dump the contents of a bible.

View File

@ -129,11 +129,6 @@ class BibleManager(RegistryProperties):
bible.session.close() bible.session.close()
delete_file(os.path.join(self.path, filename)) delete_file(os.path.join(self.path, filename))
continue 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) log.debug('Bible Name: "%s"', name)
self.db_cache[name] = bible self.db_cache[name] = bible
# Look to see if lazy load bible exists and get create getter. # Look to see if lazy load bible exists and get create getter.

View File

@ -72,11 +72,9 @@ class CustomPlugin(Plugin):
""" """
Called to find out if the custom plugin is currently using a theme. 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 len(self.db_manager.get_all_objects(CustomSlide, CustomSlide.theme_name == theme))
return True
return False
def rename_theme(self, old_theme, new_theme): def rename_theme(self, old_theme, new_theme):
""" """

View File

@ -85,6 +85,7 @@ class CustomMediaItem(MediaManagerItem):
""" """
log.debug('Config loaded') log.debug('Config loaded')
self.add_custom_from_service = Settings().value(self.settings_section + '/add custom from service') self.add_custom_from_service = Settings().value(self.settings_section + '/add custom from service')
self.is_search_as_you_type_enabled = Settings().value('advanced/search as type')
def retranslateUi(self): def retranslateUi(self):
""" """
@ -269,11 +270,12 @@ class CustomMediaItem(MediaManagerItem):
:param text: The search text :param text: The search text
""" """
search_length = 2 if self.is_search_as_you_type_enabled:
if len(text) > search_length: search_length = 2
self.on_search_text_button_clicked() if len(text) > search_length:
elif not text: self.on_search_text_button_clicked()
self.on_clear_text_button_click() elif not text:
self.on_clear_text_button_click()
def service_load(self, item): def service_load(self, item):
""" """

View File

@ -67,36 +67,13 @@ class ImagePlugin(Plugin):
'provided by the theme.') 'provided by the theme.')
return about_text 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): def upgrade_settings(self, settings):
""" """
Upgrade the settings of this plugin. Upgrade the settings of this plugin.
:param settings: The Settings object containing the old settings. :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 pass
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)
def set_plugin_text_strings(self): def set_plugin_text_strings(self):
""" """

View File

@ -119,14 +119,6 @@ class ImageMediaItem(MediaManagerItem):
icon=':/general/general_edit.png', icon=':/general/general_edit.png',
triggers=self.on_edit_click) triggers=self.on_edit_click)
create_widget_action(self.list_view, separator=True) 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( create_widget_action(
self.list_view, self.list_view,
'listView%s%sItem' % (self.plugin.name.title(), StringContent.Preview.title()), 'listView%s%sItem' % (self.plugin.name.title(), StringContent.Preview.title()),
@ -155,6 +147,14 @@ class ImageMediaItem(MediaManagerItem):
text=translate('OpenLP.MediaManagerItem', '&Add to selected Service Item'), text=translate('OpenLP.MediaManagerItem', '&Add to selected Service Item'),
icon=':/general/general_add.png', icon=':/general/general_add.png',
triggers=self.on_add_edit_click) 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() self.add_custom_context_actions()
# Create the context menu and add all actions from the list_view. # Create the context menu and add all actions from the list_view.
self.menu = QtGui.QMenu() self.menu = QtGui.QMenu()

View File

@ -137,22 +137,6 @@ class PresentationPlugin(Plugin):
self.register_controllers(controller) self.register_controllers(controller)
return bool(self.controllers) 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): def about(self):
""" """
Return information about this plugin. Return information about this plugin.

View File

@ -271,9 +271,15 @@ window.OpenLP = {
if (typeof value[0] !== "number"){ if (typeof value[0] !== "number"){
value[0] = OpenLP.escapeString(value[0]) 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") ul.append($("<li>").append($("<a>").attr("href", "#options")
.attr("data-rel", "dialog").attr("value", value[0]) .attr("data-rel", "dialog").attr("value", value[0])
.click(OpenLP.showOptions).text(value[1]))); .click(OpenLP.showOptions).text(txt)));
}); });
} }
ul.listview("refresh"); ul.listview("refresh");

View File

@ -309,10 +309,13 @@ class HttpRouter(RegistryProperties):
""" """
Translate various strings in the mobile app. 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 = { self.template_vars = {
'app_title': translate('RemotePlugin.Mobile', 'OpenLP 2.2 Remote'), 'app_title': "%s %s" % (UiStrings().OLPV2x, remote),
'stage_title': translate('RemotePlugin.Mobile', 'OpenLP 2.2 Stage View'), 'stage_title': "%s %s" % (UiStrings().OLPV2x, stage),
'live_title': translate('RemotePlugin.Mobile', 'OpenLP 2.2 Live View'), 'live_title': "%s %s" % (UiStrings().OLPV2x, live),
'service_manager': translate('RemotePlugin.Mobile', 'Service Manager'), 'service_manager': translate('RemotePlugin.Mobile', 'Service Manager'),
'slide_controller': translate('RemotePlugin.Mobile', 'Slide Controller'), 'slide_controller': translate('RemotePlugin.Mobile', 'Slide Controller'),
'alerts': translate('RemotePlugin.Mobile', 'Alerts'), 'alerts': translate('RemotePlugin.Mobile', 'Alerts'),

View File

@ -178,7 +178,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog, RegistryProperties):
if invalid_verses: if invalid_verses:
valid = create_separated_list(verse_names) valid = create_separated_list(verse_names)
if len(invalid_verses) > 1: 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.') % \ 'Valid entries are %(valid)s.\nPlease enter the verses separated by spaces.') % \
{'invalid': ', '.join(invalid_verses), 'valid': valid} {'invalid': ', '.join(invalid_verses), 'valid': valid}
else: else:

View File

@ -115,7 +115,7 @@ class SongMediaItem(MediaManagerItem):
Is triggered when the songs config is updated Is triggered when the songs config is updated
""" """
log.debug('config_updated') log.debug('config_updated')
self.search_as_you_type = Settings().value(self.settings_section + '/search as type') self.is_search_as_you_type_enabled = Settings().value('advanced/search as type')
self.update_service_on_edit = Settings().value(self.settings_section + '/update service on edit') 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.add_song_from_service = Settings().value(self.settings_section + '/add song from service')
self.display_songbook = Settings().value(self.settings_section + '/display songbook') self.display_songbook = Settings().value(self.settings_section + '/display songbook')
@ -279,7 +279,7 @@ class SongMediaItem(MediaManagerItem):
If search as type enabled invoke the search on each key press. If the Lyrics are being searched do not start If search as type enabled invoke the search on each key press. If the Lyrics are being searched do not start
till 7 characters have been entered. till 7 characters have been entered.
""" """
if self.search_as_you_type: if self.is_search_as_you_type_enabled:
search_length = 1 search_length = 1
if self.search_text_edit.current_search_type() == SongSearch.Entire: if self.search_text_edit.current_search_type() == SongSearch.Entire:
search_length = 4 search_length = 4
@ -590,4 +590,4 @@ class SongMediaItem(MediaManagerItem):
:param show_error: Is this an error? :param show_error: Is this an error?
""" """
search_results = self.search_entire(string) 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]

View File

@ -121,17 +121,7 @@ class SongXML(object):
""" """
self.song_xml = None self.song_xml = None
verse_list = [] verse_list = []
if not xml.startswith('<?xml') and not xml.startswith('<song'): if xml.startswith('<?xml'):
# 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'):
xml = xml[38:] xml = xml[38:]
try: try:
self.song_xml = objectify.fromstring(xml) self.song_xml = objectify.fromstring(xml)

View File

@ -41,9 +41,6 @@ class SongsTab(SettingsTab):
self.mode_group_box.setObjectName('mode_group_box') self.mode_group_box.setObjectName('mode_group_box')
self.mode_layout = QtGui.QVBoxLayout(self.mode_group_box) self.mode_layout = QtGui.QVBoxLayout(self.mode_group_box)
self.mode_layout.setObjectName('mode_layout') 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 = QtGui.QCheckBox(self.mode_group_box)
self.tool_bar_active_check_box.setObjectName('tool_bar_active_check_box') self.tool_bar_active_check_box.setObjectName('tool_bar_active_check_box')
self.mode_layout.addWidget(self.tool_bar_active_check_box) self.mode_layout.addWidget(self.tool_bar_active_check_box)
@ -62,7 +59,6 @@ class SongsTab(SettingsTab):
self.left_layout.addWidget(self.mode_group_box) self.left_layout.addWidget(self.mode_group_box)
self.left_layout.addStretch() self.left_layout.addStretch()
self.right_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.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.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) self.add_from_service_check_box.stateChanged.connect(self.on_add_from_service_check_box_changed)
@ -71,7 +67,6 @@ class SongsTab(SettingsTab):
def retranslateUi(self): def retranslateUi(self):
self.mode_group_box.setTitle(translate('SongsPlugin.SongsTab', 'Songs Mode')) 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', self.tool_bar_active_check_box.setText(translate('SongsPlugin.SongsTab',
'Display verses on live tool bar')) 'Display verses on live tool bar'))
self.update_on_edit_check_box.setText(translate('SongsPlugin.SongsTab', 'Update service from song edit')) self.update_on_edit_check_box.setText(translate('SongsPlugin.SongsTab', 'Update service from song edit'))
@ -103,13 +98,11 @@ class SongsTab(SettingsTab):
def load(self): def load(self):
settings = Settings() settings = Settings()
settings.beginGroup(self.settings_section) settings.beginGroup(self.settings_section)
self.song_search = settings.value('search as type')
self.tool_bar = settings.value('display songbar') self.tool_bar = settings.value('display songbar')
self.update_edit = settings.value('update service on edit') self.update_edit = settings.value('update service on edit')
self.update_load = settings.value('add song from service') self.update_load = settings.value('add song from service')
self.display_songbook = settings.value('display songbook') self.display_songbook = settings.value('display songbook')
self.display_copyright_symbol = settings.value('display copyright symbol') 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.tool_bar_active_check_box.setChecked(self.tool_bar)
self.update_on_edit_check_box.setChecked(self.update_edit) self.update_on_edit_check_box.setChecked(self.update_edit)
self.add_from_service_check_box.setChecked(self.update_load) self.add_from_service_check_box.setChecked(self.update_load)
@ -120,7 +113,6 @@ class SongsTab(SettingsTab):
def save(self): def save(self):
settings = Settings() settings = Settings()
settings.beginGroup(self.settings_section) settings.beginGroup(self.settings_section)
settings.setValue('search as type', self.song_search)
settings.setValue('display songbar', self.tool_bar) settings.setValue('display songbar', self.tool_bar)
settings.setValue('update service on edit', self.update_edit) settings.setValue('update service on edit', self.update_edit)
settings.setValue('add song from service', self.update_load) settings.setValue('add song from service', self.update_load)

View File

@ -57,7 +57,6 @@ __default_settings__ = {
'songs/last search type': SongSearch.Entire, 'songs/last search type': SongSearch.Entire,
'songs/last import type': SongFormat.OpenLyrics, 'songs/last import type': SongFormat.OpenLyrics,
'songs/update service on edit': False, 'songs/update service on edit': False,
'songs/search as type': True,
'songs/add song from service': True, 'songs/add song from service': True,
'songs/display songbar': True, 'songs/display songbar': True,
'songs/display songbook': False, 'songs/display songbook': False,
@ -226,11 +225,9 @@ class SongsPlugin(Plugin):
Called to find out if the song plugin is currently using a theme. Called to find out if the song plugin is currently using a theme.
:param theme: The theme to check for usage :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 len(self.manager.get_all_objects(Song, Song.theme_name == theme))
return True
return False
def rename_theme(self, old_theme, new_theme): def rename_theme(self, old_theme, new_theme):
""" """

View File

@ -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')

View File

@ -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')

View File

@ -71,7 +71,7 @@ class TestMainWindow(TestCase, TestMixin):
with patch('openlp.core.ui.servicemanager.ServiceManager.load_file') as mocked_load_path: with patch('openlp.core.ui.servicemanager.ServiceManager.load_file') as mocked_load_path:
# WHEN the argument is processed # 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 # 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' mocked_load_path.assert_called_with(service), 'load_path should have been called with the service\'s path'
@ -86,7 +86,7 @@ class TestMainWindow(TestCase, TestMixin):
with patch('openlp.core.ui.servicemanager.ServiceManager.load_file') as mocked_load_path: with patch('openlp.core.ui.servicemanager.ServiceManager.load_file') as mocked_load_path:
# WHEN the argument is processed # 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 # THEN the file should not be opened
assert not mocked_load_path.called, 'load_path should not have been called' assert not mocked_load_path.called, 'load_path should not have been called'

View File

@ -25,7 +25,7 @@ Package to test the openlp.core.utils.actions package.
from unittest import TestCase from unittest import TestCase
from openlp.core.common.settings import Settings 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.functional import MagicMock, patch
from tests.helpers.testmixin import TestMixin from tests.helpers.testmixin import TestMixin

View File

@ -33,7 +33,6 @@ from openlp.core.common import Settings
from tests.helpers.testmixin import TestMixin from tests.helpers.testmixin import TestMixin
from tests.functional import MagicMock, patch, call from tests.functional import MagicMock, patch, call
TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'resources')) TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'resources'))
@ -132,60 +131,3 @@ class TestInit(TestCase, TestMixin):
# THEN: It should ask if we want to create a backup # 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(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!') 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()

View File

@ -23,39 +23,13 @@
Package to test for proper bzr tags. Package to test for proper bzr tags.
""" """
import os import os
import re
from unittest import TestCase from unittest import TestCase
from subprocess import Popen, PIPE from subprocess import Popen, PIPE
TAGS = [ 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.0', '1'], '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'
['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')
class TestBzrTags(TestCase): class TestBzrTags(TestCase):
@ -70,8 +44,12 @@ class TestBzrTags(TestCase):
# WHEN getting the branches tags # WHEN getting the branches tags
bzr = Popen(('bzr', 'tags', '--directory=' + path), stdout=PIPE) bzr = Popen(('bzr', 'tags', '--directory=' + path), stdout=PIPE)
std_out = bzr.communicate()[0] std_out = bzr.communicate()[0]
tags = [line.decode('utf-8').split() for line in std_out.splitlines()] count = len(TAGS1)
tags = [t_r for t_r in tags if t_r[1] != '?' or not (t_r[1] == '?' and TAG_SEARCH.search(t_r[0]))] 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 # 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')