This commit is contained in:
Tim Bentley 2016-05-17 22:35:01 +01:00
commit 2cb3d6b684
22 changed files with 358 additions and 156 deletions

View File

@ -68,9 +68,11 @@ def get_db_path(plugin_name, db_file_name=None):
:return: The path to the database as type str
"""
if db_file_name is None:
return 'sqlite:///%s/%s.sqlite' % (AppLocation.get_section_data_path(plugin_name), plugin_name)
return 'sqlite:///{path}/{plugin}.sqlite'.format(path=AppLocation.get_section_data_path(plugin_name),
plugin=plugin_name)
else:
return 'sqlite:///%s/%s' % (AppLocation.get_section_data_path(plugin_name), db_file_name)
return 'sqlite:///{path}/{name}'.format(path=AppLocation.get_section_data_path(plugin_name),
name=db_file_name)
def handle_db_error(plugin_name, db_file_name):
@ -82,10 +84,10 @@ def handle_db_error(plugin_name, db_file_name):
:return: None
"""
db_path = get_db_path(plugin_name, db_file_name)
log.exception('Error loading database: %s', db_path)
log.exception('Error loading database: {db}'.format(db=db_path))
critical_error_message_box(translate('OpenLP.Manager', 'Database Error'),
translate('OpenLP.Manager', 'OpenLP cannot load your database.\n\nDatabase: %s')
% db_path)
translate('OpenLP.Manager',
'OpenLP cannot load your database.\n\nDatabase: {db}').format(db=db_path))
def init_url(plugin_name, db_file_name=None):
@ -101,10 +103,11 @@ def init_url(plugin_name, db_file_name=None):
if db_type == 'sqlite':
db_url = get_db_path(plugin_name, db_file_name)
else:
db_url = '%s://%s:%s@%s/%s' % (db_type, urlquote(settings.value('db username')),
urlquote(settings.value('db password')),
urlquote(settings.value('db hostname')),
urlquote(settings.value('db database')))
db_url = '{type}://{user}:{password}@{host}/{db}'.format(type=db_type,
user=urlquote(settings.value('db username')),
password=urlquote(settings.value('db password')),
host=urlquote(settings.value('db hostname')),
db=urlquote(settings.value('db database')))
settings.endGroup()
return db_url
@ -157,10 +160,10 @@ def upgrade_db(url, upgrade):
return version, upgrade.__version__
version += 1
try:
while hasattr(upgrade, 'upgrade_%d' % version):
log.debug('Running upgrade_%d', version)
while hasattr(upgrade, 'upgrade_{version:d}'.format(version=version)):
log.debug('Running upgrade_{version:d}'.format(version=version))
try:
upgrade_func = getattr(upgrade, 'upgrade_%d' % version)
upgrade_func = getattr(upgrade, 'upgrade_{version:d}'.format(version=version))
upgrade_func(session, metadata)
session.commit()
# Update the version number AFTER a commit so that we are sure the previous transaction happened
@ -168,8 +171,8 @@ def upgrade_db(url, upgrade):
session.commit()
version += 1
except (SQLAlchemyError, DBAPIError):
log.exception('Could not run database upgrade script "upgrade_%s", upgrade process has been halted.',
version)
log.exception('Could not run database upgrade script '
'"upgrade_{version:d}", upgrade process has been halted.'.format(version=version))
break
except (SQLAlchemyError, DBAPIError):
version_meta = Metadata.populate(key='version', value=int(upgrade.__version__))
@ -242,9 +245,10 @@ class Manager(object):
critical_error_message_box(
translate('OpenLP.Manager', 'Database Error'),
translate('OpenLP.Manager', 'The database being loaded was created in a more recent version of '
'OpenLP. The database is version %d, while OpenLP expects version %d. The database will '
'not be loaded.\n\nDatabase: %s') % (db_ver, up_ver, self.db_url)
)
'OpenLP. The database is version {db_ver}, while OpenLP expects version {db_up}. '
'The database will not be loaded.\n\nDatabase: {db_name}').format(db_ver=db_ver,
db_up=up_ver,
db_name=self.db_url))
return
if not session:
try:
@ -460,7 +464,7 @@ class Manager(object):
raise
except InvalidRequestError:
self.session.rollback()
log.exception('Failed to delete %s records', object_class.__name__)
log.exception('Failed to delete {name} records'.format(name=object_class.__name__))
return False
except:
self.session.rollback()

View File

@ -50,7 +50,8 @@ class FileDialog(QtWidgets.QFileDialog):
log.info('File not found. Attempting to unquote.')
file = parse.unquote(file)
if not os.path.exists(file):
log.error('File %s not found.' % file)
log.error('File {text} not found.'.format(text=file))
# TODO: Test with UiStrings() before converting to python3 strings
QtWidgets.QMessageBox.information(parent, UiStrings().FileNotFound,
UiStrings().FileNotFoundMessage % file)
continue

View File

@ -396,6 +396,7 @@ from openlp.core.lib.theme import BackgroundType, BackgroundGradientType, Vertic
log = logging.getLogger(__name__)
# TODO: Verify where this is used before converting to python3
HTMLSRC = """
<!DOCTYPE html>
<html>
@ -564,13 +565,13 @@ def build_html(item, screen, is_live, background, image=None, plugins=None):
theme_data = item.theme_data
# Image generated and poked in
if background:
bgimage_src = 'src="data:image/png;base64,%s"' % background
bgimage_src = 'src="data:image/png;base64,{image}"'.format(image=background)
elif item.bg_image_bytes:
bgimage_src = 'src="data:image/png;base64,%s"' % item.bg_image_bytes
bgimage_src = 'src="data:image/png;base64,{image}"'.format(image=item.bg_image_bytes)
else:
bgimage_src = 'style="display:none;"'
if image:
image_src = 'src="data:image/png;base64,%s"' % image
image_src = 'src="data:image/png;base64,{image}"'.format(image=image)
else:
image_src = 'style="display:none;"'
css_additions = ''
@ -601,7 +602,7 @@ def webkit_version():
"""
try:
webkit_ver = float(QtWebKit.qWebKitVersion())
log.debug('Webkit version = %s' % webkit_ver)
log.debug('Webkit version = {version}'.format(version=webkit_ver))
except AttributeError:
webkit_ver = 0
return webkit_ver
@ -621,23 +622,25 @@ def build_background_css(item, width):
if theme.background_type == BackgroundType.to_string(BackgroundType.Transparent):
background = ''
elif theme.background_type == BackgroundType.to_string(BackgroundType.Solid):
background = 'background-color: %s' % theme.background_color
background = 'background-color: {theme}'.format(theme=theme.background_color)
else:
if theme.background_direction == BackgroundGradientType.to_string(BackgroundGradientType.Horizontal):
background = 'background: -webkit-gradient(linear, left top, left bottom, from(%s), to(%s)) fixed' \
% (theme.background_start_color, theme.background_end_color)
background = 'background: -webkit-gradient(linear, left top, left bottom, from({start}), to({end})) ' \
'fixed'.format(start=theme.background_start_color, end=theme.background_end_color)
elif theme.background_direction == BackgroundGradientType.to_string(BackgroundGradientType.LeftTop):
background = 'background: -webkit-gradient(linear, left top, right bottom, from(%s), to(%s)) fixed' \
% (theme.background_start_color, theme.background_end_color)
background = 'background: -webkit-gradient(linear, left top, right bottom, from({start}), to({end})) ' \
'fixed'.format(start=theme.background_start_color, end=theme.background_end_color)
elif theme.background_direction == BackgroundGradientType.to_string(BackgroundGradientType.LeftBottom):
background = 'background: -webkit-gradient(linear, left bottom, right top, from(%s), to(%s)) fixed' \
% (theme.background_start_color, theme.background_end_color)
background = 'background: -webkit-gradient(linear, left bottom, right top, from({start}), to({end})) ' \
'fixed'.format(start=theme.background_start_color, end=theme.background_end_color)
elif theme.background_direction == BackgroundGradientType.to_string(BackgroundGradientType.Vertical):
background = 'background: -webkit-gradient(linear, left top, right top, from(%s), to(%s)) fixed' % \
(theme.background_start_color, theme.background_end_color)
background = 'background: -webkit-gradient(linear, left top, right top, from({start}), to({end})) ' \
'fixed'.format(start=theme.background_start_color, end=theme.background_end_color)
else:
background = 'background: -webkit-gradient(radial, %s 50%%, 100, %s 50%%, %s, from(%s), to(%s)) fixed'\
% (width, width, width, theme.background_start_color, theme.background_end_color)
background = 'background: -webkit-gradient(radial, {width} 50%, 100, {width} 50%, {width}, ' \
'from({start}), to({end})) fixed'.format(width=width,
start=theme.background_start_color,
end=theme.background_end_color)
return background
@ -647,6 +650,7 @@ def build_lyrics_css(item):
:param item: Service Item containing theme and location information
"""
# TODO: Verify this before converting to python3
style = """
.lyricstable {
z-index: 5;
@ -669,12 +673,13 @@ def build_lyrics_css(item):
lyrics = ''
lyricsmain = ''
if theme_data and item.main:
lyricstable = 'left: %spx; top: %spx;' % (item.main.x(), item.main.y())
lyricstable = 'left: {left}px; top: {top}px;'.format(left=item.main.x(), top=item.main.y())
lyrics = build_lyrics_format_css(theme_data, item.main.width(), item.main.height())
lyricsmain += build_lyrics_outline_css(theme_data)
if theme_data.font_main_shadow:
lyricsmain += ' text-shadow: %s %spx %spx;' % \
(theme_data.font_main_shadow_color, theme_data.font_main_shadow_size, theme_data.font_main_shadow_size)
lyricsmain += ' text-shadow: {theme} {shadow}px ' \
'{shadow}px;'.format(theme=theme_data.font_main_shadow_color,
shadow=theme_data.font_main_shadow_size)
lyrics_css = style % (lyricstable, lyrics, lyricsmain)
return lyrics_css
@ -689,7 +694,9 @@ def build_lyrics_outline_css(theme_data):
size = float(theme_data.font_main_outline_size) / 16
fill_color = theme_data.font_main_color
outline_color = theme_data.font_main_outline_color
return ' -webkit-text-stroke: %sem %s; -webkit-text-fill-color: %s; ' % (size, outline_color, fill_color)
return ' -webkit-text-stroke: {size}em {color}; -webkit-text-fill-color: {fill}; '.format(size=size,
color=outline_color,
fill=fill_color)
return ''
@ -715,13 +722,21 @@ def build_lyrics_format_css(theme_data, width, height):
padding_bottom = '0.5em'
else:
padding_bottom = '0'
lyrics = '%s word-wrap: break-word; ' \
'text-align: %s; vertical-align: %s; font-family: %s; ' \
'font-size: %spt; color: %s; line-height: %d%%; margin: 0;' \
'padding: 0; padding-bottom: %s; padding-left: %spx; width: %spx; height: %spx; ' % \
(justify, align, valign, theme_data.font_main_name, theme_data.font_main_size,
theme_data.font_main_color, 100 + int(theme_data.font_main_line_adjustment), padding_bottom,
left_margin, width, height)
lyrics = '{justify} word-wrap: break-word; ' \
'text-align: {align}; vertical-align: {valign}; font-family: {font}; ' \
'font-size: {size}pt; color: {color}; line-height: {line:d}%; margin: 0;' \
'padding: 0; padding-bottom: {bottom}; padding-left: {left}px; width: {width}px; ' \
'height: {height}px; '.format(justify=justify,
align=align,
valign=valign,
font=theme_data.font_main_name,
size=theme_data.font_main_size,
color=theme_data.font_main_color,
line=100 + int(theme_data.font_main_line_adjustment),
bottom=padding_bottom,
left=left_margin,
width=width,
height=height)
if theme_data.font_main_italics:
lyrics += 'font-style:italic; '
if theme_data.font_main_bold:
@ -737,20 +752,21 @@ def build_footer_css(item, height):
:param height:
"""
style = """
left: %spx;
bottom: %spx;
width: %spx;
font-family: %s;
font-size: %spt;
color: %s;
left: {left}px;
bottom: {bottom}px;
width: {width}px;
font-family: {family};
font-size: {size}pt;
color: {color};
text-align: left;
white-space: %s;
white-space: {space};
"""
theme = item.theme_data
if not theme or not item.footer:
return ''
bottom = height - int(item.footer.y()) - int(item.footer.height())
whitespace = 'normal' if Settings().value('themes/wrap footer') else 'nowrap'
lyrics_html = style % (item.footer.x(), bottom, item.footer.width(),
theme.font_footer_name, theme.font_footer_size, theme.font_footer_color, whitespace)
lyrics_html = style.format(left=item.footer.x(), bottom=bottom, width=item.footer.width(),
family=theme.font_footer_name, size=theme.font_footer_size,
color=theme.font_footer_color, space=whitespace)
return lyrics_html

View File

@ -236,7 +236,7 @@ class ImageManager(QtCore.QObject):
"""
Return the ``QImage`` from the cache. If not present wait for the background thread to process it.
"""
log.debug('getImage %s' % path)
log.debug('getImage {path}'.format(path=path))
image = self._cache[(path, source, width, height)]
if image.image is None:
self._conversion_queue.modify_priority(image, Priority.High)
@ -256,7 +256,7 @@ class ImageManager(QtCore.QObject):
"""
Returns the byte string for an image. If not present wait for the background thread to process it.
"""
log.debug('get_image_bytes %s' % path)
log.debug('get_image_bytes {path}'.format(path=path))
image = self._cache[(path, source, width, height)]
if image.image_bytes is None:
self._conversion_queue.modify_priority(image, Priority.Urgent)
@ -271,7 +271,7 @@ class ImageManager(QtCore.QObject):
"""
Add image to cache if it is not already there.
"""
log.debug('add_image %s' % path)
log.debug('add_image {path}'.format(path=path))
if not (path, source, width, height) in self._cache:
image = Image(path, source, background, width, height)
self._cache[(path, source, width, height)] = image

View File

@ -186,7 +186,7 @@ class MediaManagerItem(QtWidgets.QWidget, RegistryProperties):
for action in toolbar_actions:
if action[0] == StringContent.Preview:
self.toolbar.addSeparator()
self.toolbar.add_toolbar_action('%s%sAction' % (self.plugin.name, action[0]),
self.toolbar.add_toolbar_action('{name}{action}Action'.format(name=self.plugin.name, action=action[0]),
text=self.plugin.get_string(action[1])['title'], icon=action[2],
tooltip=self.plugin.get_string(action[1])['tooltip'],
triggers=action[3])
@ -200,7 +200,7 @@ class MediaManagerItem(QtWidgets.QWidget, RegistryProperties):
self.list_view.setSpacing(1)
self.list_view.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
self.list_view.setAlternatingRowColors(True)
self.list_view.setObjectName('%sListView' % self.plugin.name)
self.list_view.setObjectName('{name}ListView'.format(name=self.plugin.name))
# Add to page_layout
self.page_layout.addWidget(self.list_view)
# define and add the context menu
@ -212,19 +212,22 @@ class MediaManagerItem(QtWidgets.QWidget, RegistryProperties):
triggers=self.on_edit_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()),
'listView{plugin}{preview}Item'.format(plugin=self.plugin.name.title(),
preview=StringContent.Preview.title()),
text=self.plugin.get_string(StringContent.Preview)['title'],
icon=':/general/general_preview.png',
can_shortcuts=True,
triggers=self.on_preview_click)
create_widget_action(self.list_view,
'listView%s%sItem' % (self.plugin.name.title(), StringContent.Live.title()),
'listView{plugin}{live}Item'.format(plugin=self.plugin.name.title(),
live=StringContent.Live.title()),
text=self.plugin.get_string(StringContent.Live)['title'],
icon=':/general/general_live.png',
can_shortcuts=True,
triggers=self.on_live_click)
create_widget_action(self.list_view,
'listView%s%sItem' % (self.plugin.name.title(), StringContent.Service.title()),
'listView{plugin}{service}Item'.format(plugin=self.plugin.name.title(),
service=StringContent.Service.title()),
can_shortcuts=True,
text=self.plugin.get_string(StringContent.Service)['title'],
icon=':/general/general_add.png',
@ -232,7 +235,8 @@ class MediaManagerItem(QtWidgets.QWidget, RegistryProperties):
if self.has_delete_icon:
create_widget_action(self.list_view, separator=True)
create_widget_action(self.list_view,
'listView%s%sItem' % (self.plugin.name.title(), StringContent.Delete.title()),
'listView{plugin}{delete}Item'.format(plugin=self.plugin.name.title(),
delete=StringContent.Delete.title()),
text=self.plugin.get_string(StringContent.Delete)['title'],
icon=':/general/general_delete.png',
can_shortcuts=True, triggers=self.on_delete_click)
@ -313,7 +317,7 @@ class MediaManagerItem(QtWidgets.QWidget, RegistryProperties):
files = FileDialog.getOpenFileNames(self, self.on_new_prompt,
Settings().value(self.settings_section + '/last directory'),
self.on_new_file_masks)
log.info('New files(s) %s' % files)
log.info('New files(s) {files}'.format(files=files))
if files:
self.application.set_busy_cursor()
self.validate_and_load(files)
@ -333,7 +337,8 @@ class MediaManagerItem(QtWidgets.QWidget, RegistryProperties):
if not error_shown:
critical_error_message_box(translate('OpenLP.MediaManagerItem', 'Invalid File Type'),
translate('OpenLP.MediaManagerItem',
'Invalid File %s.\nSuffix not supported') % file_name)
'Invalid File {name}.\n'
'Suffix not supported').format(name=file_name))
error_shown = True
else:
new_files.append(file_name)
@ -375,7 +380,8 @@ class MediaManagerItem(QtWidgets.QWidget, RegistryProperties):
self.load_list(full_list, target_group)
last_dir = os.path.split(files[0])[0]
Settings().setValue(self.settings_section + '/last directory', last_dir)
Settings().setValue('%s/%s files' % (self.settings_section, self.settings_section), self.get_file_list())
Settings().setValue('{section}/{section} files'.format(section=self.settings_section),
self.get_file_list())
if duplicates_found:
critical_error_message_box(UiStrings().Duplicate,
translate('OpenLP.MediaManagerItem',
@ -550,7 +556,7 @@ class MediaManagerItem(QtWidgets.QWidget, RegistryProperties):
# Is it possible to process multiple list items to generate
# multiple service items?
if self.single_service_item:
log.debug('%s Add requested', self.plugin.name)
log.debug('{plugin} Add requested'.format(plugin=self.plugin.name))
self.add_to_service(replace=self.remote_triggered)
else:
items = self.list_view.selectedIndexes()
@ -591,7 +597,7 @@ class MediaManagerItem(QtWidgets.QWidget, RegistryProperties):
translate('OpenLP.MediaManagerItem',
'You must select one or more items.'))
else:
log.debug('%s Add requested', self.plugin.name)
log.debug('{plugin} Add requested'.format(plugin=self.plugin.name))
service_item = self.service_manager.get_service_item()
if not service_item:
QtWidgets.QMessageBox.information(self, UiStrings().NISs,
@ -604,7 +610,8 @@ class MediaManagerItem(QtWidgets.QWidget, RegistryProperties):
# Turn off the remote edit update message indicator
QtWidgets.QMessageBox.information(self, translate('OpenLP.MediaManagerItem', 'Invalid Service Item'),
translate('OpenLP.MediaManagerItem',
'You must select a %s service item.') % self.title)
'You must select a {title} '
'service item.').format(title=self.title))
def build_service_item(self, item=None, xml_version=False, remote=False, context=ServiceItemContext.Live):
"""

View File

@ -130,7 +130,7 @@ class Plugin(QtCore.QObject, RegistryProperties):
:param settings_tab_class: The class name of the plugin's settings tab.
:param version: Defaults to *None*, which means that the same version number is used as OpenLP's version number.
"""
log.debug('Plugin %s initialised' % name)
log.debug('Plugin {plugin} initialised'.format(plugin=name))
super(Plugin, self).__init__()
self.name = name
self.text_strings = {}
@ -154,11 +154,11 @@ class Plugin(QtCore.QObject, RegistryProperties):
# Append a setting for files in the mediamanager (note not all plugins
# which have a mediamanager need this).
if media_item_class is not None:
default_settings['%s/%s files' % (name, name)] = []
default_settings['{name}/{name} files'.format(name=name)] = []
# Add settings to the dict of all settings.
Settings.extend_default_settings(default_settings)
Registry().register_function('%s_add_service_item' % self.name, self.process_add_service_event)
Registry().register_function('%s_config_updated' % self.name, self.config_update)
Registry().register_function('{name}_add_service_item'.format(name=self.name), self.process_add_service_event)
Registry().register_function('{name}_config_updated'.format(name=self.name), self.config_update)
def check_pre_conditions(self):
"""
@ -256,7 +256,7 @@ class Plugin(QtCore.QObject, RegistryProperties):
"""
Generic Drag and drop handler triggered from service_manager.
"""
log.debug('process_add_service_event event called for plugin %s' % self.name)
log.debug('process_add_service_event event called for plugin {name}'.format(name=self.name))
if replace:
self.media_item.on_add_edit_click()
else:

View File

@ -43,7 +43,7 @@ class PluginManager(RegistryMixin, OpenLPMixin, RegistryProperties):
super(PluginManager, self).__init__(parent)
self.log_info('Plugin manager Initialising')
self.base_path = os.path.abspath(AppLocation.get_directory(AppLocation.PluginsDir))
self.log_debug('Base path %s ' % self.base_path)
self.log_debug('Base path {path}'.format(path=self.base_path))
self.plugins = []
self.log_info('Plugin manager Initialised')
@ -73,7 +73,7 @@ class PluginManager(RegistryMixin, OpenLPMixin, RegistryProperties):
"""
start_depth = len(os.path.abspath(self.base_path).split(os.sep))
present_plugin_dir = os.path.join(self.base_path, 'presentations')
self.log_debug('finding plugins in %s at depth %d' % (self.base_path, start_depth))
self.log_debug('finding plugins in {path} at depth {depth:d}'.format(path=self.base_path, depth=start_depth))
for root, dirs, files in os.walk(self.base_path):
for name in files:
if name.endswith('.py') and not name.startswith('__'):
@ -84,7 +84,9 @@ class PluginManager(RegistryMixin, OpenLPMixin, RegistryProperties):
break
module_name = name[:-3]
# import the modules
self.log_debug('Importing %s from %s. Depth %d' % (module_name, root, this_depth))
self.log_debug('Importing {name} from {root}. Depth {depth:d}'.format(name=module_name,
root=root,
depth=this_depth))
try:
# Use the "imp" library to try to get around a problem with the PyUNO library which
# monkey-patches the __import__ function to do some magic. This causes issues with our tests.
@ -93,21 +95,21 @@ class PluginManager(RegistryMixin, OpenLPMixin, RegistryProperties):
# Then load the module (do the actual import) using the details from find_module()
imp.load_module(module_name, fp, path_name, description)
except ImportError as e:
self.log_exception('Failed to import module %s on path %s: %s'
% (module_name, path, e.args[0]))
self.log_exception('Failed to import module {name} on path {path}: '
'{args}'.format(name=module_name, path=path, args=e.args[0]))
plugin_classes = Plugin.__subclasses__()
plugin_objects = []
for p in plugin_classes:
try:
plugin = p()
self.log_debug('Loaded plugin %s' % str(p))
self.log_debug('Loaded plugin {plugin}'.format(plugin=str(p)))
plugin_objects.append(plugin)
except TypeError:
self.log_exception('Failed to load plugin %s' % str(p))
self.log_exception('Failed to load plugin {plugin}'.format(plugin=str(p)))
plugins_list = sorted(plugin_objects, key=lambda plugin: plugin.weight)
for plugin in plugins_list:
if plugin.check_pre_conditions():
self.log_debug('Plugin %s active' % str(plugin.name))
self.log_debug('Plugin {plugin} active'.format(plugin=str(plugin.name)))
plugin.set_status()
else:
plugin.status = PluginStatus.Disabled
@ -175,10 +177,11 @@ class PluginManager(RegistryMixin, OpenLPMixin, RegistryProperties):
Loop through all the plugins and give them an opportunity to initialise themselves.
"""
for plugin in self.plugins:
self.log_info('initialising plugins %s in a %s state' % (plugin.name, plugin.is_active()))
self.log_info('initialising plugins {plugin} in a {state} state'.format(plugin=plugin.name,
state=plugin.is_active()))
if plugin.is_active():
plugin.initialise()
self.log_info('Initialisation Complete for %s ' % plugin.name)
self.log_info('Initialisation Complete for {plugin}'.format(plugin=plugin.name))
def finalise_plugins(self):
"""
@ -187,7 +190,7 @@ class PluginManager(RegistryMixin, OpenLPMixin, RegistryProperties):
for plugin in self.plugins:
if plugin.is_active():
plugin.finalise()
self.log_info('Finalisation Complete for %s ' % plugin.name)
self.log_info('Finalisation Complete for {plugin}'.format(plugin=plugin.name))
def get_plugin_by_name(self, name):
"""

View File

@ -107,7 +107,7 @@ class Renderer(OpenLPMixin, RegistryMixin, RegistryProperties):
:param theme_name: The theme name
"""
self.log_debug("_set_theme with theme %s" % theme_name)
self.log_debug("_set_theme with theme {theme}".format(theme=theme_name))
if theme_name not in self._theme_dimensions:
theme_data = self.theme_manager.get_theme_data(theme_name)
main_rect = self.get_main_rectangle(theme_data)
@ -183,7 +183,7 @@ class Renderer(OpenLPMixin, RegistryMixin, RegistryProperties):
:param item_theme_name: The item theme's name.
"""
self.log_debug("set_item_theme with theme %s" % item_theme_name)
self.log_debug("set_item_theme with theme {theme}".format(theme=item_theme_name))
self._set_theme(item_theme_name)
self.item_theme_name = item_theme_name
@ -317,7 +317,7 @@ class Renderer(OpenLPMixin, RegistryMixin, RegistryProperties):
self.width = screen_size.width()
self.height = screen_size.height()
self.screen_ratio = self.height / self.width
self.log_debug('_calculate default %s, %f' % (screen_size, self.screen_ratio))
self.log_debug('_calculate default {size}, {ratio:f}'.format(size=screen_size, ratio=self.screen_ratio))
# 90% is start of footer
self.footer_start = int(self.height * 0.90)
@ -354,7 +354,7 @@ class Renderer(OpenLPMixin, RegistryMixin, RegistryProperties):
:param rect_main: The main text block.
:param rect_footer: The footer text block.
"""
self.log_debug('_set_text_rectangle %s , %s' % (rect_main, rect_footer))
self.log_debug('_set_text_rectangle {main} , {footer}'.format(main=rect_main, footer=rect_footer))
self._rect = rect_main
self._rect_footer = rect_footer
self.page_width = self._rect.width()
@ -370,6 +370,7 @@ class Renderer(OpenLPMixin, RegistryMixin, RegistryProperties):
self.web.resize(self.page_width, self.page_height)
self.web_frame = self.web.page().mainFrame()
# Adjust width and height to account for shadow. outline done in css.
# TODO: Verify before converting to python3 strings
html = """<!DOCTYPE html><html><head><script>
function show_text(newtext) {
var main = document.getElementById('main');
@ -518,7 +519,8 @@ class Renderer(OpenLPMixin, RegistryMixin, RegistryProperties):
:param text: The text to check. It may contain HTML tags.
"""
self.web_frame.evaluateJavaScript('show_text("%s")' % text.replace('\\', '\\\\').replace('\"', '\\\"'))
self.web_frame.evaluateJavaScript('show_text'
'("{text}")'.format(text=text.replace('\\', '\\\\').replace('\"', '\\\"')))
return self.web_frame.contentsSize().height() <= self.empty_height

View File

@ -78,7 +78,7 @@ class ScreenList(object):
``number``
The number of the screen, which size has changed.
"""
log.info('screen_resolution_changed %d' % number)
log.info('screen_resolution_changed {number:d}'.format(number=number))
for screen in self.screen_list:
if number == screen['number']:
new_screen = {
@ -105,7 +105,7 @@ class ScreenList(object):
"""
# Do not log at start up.
if changed_screen != -1:
log.info('screen_count_changed %d' % self.desktop.screenCount())
log.info('screen_count_changed {count:d}'.format(count=self.desktop.screenCount()))
# Remove unplugged screens.
for screen in copy.deepcopy(self.screen_list):
if screen['number'] == self.desktop.screenCount():
@ -132,9 +132,11 @@ class ScreenList(object):
"""
screen_list = []
for screen in self.screen_list:
screen_name = '%s %d' % (translate('OpenLP.ScreenList', 'Screen'), screen['number'] + 1)
screen_name = '{name} {number:d}'.format(name=translate('OpenLP.ScreenList', 'Screen'),
number=screen['number'] + 1)
if screen['primary']:
screen_name = '%s (%s)' % (screen_name, translate('OpenLP.ScreenList', 'primary'))
screen_name = '{name} ({primary})'.format(name=screen_name,
primary=translate('OpenLP.ScreenList', 'primary'))
screen_list.append(screen_name)
return screen_list
@ -152,7 +154,7 @@ class ScreenList(object):
'size': PyQt5.QtCore.QRect(0, 0, 1024, 768)
}
"""
log.info('Screen %d found with resolution %s' % (screen['number'], screen['size']))
log.info('Screen {number:d} found with resolution {size}'.format(number=screen['number'], size=screen['size']))
if screen['primary']:
self.current = screen
self.override = copy.deepcopy(self.current)
@ -165,7 +167,7 @@ class ScreenList(object):
:param number: The screen number (int).
"""
log.info('remove_screen %d' % number)
log.info('remove_screen {number:d}'.forma(number=number))
for screen in self.screen_list:
if screen['number'] == number:
self.screen_list.remove(screen)
@ -189,7 +191,7 @@ class ScreenList(object):
:param number: The screen number (int).
"""
log.debug('set_current_display %s' % number)
log.debug('set_current_display {number}'.format(number=number))
if number + 1 > self.display_count:
self.current = self.screen_list[0]
else:

View File

@ -62,9 +62,10 @@ class SearchEdit(QtWidgets.QLineEdit):
right_padding = self.clear_button.width() + frame_width
if hasattr(self, 'menu_button'):
left_padding = self.menu_button.width()
stylesheet = 'QLineEdit { padding-left: %spx; padding-right: %spx; } ' % (left_padding, right_padding)
stylesheet = 'QLineEdit {{ padding-left:{left}px; padding-right: {right}px; }} '.format(left=left_padding,
right=right_padding)
else:
stylesheet = 'QLineEdit { padding-right: %spx; } ' % right_padding
stylesheet = 'QLineEdit {{ padding-right: {right}px; }} '.format(right=right_padding)
self.setStyleSheet(stylesheet)
msz = self.minimumSizeHint()
self.setMinimumSize(max(msz.width(), self.clear_button.width() + (frame_width * 2) + 2),

View File

@ -247,7 +247,7 @@ class ServiceItem(RegistryProperties):
self.renderer.set_item_theme(self.theme)
self.theme_data, self.main, self.footer = self.renderer.pre_render()
if self.service_item_type == ServiceItemType.Text:
log.debug('Formatting slides: %s' % self.title)
log.debug('Formatting slides: {title}'.format(title=self.title))
# Save rendered pages to this dict. In the case that a slide is used twice we can use the pages saved to
# the dict instead of rendering them again.
previous_pages = {}
@ -270,7 +270,7 @@ class ServiceItem(RegistryProperties):
elif self.service_item_type == ServiceItemType.Image or self.service_item_type == ServiceItemType.Command:
pass
else:
log.error('Invalid value renderer: %s' % self.service_item_type)
log.error('Invalid value renderer: {item}'.format(item=self.service_item_type))
self.title = clean_tags(self.title)
# The footer should never be None, but to be compatible with a few
# nightly builds between 1.9.4 and 1.9.5, we have to correct this to
@ -325,7 +325,8 @@ class ServiceItem(RegistryProperties):
self.service_item_type = ServiceItemType.Command
# If the item should have a display title but this frame doesn't have one, we make one up
if self.is_capable(ItemCapabilities.HasDisplayTitle) and not display_title:
display_title = translate('OpenLP.ServiceItem', '[slide %d]') % (len(self._raw_frames) + 1)
display_title = translate('OpenLP.ServiceItem',
'[slide {frame:d}]').format(frame=len(self._raw_frames) + 1)
# Update image path to match servicemanager location if file was loaded from service
if image and not self.has_original_files and self.name == 'presentations':
file_location = os.path.join(path, file_name)
@ -392,7 +393,7 @@ class ServiceItem(RegistryProperties):
:param path: Defaults to *None*. This is the service manager path for things which have their files saved
with them or None when the saved service is lite and the original file paths need to be preserved.
"""
log.debug('set_from_service called with path %s' % path)
log.debug('set_from_service called with path {path}'.format(path=path))
header = service_item['serviceitem']['header']
self.title = header['title']
self.name = header['name']
@ -608,11 +609,13 @@ class ServiceItem(RegistryProperties):
start = None
end = None
if self.start_time != 0:
start = translate('OpenLP.ServiceItem', '<strong>Start</strong>: %s') % \
str(datetime.timedelta(seconds=self.start_time))
time = str(datetime.timedelta(seconds=self.start_time))
start = translate('OpenLP.ServiceItem',
'<strong>Start</strong>: {start}').format(start=time)
if self.media_length != 0:
end = translate('OpenLP.ServiceItem', '<strong>Length</strong>: %s') % \
str(datetime.timedelta(seconds=self.media_length // 1000))
length = str(datetime.timedelta(seconds=self.media_length // 1000))
end = translate('OpenLP.ServiceItem', '<strong>Length</strong>: {length}').format(length=length)
if not start and not end:
return ''
elif start and not end:
@ -620,7 +623,7 @@ class ServiceItem(RegistryProperties):
elif not start and end:
return end
else:
return '%s <br>%s' % (start, end)
return '{start} <br>{end}'.format(start=start, end=end)
def update_theme(self, theme):
"""

View File

@ -135,4 +135,4 @@ class SettingsTab(QtWidgets.QWidget, RegistryProperties):
"""
Tab has just been made visible to the user
"""
self.tab_visited = True
pass

View File

@ -427,7 +427,7 @@ class ThemeXML(object):
try:
theme_xml = objectify.fromstring(xml)
except etree.XMLSyntaxError:
log.exception('Invalid xml %s', xml)
log.exception('Invalid xml {text}'.format(text=xml))
return
xml_iter = theme_xml.getiterator()
for element in xml_iter:
@ -513,6 +513,7 @@ class ThemeXML(object):
theme_strings = []
for key in dir(self):
if key[0:1] != '_':
# TODO: Verify spacing format before converting to python3 string
theme_strings.append('%30s: %s' % (key, getattr(self, key)))
return '\n'.join(theme_strings)

View File

@ -165,7 +165,7 @@ def create_button(parent, name, **kwargs):
kwargs.setdefault('icon', ':/services/service_down.png')
kwargs.setdefault('tooltip', translate('OpenLP.Ui', 'Move selection down one position.'))
else:
log.warning('The role "%s" is not defined in create_push_button().', role)
log.warning('The role "{role}" is not defined in create_push_button().'.format(role=role))
if kwargs.pop('btn_class', '') == 'toolbutton':
button = QtWidgets.QToolButton(parent)
else:
@ -183,7 +183,7 @@ def create_button(parent, name, **kwargs):
button.clicked.connect(kwargs.pop('click'))
for key in list(kwargs.keys()):
if key not in ['text', 'icon', 'tooltip', 'click']:
log.warning('Parameter %s was not consumed in create_button().', key)
log.warning('Parameter {key} was not consumed in create_button().'.format(key=key))
return button
@ -270,7 +270,7 @@ def create_action(parent, name, **kwargs):
action.triggered.connect(kwargs.pop('triggers'))
for key in list(kwargs.keys()):
if key not in ['text', 'icon', 'tooltip', 'statustip', 'checked', 'can_shortcuts', 'category', 'triggers']:
log.warning('Parameter %s was not consumed in create_action().' % key)
log.warning('Parameter {key} was not consumed in create_action().'.format(key=key))
return action

View File

@ -133,37 +133,37 @@ def get_web_page(url, header=None, update_openlp=False):
time.sleep(0.1)
try:
page = urllib.request.urlopen(req, timeout=CONNECTION_TIMEOUT)
log.debug('Downloaded page {}'.format(page.geturl()))
log.debug('Downloaded page {text}'.format(text=page.geturl()))
break
except urllib.error.URLError as err:
log.exception('URLError on {}'.format(url))
log.exception('URLError: {}'.format(err.reason))
log.exception('URLError on {text}'.format(text=url))
log.exception('URLError: {text}'.format(text=err.reason))
page = None
if retries > CONNECTION_RETRIES:
raise
except socket.timeout:
log.exception('Socket timeout: {}'.format(url))
log.exception('Socket timeout: {text}'.format(text=url))
page = None
if retries > CONNECTION_RETRIES:
raise
except socket.gaierror:
log.exception('Socket gaierror: {}'.format(url))
log.exception('Socket gaierror: {text}'.format(text=url))
page = None
if retries > CONNECTION_RETRIES:
raise
except ConnectionRefusedError:
log.exception('ConnectionRefused: {}'.format(url))
log.exception('ConnectionRefused: {text}'.format(text=url))
page = None
if retries > CONNECTION_RETRIES:
raise
break
except ConnectionError:
log.exception('Connection error: {}'.format(url))
log.exception('Connection error: {text}'.format(text=url))
page = None
if retries > CONNECTION_RETRIES:
raise
except HTTPException:
log.exception('HTTPException error: {}'.format(url))
log.exception('HTTPException error: {text}'.format(text=url))
page = None
if retries > CONNECTION_RETRIES:
raise
@ -173,7 +173,7 @@ def get_web_page(url, header=None, update_openlp=False):
if update_openlp:
Registry().get('application').process_events()
if not page:
log.exception('{} could not be downloaded'.format(url))
log.exception('{text} could not be downloaded'.format(text=url))
return None
log.debug(page)
return page

View File

@ -53,15 +53,9 @@ class Ui_PluginViewDialog(object):
self.plugin_info_layout.setObjectName('plugin_info_layout')
self.status_label = QtWidgets.QLabel(self.plugin_info_group_box)
self.status_label.setObjectName('status_label')
self.status_combo_box = QtWidgets.QComboBox(self.plugin_info_group_box)
self.status_combo_box.addItems(('', ''))
self.status_combo_box.setObjectName('status_combo_box')
self.plugin_info_layout.addRow(self.status_label, self.status_combo_box)
self.version_label = QtWidgets.QLabel(self.plugin_info_group_box)
self.version_label.setObjectName('version_label')
self.version_number_label = QtWidgets.QLabel(self.plugin_info_group_box)
self.version_number_label.setObjectName('version_number_label')
self.plugin_info_layout.addRow(self.version_label, self.version_number_label)
self.status_checkbox = QtWidgets.QCheckBox(self.plugin_info_group_box)
self.status_checkbox.setObjectName('status_checkbox')
self.plugin_info_layout.addRow(self.status_label, self.status_checkbox)
self.about_label = QtWidgets.QLabel(self.plugin_info_group_box)
self.about_label.setObjectName('about_label')
self.about_text_browser = QtWidgets.QTextBrowser(self.plugin_info_group_box)
@ -80,8 +74,6 @@ class Ui_PluginViewDialog(object):
"""
plugin_view_dialog.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)
self.status_label.setText(translate('OpenLP.PluginForm', 'Status:'))
self.status_combo_box.setItemText(0, translate('OpenLP.PluginForm', 'Active'))
self.status_combo_box.setItemText(1, translate('OpenLP.PluginForm', 'Inactive'))
self.status_checkbox.setText(translate('OpenLP.PluginForm', 'Active'))

View File

@ -49,7 +49,7 @@ class PluginForm(QtWidgets.QDialog, Ui_PluginViewDialog, RegistryProperties):
self._clear_details()
# Right, now let's put some signals and slots together!
self.plugin_list_widget.itemSelectionChanged.connect(self.on_plugin_list_widget_selection_changed)
self.status_combo_box.currentIndexChanged.connect(self.on_status_combo_box_changed)
self.status_checkbox.stateChanged.connect(self.on_status_checkbox_changed)
def load(self):
"""
@ -86,24 +86,23 @@ class PluginForm(QtWidgets.QDialog, Ui_PluginViewDialog, RegistryProperties):
"""
Clear the plugin details widgets
"""
self.status_combo_box.setCurrentIndex(-1)
self.version_number_label.setText('')
self.status_checkbox.setChecked(False)
self.about_text_browser.setHtml('')
self.status_combo_box.setEnabled(False)
self.status_checkbox.setEnabled(False)
def _set_details(self):
"""
Set the details of the currently selected plugin
"""
log.debug('PluginStatus: %s', str(self.active_plugin.status))
self.version_number_label.setText(self.active_plugin.version)
self.about_text_browser.setHtml(self.active_plugin.about())
self.programatic_change = True
status = PluginStatus.Active
if self.active_plugin.status == PluginStatus.Active:
status = PluginStatus.Inactive
self.status_combo_box.setCurrentIndex(status)
self.status_combo_box.setEnabled(True)
if self.active_plugin.status != PluginStatus.Disabled:
self.status_checkbox.setChecked(self.active_plugin.status == PluginStatus.Active)
self.status_checkbox.setEnabled(True)
else:
self.status_checkbox.setChecked(False)
self.status_checkbox.setEnabled(False)
self.programatic_change = False
def on_plugin_list_widget_selection_changed(self):
@ -116,22 +115,21 @@ class PluginForm(QtWidgets.QDialog, Ui_PluginViewDialog, RegistryProperties):
plugin_name_singular = self.plugin_list_widget.currentItem().text().split('(')[0][:-1]
self.active_plugin = None
for plugin in self.plugin_manager.plugins:
if plugin.status != PluginStatus.Disabled:
if plugin.name_strings['singular'] == plugin_name_singular:
self.active_plugin = plugin
break
if plugin.name_strings['singular'] == plugin_name_singular:
self.active_plugin = plugin
break
if self.active_plugin:
self._set_details()
else:
self._clear_details()
def on_status_combo_box_changed(self, status):
def on_status_checkbox_changed(self, status):
"""
If the status of a plugin is altered, apply the change
"""
if self.programatic_change or status == PluginStatus.Disabled:
if self.programatic_change or self.active_plugin is None:
return
if status == PluginStatus.Inactive:
if status:
self.application.set_busy_cursor()
self.active_plugin.toggle_status(PluginStatus.Active)
self.application.set_normal_cursor()

View File

@ -1326,6 +1326,8 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa
visible = not self.renderer.theme_level == ThemeLevel.Global
self.toolbar.actions['theme_combo_box'].setVisible(visible)
self.toolbar.actions['theme_label'].setVisible(visible)
self.regenerate_service_items()
def regenerate_service_items(self, changed=False):
"""

View File

@ -60,7 +60,8 @@ class SettingsForm(QtWidgets.QDialog, Ui_SettingsDialog, RegistryProperties):
"""
Execute the form
"""
# load all the settings
# load all the
self.setting_list_widget.blockSignals(True)
self.setting_list_widget.clear()
while self.stacked_layout.count():
# take at 0 and the rest shuffle up.
@ -74,6 +75,7 @@ class SettingsForm(QtWidgets.QDialog, Ui_SettingsDialog, RegistryProperties):
if plugin.settings_tab:
self.insert_tab(plugin.settings_tab, plugin.is_active())
self.setting_list_widget.setCurrentRow(0)
self.setting_list_widget.blockSignals(False)
return QtWidgets.QDialog.exec(self)
def insert_tab(self, tab_widget, is_visible=True):
@ -177,6 +179,7 @@ class SettingsForm(QtWidgets.QDialog, Ui_SettingsDialog, RegistryProperties):
# Check that the title of the tab (i.e. plugin name) is the same as the data in the list item
if tab_widget.tab_title == list_item.data(QtCore.Qt.UserRole):
# Make the matching tab visible
tab_widget.tab_visited = True
self.stacked_layout.setCurrentIndex(tab_index)
self.stacked_layout.currentWidget().tab_visible()

View File

@ -111,6 +111,21 @@ class TestCategoryActionList(TestCase):
self.assertEqual(self.list.actions[0], (41, self.action2))
self.assertEqual(self.list.actions[1], (42, self.action1))
def iterator_test(self):
"""
Test the __iter__ and __next__ methods
"""
# GIVEN: The list including two actions
self.list.add(self.action1)
self.list.add(self.action2)
# WHEN: Iterating over the list
l = [a for a in self.list]
# THEN: Make sure they are returned in correct order
self.assertEquals(len(self.list), 2)
self.assertIs(l[0], self.action1)
self.assertIs(l[1], self.action2)
def remove_test(self):
"""
Test the remove() method

View File

@ -112,7 +112,7 @@ class TestPJLink(TestCase):
@patch.object(pjlink_test, 'projectorReceivedData')
def projector_process_lamp_test(self, mock_projectorReceivedData):
"""
Test setting lamp on/off and hours
Test status lamp on/off and hours
"""
# GIVEN: Test object
pjlink = pjlink_test
@ -129,7 +129,7 @@ class TestPJLink(TestCase):
@patch.object(pjlink_test, 'projectorReceivedData')
def projector_process_multiple_lamp_test(self, mock_projectorReceivedData):
"""
Test setting multiple lamp on/off and hours
Test status multiple lamp on/off and hours
"""
# GIVEN: Test object
pjlink = pjlink_test
@ -156,7 +156,7 @@ class TestPJLink(TestCase):
@patch.object(pjlink_test, 'projectorReceivedData')
def projector_process_power_on_test(self, mock_projectorReceivedData):
"""
Test setting power to ON
Test status power to ON
"""
# GIVEN: Test object and preset
pjlink = pjlink_test
@ -171,7 +171,7 @@ class TestPJLink(TestCase):
@patch.object(pjlink_test, 'projectorReceivedData')
def projector_process_power_off_test(self, mock_projectorReceivedData):
"""
Test setting power to STANDBY
Test status power to STANDBY
"""
# GIVEN: Test object and preset
pjlink = pjlink_test
@ -182,3 +182,71 @@ class TestPJLink(TestCase):
# THEN: Power should be set to STANDBY
self.assertEquals(pjlink.power, S_STANDBY, 'Power should have been set to STANDBY')
@patch.object(pjlink_test, 'projectorUpdateIcons')
def projector_process_avmt_closed_unmuted_test(self, mock_projectorReceivedData):
"""
Test avmt status shutter closed and audio muted
"""
# GIVEN: Test object
pjlink = pjlink_test
pjlink.shutter = False
pjlink.mute = True
# WHEN: Called with setting shutter closed and mute off
pjlink.process_avmt('11')
# THEN: Shutter should be True and mute should be False
self.assertTrue(pjlink.shutter, 'Shutter should have been set to closed')
self.assertFalse(pjlink.mute, 'Audio should be off')
@patch.object(pjlink_test, 'projectorUpdateIcons')
def projector_process_avmt_open_muted_test(self, mock_projectorReceivedData):
"""
Test avmt status shutter open and mute on
"""
# GIVEN: Test object
pjlink = pjlink_test
pjlink.shutter = True
pjlink.mute = False
# WHEN: Called with setting shutter closed and mute on
pjlink.process_avmt('21')
# THEN: Shutter should be closed and mute should be True
self.assertFalse(pjlink.shutter, 'Shutter should have been set to closed')
self.assertTrue(pjlink.mute, 'Audio should be off')
@patch.object(pjlink_test, 'projectorUpdateIcons')
def projector_process_avmt_open_unmuted_test(self, mock_projectorReceivedData):
"""
Test avmt status shutter open and mute off off
"""
# GIVEN: Test object
pjlink = pjlink_test
pjlink.shutter = True
pjlink.mute = True
# WHEN: Called with setting shutter to closed and mute on
pjlink.process_avmt('30')
# THEN: Shutter should be closed and mute should be True
self.assertFalse(pjlink.shutter, 'Shutter should have been set to open')
self.assertFalse(pjlink.mute, 'Audio should be on')
@patch.object(pjlink_test, 'projectorUpdateIcons')
def projector_process_avmt_closed_muted_test(self, mock_projectorReceivedData):
"""
Test avmt status shutter closed and mute off
"""
# GIVEN: Test object
pjlink = pjlink_test
pjlink.shutter = False
pjlink.mute = False
# WHEN: Called with setting shutter to closed and mute on
pjlink.process_avmt('31')
# THEN: Shutter should be closed and mute should be True
self.assertTrue(pjlink.shutter, 'Shutter should have been set to closed')
self.assertTrue(pjlink.mute, 'Audio should be on')

View File

@ -0,0 +1,84 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2016 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.ThemeTab package.
"""
from unittest import TestCase
from openlp.core.common import Registry
from openlp.core.ui.themestab import ThemesTab
from openlp.core.ui.settingsform import SettingsForm
from tests.helpers.testmixin import TestMixin
from tests.functional import MagicMock
class TestThemeTab(TestCase, TestMixin):
def setUp(self):
"""
Set up a few things for the tests
"""
Registry.create()
def test_creation(self):
"""
Test that Themes Tab is created.
"""
# GIVEN: A new Advanced Tab
settings_form = SettingsForm(None)
# WHEN: I create an advanced tab
themes_tab = ThemesTab(settings_form)
# THEN:
self.assertEqual("Themes", themes_tab.tab_title, 'The tab title should be Theme')
def test_save_triggers_processes_true(self):
"""
Test that the global theme event is triggered when the tab is visited.
"""
# GIVEN: A new Advanced Tab
settings_form = SettingsForm(None)
themes_tab = ThemesTab(settings_form)
Registry().register('renderer', MagicMock())
themes_tab.tab_visited = True
# WHEN: I change search as type check box
themes_tab.save()
# THEN: we should have two post save processed to run
self.assertEqual(1, len(settings_form.processes), 'One post save processes should be created')
def test_save_triggers_processes_false(self):
"""
Test that the global theme event is not triggered when the tab is not visited.
"""
# GIVEN: A new Advanced Tab
settings_form = SettingsForm(None)
themes_tab = ThemesTab(settings_form)
Registry().register('renderer', MagicMock())
themes_tab.tab_visited = False
# WHEN: I change search as type check box
themes_tab.save()
# THEN: we should have two post save processed to run
self.assertEqual(0, len(settings_form.processes), 'No post save processes should be created')