- Merged trunk on 21.5.16

This commit is contained in:
suutari-olli 2016-05-21 00:45:14 +03:00
commit dcfcd3e576
58 changed files with 1290 additions and 519 deletions

View File

@ -114,7 +114,7 @@ class CategoryActionList(object):
if item[1] == action:
self.actions.remove(item)
return
raise ValueError('Action "%s" does not exist.' % action)
raise ValueError('Action "{action}" does not exist.'.format(action=action))
class CategoryList(object):
@ -138,7 +138,7 @@ class CategoryList(object):
for category in self.categories:
if category.name == key:
return category
raise KeyError('Category "%s" does not exist.' % key)
raise KeyError('Category "{keY}" does not exist.'.format(key=key))
def __len__(self):
"""
@ -203,7 +203,7 @@ class CategoryList(object):
if category.name == name:
self.categories.remove(category)
return
raise ValueError('Category "%s" does not exist.' % name)
raise ValueError('Category "{name}" does not exist.'.format(name=name))
class ActionList(object):
@ -272,8 +272,9 @@ class ActionList(object):
actions.append(action)
ActionList.shortcut_map[shortcuts[1]] = actions
else:
log.warning('Shortcut "%s" is removed from "%s" because another action already uses this shortcut.' %
(shortcuts[1], action.objectName()))
log.warning('Shortcut "{shortcut}" is removed from "{action}" because another '
'action already uses this shortcut.'.format(shortcut=shortcuts[1],
action=action.objectName()))
shortcuts.remove(shortcuts[1])
# Check the primary shortcut.
existing_actions = ActionList.shortcut_map.get(shortcuts[0], [])
@ -283,8 +284,9 @@ class ActionList(object):
actions.append(action)
ActionList.shortcut_map[shortcuts[0]] = actions
else:
log.warning('Shortcut "%s" is removed from "%s" because another action already uses this shortcut.' %
(shortcuts[0], action.objectName()))
log.warning('Shortcut "{shortcut}" is removed from "{action}" '
'because another action already uses this shortcut.'.format(shortcut=shortcuts[0],
action=action.objectName()))
shortcuts.remove(shortcuts[0])
action.setShortcuts([QtGui.QKeySequence(shortcut) for shortcut in shortcuts])

View File

@ -68,7 +68,7 @@ class LanguageManager(object):
"""
Find all available language files in this OpenLP install
"""
log.debug('Translation files: %s', AppLocation.get_directory(AppLocation.LanguageDir))
log.debug('Translation files: {files}'.format(files=AppLocation.get_directory(AppLocation.LanguageDir)))
trans_dir = QtCore.QDir(AppLocation.get_directory(AppLocation.LanguageDir))
file_names = trans_dir.entryList(['*.qm'], QtCore.QDir.Files, QtCore.QDir.Name)
# Remove qm files from the list which start with "qt_".
@ -93,7 +93,7 @@ class LanguageManager(object):
"""
language = Settings().value('core/language')
language = str(language)
log.info('Language file: \'%s\' Loaded from conf file' % language)
log.info("Language file: '{language}' Loaded from conf file".format(language=language))
if re.match(r'[[].*[]]', language):
LanguageManager.auto_language = True
language = re.sub(r'[\[\]]', '', language)
@ -117,9 +117,9 @@ class LanguageManager(object):
qm_list = LanguageManager.get_qm_list()
language = str(qm_list[action_name])
if LanguageManager.auto_language:
language = '[%s]' % language
language = '[{language}]'.format(language=language)
Settings().setValue('core/language', language)
log.info('Language file: \'%s\' written to conf file' % language)
log.info("Language file: '{language}' written to conf file".format(language=language))
if message:
QtWidgets.QMessageBox.information(None,
translate('OpenLP.LanguageManager', 'Language'),
@ -136,7 +136,8 @@ class LanguageManager(object):
for counter, qmf in enumerate(qm_files):
reg_ex = QtCore.QRegExp("^.*i18n/(.*).qm")
if reg_ex.exactMatch(qmf):
name = '%s' % reg_ex.cap(1)
name = '{regex}'.format(regex=reg_ex.cap(1))
# TODO: Test before converting to python3 string format
LanguageManager.__qm_list__['%#2i %s' % (counter + 1, LanguageManager.language_name(qmf))] = name
@staticmethod

View File

@ -49,12 +49,13 @@ class OpenLPMixin(object):
Code to added debug wrapper to work on called functions within a decorated class.
"""
def wrapped(*args, **kwargs):
parent.logger.debug("Entering %s" % func.__name__)
parent.logger.debug("Entering {function}".format(function=func.__name__))
try:
return func(*args, **kwargs)
except Exception as e:
if parent.logger.getEffectiveLevel() <= logging.ERROR:
parent.logger.error('Exception in %s : %s' % (func.__name__, e))
parent.logger.error('Exception in {function} : {error}'.format(function=func.__name__,
error=e))
raise e
return wrapped

View File

@ -71,8 +71,8 @@ class Registry(object):
else:
if not self.initialising:
trace_error_handler(log)
log.error('Service %s not found in list' % key)
raise KeyError('Service %s not found in list' % key)
log.error('Service {key} not found in list'.format(key=key))
raise KeyError('Service {key} not found in list'.format(key=key))
def register(self, key, reference):
"""
@ -83,8 +83,8 @@ class Registry(object):
"""
if key in self.service_list:
trace_error_handler(log)
log.error('Duplicate service exception %s' % key)
raise KeyError('Duplicate service exception %s' % key)
log.error('Duplicate service exception {key}'.format(key=key))
raise KeyError('Duplicate service exception {key}'.format(key=key))
else:
self.service_list[key] = reference
@ -140,8 +140,8 @@ class Registry(object):
except TypeError:
# Who has called me can help in debugging
trace_error_handler(log)
log.exception('Exception for function %s', function)
log.exception('Exception for function {function}'.format(function=function))
else:
trace_error_handler(log)
log.error("Event %s called but not registered" % event)
log.error("Event {event} called but not registered".format(event=event))
return results

View File

@ -487,16 +487,16 @@ class Settings(QtCore.QSettings):
# Do NOT do this anywhere else!
settings = QtCore.QSettings(self.fileName(), Settings.IniFormat)
settings.beginGroup(plugin.settings_section)
if settings.contains('%s count' % plugin.name):
if settings.contains('{name} count'.format(name=plugin.name)):
# Get the count.
list_count = int(settings.value('%s count' % plugin.name, 0))
list_count = int(settings.value('{name} count'.format(name=plugin.name), 0))
if list_count:
for counter in range(list_count):
# The keys were named e. g.: "image 0"
item = settings.value('%s %d' % (plugin.name, counter), '')
item = settings.value('{name} {counter:d}'.format(name=plugin.name, counter=counter), '')
if item:
files_list.append(item)
settings.remove('%s %d' % (plugin.name, counter))
settings.remove('%s count' % plugin.name)
settings.remove('{name} {counter:d}'.format(name=plugin.name, counter=counter))
settings.remove('{name} count'.format(name=plugin.name))
settings.endGroup()
return files_list

View File

@ -81,6 +81,7 @@ class UiStrings(object):
self.Export = translate('OpenLP.Ui', 'Export')
self.File = translate('OpenLP.Ui', 'File')
self.FileNotFound = translate('OpenLP.Ui', 'File Not Found')
# TODO: Check before converting to python3 string
self.FileNotFoundMessage = translate('OpenLP.Ui', 'File %s not found.\nPlease try selecting it individually.')
self.FontSizePtUnit = translate('OpenLP.Ui', 'pt', 'Abbreviated font pointsize unit')
self.Help = translate('OpenLP.Ui', 'Help')
@ -111,8 +112,8 @@ class UiStrings(object):
self.NISs = translate('OpenLP.Ui', 'No Item Selected', 'Singular')
self.NISp = translate('OpenLP.Ui', 'No Items Selected', 'Plural')
self.OLP = translate('OpenLP.Ui', 'OpenLP')
self.OLPV2 = "%s %s" % (self.OLP, "2")
self.OLPV2x = "%s %s" % (self.OLP, "2.4")
self.OLPV2 = "{name} {version}".format(name=self.OLP, version="2")
self.OLPV2x = "{name} {version}".format(name=self.OLP, version="2.4")
self.OpenLPStart = translate('OpenLP.Ui', 'OpenLP is already running. Do you wish to continue?')
self.OpenService = translate('OpenLP.Ui', 'Open service.')
self.PlaySlidesInLoop = translate('OpenLP.Ui', 'Play Slides in Loop')
@ -140,6 +141,7 @@ class UiStrings(object):
self.Split = translate('OpenLP.Ui', 'Optional &Split')
self.SplitToolTip = translate('OpenLP.Ui',
'Split a slide into two only if it does not fit on the screen as one slide.')
# TODO: Check before converting to python3 string
self.StartTimeCode = translate('OpenLP.Ui', 'Start %s')
self.StopPlaySlidesInLoop = translate('OpenLP.Ui', 'Stop Play Slides in Loop')
self.StopPlaySlidesToEnd = translate('OpenLP.Ui', 'Stop Play Slides to End')

View File

@ -44,9 +44,10 @@ class VersionThread(QtCore.QThread):
log.debug('Version thread - run')
app_version = get_application_version()
version = check_latest_version(app_version)
log.debug("Versions %s and %s " % (LooseVersion(str(version)), LooseVersion(str(app_version['full']))))
log.debug("Versions {version1} and {version2} ".format(version1=LooseVersion(str(version)),
version2=LooseVersion(str(app_version['full']))))
if LooseVersion(str(version)) > LooseVersion(str(app_version['full'])):
self.main_window.openlp_version_check.emit('%s' % version)
self.main_window.openlp_version_check.emit('{version}'.format(version=version))
def get_application_version():
@ -91,7 +92,7 @@ def get_application_version():
if tree_revision == tag_revision:
full_version = tag_version.strip()
else:
full_version = '%s-bzr%s' % (tag_version.strip(), tree_revision.strip())
full_version = '{tag}-bzr{tree}'.format(tag=tag_version.strip(), tree=tree_revision.strip())
else:
# We're not running the development version, let's use the file.
file_path = AppLocation.get_directory(AppLocation.VersionDir)
@ -113,9 +114,10 @@ def get_application_version():
'build': bits[1] if len(bits) > 1 else None
}
if APPLICATION_VERSION['build']:
log.info('Openlp version %s build %s', APPLICATION_VERSION['version'], APPLICATION_VERSION['build'])
log.info('Openlp version {version} build {build}'.format(version=APPLICATION_VERSION['version'],
build=APPLICATION_VERSION['build']))
else:
log.info('Openlp version %s' % APPLICATION_VERSION['version'])
log.info('Openlp version {version}'.format(version=APPLICATION_VERSION['version']))
return APPLICATION_VERSION
@ -149,8 +151,9 @@ def check_latest_version(current_version):
req = urllib.request.Request('http://www.openlp.org/files/dev_version.txt')
else:
req = urllib.request.Request('http://www.openlp.org/files/version.txt')
req.add_header('User-Agent', 'OpenLP/%s %s/%s; ' % (current_version['full'], platform.system(),
platform.release()))
req.add_header('User-Agent', 'OpenLP/{version} {system}/{release}; '.format(version=current_version['full'],
system=platform.system(),
release=platform.release()))
remote_version = None
retries = 0
while True:

View File

@ -55,9 +55,13 @@ class ImageSource(object):
``Theme``
This says, that the image is used by a theme.
``CommandPlugins``
This states that an image is being used by a command plugin.
"""
ImagePlugin = 1
Theme = 2
CommandPlugins = 3
class MediaType(object):
@ -174,10 +178,30 @@ def create_thumb(image_path, thumb_path, return_icon=True, size=None):
ext = os.path.splitext(thumb_path)[1].lower()
reader = QtGui.QImageReader(image_path)
if size is None:
ratio = reader.size().width() / reader.size().height()
# No size given; use default height of 88
if reader.size().isEmpty():
ratio = 1
else:
ratio = reader.size().width() / reader.size().height()
reader.setScaledSize(QtCore.QSize(int(ratio * 88), 88))
else:
elif size.isValid():
# Complete size given
reader.setScaledSize(size)
else:
# Invalid size given
if reader.size().isEmpty():
ratio = 1
else:
ratio = reader.size().width() / reader.size().height()
if size.width() >= 0:
# Valid width; scale height
reader.setScaledSize(QtCore.QSize(size.width(), int(size.width() / ratio)))
elif size.height() >= 0:
# Valid height; scale width
reader.setScaledSize(QtCore.QSize(int(ratio * size.height()), size.height()))
else:
# Invalid; use default height of 88
reader.setScaledSize(QtCore.QSize(int(ratio * 88), 88))
thumb = reader.read()
thumb.save(thumb_path, ext[1:])
if not return_icon:

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

@ -131,7 +131,7 @@ class Source(CommonBase, Base):
"""
Return basic representation of Source table entry.
"""
return '<Source(pjlink_name="{name}", pjlink_code="{code}", text="{Text}")>'.format(name=self.pjlink_name,
return '<Source(pjlink_name="{name}", pjlink_code="{code}", text="{text}")>'.format(name=self.pjlink_name,
code=self.pjlink_code,
text=self.text)
model_id = Column(Integer, ForeignKey('model.id'))

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)
@ -334,6 +335,8 @@ class ServiceItem(RegistryProperties):
file_location_hash, ntpath.basename(image))
self._raw_frames.append({'title': file_name, 'image': image, 'path': path,
'display_title': display_title, 'notes': notes})
if self.is_capable(ItemCapabilities.HasThumbnails):
self.image_manager.add_image(image, ImageSource.CommandPlugins, '#000000')
self._new_item()
def get_service_repr(self, lite_save):
@ -390,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']
@ -606,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:
@ -618,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

@ -88,7 +88,7 @@ class UiAboutDialog(object):
:param about_dialog: The QDialog object to translate
"""
about_dialog.setWindowTitle('%s OpenLP' % UiStrings().About)
about_dialog.setWindowTitle('{about} OpenLP'.format(about=UiStrings().About))
self.about_text_edit.setPlainText(
translate('OpenLP.AboutForm',
'OpenLP <version><revision> - Open Source Lyrics Projection\n'
@ -200,115 +200,115 @@ class UiAboutDialog(object):
' bring this software to you for free because\n'
' He has set us free.')
self.credits_text_edit.setPlainText(
'%s\n'
' %s\n'
'{titleLead}\n'
' {nameLead}\n'
'\n'
'%s\n'
' %s\n'
'{titleDevs}\n'
' {nameDevs}\n'
'\n'
'%s\n'
' %s\n'
'{titleContrib}\n'
' {nameContrib}\n'
'\n'
'%s\n'
' %s\n'
'{titleTesters}\n'
' {nameTesters}\n'
'\n'
'%s\n'
' %s\n'
'{titlePackagers}\n'
' {namePackagers}\n'
'\n'
'%s\n'
' %s\n'
' %s\n'
' %s\n'
' %s\n'
' %s\n'
' %s\n'
' %s\n'
' %s\n'
' %s\n'
' %s\n'
' %s\n'
' %s\n'
' %s\n'
' %s\n'
' %s\n'
' %s\n'
' %s\n'
' %s\n'
' %s\n'
' %s\n'
' %s\n'
' %s\n'
' %s\n'
' %s\n'
' %s\n'
' %s\n'
' %s\n'
' %s\n'
' %s\n'
' %s\n'
' %s\n'
' %s\n'
' %s\n'
' %s\n'
' %s\n'
' %s\n'
' %s\n'
' %s\n'
' %s\n'
' %s\n'
' %s\n'
' %s\n'
' %s\n'
' %s\n'
'{titleTranslators}\n'
' {titleAF}\n'
' {nameAF}\n'
' {titleCS}\n'
' {nameCS}\n'
' {titleDA}\n'
' {nameDA}\n'
' {titleDE}\n'
' {nameDE}\n'
' {titleEL}\n'
' {nameEL}\n'
' {titleGB}\n'
' {nameGB}\n'
' {titleENZA}\n'
' {nameENZA}\n'
' {titleES}\n'
' {nameES}\n'
' {titleET}\n'
' {nameET}\n'
' {titleFI}\n'
' {nameFI}\n'
' {titleFR}\n'
' {nameFR}\n'
' {titleHU}\n'
' {nameHU}\n'
' {titleIND}\n'
' {nameIND}\n'
' {titleJA}\n'
' {nameJA}\n'
' {titleNB}\n'
' {nameNB}\n'
' {titleNL}\n'
' {nameNL}\n'
' {titlePL}\n'
' {namePL}\n'
' {titlePTBR}\n'
' {namePTBR}\n'
' {titleRU}\n'
' {nameRU}\n'
' {titleSV}\n'
' {nameSV}\n'
' {titleTALK}\n'
' {nameTALK}\n'
' {titleZHCN}\n'
' {nameZHCN}\n'
'\n'
'%s\n'
' %s\n'
'{titleDOCS}\n'
' {nameDOCS}\n'
'\n'
'%s\n%s' %
(project_lead, lead,
devs, '\n '.join(developers),
cons, '\n '.join(contributors),
tests, '\n '.join(testers),
packs, '\n '.join(packagers),
laters,
af, '\n '.join(translators['af']),
cs, '\n '.join(translators['cs']),
da, '\n '.join(translators['da']),
de, '\n '.join(translators['de']),
el, '\n '.join(translators['el']),
gb, '\n '.join(translators['en_GB']),
enza, '\n '.join(translators['en_ZA']),
es, '\n '.join(translators['es']),
et, '\n '.join(translators['et']),
fi, '\n '.join(translators['fi']),
fr, '\n '.join(translators['fr']),
hu, '\n '.join(translators['hu']),
ind, '\n '.join(translators['id']),
ja, '\n '.join(translators['ja']),
nb, '\n '.join(translators['nb']),
nl, '\n '.join(translators['nl']),
pl, '\n '.join(translators['pl']),
ptbr, '\n '.join(translators['pt_BR']),
ru, '\n '.join(translators['ru']),
sv, '\n '.join(translators['sv']),
talk, '\n '.join(translators['ta_LK']),
zhcn, '\n '.join(translators['zh_CN']),
documentation, '\n '.join(documentors),
built_with, final_credit))
'{build}\n{final}'.format(titleLead=project_lead, nameLead=lead,
titleDevs=devs, nameDevs='\n '.join(developers),
titleContrib=cons, nameContrib='\n '.join(contributors),
titleTesters=tests, nameTesters='\n '.join(testers),
titlePackagers=packs, namePackagers='\n '.join(packagers),
titleTranslators=laters,
titleAF=af, nameAF='\n '.join(translators['af']),
titleCS=cs, nameCS='\n '.join(translators['cs']),
titleDA=da, nameDA='\n '.join(translators['da']),
titleDE=de, nameDE='\n '.join(translators['de']),
titleEL=el, nameEL='\n '.join(translators['el']),
titleGB=gb, nameGB='\n '.join(translators['en_GB']),
titleENZA=enza, nameENZA='\n '.join(translators['en_ZA']),
titleES=es, nameES='\n '.join(translators['es']),
titleET=et, nameET='\n '.join(translators['et']),
titleFI=fi, nameFI='\n '.join(translators['fi']),
titleFR=fr, nameFR='\n '.join(translators['fr']),
titleHU=hu, nameHU='\n '.join(translators['hu']),
titleIND=ind, nameIND='\n '.join(translators['id']),
titleJA=ja, nameJA='\n '.join(translators['ja']),
titleNB=nb, nameNB='\n '.join(translators['nb']),
titleNL=nl, nameNL='\n '.join(translators['nl']),
titlePL=pl, namePL='\n '.join(translators['pl']),
titlePTBR=ptbr, namePTBR='\n '.join(translators['pt_BR']),
titleRU=ru, nameRU='\n '.join(translators['ru']),
titleSV=sv, nameSV='\n '.join(translators['sv']),
titleTALK=talk, nameTALK='\n '.join(translators['ta_LK']),
titleZHCN=zhcn, nameZHCN='\n '.join(translators['zh_CN']),
titleDOCS=documentation, nameDOCS='\n '.join(documentors),
build=built_with,
final=final_credit))
self.about_notebook.setTabText(self.about_notebook.indexOf(self.credits_tab),
translate('OpenLP.AboutForm', 'Credits'))
cr_others = ('Tim Bentley, Gerald Britton, Jonathan Corwin, Samuel Findlay, '
'Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, '
'Armin K\xf6hler, Erik Lundin, Edwin Lunando, Joshua Miller, '
'Brian T. Meyer, Stevan Pettit, Andreas Preikschat, '
'Mattias P\xf5ldaru, Christian Richter, Philip Ridout, '
'Ken Roberts, Simon Scudder, Jeffrey Smith, Maikel Stuivenberg, '
'Martin Thompson, Jon Tibble, Dave Warnock, Frode Woldsund, '
'Martin Zibricky, Patrick Zimmermann')
copyright_note = translate('OpenLP.AboutForm',
'Copyright \xa9 2004-2016 %s\n'
'Portions copyright \xa9 2004-2016 %s') % \
('Raoul Snyman',
'Tim Bentley, Gerald Britton, Jonathan Corwin, Samuel Findlay, '
'Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, '
'Armin K\xf6hler, Erik Lundin, Edwin Lunando, Joshua Miller, '
'Brian T. Meyer, Stevan Pettit, Andreas Preikschat, '
'Mattias P\xf5ldaru, Christian Richter, '
'Philip Ridout, Simon Scudder, Jeffrey Smith, Maikel Stuivenberg, '
'Martin Thompson, Jon Tibble, Dave Warnock, Frode Woldsund, '
'Martin Zibricky, Patrick Zimmermann')
'Copyright \xa9 2004-2016 {cr}\n\n'
'Portions copyright \xa9 2004-2016 {others}').format(cr='Raoul Snyman',
others=cr_others)
licence = translate('OpenLP.AboutForm',
'This program is free software; you can redistribute it and/or '
'modify it under the terms of the GNU General Public License as '
@ -690,7 +690,11 @@ class UiAboutDialog(object):
'linking proprietary applications with the library. If this is '
'what you want to do, use the GNU Lesser General Public License '
'instead of this License.')
self.license_text_edit.setPlainText('%s\n\n%s\n\n%s\n\n\n%s' % (copyright_note, licence, disclaimer, gpl_text))
self.license_text_edit.setPlainText('{crnote}\n\n{license}\n\n{disclaimer}'
'\n\n\n{gpl}'.format(crnote=copyright_note,
license=licence,
disclaimer=disclaimer,
gpl=gpl_text))
self.about_notebook.setTabText(self.about_notebook.indexOf(self.license_tab),
translate('OpenLP.AboutForm', 'License'))
self.volunteer_button.setText(translate('OpenLP.AboutForm', 'Volunteer'))

View File

@ -52,7 +52,7 @@ class AboutForm(QtWidgets.QDialog, UiAboutDialog):
about_text = self.about_text_edit.toPlainText()
about_text = about_text.replace('<version>', application_version['version'])
if application_version['build']:
build_text = translate('OpenLP.AboutForm', ' build %s') % application_version['build']
build_text = translate('OpenLP.AboutForm', ' build {version}').format(version=application_version['build'])
else:
build_text = ''
about_text = about_text.replace('<revision>', build_text)

View File

@ -308,8 +308,8 @@ class AdvancedTab(SettingsTab):
self.service_name_label.setText(translate('OpenLP.AdvancedTab', 'Name:'))
self.service_name_edit.setToolTip(translate('OpenLP.AdvancedTab', 'Consult the OpenLP manual for usage.'))
self.service_name_revert_button.setToolTip(
translate('OpenLP.AdvancedTab', 'Revert to the default service name "%s".') %
UiStrings().DefaultServiceName)
translate('OpenLP.AdvancedTab',
'Revert to the default service name "{name}".').format(name=UiStrings().DefaultServiceName))
self.service_name_example_label.setText(translate('OpenLP.AdvancedTab', 'Example:'))
self.hide_mouse_group_box.setTitle(translate('OpenLP.AdvancedTab', 'Mouse Cursor'))
self.hide_mouse_check_box.setText(translate('OpenLP.AdvancedTab', 'Hide mouse cursor when over display window'))
@ -391,16 +391,16 @@ class AdvancedTab(SettingsTab):
# Since data location can be changed, make sure the path is present.
self.current_data_path = AppLocation.get_data_path()
if not os.path.exists(self.current_data_path):
log.error('Data path not found %s' % self.current_data_path)
log.error('Data path not found {path}'.format(path=self.current_data_path))
answer = QtWidgets.QMessageBox.critical(
self, translate('OpenLP.AdvancedTab', 'Data Directory Error'),
translate('OpenLP.AdvancedTab', 'OpenLP data directory was not found\n\n%s\n\n'
translate('OpenLP.AdvancedTab', 'OpenLP data directory was not found\n\n{path}\n\n'
'This data directory was previously changed from the OpenLP '
'default location. If the new location was on removable '
'media, that media needs to be made available.\n\n'
'Click "No" to stop loading OpenLP. allowing you to fix the the problem.\n\n'
'Click "Yes" to reset the data directory to the default '
'location.').replace('%s', self.current_data_path),
'location.').format(path=self.current_data_path),
QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No),
QtWidgets.QMessageBox.No)
if answer == QtWidgets.QMessageBox.No:
@ -410,7 +410,7 @@ class AdvancedTab(SettingsTab):
# Set data location to default.
settings.remove('advanced/data path')
self.current_data_path = AppLocation.get_data_path()
log.warning('User requested data path set to default %s' % self.current_data_path)
log.warning('User requested data path set to default {path}'.format(path=self.current_data_path))
self.data_directory_label.setText(os.path.abspath(self.current_data_path))
# Don't allow data directory move if running portable.
if settings.value('advanced/is portable'):
@ -542,9 +542,9 @@ class AdvancedTab(SettingsTab):
# Make sure they want to change the data.
answer = QtWidgets.QMessageBox.question(self, translate('OpenLP.AdvancedTab', 'Confirm Data Directory Change'),
translate('OpenLP.AdvancedTab', 'Are you sure you want to change the '
'location of the OpenLP data directory to:\n\n%s\n\nThe data '
'directory will be changed when OpenLP is closed.').
replace('%s', new_data_path),
'location of the OpenLP data directory to:\n\n{path}'
'\n\nThe data directory will be changed when OpenLP is '
'closed.').format(path=new_data_path),
QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes |
QtWidgets.QMessageBox.No),
QtWidgets.QMessageBox.No)
@ -608,10 +608,10 @@ class AdvancedTab(SettingsTab):
answer = QtWidgets.QMessageBox.warning(self,
translate('OpenLP.AdvancedTab', 'Overwrite Existing Data'),
translate('OpenLP.AdvancedTab',
'WARNING: \n\nThe location you have selected \n\n%s\n\n'
'appears to contain OpenLP data files. Do you wish to '
'replace these files with the current data files?').
replace('%s', os.path.abspath(data_path,)),
'WARNING: \n\nThe location you have selected \n\n{path}'
'\n\nappears to contain OpenLP data files. Do you wish to '
'replace these files with the current data '
'files?').format(path=os.path.abspath(data_path,)),
QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes |
QtWidgets.QMessageBox.No),
QtWidgets.QMessageBox.No)

View File

@ -91,6 +91,7 @@ class ExceptionForm(QtWidgets.QDialog, Ui_ExceptionDialog, RegistryProperties):
super(ExceptionForm, self).__init__(None, QtCore.Qt.WindowSystemMenuHint | QtCore.Qt.WindowTitleHint)
self.setupUi(self)
self.settings_section = 'crashreport'
# TODO: Need to see how to format strings when string with tags is actually a variable
self.report_text = '**OpenLP Bug Report**\n' \
'Version: %s\n\n' \
'--- Details of the Exception. ---\n\n%s\n\n ' \
@ -114,21 +115,17 @@ class ExceptionForm(QtWidgets.QDialog, Ui_ExceptionDialog, RegistryProperties):
openlp_version = get_application_version()
description = self.description_text_edit.toPlainText()
traceback = self.exception_text_edit.toPlainText()
system = translate('OpenLP.ExceptionForm', 'Platform: %s\n') % platform.platform()
libraries = 'Python: %s\n' % platform.python_version() + \
'Qt5: %s\n' % Qt.qVersion() + \
'PyQt5: %s\n' % Qt.PYQT_VERSION_STR + \
'QtWebkit: %s\n' % WEBKIT_VERSION + \
'SQLAlchemy: %s\n' % sqlalchemy.__version__ + \
'SQLAlchemy Migrate: %s\n' % MIGRATE_VERSION + \
'BeautifulSoup: %s\n' % bs4.__version__ + \
'lxml: %s\n' % etree.__version__ + \
'Chardet: %s\n' % CHARDET_VERSION + \
'PyEnchant: %s\n' % ENCHANT_VERSION + \
'Mako: %s\n' % MAKO_VERSION + \
'pyICU: %s\n' % ICU_VERSION + \
'pyUNO bridge: %s\n' % self._pyuno_import() + \
'VLC: %s\n' % VLC_VERSION
system = translate('OpenLP.ExceptionForm', 'Platform: {platform}\n').format(platform=platform.platform())
libraries = ('Python: {python}\nQt5: {qt5}\nPyQt5: {pyqt5}\nQtWebkit: {qtwebkit}\nSQLAlchemy: {sqalchemy}\n'
'SQLAlchemy Migrate: {migrate}\nBeautifulSoup: {soup}\nlxml: {etree}\nChardet: {chardet}\n'
'PyEnchant: {enchant}\nMako: {mako}\npyICU: {icu}\npyUNO bridge: {uno}\n'
'VLC: {vlc}\n').format(python=platform.python_version(), qt5=Qt.qVersion(),
pyqt5=Qt.PYQT_VERSION_STR, qtwebkit=WEBKIT_VERSION,
sqalchemy=sqlalchemy.__version__, migrate=MIGRATE_VERSION,
soup=bs4.__version__, etree=etree.__version__, chardet=CHARDET_VERSION,
enchant=ENCHANT_VERSION, mako=MAKO_VERSION, icu=ICU_VERSION,
uno=self._pyuno_import(), vlc=VLC_VERSION)
if is_linux():
if os.environ.get('KDE_FULL_SESSION') == 'true':
system += 'Desktop: KDE SC\n'
@ -178,9 +175,10 @@ class ExceptionForm(QtWidgets.QDialog, Ui_ExceptionDialog, RegistryProperties):
source = re.sub(r'.*[/\\]openlp[/\\](.*)".*', r'\1', line)
if ':' in line:
exception = line.split('\n')[-1].split(':')[0]
subject = 'Bug report: %s in %s' % (exception, source)
subject = 'Bug report: {error} in {source}'.format(error=exception, source=source)
mail_urlquery = QtCore.QUrlQuery()
mail_urlquery.addQueryItem('subject', subject)
# TODO: Find out how to format() text that is in a variable
mail_urlquery.addQueryItem('body', self.report_text % content)
if self.file_attachment:
mail_urlquery.addQueryItem('attach', self.file_attachment)
@ -199,7 +197,7 @@ class ExceptionForm(QtWidgets.QDialog, Ui_ExceptionDialog, RegistryProperties):
else:
self.__button_state(False)
self.description_word_count.setText(
translate('OpenLP.ExceptionDialog', 'Description characters to enter : %s') % count)
translate('OpenLP.ExceptionDialog', 'Description characters to enter : {count}').format(count=count))
def on_attach_file_button_clicked(self):
"""
@ -210,7 +208,7 @@ class ExceptionForm(QtWidgets.QDialog, Ui_ExceptionDialog, RegistryProperties):
'Select Attachment'),
Settings().value(self.settings_section +
'/last directory'),
'%s (*)' % UiStrings().AllFiles)
'{text} (*)'.format(text=UiStrings().AllFiles))
log.info('New files(s) %s', str(files))
if files:
self.file_attachment = str(files)

View File

@ -72,7 +72,7 @@ class ThemeScreenshotWorker(QtCore.QObject):
if self.was_download_cancelled:
return
try:
urllib.request.urlretrieve('%s%s' % (self.themes_url, self.screenshot),
urllib.request.urlretrieve('{host}{name}'.format(host=self.themes_url, name=self.screenshot),
os.path.join(gettempdir(), 'openlp', self.screenshot))
# Signal that the screenshot has been downloaded
self.screenshot_downloaded.emit(self.title, self.filename, self.sha256)
@ -180,11 +180,13 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties):
user_agent = 'OpenLP/' + Registry().get('application').applicationVersion()
self.application.process_events()
try:
web_config = get_web_page('%s%s' % (self.web, 'download.cfg'), header=('User-Agent', user_agent))
web_config = get_web_page('{host}{name}'.format(host=self.web, name='download.cfg'),
header=('User-Agent', user_agent))
except (urllib.error.URLError, ConnectionError) as err:
msg = QtWidgets.QMessageBox()
title = translate('OpenLP.FirstTimeWizard', 'Network Error')
msg.setText('{} {}'.format(title, err.code if hasattr(err, 'code') else ''))
msg.setText('{title} {error}'.format(title=title,
error=err.code if hasattr(err, 'code') else ''))
msg.setInformativeText(translate('OpenLP.FirstTimeWizard',
'There was a network error attempting to '
'connect to retrieve initial configuration information'))
@ -205,6 +207,7 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties):
trace_error_handler(log)
self.update_screen_list_combo()
self.application.process_events()
# TODO: Figure out how to use a variable with format()
self.downloading = translate('OpenLP.FirstTimeWizard', 'Downloading %s...')
if self.has_run_wizard:
self.songs_check_box.setChecked(self.plugin_manager.get_plugin_by_name('songs').is_active())
@ -223,9 +226,9 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties):
songs = songs.split(',')
for song in songs:
self.application.process_events()
title = self.config.get('songs_%s' % song, 'title')
filename = self.config.get('songs_%s' % song, 'filename')
sha256 = self.config.get('songs_%s' % song, 'sha256', fallback='')
title = self.config.get('songs_{song}'.format(song=song), 'title')
filename = self.config.get('songs_{song}'.format(song=song), 'filename')
sha256 = self.config.get('songs_{song}'.format(song=song), 'sha256', fallback='')
item = QtWidgets.QListWidgetItem(title, self.songs_list_widget)
item.setData(QtCore.Qt.UserRole, (filename, sha256))
item.setCheckState(QtCore.Qt.Unchecked)
@ -234,15 +237,15 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties):
bible_languages = bible_languages.split(',')
for lang in bible_languages:
self.application.process_events()
language = self.config.get('bibles_%s' % lang, 'title')
language = self.config.get('bibles_{lang}'.format(lang=lang), 'title')
lang_item = QtWidgets.QTreeWidgetItem(self.bibles_tree_widget, [language])
bibles = self.config.get('bibles_%s' % lang, 'translations')
bibles = self.config.get('bibles_{lang}'.format(lang=lang), 'translations')
bibles = bibles.split(',')
for bible in bibles:
self.application.process_events()
title = self.config.get('bible_%s' % bible, 'title')
filename = self.config.get('bible_%s' % bible, 'filename')
sha256 = self.config.get('bible_%s' % bible, 'sha256', fallback='')
title = self.config.get('bible_{bible}'.format(bible=bible), 'title')
filename = self.config.get('bible_{bible}'.format(bible=bible), 'filename')
sha256 = self.config.get('bible_{bible}'.format(bible=bible), 'sha256', fallback='')
item = QtWidgets.QTreeWidgetItem(lang_item, [title])
item.setData(0, QtCore.Qt.UserRole, (filename, sha256))
item.setCheckState(0, QtCore.Qt.Unchecked)
@ -252,10 +255,10 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties):
# Download the theme screenshots
themes = self.config.get('themes', 'files').split(',')
for theme in themes:
title = self.config.get('theme_%s' % theme, 'title')
filename = self.config.get('theme_%s' % theme, 'filename')
sha256 = self.config.get('theme_%s' % theme, 'sha256', fallback='')
screenshot = self.config.get('theme_%s' % theme, 'screenshot')
title = self.config.get('theme_{theme}'.format(theme=theme), 'title')
filename = self.config.get('theme_{theme}'.format(theme=theme), 'filename')
sha256 = self.config.get('theme_{theme}'.format(theme=theme), 'sha256', fallback='')
screenshot = self.config.get('theme_{theme}'.format(theme=theme), 'screenshot')
worker = ThemeScreenshotWorker(self.themes_url, title, filename, sha256, screenshot)
self.theme_screenshot_workers.append(worker)
worker.screenshot_downloaded.connect(self.on_screenshot_downloaded)
@ -421,7 +424,7 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties):
self._download_progress(block_count, block_size)
filename.close()
if sha256 and hasher.hexdigest() != sha256:
log.error('sha256 sums did not match for file: {}'.format(f_path))
log.error('sha256 sums did not match for file: {file}'.format(file=f_path))
os.remove(f_path)
return False
except (urllib.error.URLError, socket.timeout) as err:
@ -447,7 +450,7 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties):
themes = self.config.get('themes', 'files')
themes = themes.split(',')
for index, theme in enumerate(themes):
screenshot = self.config.get('theme_%s' % theme, 'screenshot')
screenshot = self.config.get('theme_{theme}'.format(theme=theme), 'screenshot')
item = self.themes_list_widget.item(index)
if item:
item.setIcon(build_icon(os.path.join(gettempdir(), 'openlp', screenshot)))
@ -507,7 +510,7 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties):
item = self.songs_list_widget.item(i)
if item.checkState() == QtCore.Qt.Checked:
filename, sha256 = item.data(QtCore.Qt.UserRole)
size = self._get_file_size('%s%s' % (self.songs_url, filename))
size = self._get_file_size('{path}{name}'.format(path=self.songs_url, name=filename))
self.max_progress += size
# Loop through the Bibles list and increase for each selected item
iterator = QtWidgets.QTreeWidgetItemIterator(self.bibles_tree_widget)
@ -516,7 +519,7 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties):
item = iterator.value()
if item.parent() and item.checkState(0) == QtCore.Qt.Checked:
filename, sha256 = item.data(0, QtCore.Qt.UserRole)
size = self._get_file_size('%s%s' % (self.bibles_url, filename))
size = self._get_file_size('{path}{name}'.format(path=self.bibles_url, name=filename))
self.max_progress += size
iterator += 1
# Loop through the themes list and increase for each selected item
@ -525,7 +528,7 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties):
item = self.themes_list_widget.item(i)
if item.checkState() == QtCore.Qt.Checked:
filename, sha256 = item.data(QtCore.Qt.UserRole)
size = self._get_file_size('%s%s' % (self.themes_url, filename))
size = self._get_file_size('{path}{name}'.format(path=self.themes_url, name=filename))
self.max_progress += size
except urllib.error.URLError:
trace_error_handler(log)
@ -560,22 +563,26 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties):
if self.max_progress:
self.progress_bar.setValue(self.progress_bar.maximum())
if self.has_run_wizard:
self.progress_label.setText(translate('OpenLP.FirstTimeWizard',
'Download complete. Click the %s button to return to OpenLP.') %
clean_button_text(self.buttonText(QtWidgets.QWizard.FinishButton)))
text = translate('OpenLP.FirstTimeWizard',
'Download complete. Click the {button} button to return to OpenLP.'
).format(text=clean_button_text(self.buttonText(QtWidgets.QWizard.FinishButton)))
self.progress_label.setText(text)
else:
self.progress_label.setText(translate('OpenLP.FirstTimeWizard',
'Download complete. Click the %s button to start OpenLP.') %
clean_button_text(self.buttonText(QtWidgets.QWizard.FinishButton)))
text = translate('OpenLP.FirstTimeWizard',
'Download complete. Click the {button} button to start OpenLP.'
).format(button=clean_button_text(self.buttonText(QtWidgets.QWizard.FinishButton)))
self.progress_label.setText()
else:
if self.has_run_wizard:
self.progress_label.setText(translate('OpenLP.FirstTimeWizard',
'Click the %s button to return to OpenLP.') %
clean_button_text(self.buttonText(QtWidgets.QWizard.FinishButton)))
text = translate('OpenLP.FirstTimeWizard',
'Click the {button} button to return to OpenLP.'
).format(button=clean_button_text(self.buttonText(QtWidgets.QWizard.FinishButton)))
self.progress_label.setText(text)
else:
self.progress_label.setText(translate('OpenLP.FirstTimeWizard',
'Click the %s button to start OpenLP.') %
clean_button_text(self.buttonText(QtWidgets.QWizard.FinishButton)))
text = translate('OpenLP.FirstTimeWizard',
'Click the {button} button to start OpenLP.'
).format(button=clean_button_text(self.buttonText(QtWidgets.QWizard.FinishButton)))
self.progress_label.setText()
self.finish_button.setVisible(True)
self.finish_button.setEnabled(True)
self.cancel_button.setVisible(False)
@ -628,8 +635,9 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties):
self._increment_progress_bar(self.downloading % filename, 0)
self.previous_size = 0
destination = os.path.join(songs_destination, str(filename))
if not self.url_get_file('%s%s' % (self.songs_url, filename), destination, sha256):
missed_files.append('Song: {}'.format(filename))
if not self.url_get_file('{path}{name}'.format(path=self.songs_url, name=filename),
destination, sha256):
missed_files.append('Song: {name}'.format(name=filename))
# Download Bibles
bibles_iterator = QtWidgets.QTreeWidgetItemIterator(self.bibles_tree_widget)
while bibles_iterator.value():
@ -638,31 +646,34 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties):
bible, sha256 = item.data(0, QtCore.Qt.UserRole)
self._increment_progress_bar(self.downloading % bible, 0)
self.previous_size = 0
if not self.url_get_file('%s%s' % (self.bibles_url, bible), os.path.join(bibles_destination, bible),
if not self.url_get_file('{path}{name}'.format(path=self.bibles_url, name=bible),
os.path.join(bibles_destination, bible),
sha256):
missed_files.append('Bible: {}'.format(bible))
missed_files.append('Bible: {name}'.format(name=bible))
bibles_iterator += 1
# Download themes
for i in range(self.themes_list_widget.count()):
item = self.themes_list_widget.item(i)
if item.checkState() == QtCore.Qt.Checked:
theme, sha256 = item.data(QtCore.Qt.UserRole)
# TODO: Verify how to use format() with strings in a variable
self._increment_progress_bar(self.downloading % theme, 0)
self.previous_size = 0
if not self.url_get_file('%s%s' % (self.themes_url, theme), os.path.join(themes_destination, theme),
if not self.url_get_file('{path}{name}'.format(path=self.themes_url, name=theme),
os.path.join(themes_destination, theme),
sha256):
missed_files.append('Theme: {}'.format(theme))
missed_files.append('Theme: {name}'.format(name=theme))
if missed_files:
file_list = ''
for entry in missed_files:
file_list += '{}<br \>'.format(entry)
file_list += '{text}<br \>'.format(text=entry)
msg = QtWidgets.QMessageBox()
msg.setIcon(QtWidgets.QMessageBox.Warning)
msg.setWindowTitle(translate('OpenLP.FirstTimeWizard', 'Network Error'))
msg.setText(translate('OpenLP.FirstTimeWizard', 'Unable to download some files'))
msg.setInformativeText(translate('OpenLP.FirstTimeWizard',
'The following files were not able to be '
'downloaded:<br \>{}'.format(file_list)))
'downloaded:<br \>{text}'.format(text=file_list)))
msg.setStandardButtons(msg.Ok)
ans = msg.exec()
return True

View File

@ -228,12 +228,13 @@ class UiFirstTimeWizard(object):
:param first_time_wizard: The wizard form
"""
first_time_wizard.setWindowTitle(translate('OpenLP.FirstTimeWizard', 'First Time Wizard'))
first_time_wizard.title_label.setText('<span style="font-size:14pt; font-weight:600;">%s</span>' %
translate('OpenLP.FirstTimeWizard', 'Welcome to the First Time Wizard'))
text = translate('OpenLP.FirstTimeWizard', 'Welcome to the First Time Wizard')
first_time_wizard.title_label.setText('<span style="font-size:14pt; font-weight:600;">{text}'
'</span>'.format(text=text))
button = clean_button_text(first_time_wizard.buttonText(QtWidgets.QWizard.NextButton))
first_time_wizard.information_label.setText(
translate('OpenLP.FirstTimeWizard', 'This wizard will help you to configure OpenLP for initial use. '
'Click the %s button below to start.') %
clean_button_text(first_time_wizard.buttonText(QtWidgets.QWizard.NextButton)))
'Click the {button} button below to start.').format(button=button))
self.download_page.setTitle(translate('OpenLP.FirstTimeWizard', 'Downloading Resource Index'))
self.download_page.setSubTitle(translate('OpenLP.FirstTimeWizard', 'Please wait while the resource index is '
'downloaded.'))
@ -264,18 +265,19 @@ class UiFirstTimeWizard(object):
self.no_internet_page.setTitle(translate('OpenLP.FirstTimeWizard', 'No Internet Connection'))
self.no_internet_page.setSubTitle(
translate('OpenLP.FirstTimeWizard', 'Unable to detect an Internet connection.'))
button = clean_button_text(first_time_wizard.buttonText(QtWidgets.QWizard.FinishButton))
self.no_internet_text = translate('OpenLP.FirstTimeWizard',
'No Internet connection was found. The First Time Wizard needs an Internet '
'connection in order to be able to download sample songs, Bibles and themes.'
' Click the %s button now to start OpenLP with initial settings and '
' Click the {button} button now to start OpenLP with initial settings and '
'no sample data.\n\nTo re-run the First Time Wizard and import this sample '
'data at a later time, check your Internet connection and re-run this '
'wizard by selecting "Tools/Re-run First Time Wizard" from OpenLP.') % \
clean_button_text(first_time_wizard.buttonText(QtWidgets.QWizard.FinishButton))
'wizard by selecting "Tools/Re-run First Time Wizard" from OpenLP.'
).format(button=button)
button = clean_button_text(first_time_wizard.buttonText(QtWidgets.QWizard.CancelButton))
self.cancel_wizard_text = translate('OpenLP.FirstTimeWizard',
'\n\nTo cancel the First Time Wizard completely (and not start OpenLP), '
'click the %s button now.') % \
clean_button_text(first_time_wizard.buttonText(QtWidgets.QWizard.CancelButton))
'click the {button} button now.').format(button=button)
self.songs_page.setTitle(translate('OpenLP.FirstTimeWizard', 'Sample Songs'))
self.songs_page.setSubTitle(translate('OpenLP.FirstTimeWizard', 'Select and download public domain songs.'))
self.bibles_page.setTitle(translate('OpenLP.FirstTimeWizard', 'Sample Bibles'))

View File

@ -72,19 +72,19 @@ class FormattingTagController(object):
"""
for line_number, html1 in enumerate(self.protected_tags):
if self._strip(html1['start tag']) == tag:
return translate('OpenLP.FormattingTagForm', 'Tag %s already defined.') % tag
return translate('OpenLP.FormattingTagForm', 'Tag {tag} already defined.').format(tag=tag)
if self._strip(html1['desc']) == desc:
return translate('OpenLP.FormattingTagForm', 'Description %s already defined.') % tag
return translate('OpenLP.FormattingTagForm', 'Description {tag} already defined.').format(tag=tag)
for line_number, html1 in enumerate(self.custom_tags):
if self._strip(html1['start tag']) == tag:
return translate('OpenLP.FormattingTagForm', 'Tag %s already defined.') % tag
return translate('OpenLP.FormattingTagForm', 'Tag {tag} already defined.').format(tag=tag)
if self._strip(html1['desc']) == desc:
return translate('OpenLP.FormattingTagForm', 'Description %s already defined.') % tag
return translate('OpenLP.FormattingTagForm', 'Description {tag} already defined.').format(tag=tag)
tag = {
'desc': desc,
'start tag': '{%s}' % tag,
'start tag': '{{{tag}}}'.format(tag=tag),
'start html': start_html,
'end tag': '{/%s}' % tag,
'end tag': '{/{tag}}}'.format(tag=tag),
'end html': end_html,
'protected': False,
'temporary': False
@ -130,6 +130,7 @@ class FormattingTagController(object):
elif not match.group('empty'):
end_tags.append(tag)
match = self.html_tag_regex.search(start_html, match.end())
# TODO: Verify format() works with lambda
return ''.join(map(lambda tag: '</%s>' % tag, reversed(end_tags)))
def start_tag_changed(self, start_html, end_html):
@ -146,7 +147,8 @@ class FormattingTagController(object):
end = self.start_html_to_end_html(start_html)
if not end_html:
if not end:
return translate('OpenLP.FormattingTagForm', 'Start tag %s is not valid HTML') % start_html, None
return translate('OpenLP.FormattingTagForm',
'Start tag {tag} is not valid HTML').format(tag=start_html), None
return None, end
return None, None
@ -165,7 +167,8 @@ class FormattingTagController(object):
if not end_html:
return None, end
if end and end != end_html:
return translate('OpenLP.FormattingTagForm',
'End tag %(end)s does not match end tag for start tag %(start)s') % \
{'end': end, 'start': start_html}, None
return (translate('OpenLP.FormattingTagForm',
'End tag {end} does not match end tag for start tag {start}').format(end=end,
start=start_html),
None)
return None, None

View File

@ -90,9 +90,10 @@ class FormattingTagForm(QtWidgets.QDialog, Ui_FormattingTagDialog, FormattingTag
"""
new_row = self.tag_table_widget.rowCount()
self.tag_table_widget.insertRow(new_row)
self.tag_table_widget.setItem(new_row, 0, QtWidgets.QTableWidgetItem(translate('OpenLP.FormattingTagForm',
'New Tag %d' % new_row)))
self.tag_table_widget.setItem(new_row, 1, QtWidgets.QTableWidgetItem('n%d' % new_row))
self.tag_table_widget.setItem(new_row, 0,
QtWidgets.QTableWidgetItem(translate('OpenLP.FormattingTagForm',
'New Tag {row:d}').format(row=new_row)))
self.tag_table_widget.setItem(new_row, 1, QtWidgets.QTableWidgetItem('n{row:d}'.format(row=new_row)))
self.tag_table_widget.setItem(new_row, 2,
QtWidgets.QTableWidgetItem(translate('OpenLP.FormattingTagForm', '<HTML here>')))
self.tag_table_widget.setItem(new_row, 3, QtWidgets.QTableWidgetItem(''))

View File

@ -400,7 +400,7 @@ class GeneralTab(SettingsTab):
"""
Select the logo file
"""
file_filters = '%s;;%s (*.*)' % (get_images_filter(), UiStrings().AllFiles)
file_filters = '{text};;{names} (*.*)'.format(text=get_images_filter(), names=UiStrings().AllFiles)
filename, filter_used = QtWidgets.QFileDialog.getOpenFileName(self,
translate('OpenLP.AdvancedTab', 'Open File'), '',
file_filters)

View File

@ -27,7 +27,7 @@ It is based on a QTableWidget but represents its contents in list form.
from PyQt5 import QtCore, QtGui, QtWidgets
from openlp.core.common import RegistryProperties, Settings
from openlp.core.lib import ImageSource, ServiceItem
from openlp.core.lib import ImageSource, ItemCapabilities, ServiceItem
class ListPreviewWidget(QtWidgets.QTableWidget, RegistryProperties):
@ -152,14 +152,16 @@ class ListPreviewWidget(QtWidgets.QTableWidget, RegistryProperties):
else:
label.setScaledContents(True)
if self.service_item.is_command():
pixmap = QtGui.QPixmap(frame['image'])
pixmap.setDevicePixelRatio(label.devicePixelRatio())
label.setPixmap(pixmap)
if self.service_item.is_capable(ItemCapabilities.HasThumbnails):
image = self.image_manager.get_image(frame['image'], ImageSource.CommandPlugins)
pixmap = QtGui.QPixmap.fromImage(image)
else:
pixmap = QtGui.QPixmap(frame['image'])
else:
image = self.image_manager.get_image(frame['path'], ImageSource.ImagePlugin)
pixmap = QtGui.QPixmap.fromImage(image)
pixmap.setDevicePixelRatio(label.devicePixelRatio())
label.setPixmap(pixmap)
pixmap.setDevicePixelRatio(label.devicePixelRatio())
label.setPixmap(pixmap)
slide_height = width // self.screen_ratio
# Setup and validate row height cap if in use.
max_img_row_height = Settings().value('advanced/slide max height')

View File

@ -471,7 +471,8 @@ class Ui_MainWindow(object):
self.web_site_item.setText(translate('OpenLP.MainWindow', '&Web Site'))
for item in self.language_group.actions():
item.setText(item.objectName())
item.setStatusTip(translate('OpenLP.MainWindow', 'Set the interface language to %s') % item.objectName())
item.setStatusTip(translate('OpenLP.MainWindow',
'Set the interface language to {name}').format(name=item.objectName()))
self.auto_language_item.setText(translate('OpenLP.MainWindow', '&Autodetect'))
self.auto_language_item.setStatusTip(translate('OpenLP.MainWindow', 'Use the system language, if available.'))
self.tools_add_tool_item.setText(translate('OpenLP.MainWindow', 'Add &Tool...'))
@ -1334,8 +1335,10 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow, RegistryProperties):
for file_id, filename in enumerate(recent_files_to_display):
log.debug('Recent file name: {name}'.format(name=filename))
# TODO: Verify ''.format() before committing
action = create_action(self, '', text='&%d %s' % (file_id + 1,
os.path.splitext(os.path.basename(str(filename)))[0]), data=filename,
action = create_action(self, '',
text='&{n} {name}'.format(n=file_id + 1,
name=os.path.splitext(os.path.basename(str(filename)))[0]),
data=filename,
triggers=self.service_manager_contents.on_recent_service_clicked)
self.recent_files_menu.addAction(action)
clear_recent_files_action = create_action(self, '',

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.about_label.setText('{about}:'.format(about=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):
"""
@ -60,6 +60,7 @@ class PluginForm(QtWidgets.QDialog, Ui_PluginViewDialog, RegistryProperties):
self._clear_details()
self.programatic_change = True
plugin_list_width = 0
# TODO: See how to use format() with variables
for plugin in self.plugin_manager.plugins:
item = QtWidgets.QListWidgetItem(self.plugin_list_widget)
# We do this just to make 100% sure the status is an integer as
@ -86,24 +87,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)
log.debug('PluginStatus: {status}'.format(status=str(self.active_plugin.status)))
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,28 +116,28 @@ 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()
self.active_plugin.app_startup()
else:
self.active_plugin.toggle_status(PluginStatus.Inactive)
# TODO: Verify using format() with a variable
status_text = translate('OpenLP.PluginForm', '%s (Inactive)')
if self.active_plugin.status == PluginStatus.Active:
status_text = translate('OpenLP.PluginForm', '%s (Active)')

View File

@ -118,7 +118,7 @@ class Ui_ServiceManager(object):
tooltip=translate('OpenLP.ServiceManager', 'Save this service.'),
triggers=self.decide_save_method)
self.toolbar.addSeparator()
self.theme_label = QtWidgets.QLabel('%s:' % UiStrings().Theme, widget)
self.theme_label = QtWidgets.QLabel('{theme}:'.format(theme=UiStrings().Theme), widget)
self.theme_label.setContentsMargins(3, 3, 3, 3)
self.theme_label.setObjectName('theme_label')
self.toolbar.add_toolbar_widget(self.theme_label)
@ -503,8 +503,8 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa
path_file_name = str(self.file_name())
path, file_name = os.path.split(path_file_name)
base_name = os.path.splitext(file_name)[0]
service_file_name = '%s.osj' % base_name
self.log_debug('ServiceManager.save_file - %s' % path_file_name)
service_file_name = '{name}.osj'.format(name=base_name)
self.log_debug('ServiceManager.save_file - {name}'.format(name=path_file_name))
Settings().setValue(self.main_window.service_manager_settings_section + '/last directory', path)
service = self.create_basic_service()
write_list = []
@ -530,8 +530,9 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa
self.application.set_normal_cursor()
title = translate('OpenLP.ServiceManager', 'Service File(s) Missing')
message = translate('OpenLP.ServiceManager',
'The following file(s) in the service are missing: %s\n\n'
'These files will be removed if you continue to save.') % "\n\t".join(missing_list)
'The following file(s) in the service are missing: {name}\n\n'
'These files will be removed if you continue to save.'
).format(name="\n\t".join(missing_list))
answer = QtWidgets.QMessageBox.critical(self, title, message,
QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Ok |
QtWidgets.QMessageBox.Cancel))
@ -561,7 +562,7 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa
service_content = json.dumps(service)
# Usual Zip file cannot exceed 2GiB, file with Zip64 cannot be extracted using unzip in UNIX.
allow_zip_64 = (total_size > 2147483648 + len(service_content))
self.log_debug('ServiceManager.save_file - allowZip64 is %s' % allow_zip_64)
self.log_debug('ServiceManager.save_file - allowZip64 is {text}'.format(text=allow_zip_64))
zip_file = None
success = True
self.main_window.increment_progress_bar()
@ -584,7 +585,7 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa
shutil.copy(audio_from, save_file)
zip_file.write(audio_from, audio_to)
except IOError:
self.log_exception('Failed to save service to disk: %s' % temp_file_name)
self.log_exception('Failed to save service to disk: {name}'.format(name=temp_file_name))
self.main_window.error_message(translate('OpenLP.ServiceManager', 'Error Saving File'),
translate('OpenLP.ServiceManager', 'There was an error saving your file.'))
success = False
@ -601,7 +602,7 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa
except OSError as ose:
QtWidgets.QMessageBox.critical(self, translate('OpenLP.ServiceManager', 'Error Saving File'),
translate('OpenLP.ServiceManager', 'An error occurred while writing the '
'service file: %s') % ose.strerror,
'service file: {error}').format(error=ose.strerror),
QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Ok))
success = False
self.main_window.add_recent_file(path_file_name)
@ -623,8 +624,8 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa
path_file_name = str(self.file_name())
path, file_name = os.path.split(path_file_name)
base_name = os.path.splitext(file_name)[0]
service_file_name = '%s.osj' % base_name
self.log_debug('ServiceManager.save_file - %s' % path_file_name)
service_file_name = '{name}.osj'.format(name=base_name)
self.log_debug('ServiceManager.save_file - {name}'.format(name=path_file_name))
Settings().setValue(self.main_window.service_manager_settings_section + '/last directory', path)
service = self.create_basic_service()
self.application.set_busy_cursor()
@ -645,7 +646,7 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa
# First we add service contents.
zip_file.writestr(service_file_name, service_content)
except IOError:
self.log_exception('Failed to save service to disk: %s', temp_file_name)
self.log_exception('Failed to save service to disk: {name}'.format(name=temp_file_name))
self.main_window.error_message(translate('OpenLP.ServiceManager', 'Error Saving File'),
translate('OpenLP.ServiceManager', 'There was an error saving your file.'))
success = False
@ -740,13 +741,13 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa
try:
ucs_file = zip_info.filename
except UnicodeDecodeError:
self.log_exception('file_name "%s" is not valid UTF-8' % zip_info.file_name)
self.log_exception('file_name "{name}" is not valid UTF-8'.format(name=zip_info.file_name))
critical_error_message_box(message=translate('OpenLP.ServiceManager',
'File is not a valid service.\n The content encoding is not UTF-8.'))
continue
os_file = ucs_file.replace('/', os.path.sep)
os_file = os.path.basename(os_file)
self.log_debug('Extract file: %s' % os_file)
self.log_debug('Extract file: {name}'.format(name=os_file))
zip_info.filename = os_file
zip_file.extract(zip_info, self.service_path)
if os_file.endswith('osj') or os_file.endswith('osd'):
@ -774,18 +775,18 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa
critical_error_message_box(message=translate('OpenLP.ServiceManager', 'File is not a valid service.'))
self.log_error('File contains no service data')
except (IOError, NameError, zipfile.BadZipfile):
self.log_exception('Problem loading service file %s' % file_name)
self.log_exception('Problem loading service file {name}'.format(name=file_name))
critical_error_message_box(message=translate('OpenLP.ServiceManager',
'File could not be opened because it is corrupt.'))
except zipfile.BadZipfile:
if os.path.getsize(file_name) == 0:
self.log_exception('Service file is zero sized: %s' % file_name)
self.log_exception('Service file is zero sized: {name}'.format(name=file_name))
QtWidgets.QMessageBox.information(self, translate('OpenLP.ServiceManager', 'Empty File'),
translate('OpenLP.ServiceManager',
'This service file does not contain '
'any data.'))
else:
self.log_exception('Service file is cannot be extracted as zip: %s' % file_name)
self.log_exception('Service file is cannot be extracted as zip: {name}'.format(name=file_name))
QtWidgets.QMessageBox.information(self, translate('OpenLP.ServiceManager', 'Corrupt File'),
translate('OpenLP.ServiceManager',
'This file is either corrupt or it is not an OpenLP 2 '
@ -874,7 +875,7 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa
self.auto_play_slides_loop.setChecked(service_item['service_item'].auto_play_slides_loop)
self.timed_slide_interval.setChecked(service_item['service_item'].timed_slide_interval > 0)
if service_item['service_item'].timed_slide_interval > 0:
delay_suffix = ' %s s' % str(service_item['service_item'].timed_slide_interval)
delay_suffix = ' {text} s'.format(text=str(service_item['service_item'].timed_slide_interval))
else:
delay_suffix = ' ...'
self.timed_slide_interval.setText(
@ -1268,14 +1269,17 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa
tree_widget_item.setText(0, service_item_from_item.get_display_title())
tips = []
if service_item_from_item.temporary_edit:
tips.append('<strong>%s:</strong> <em>%s</em>' % (translate('OpenLP.ServiceManager', 'Edit'),
(translate('OpenLP.ServiceManager', 'Service copy only'))))
text1 = translate('OpenLP.ServiceManager', 'Edit')
text2 = translate('OpenLP.ServiceManager', 'Service copy only')
tips.append('<strong>{text1}:</strong> <em>{text2}</em>'.format(text1=text1, text2=text2))
if service_item_from_item.theme and service_item_from_item.theme != -1:
tips.append('<strong>%s:</strong> <em>%s</em>' %
(translate('OpenLP.ServiceManager', 'Slide theme'), service_item_from_item.theme))
text = translate('OpenLP.ServiceManager', 'Slide theme')
tips.append('<strong>{text1}:</strong> <em>{text2}</em>'.format(text1=text,
text2=service_item_from_item.theme))
if service_item_from_item.notes:
tips.append('<strong>%s: </strong> %s' %
(translate('OpenLP.ServiceManager', 'Notes'), html.escape(service_item_from_item.notes)))
text1 = translate('OpenLP.ServiceManager', 'Notes')
text2 = html.escape(service_item_from_item.notes)
tips.append('<strong>{text1}: </strong> {text2}'.format(text1=text1, text2=text2))
if item['service_item'].is_capable(ItemCapabilities.HasVariableStartTime):
tips.append(item['service_item'].get_media_time())
tree_widget_item.setToolTip(0, '<br>'.join(tips))
@ -1324,8 +1328,9 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa
The theme may have changed in the settings dialog so make sure the theme combo box is in the correct state.
"""
visible = not self.renderer.theme_level == ThemeLevel.Global
self.theme_label.setVisible(visible)
self.theme_combo_box.setVisible(visible)
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):
"""
@ -1636,7 +1641,7 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa
replace = True
else:
self.drop_position = get_parent_item_data(item) - 1
Registry().execute('%s_add_service_item' % plugin, replace)
Registry().execute('{plugin}_add_service_item'.format(plugin=plugin), replace)
def update_theme_list(self, theme_list):
"""

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):
@ -83,7 +85,7 @@ class SettingsForm(QtWidgets.QDialog, Ui_SettingsDialog, RegistryProperties):
:param tab_widget: The widget to add
:param is_visible: If this tab should be visible
"""
log.debug('Inserting %s tab' % tab_widget.tab_title)
log.debug('Inserting {text} tab'.format(text=tab_widget.tab_title))
# add the tab to get it to display in the correct part of the screen
self.stacked_layout.addWidget(tab_widget)
if is_visible:
@ -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

@ -425,11 +425,12 @@ class ShortcutListForm(QtWidgets.QDialog, Ui_ShortcutListDialog, RegistryPropert
if changing_action.shortcutContext() in [QtCore.Qt.WindowShortcut, QtCore.Qt.ApplicationShortcut]:
is_valid = False
if not is_valid:
text = translate('OpenLP.ShortcutListDialog',
'The shortcut "{key}" is already assigned to another action, please'
' use a different shortcut.'
).format(key=self.get_shortcut_string(key_sequence))
self.main_window.warning_message(translate('OpenLP.ShortcutListDialog', 'Duplicate Shortcut'),
translate('OpenLP.ShortcutListDialog',
'The shortcut "%s" is already assigned to another action, please'
' use a different shortcut.') %
self.get_shortcut_string(key_sequence, for_display=True))
text, for_display=True)
self.dialog_was_shown = True
return is_valid

View File

@ -98,7 +98,7 @@ class DisplayController(QtWidgets.QWidget):
"""
sender = self.sender().objectName() if self.sender().objectName() else self.sender().text()
controller = self
Registry().execute('%s' % sender, [controller, args])
Registry().execute('{text}'.format(text=sender), [controller, args])
class InfoLabel(QtWidgets.QLabel):
@ -395,7 +395,7 @@ class SlideController(DisplayController, RegistryProperties):
{'key': 'O', 'configurable': True, 'text': translate('OpenLP.SlideController', 'Go to "Other"')}
]
shortcuts.extend([{'key': str(number)} for number in range(10)])
self.controller.addActions([create_action(self, 'shortcutAction_%s' % s['key'],
self.controller.addActions([create_action(self, 'shortcutAction_{key}'.format(key=s['key']),
text=s.get('text'),
can_shortcuts=True,
context=QtCore.Qt.WidgetWithChildrenShortcut,
@ -417,14 +417,20 @@ class SlideController(DisplayController, RegistryProperties):
self.preview_widget.doubleClicked.connect(self.on_preview_double_click)
self.toolbar.set_widget_visible(['editSong'], False)
self.controller.addActions([self.next_item, self.previous_item])
Registry().register_function('slidecontroller_%s_stop_loop' % self.type_prefix, self.on_stop_loop)
Registry().register_function('slidecontroller_%s_change' % self.type_prefix, self.on_slide_change)
Registry().register_function('slidecontroller_%s_blank' % self.type_prefix, self.on_slide_blank)
Registry().register_function('slidecontroller_%s_unblank' % self.type_prefix, self.on_slide_unblank)
Registry().register_function('slidecontroller_{text}_stop_loop'.format(text=self.type_prefix),
self.on_stop_loop)
Registry().register_function('slidecontroller_{text}_change'.format(text=self.type_prefix),
self.on_slide_change)
Registry().register_function('slidecontroller_{text}_blank'.format(text=self.type_prefix),
self.on_slide_blank)
Registry().register_function('slidecontroller_{text}_unblank'.format(text=self.type_prefix),
self.on_slide_unblank)
Registry().register_function('slidecontroller_update_slide_limits', self.update_slide_limits)
getattr(self, 'slidecontroller_%s_set' % self.type_prefix).connect(self.on_slide_selected_index)
getattr(self, 'slidecontroller_%s_next' % self.type_prefix).connect(self.on_slide_selected_next)
getattr(self, 'slidecontroller_%s_previous' % self.type_prefix).connect(self.on_slide_selected_previous)
getattr(self, 'slidecontroller_{text}_set'.format(text=self.type_prefix)).connect(self.on_slide_selected_index)
getattr(self, 'slidecontroller_{text}_next'.format(text=self.type_prefix)).connect(self.on_slide_selected_next)
# NOTE: {t} used to keep line length < maxline
getattr(self,
'slidecontroller_{t}_previous'.format(t=self.type_prefix)).connect(self.on_slide_selected_previous)
def _slide_shortcut_activated(self):
"""
@ -841,7 +847,8 @@ class SlideController(DisplayController, RegistryProperties):
self.service_item = copy.copy(service_item)
if self.service_item.is_command():
Registry().execute(
'%s_start' % service_item.name.lower(), [self.service_item, self.is_live, self.hide_mode(), slide_no])
'{text}_start'.format(text=service_item.name.lower()),
[self.service_item, self.is_live, self.hide_mode(), slide_no])
# Reset blanking if needed
if old_item and self.is_live and (old_item.is_capable(ItemCapabilities.ProvidesOwnDisplay) or
self.service_item.is_capable(ItemCapabilities.ProvidesOwnDisplay)):
@ -879,8 +886,8 @@ class SlideController(DisplayController, RegistryProperties):
if frame['verseTag']:
# These tags are already translated.
verse_def = frame['verseTag']
verse_def = '%s%s' % (verse_def[0], verse_def[1:])
two_line_def = '%s\n%s' % (verse_def[0], verse_def[1:])
verse_def = '{def1}{def2}'.format(def1=verse_def[0], def2=verse_def[1:])
two_line_def = '{def1}\n{def2}'.format(def1=verse_def[0], def2=verse_def[1:])
row = two_line_def
if verse_def not in self.slide_list:
self.slide_list[verse_def] = frame_number
@ -915,10 +922,10 @@ class SlideController(DisplayController, RegistryProperties):
# close the previous, so make sure we don't close the new one.
if old_item.is_command() and not self.service_item.is_command() or \
old_item.is_command() and not old_item.is_media() and self.service_item.is_media():
Registry().execute('%s_stop' % old_item.name.lower(), [old_item, self.is_live])
Registry().execute('{name}_stop'.format(name=old_item.name.lower()), [old_item, self.is_live])
if old_item.is_media() and not self.service_item.is_media():
self.on_media_close()
Registry().execute('slidecontroller_%s_started' % self.type_prefix, [self.service_item])
Registry().execute('slidecontroller_{item}_started'.format(item=self.type_prefix), [self.service_item])
def on_slide_selected_index(self, message):
"""
@ -930,7 +937,8 @@ class SlideController(DisplayController, RegistryProperties):
if not self.service_item:
return
if self.service_item.is_command():
Registry().execute('%s_slide' % self.service_item.name.lower(), [self.service_item, self.is_live, index])
Registry().execute('{name}_slide'.format(name=self.service_item.name.lower()),
[self.service_item, self.is_live, index])
self.update_preview()
self.selected_row = index
else:
@ -975,7 +983,7 @@ class SlideController(DisplayController, RegistryProperties):
"""
if checked is None:
checked = self.blank_screen.isChecked()
self.log_debug('on_blank_display %s' % checked)
self.log_debug('on_blank_display {text}'.format(text=checked))
self.hide_menu.setDefaultAction(self.blank_screen)
self.blank_screen.setChecked(checked)
self.theme_screen.setChecked(False)
@ -996,7 +1004,7 @@ class SlideController(DisplayController, RegistryProperties):
"""
if checked is None:
checked = self.theme_screen.isChecked()
self.log_debug('on_theme_display %s' % checked)
self.log_debug('on_theme_display {text}'.format(text=checked))
self.hide_menu.setDefaultAction(self.theme_screen)
self.blank_screen.setChecked(False)
self.theme_screen.setChecked(checked)
@ -1017,7 +1025,7 @@ class SlideController(DisplayController, RegistryProperties):
"""
if checked is None:
checked = self.desktop_screen.isChecked()
self.log_debug('on_hide_display %s' % checked)
self.log_debug('on_hide_display {text}'.format(text=checked))
self.hide_menu.setDefaultAction(self.desktop_screen)
self.blank_screen.setChecked(False)
self.theme_screen.setChecked(False)
@ -1035,17 +1043,18 @@ class SlideController(DisplayController, RegistryProperties):
Blank/Hide the display screen within a plugin if required.
"""
hide_mode = self.hide_mode()
self.log_debug('blank_plugin %s ' % hide_mode)
self.log_debug('blank_plugin {text}'.format(text=hide_mode))
if self.service_item is not None:
if hide_mode:
if not self.service_item.is_command():
Registry().execute('live_display_hide', hide_mode)
Registry().execute('%s_blank' %
self.service_item.name.lower(), [self.service_item, self.is_live, hide_mode])
Registry().execute('{text}_blank'.format(text=self.service_item.name.lower()),
[self.service_item, self.is_live, hide_mode])
else:
if not self.service_item.is_command():
Registry().execute('live_display_show')
Registry().execute('%s_unblank' % self.service_item.name.lower(), [self.service_item, self.is_live])
Registry().execute('{text}_unblank'.format(text=self.service_item.name.lower()),
[self.service_item, self.is_live])
else:
if hide_mode:
Registry().execute('live_display_hide', hide_mode)
@ -1056,15 +1065,17 @@ class SlideController(DisplayController, RegistryProperties):
"""
Tell the plugin to hide the display screen.
"""
self.log_debug('hide_plugin %s ' % hide)
self.log_debug('hide_plugin {text}'.format(text=hide))
if self.service_item is not None:
if hide:
Registry().execute('live_display_hide', HideMode.Screen)
Registry().execute('%s_hide' % self.service_item.name.lower(), [self.service_item, self.is_live])
Registry().execute('{text}_hide'.format(text=self.service_item.name.lower()),
[self.service_item, self.is_live])
else:
if not self.service_item.is_command():
Registry().execute('live_display_show')
Registry().execute('%s_unblank' % self.service_item.name.lower(), [self.service_item, self.is_live])
Registry().execute('{text}_unblank'.format(text=self.service_item.name.lower()),
[self.service_item, self.is_live])
else:
if hide:
Registry().execute('live_display_hide', HideMode.Screen)
@ -1099,8 +1110,8 @@ class SlideController(DisplayController, RegistryProperties):
if -1 < row < self.preview_widget.slide_count():
if self.service_item.is_command():
if self.is_live and not start:
Registry().execute('%s_slide' %
self.service_item.name.lower(), [self.service_item, self.is_live, row])
Registry().execute('{text}_slide'.format(text=self.service_item.name.lower()),
[self.service_item, self.is_live, row])
else:
to_display = self.service_item.get_rendered_frame(row)
if self.service_item.is_text():
@ -1133,11 +1144,23 @@ class SlideController(DisplayController, RegistryProperties):
"""
This updates the preview frame, for example after changing a slide or using *Blank to Theme*.
"""
self.log_debug('update_preview %s ' % self.screens.current['primary'])
self.log_debug('update_preview {text} '.format(text=self.screens.current['primary']))
if self.service_item and self.service_item.is_capable(ItemCapabilities.ProvidesOwnDisplay):
# Grab now, but try again in a couple of seconds if slide change is slow
QtCore.QTimer.singleShot(500, self.grab_maindisplay)
QtCore.QTimer.singleShot(2500, self.grab_maindisplay)
if self.is_live:
# If live, grab screen-cap of main display now
QtCore.QTimer.singleShot(500, self.grab_maindisplay)
# but take another in a couple of seconds in case slide change is slow
QtCore.QTimer.singleShot(2500, self.grab_maindisplay)
else:
# If not live, use the slide's thumbnail/icon instead
image_path = self.service_item.get_rendered_frame(self.selected_row)
if self.service_item.is_capable(ItemCapabilities.HasThumbnails):
image = self.image_manager.get_image(image_path, ImageSource.CommandPlugins)
self.slide_image = QtGui.QPixmap.fromImage(image)
else:
self.slide_image = QtGui.QPixmap(image_path)
self.slide_image.setDevicePixelRatio(self.main_window.devicePixelRatio())
self.slide_preview.setPixmap(self.slide_image)
else:
self.slide_image = self.display.preview()
self.slide_image.setDevicePixelRatio(self.main_window.devicePixelRatio())
@ -1173,7 +1196,8 @@ class SlideController(DisplayController, RegistryProperties):
if not self.service_item:
return
if self.service_item.is_command():
Registry().execute('%s_next' % self.service_item.name.lower(), [self.service_item, self.is_live])
Registry().execute('{text}_next'.format(text=self.service_item.name.lower()),
[self.service_item, self.is_live])
if self.is_live:
self.update_preview()
else:
@ -1201,7 +1225,8 @@ class SlideController(DisplayController, RegistryProperties):
if not self.service_item:
return
if self.service_item.is_command():
Registry().execute('%s_previous' % self.service_item.name.lower(), [self.service_item, self.is_live])
Registry().execute('{text}_previous'.format(text=self.service_item.name.lower()),
[self.service_item, self.is_live])
if self.is_live:
self.update_preview()
else:
@ -1253,7 +1278,7 @@ class SlideController(DisplayController, RegistryProperties):
checked = self.play_slides_loop.isChecked()
else:
self.play_slides_loop.setChecked(checked)
self.log_debug('on_play_slides_loop %s' % checked)
self.log_debug('on_play_slides_loop {text}'.format(text=checked))
if checked:
self.play_slides_loop.setIcon(build_icon(':/media/media_stop.png'))
self.play_slides_loop.setText(UiStrings().StopPlaySlidesInLoop)
@ -1276,7 +1301,7 @@ class SlideController(DisplayController, RegistryProperties):
checked = self.play_slides_once.isChecked()
else:
self.play_slides_once.setChecked(checked)
self.log_debug('on_play_slides_once %s' % checked)
self.log_debug('on_play_slides_once {text}'.format(text=checked))
if checked:
self.play_slides_once.setIcon(build_icon(':/media/media_stop.png'))
self.play_slides_once.setText(UiStrings().StopPlaySlidesToEnd)
@ -1342,7 +1367,8 @@ class SlideController(DisplayController, RegistryProperties):
# Live and Preview have issues if we have video or presentations
# playing in both at the same time.
if self.service_item.is_command():
Registry().execute('%s_stop' % self.service_item.name.lower(), [self.service_item, self.is_live])
Registry().execute('{text}_stop'.format(text=self.service_item.name.lower()),
[self.service_item, self.is_live])
if self.service_item.is_media():
self.on_media_close()
self.on_go_live()

View File

@ -56,9 +56,9 @@ class StartTimeForm(QtWidgets.QDialog, Ui_StartTimeDialog, RegistryProperties):
self.hour_finish_spin_box.setValue(hours)
self.minute_finish_spin_box.setValue(minutes)
self.second_finish_spin_box.setValue(seconds)
self.hour_finish_label.setText('%s%s' % (str(hour), UiStrings().Hours))
self.minute_finish_label.setText('%s%s' % (str(minutes), UiStrings().Minutes))
self.second_finish_label.setText('%s%s' % (str(seconds), UiStrings().Seconds))
self.hour_finish_label.setText('{val:d}{text}'.format(val=hour, text=UiStrings().Hours))
self.minute_finish_label.setText('{val:d}{text}'.format(val=minutes, text=UiStrings().Minutes))
self.second_finish_label.setText('{val:d}{text}'.format(val=seconds, text=UiStrings().Seconds))
return QtWidgets.QDialog.exec(self)
def accept(self):

View File

@ -263,7 +263,7 @@ class ThemeForm(QtWidgets.QWizard, Ui_ThemeWizard, RegistryProperties):
"""
Run the wizard.
"""
log.debug('Editing theme %s' % self.theme.theme_name)
log.debug('Editing theme {name}'.format(name=self.theme.theme_name))
self.temp_background_filename = ''
self.update_theme_allowed = False
self.set_defaults()
@ -272,7 +272,8 @@ class ThemeForm(QtWidgets.QWizard, Ui_ThemeWizard, RegistryProperties):
self.theme_name_edit.setVisible(not edit)
self.edit_mode = edit
if edit:
self.setWindowTitle(translate('OpenLP.ThemeWizard', 'Edit Theme - %s') % self.theme.theme_name)
self.setWindowTitle(translate('OpenLP.ThemeWizard', 'Edit Theme - {name}'
).format(name=self.theme.theme_name))
self.next()
else:
self.setWindowTitle(UiStrings().NewTheme)
@ -282,7 +283,7 @@ class ThemeForm(QtWidgets.QWizard, Ui_ThemeWizard, RegistryProperties):
"""
Set up the pages for Initial run through dialog
"""
log.debug('initializePage %s' % page_id)
log.debug('initializePage {page}'.format(page=page_id))
wizard_page = self.page(page_id)
if wizard_page == self.background_page:
self.set_background_page_values()
@ -445,7 +446,7 @@ class ThemeForm(QtWidgets.QWizard, Ui_ThemeWizard, RegistryProperties):
Background Image button pushed.
"""
images_filter = get_images_filter()
images_filter = '%s;;%s (*.*)' % (images_filter, UiStrings().AllFiles)
images_filter = '{name};;{text} (*.*)'.format(name=images_filter, text=UiStrings().AllFiles)
filename, filter_used = QtWidgets.QFileDialog.getOpenFileName(
self, translate('OpenLP.ThemeWizard', 'Select Image'),
self.image_file_edit.text(), images_filter)
@ -463,6 +464,7 @@ class ThemeForm(QtWidgets.QWizard, Ui_ThemeWizard, RegistryProperties):
"""
Background video button pushed.
"""
# TODO: Check this before converting
visible_formats = '(%s)' % '; '.join(VIDEO_EXT)
actual_formats = '(%s)' % ' '.join(VIDEO_EXT)
video_filter = '{trans} {visible} {actual}'.format(trans=translate('OpenLP', 'Video Files'),

View File

@ -203,7 +203,7 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage
Change the global theme when it is changed through the Themes settings tab
"""
self.global_theme = Settings().value(self.settings_section + '/global theme')
self.log_debug('change_global_from_tab %s' % self.global_theme)
self.log_debug('change_global_from_tab {text}'.format(text=self.global_theme))
for count in range(0, self.theme_list_widget.count()):
# reset the old name
item = self.theme_list_widget.item(count)
@ -213,7 +213,7 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage
self.theme_list_widget.item(count).setText(new_name)
# Set the new name
if self.global_theme == new_name:
name = translate('OpenLP.ThemeManager', '%s (default)') % new_name
name = translate('OpenLP.ThemeManager', '{text} (default)').format(text=new_name)
self.theme_list_widget.item(count).setText(name)
self.delete_toolbar_action.setVisible(item not in self.theme_list_widget.selectedItems())
@ -233,7 +233,7 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage
# Set the new name
if count == selected_row:
self.global_theme = self.theme_list_widget.item(count).text()
name = translate('OpenLP.ThemeManager', '%s (default)') % self.global_theme
name = translate('OpenLP.ThemeManager', '{text} (default)').format(text=self.global_theme)
self.theme_list_widget.item(count).setText(name)
Settings().setValue(self.settings_section + '/global theme', self.global_theme)
Registry().execute('theme_update_global')
@ -256,6 +256,7 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage
Renames an existing theme to a new name
:param field:
"""
# TODO: Check for delayed format() conversions
if self._validate_theme_action(translate('OpenLP.ThemeManager', 'You must select a theme to rename.'),
translate('OpenLP.ThemeManager', 'Rename Confirmation'),
translate('OpenLP.ThemeManager', 'Rename %s theme?'), False, False):
@ -284,7 +285,8 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage
item = self.theme_list_widget.currentItem()
old_theme_name = item.data(QtCore.Qt.UserRole)
self.file_rename_form.file_name_edit.setText(translate('OpenLP.ThemeManager',
'Copy of %s', 'Copy of <theme name>') % old_theme_name)
'Copy of {name}',
'Copy of <theme name>').format(name=old_theme_name))
if self.file_rename_form.exec(True):
new_theme_name = self.file_rename_form.file_name_edit.text()
if self.check_if_theme_exists(new_theme_name):
@ -331,6 +333,7 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage
Delete a theme triggered by the UI.
:param field:
"""
# TODO: Verify delayed format() conversions
if self._validate_theme_action(translate('OpenLP.ThemeManager', 'You must select a theme to delete.'),
translate('OpenLP.ThemeManager', 'Delete Confirmation'),
translate('OpenLP.ThemeManager', 'Delete %s theme?')):
@ -351,7 +354,7 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage
:param theme: The theme to delete.
"""
self.theme_list.remove(theme)
thumb = '%s.png' % theme
thumb = '{name}.png'.format(name=theme)
delete_file(os.path.join(self.path, thumb))
delete_file(os.path.join(self.thumb_path, thumb))
try:
@ -363,7 +366,7 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage
shutil.rmtree(os.path.join(self.path, theme).encode(encoding))
except OSError as os_error:
shutil.Error = os_error
self.log_exception('Error deleting theme %s' % theme)
self.log_exception('Error deleting theme {name}'.format(name=theme))
def on_export_theme(self, field=None):
"""
@ -376,7 +379,8 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage
return
theme = item.data(QtCore.Qt.UserRole)
path = QtWidgets.QFileDialog.getExistingDirectory(self,
translate('OpenLP.ThemeManager', 'Save Theme - (%s)') % theme,
translate('OpenLP.ThemeManager',
'Save Theme - ({name})').format(name=theme),
Settings().value(self.settings_section +
'/last directory export'))
self.application.set_busy_cursor()
@ -409,7 +413,7 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage
self.log_exception('Export Theme Failed')
critical_error_message_box(translate('OpenLP.ThemeManager', 'Theme Export Failed'),
translate('OpenLP.ThemeManager', 'The theme export failed because this error '
'occurred: %s') % ose.strerror)
'occurred: {err}').format(err=ose.strerror))
if theme_zip:
theme_zip.close()
shutil.rmtree(theme_path, True)
@ -425,7 +429,7 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage
translate('OpenLP.ThemeManager', 'Select Theme Import File'),
Settings().value(self.settings_section + '/last directory import'),
translate('OpenLP.ThemeManager', 'OpenLP Themes (*.otz)'))
self.log_info('New Themes %s' % str(files))
self.log_info('New Themes {name}'.format(name=str(files)))
if not files:
return
self.application.set_busy_cursor()
@ -472,10 +476,10 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage
if os.path.exists(theme):
text_name = os.path.splitext(name)[0]
if text_name == self.global_theme:
name = translate('OpenLP.ThemeManager', '%s (default)') % text_name
name = translate('OpenLP.ThemeManager', '{name} (default)').format(name=text_name)
else:
name = text_name
thumb = os.path.join(self.thumb_path, '%s.png' % text_name)
thumb = os.path.join(self.thumb_path, '{name}.png'.format(name=text_name))
item_name = QtWidgets.QListWidgetItem(name)
if validate_thumb(theme, thumb):
icon = build_icon(thumb)
@ -506,7 +510,7 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage
:param theme_name: Name of the theme to load from file
:return: The theme object.
"""
self.log_debug('get theme data for theme %s' % theme_name)
self.log_debug('get theme data for theme {name}'.format(name=theme_name))
xml_file = os.path.join(self.path, str(theme_name), str(theme_name) + '.xml')
xml = get_text_file_string(xml_file)
if not xml:
@ -524,8 +528,8 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage
"""
ret = QtWidgets.QMessageBox.question(self, translate('OpenLP.ThemeManager', 'Theme Already Exists'),
translate('OpenLP.ThemeManager',
'Theme %s already exists. Do you want to replace it?')
.replace('%s', theme_name),
'Theme {name} already exists. '
'Do you want to replace it?').format(name=theme_name),
QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes |
QtWidgets.QMessageBox.No),
QtWidgets.QMessageBox.No)
@ -538,7 +542,7 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage
:param file_name:
:param directory:
"""
self.log_debug('Unzipping theme %s' % file_name)
self.log_debug('Unzipping theme {name}'.format(name=file_name))
theme_zip = None
out_file = None
file_xml = None
@ -547,7 +551,7 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage
theme_zip = zipfile.ZipFile(file_name)
xml_file = [name for name in theme_zip.namelist() if os.path.splitext(name)[1].lower() == '.xml']
if len(xml_file) != 1:
self.log_error('Theme contains "%s" XML files' % len(xml_file))
self.log_error('Theme contains "{val:d}" XML files'.format(val=len(xml_file)))
raise ValidationError
xml_tree = ElementTree(element=XML(theme_zip.read(xml_file[0]))).getroot()
theme_version = xml_tree.get('version', default=None)
@ -579,7 +583,7 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage
out_file.write(theme_zip.read(name))
out_file.close()
except (IOError, zipfile.BadZipfile):
self.log_exception('Importing theme from zip failed %s' % file_name)
self.log_exception('Importing theme from zip failed {name|'.format(name=file_name))
raise ValidationError
except ValidationError:
critical_error_message_box(translate('OpenLP.ThemeManager', 'Validation Error'),
@ -601,7 +605,7 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage
critical_error_message_box(
translate('OpenLP.ThemeManager', 'Validation Error'),
translate('OpenLP.ThemeManager', 'File is not a valid theme.'))
self.log_error('Theme file does not contain XML data %s' % file_name)
self.log_error('Theme file does not contain XML data {name}'.format(name=file_name))
def check_if_theme_exists(self, theme_name):
"""
@ -682,7 +686,7 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage
if os.path.exists(sample_path_name):
os.unlink(sample_path_name)
frame.save(sample_path_name, 'png')
thumb = os.path.join(self.thumb_path, '%s.png' % name)
thumb = os.path.join(self.thumb_path, '{name}.png'.format(name=name))
create_thumb(sample_path_name, thumb, False)
def update_preview_images(self):
@ -760,14 +764,17 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage
for plugin in self.plugin_manager.plugins:
used_count = plugin.uses_theme(theme)
if used_count:
plugin_usage = "%s%s" % (plugin_usage, (translate('OpenLP.ThemeManager',
'%(count)s time(s) by %(plugin)s') %
{'count': used_count, 'plugin': plugin.name}))
plugin_usage = "{plug}{text}".format(plug=plugin_usage,
text=(translate('OpenLP.ThemeManager',
'{count} time(s) by {plugin}'
).format(name=used_count,
plugin=plugin.name)))
plugin_usage = "%s\n" % plugin_usage
if plugin_usage:
critical_error_message_box(translate('OpenLP.ThemeManager', 'Unable to delete theme'),
translate('OpenLP.ThemeManager', 'Theme is currently used \n\n%s') %
plugin_usage)
translate('OpenLP.ThemeManager',
'Theme is currently used \n\n{text}'
).format(text=plugin_usage))
return False
return True

View File

@ -405,8 +405,8 @@ class Ui_ThemeWizard(object):
Translate the UI on the fly
"""
theme_wizard.setWindowTitle(translate('OpenLP.ThemeWizard', 'Theme Wizard'))
self.title_label.setText('<span style="font-size:14pt; font-weight:600;">%s</span>' %
translate('OpenLP.ThemeWizard', 'Welcome to the Theme Wizard'))
text = translate('OpenLP.ThemeWizard', 'Welcome to the Theme Wizard')
self.title_label.setText('<span style="font-size:14pt; font-weight:600;">{text}</span>'.format(text=text))
self.information_label.setText(
translate('OpenLP.ThemeWizard', 'This wizard will help you to create and edit your themes. Click the next '
'button below to start the process by setting up your background.'))
@ -435,9 +435,9 @@ class Ui_ThemeWizard(object):
self.gradient_combo_box.setItemText(BackgroundGradientType.LeftBottom,
translate('OpenLP.ThemeWizard', 'Bottom Left - Top Right'))
self.image_color_label.setText(translate('OpenLP.ThemeWizard', 'Background color:'))
self.image_label.setText('%s:' % UiStrings().Image)
self.image_label.setText('{text}:'.format(text=UiStrings().Image))
self.video_color_label.setText(translate('OpenLP.ThemeWizard', 'Background color:'))
self.video_label.setText('%s:' % UiStrings().Video)
self.video_label.setText('{text}:'.format(text=UiStrings().Video))
self.main_area_page.setTitle(translate('OpenLP.ThemeWizard', 'Main Area Font Details'))
self.main_area_page.setSubTitle(translate('OpenLP.ThemeWizard', 'Define the font and display '
'characteristics for the Display text'))

View File

@ -242,13 +242,13 @@ class PresentationDocument(object):
def convert_thumbnail(self, file, idx):
"""
Convert the slide image the application made to a standard 320x240 .png image.
Convert the slide image the application made to a scaled 360px height .png image.
"""
if self.check_thumbnails():
return
if os.path.isfile(file):
thumb_path = self.get_thumbnail_path(idx, False)
create_thumb(file, thumb_path, False, QtCore.QSize(320, 240))
create_thumb(file, thumb_path, False, QtCore.QSize(-1, 360))
def get_thumbnail_path(self, slide_no, check_exists):
"""

View File

@ -221,9 +221,13 @@ class HttpRouter(RegistryProperties):
self.request_data = None
url_path_split = urlparse(url_path)
url_query = parse_qs(url_path_split.query)
# GET
if 'data' in url_query.keys():
self.request_data = url_query['data'][0]
# Get data from HTTP request
if self.command == 'GET':
if 'data' in url_query.keys():
self.request_data = url_query['data'][0]
elif self.command == 'POST':
content_len = int(self.headers['content-length'])
self.request_data = self.rfile.read(content_len).decode("utf-8")
for route, func in self.routes:
match = re.match(route, url_path_split.path)
if match:
@ -401,10 +405,8 @@ class HttpRouter(RegistryProperties):
log.debug('serve file request %s' % file_name)
if not file_name:
file_name = 'index.html'
elif file_name == 'stage':
file_name = 'stage.html'
elif file_name == 'main':
file_name = 'main.html'
if '.' not in file_name:
file_name += '.html'
if file_name.startswith('/'):
file_name = file_name[1:]
path = os.path.normpath(os.path.join(self.html_dir, file_name))

View File

@ -167,7 +167,6 @@ class HTTPSServer(HTTPServer):
local_data = AppLocation.get_directory(AppLocation.DataDir)
self.socket = ssl.SSLSocket(
sock=socket.socket(self.address_family, self.socket_type),
ssl_version=ssl.PROTOCOL_TLSv1_2,
certfile=os.path.join(local_data, 'remotes', 'openlp.crt'),
keyfile=os.path.join(local_data, 'remotes', 'openlp.key'),
server_side=True)

View File

@ -93,6 +93,7 @@ MODULES = [
'bs4',
'mako',
'uno',
'six'
]

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

@ -250,7 +250,7 @@ class TestLib(TestCase):
def create_thumb_with_size_test(self):
"""
Test the create_thumb() function
Test the create_thumb() function with a given size.
"""
# GIVEN: An image to create a thumb of.
image_path = os.path.join(TEST_PATH, 'church.jpg')
@ -270,7 +270,7 @@ class TestLib(TestCase):
# WHEN: Create the thumb.
icon = create_thumb(image_path, thumb_path, size=thumb_size)
# THEN: Check if the thumb was created.
# THEN: Check if the thumb was created and scaled to the given size.
self.assertTrue(os.path.exists(thumb_path), 'Test was not ran, because the thumb already exists')
self.assertIsInstance(icon, QtGui.QIcon, 'The icon should be a QIcon')
self.assertFalse(icon.isNull(), 'The icon should not be null')
@ -282,6 +282,193 @@ class TestLib(TestCase):
except:
pass
def create_thumb_no_size_test(self):
"""
Test the create_thumb() function with no size specified.
"""
# GIVEN: An image to create a thumb of.
image_path = os.path.join(TEST_PATH, 'church.jpg')
thumb_path = os.path.join(TEST_PATH, 'church_thumb.jpg')
expected_size = QtCore.QSize(63, 88)
# Remove the thumb so that the test actually tests if the thumb will be created. Maybe it was not deleted in the
# last test.
try:
os.remove(thumb_path)
except:
pass
# Only continue when the thumb does not exist.
self.assertFalse(os.path.exists(thumb_path), 'Test was not run, because the thumb already exists.')
# WHEN: Create the thumb.
icon = create_thumb(image_path, thumb_path)
# THEN: Check if the thumb was created, retaining its aspect ratio.
self.assertTrue(os.path.exists(thumb_path), 'Test was not ran, because the thumb already exists')
self.assertIsInstance(icon, QtGui.QIcon, 'The icon should be a QIcon')
self.assertFalse(icon.isNull(), 'The icon should not be null')
self.assertEqual(expected_size, QtGui.QImageReader(thumb_path).size(), 'The thumb should have the given size')
# Remove the thumb so that the test actually tests if the thumb will be created.
try:
os.remove(thumb_path)
except:
pass
def create_thumb_invalid_size_test(self):
"""
Test the create_thumb() function with invalid size specified.
"""
# GIVEN: An image to create a thumb of.
image_path = os.path.join(TEST_PATH, 'church.jpg')
thumb_path = os.path.join(TEST_PATH, 'church_thumb.jpg')
thumb_size = QtCore.QSize(-1, -1)
expected_size = QtCore.QSize(63, 88)
# Remove the thumb so that the test actually tests if the thumb will be created. Maybe it was not deleted in the
# last test.
try:
os.remove(thumb_path)
except:
pass
# Only continue when the thumb does not exist.
self.assertFalse(os.path.exists(thumb_path), 'Test was not run, because the thumb already exists.')
# WHEN: Create the thumb.
icon = create_thumb(image_path, thumb_path, size=thumb_size)
# THEN: Check if the thumb was created, retaining its aspect ratio.
self.assertTrue(os.path.exists(thumb_path), 'Test was not ran, because the thumb already exists')
self.assertIsInstance(icon, QtGui.QIcon, 'The icon should be a QIcon')
self.assertFalse(icon.isNull(), 'The icon should not be null')
self.assertEqual(expected_size, QtGui.QImageReader(thumb_path).size(), 'The thumb should have the given size')
# Remove the thumb so that the test actually tests if the thumb will be created.
try:
os.remove(thumb_path)
except:
pass
def create_thumb_width_only_test(self):
"""
Test the create_thumb() function with a size of only width specified.
"""
# GIVEN: An image to create a thumb of.
image_path = os.path.join(TEST_PATH, 'church.jpg')
thumb_path = os.path.join(TEST_PATH, 'church_thumb.jpg')
thumb_size = QtCore.QSize(100, -1)
expected_size = QtCore.QSize(100, 137)
# Remove the thumb so that the test actually tests if the thumb will be created. Maybe it was not deleted in the
# last test.
try:
os.remove(thumb_path)
except:
pass
# Only continue when the thumb does not exist.
self.assertFalse(os.path.exists(thumb_path), 'Test was not run, because the thumb already exists.')
# WHEN: Create the thumb.
icon = create_thumb(image_path, thumb_path, size=thumb_size)
# THEN: Check if the thumb was created, retaining its aspect ratio.
self.assertTrue(os.path.exists(thumb_path), 'Test was not ran, because the thumb already exists')
self.assertIsInstance(icon, QtGui.QIcon, 'The icon should be a QIcon')
self.assertFalse(icon.isNull(), 'The icon should not be null')
self.assertEqual(expected_size, QtGui.QImageReader(thumb_path).size(), 'The thumb should have the given size')
# Remove the thumb so that the test actually tests if the thumb will be created.
try:
os.remove(thumb_path)
except:
pass
def create_thumb_height_only_test(self):
"""
Test the create_thumb() function with a size of only height specified.
"""
# GIVEN: An image to create a thumb of.
image_path = os.path.join(TEST_PATH, 'church.jpg')
thumb_path = os.path.join(TEST_PATH, 'church_thumb.jpg')
thumb_size = QtCore.QSize(-1, 100)
expected_size = QtCore.QSize(72, 100)
# Remove the thumb so that the test actually tests if the thumb will be created. Maybe it was not deleted in the
# last test.
try:
os.remove(thumb_path)
except:
pass
# Only continue when the thumb does not exist.
self.assertFalse(os.path.exists(thumb_path), 'Test was not run, because the thumb already exists.')
# WHEN: Create the thumb.
icon = create_thumb(image_path, thumb_path, size=thumb_size)
# THEN: Check if the thumb was created, retaining its aspect ratio.
self.assertTrue(os.path.exists(thumb_path), 'Test was not ran, because the thumb already exists')
self.assertIsInstance(icon, QtGui.QIcon, 'The icon should be a QIcon')
self.assertFalse(icon.isNull(), 'The icon should not be null')
self.assertEqual(expected_size, QtGui.QImageReader(thumb_path).size(), 'The thumb should have the given size')
# Remove the thumb so that the test actually tests if the thumb will be created.
try:
os.remove(thumb_path)
except:
pass
def create_thumb_empty_img_test(self):
"""
Test the create_thumb() function with a size of only height specified.
"""
# GIVEN: An image to create a thumb of.
image_path = os.path.join(TEST_PATH, 'church.jpg')
thumb_path = os.path.join(TEST_PATH, 'church_thumb.jpg')
thumb_size = QtCore.QSize(-1, 100)
expected_size_1 = QtCore.QSize(88, 88)
expected_size_2 = QtCore.QSize(100, 100)
# Remove the thumb so that the test actually tests if the thumb will be created. Maybe it was not deleted in the
# last test.
try:
os.remove(thumb_path)
except:
pass
# Only continue when the thumb does not exist.
self.assertFalse(os.path.exists(thumb_path), 'Test was not run, because the thumb already exists.')
# WHEN: Create the thumb.
with patch('openlp.core.lib.QtGui.QImageReader.size') as mocked_size:
mocked_size.return_value = QtCore.QSize(0, 0)
icon = create_thumb(image_path, thumb_path, size=None)
# THEN: Check if the thumb was created with aspect ratio of 1.
self.assertTrue(os.path.exists(thumb_path), 'Test was not ran, because the thumb already exists')
self.assertIsInstance(icon, QtGui.QIcon, 'The icon should be a QIcon')
self.assertFalse(icon.isNull(), 'The icon should not be null')
self.assertEqual(expected_size_1, QtGui.QImageReader(thumb_path).size(), 'The thumb should have the given size')
# WHEN: Create the thumb.
with patch('openlp.core.lib.QtGui.QImageReader.size') as mocked_size:
mocked_size.return_value = QtCore.QSize(0, 0)
icon = create_thumb(image_path, thumb_path, size=thumb_size)
# THEN: Check if the thumb was created with aspect ratio of 1.
self.assertIsInstance(icon, QtGui.QIcon, 'The icon should be a QIcon')
self.assertFalse(icon.isNull(), 'The icon should not be null')
self.assertEqual(expected_size_2, QtGui.QImageReader(thumb_path).size(), 'The thumb should have the given size')
# Remove the thumb so that the test actually tests if the thumb will be created.
try:
os.remove(thumb_path)
except:
pass
def check_item_selected_true_test(self):
"""
Test that the check_item_selected() function returns True when there are selected indexes

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

@ -28,7 +28,7 @@ PREREQUISITE: add_record() and get_all() functions validated.
import os
from unittest import TestCase
from openlp.core.lib.projector.db import Manufacturer, Model, Projector, ProjectorDB, ProjectorSource
from openlp.core.lib.projector.db import Manufacturer, Model, Projector, ProjectorDB, ProjectorSource, Source
from tests.functional import MagicMock, patch
from tests.resources.projector.data import TEST_DB, TEST1_DATA, TEST2_DATA, TEST3_DATA
@ -206,3 +206,33 @@ class TestProjectorDB(TestCase):
# THEN: __repr__ should return a proper string
self.assertEqual(str(manufacturer), '<Manufacturer(name="OpenLP Test")>',
'Manufacturer.__repr__() should have returned a proper representation string')
def model_repr_test(self):
"""
Test model class __repr__ text
"""
# GIVEN: Test object
model = Model()
# WHEN: Name is set
model.name = 'OpenLP Test'
# THEN: __repr__ should return a proper string
self.assertEqual(str(model), '<Model(name='"OpenLP Test"')>',
'Model.__repr__() should have returned a proper representation string')
def source_repr_test(self):
"""
Test source.__repr__ text
"""
# GIVEN: Test object
source = Source()
# WHEN: Source() information is set
source.pjlink_name = 'Test object'
source.pjlink_code = '11'
source.text = 'Input text'
# THEN: __repr__ should return a proper string
self.assertEqual(str(source), '<Source(pjlink_name="Test object", pjlink_code="11", text="Input text")>',
'Source.__repr__() should have returned a proper representation string')

View File

@ -244,14 +244,16 @@ class TestServiceItem(TestCase):
self.assertEqual(service_item.service_item_type, ServiceItemType.Command, 'It should be a Command')
self.assertEqual(service_item.get_frames()[0], frame, 'Frames should match')
@patch(u'openlp.core.lib.serviceitem.ServiceItem.image_manager')
@patch('openlp.core.lib.serviceitem.AppLocation.get_section_data_path')
def add_from_command_for_a_presentation_thumb_test(self, mocked_get_section_data_path):
def add_from_command_for_a_presentation_thumb_test(self, mocked_get_section_data_path, mocked_image_manager):
"""
Test the Service Item - adding a presentation, and updating the thumb path
Test the Service Item - adding a presentation, updating the thumb path & adding the thumb to image_manager
"""
# GIVEN: A service item, a mocked AppLocation and presentation data
mocked_get_section_data_path.return_value = os.path.join('mocked', 'section', 'path')
service_item = ServiceItem(None)
service_item.add_capability(ItemCapabilities.HasThumbnails)
service_item.has_original_files = False
service_item.name = 'presentations'
presentation_name = 'test.pptx'
@ -270,6 +272,7 @@ class TestServiceItem(TestCase):
# THEN: verify that it is setup as a Command and that the frame data matches
self.assertEqual(service_item.service_item_type, ServiceItemType.Command, 'It should be a Command')
self.assertEqual(service_item.get_frames()[0], frame, 'Frames should match')
self.assertEqual(1, mocked_image_manager.add_image.call_count, 'image_manager should be used')
def service_item_load_optical_media_from_service_test(self):
"""

View File

@ -26,7 +26,7 @@ from PyQt5 import QtCore, QtGui
from unittest import TestCase
from openlp.core import Registry
from openlp.core.lib import ServiceItemAction
from openlp.core.lib import ImageSource, ServiceItemAction
from openlp.core.ui import SlideController, LiveController, PreviewController
from openlp.core.ui.slidecontroller import InfoLabel, WIDE_MENU, NON_TEXT_MENU
@ -713,6 +713,175 @@ class TestSlideController(TestCase):
slide_controller.theme_screen, slide_controller.blank_screen
])
@patch(u'openlp.core.ui.slidecontroller.SlideController.image_manager')
@patch(u'PyQt5.QtCore.QTimer.singleShot')
def update_preview_test_live(self, mocked_singleShot, mocked_image_manager):
"""
Test that the preview screen is updated with a screen grab for live service items
"""
# GIVEN: A mocked live service item, a mocked image_manager, a mocked Registry,
# and a slide controller with many mocks.
# Mocked Live Item
mocked_live_item = MagicMock()
mocked_live_item.get_rendered_frame.return_value = ''
mocked_live_item.is_capable = MagicMock()
mocked_live_item.is_capable.side_effect = [True, True]
# Mock image_manager
mocked_image_manager.get_image.return_value = QtGui.QImage()
# Mock Registry
Registry.create()
mocked_main_window = MagicMock()
Registry().register('main_window', mocked_main_window)
# Mock SlideController
slide_controller = SlideController(None)
slide_controller.service_item = mocked_live_item
slide_controller.is_live = True
slide_controller.log_debug = MagicMock()
slide_controller.selected_row = MagicMock()
slide_controller.screens = MagicMock()
slide_controller.screens.current = {'primary': ''}
slide_controller.display = MagicMock()
slide_controller.display.preview.return_value = QtGui.QImage()
slide_controller.grab_maindisplay = MagicMock()
slide_controller.slide_preview = MagicMock()
slide_controller.slide_count = 0
# WHEN: update_preview is called
slide_controller.update_preview()
# THEN: A screen_grab should have been called
self.assertEqual(0, slide_controller.slide_preview.setPixmap.call_count, 'setPixmap should not be called')
self.assertEqual(0, slide_controller.display.preview.call_count, 'display.preview() should not be called')
self.assertEqual(2, mocked_singleShot.call_count,
'Timer to grab_maindisplay should have been called 2 times')
self.assertEqual(0, mocked_image_manager.get_image.call_count, 'image_manager not be called')
@patch(u'openlp.core.ui.slidecontroller.SlideController.image_manager')
@patch(u'PyQt5.QtCore.QTimer.singleShot')
def update_preview_test_pres(self, mocked_singleShot, mocked_image_manager):
"""
Test that the preview screen is updated with the correct preview for presentation service items
"""
# GIVEN: A mocked presentation service item, a mocked image_manager, a mocked Registry,
# and a slide controller with many mocks.
# Mocked Presentation Item
mocked_pres_item = MagicMock()
mocked_pres_item.get_rendered_frame.return_value = ''
mocked_pres_item.is_capable = MagicMock()
mocked_pres_item.is_capable.side_effect = [True, True]
# Mock image_manager
mocked_image_manager.get_image.return_value = QtGui.QImage()
# Mock Registry
Registry.create()
mocked_main_window = MagicMock()
Registry().register('main_window', mocked_main_window)
# Mock SlideController
slide_controller = SlideController(None)
slide_controller.service_item = mocked_pres_item
slide_controller.is_live = False
slide_controller.log_debug = MagicMock()
slide_controller.selected_row = MagicMock()
slide_controller.screens = MagicMock()
slide_controller.screens.current = {'primary': ''}
slide_controller.display = MagicMock()
slide_controller.display.preview.return_value = QtGui.QImage()
slide_controller.grab_maindisplay = MagicMock()
slide_controller.slide_preview = MagicMock()
slide_controller.slide_count = 0
# WHEN: update_preview is called
slide_controller.update_preview()
# THEN: setPixmap and the image_manager should have been called
self.assertEqual(1, slide_controller.slide_preview.setPixmap.call_count, 'setPixmap should be called')
self.assertEqual(0, slide_controller.display.preview.call_count, 'display.preview() should not be called')
self.assertEqual(0, mocked_singleShot.call_count, 'Timer to grab_maindisplay should not be called')
self.assertEqual(1, mocked_image_manager.get_image.call_count, 'image_manager should be called')
@patch(u'openlp.core.ui.slidecontroller.SlideController.image_manager')
@patch(u'PyQt5.QtCore.QTimer.singleShot')
def update_preview_test_media(self, mocked_singleShot, mocked_image_manager):
"""
Test that the preview screen is updated with the correct preview for media service items
"""
# GIVEN: A mocked media service item, a mocked image_manager, a mocked Registry,
# and a slide controller with many mocks.
# Mocked Media Item
mocked_media_item = MagicMock()
mocked_media_item.get_rendered_frame.return_value = ''
mocked_media_item.is_capable = MagicMock()
mocked_media_item.is_capable.side_effect = [True, False]
# Mock image_manager
mocked_image_manager.get_image.return_value = QtGui.QImage()
# Mock Registry
Registry.create()
mocked_main_window = MagicMock()
Registry().register('main_window', mocked_main_window)
# Mock SlideController
slide_controller = SlideController(None)
slide_controller.service_item = mocked_media_item
slide_controller.is_live = False
slide_controller.log_debug = MagicMock()
slide_controller.selected_row = MagicMock()
slide_controller.screens = MagicMock()
slide_controller.screens.current = {'primary': ''}
slide_controller.display = MagicMock()
slide_controller.display.preview.return_value = QtGui.QImage()
slide_controller.grab_maindisplay = MagicMock()
slide_controller.slide_preview = MagicMock()
slide_controller.slide_count = 0
# WHEN: update_preview is called
slide_controller.update_preview()
# THEN: setPixmap should have been called
self.assertEqual(1, slide_controller.slide_preview.setPixmap.call_count, 'setPixmap should be called')
self.assertEqual(0, slide_controller.display.preview.call_count, 'display.preview() should not be called')
self.assertEqual(0, mocked_singleShot.call_count, 'Timer to grab_maindisplay should not be called')
self.assertEqual(0, mocked_image_manager.get_image.call_count, 'image_manager should not be called')
@patch(u'openlp.core.ui.slidecontroller.SlideController.image_manager')
@patch(u'PyQt5.QtCore.QTimer.singleShot')
def update_preview_test_image(self, mocked_singleShot, mocked_image_manager):
"""
Test that the preview screen is updated with the correct preview for image service items
"""
# GIVEN: A mocked image service item, a mocked image_manager, a mocked Registry,
# and a slide controller with many mocks.
# Mocked Image Item
mocked_img_item = MagicMock()
mocked_img_item.get_rendered_frame.return_value = ''
mocked_img_item.is_capable = MagicMock()
mocked_img_item.is_capable.side_effect = [False, True]
# Mock image_manager
mocked_image_manager.get_image.return_value = QtGui.QImage()
# Mock Registry
Registry.create()
mocked_main_window = MagicMock()
Registry().register('main_window', mocked_main_window)
# Mock SlideController
slide_controller = SlideController(None)
slide_controller.service_item = mocked_img_item
slide_controller.is_live = False
slide_controller.log_debug = MagicMock()
slide_controller.selected_row = MagicMock()
slide_controller.screens = MagicMock()
slide_controller.screens.current = {'primary': ''}
slide_controller.display = MagicMock()
slide_controller.display.preview.return_value = QtGui.QImage()
slide_controller.grab_maindisplay = MagicMock()
slide_controller.slide_preview = MagicMock()
slide_controller.slide_count = 0
# WHEN: update_preview is called
slide_controller.update_preview()
# THEN: setPixmap and display.preview should have been called
self.assertEqual(1, slide_controller.slide_preview.setPixmap.call_count, 'setPixmap should be called')
self.assertEqual(1, slide_controller.display.preview.call_count, 'display.preview() should be called')
self.assertEqual(0, mocked_singleShot.call_count, 'Timer to grab_maindisplay should not be called')
self.assertEqual(0, mocked_image_manager.get_image.call_count, 'image_manager should not be called')
class TestInfoLabel(TestCase):

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

View File

@ -24,9 +24,11 @@ Package to test the openlp.core.ui.lib.listpreviewwidget package.
"""
from unittest import TestCase
from PyQt5 import QtGui
from openlp.core.common import Settings
from openlp.core.ui.lib.listpreviewwidget import ListPreviewWidget
from openlp.core.lib import ServiceItem
from openlp.core.lib import ImageSource, ServiceItem
from tests.functional import MagicMock, patch, call
@ -72,6 +74,53 @@ class TestListPreviewWidget(TestCase):
self.assertIsNotNone(list_preview_widget, 'The ListPreviewWidget object should not be None')
self.assertEquals(list_preview_widget.screen_ratio, 1, 'Should not be called')
@patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.image_manager')
@patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.resizeRowsToContents')
@patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.setRowHeight')
def replace_service_item_test_thumbs(self, mocked_setRowHeight, mocked_resizeRowsToContents,
mocked_image_manager):
"""
Test that thubmails for different slides are loaded properly in replace_service_item.
"""
# GIVEN: A setting to adjust "Max height for non-text slides in slide controller",
# different ServiceItem(s), an ImageManager, and a ListPreviewWidget.
# Mock Settings().value('advanced/slide max height')
self.mocked_Settings_obj.value.return_value = 0
# Mock self.viewport().width()
self.mocked_viewport_obj.width.return_value = 200
# Mock Image service item
mocked_img_service_item = MagicMock()
mocked_img_service_item.is_text.return_value = False
mocked_img_service_item.is_media.return_value = False
mocked_img_service_item.is_command.return_value = False
mocked_img_service_item.is_capable.return_value = False
mocked_img_service_item.get_frames.return_value = [{'title': None, 'path': 'TEST1', 'image': 'FAIL'},
{'title': None, 'path': 'TEST2', 'image': 'FAIL'}]
# Mock Command service item
mocked_cmd_service_item = MagicMock()
mocked_cmd_service_item.is_text.return_value = False
mocked_cmd_service_item.is_media.return_value = False
mocked_cmd_service_item.is_command.return_value = True
mocked_cmd_service_item.is_capable.return_value = True
mocked_cmd_service_item.get_frames.return_value = [{'title': None, 'path': 'FAIL', 'image': 'TEST3'},
{'title': None, 'path': 'FAIL', 'image': 'TEST4'}]
# Mock image_manager
mocked_image_manager.get_image.return_value = QtGui.QImage()
# init ListPreviewWidget and load service item
list_preview_widget = ListPreviewWidget(None, 1)
# WHEN: replace_service_item is called
list_preview_widget.replace_service_item(mocked_img_service_item, 200, 0)
list_preview_widget.replace_service_item(mocked_cmd_service_item, 200, 0)
# THEN: The ImageManager should be called in the appriopriate manner for each service item.
self.assertEquals(mocked_image_manager.get_image.call_count, 4, 'Should be called once for each slide')
calls = [call('TEST1', ImageSource.ImagePlugin), call('TEST2', ImageSource.ImagePlugin),
call('TEST3', ImageSource.CommandPlugins), call('TEST4', ImageSource.CommandPlugins)]
mocked_image_manager.get_image.assert_has_calls(calls)
@patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.resizeRowsToContents')
@patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.setRowHeight')
def replace_recalculate_layout_test_text(self, mocked_setRowHeight, mocked_resizeRowsToContents):
@ -120,6 +169,7 @@ class TestListPreviewWidget(TestCase):
# Mock image service item
service_item = MagicMock()
service_item.is_text.return_value = False
service_item.is_capable.return_value = False
service_item.get_frames.return_value = [{'title': None, 'path': None, 'image': None},
{'title': None, 'path': None, 'image': None}]
# init ListPreviewWidget and load service item
@ -156,6 +206,7 @@ class TestListPreviewWidget(TestCase):
# Mock image service item
service_item = MagicMock()
service_item.is_text.return_value = False
service_item.is_capable.return_value = False
service_item.get_frames.return_value = [{'title': None, 'path': None, 'image': None},
{'title': None, 'path': None, 'image': None}]
# init ListPreviewWidget and load service item
@ -225,6 +276,7 @@ class TestListPreviewWidget(TestCase):
# Mock image service item
service_item = MagicMock()
service_item.is_text.return_value = False
service_item.is_capable.return_value = False
service_item.get_frames.return_value = [{'title': None, 'path': None, 'image': None},
{'title': None, 'path': None, 'image': None}]
# Mock self.cellWidget().children().setMaximumWidth()
@ -261,6 +313,7 @@ class TestListPreviewWidget(TestCase):
# Mock image service item
service_item = MagicMock()
service_item.is_text.return_value = False
service_item.is_capable.return_value = False
service_item.get_frames.return_value = [{'title': None, 'path': None, 'image': None},
{'title': None, 'path': None, 'image': None}]
# Mock self.cellWidget().children().setMaximumWidth()

View File

@ -94,6 +94,7 @@ class TestRouter(TestCase, TestMixin):
(r'^/stage/api/poll$', {'function': mocked_function, 'secure': False}),
]
self.router.routes = test_route
self.router.command = 'GET'
# WHEN: called with a poll route
function, args = self.router.process_http_request('/stage/api/poll', None)
@ -121,6 +122,7 @@ class TestRouter(TestCase, TestMixin):
self.router.send_header = MagicMock()
self.router.end_headers = MagicMock()
self.router.wfile = MagicMock()
self.router.command = 'GET'
# WHEN: called with a poll route
self.router.do_post_processor()
@ -211,6 +213,29 @@ class TestRouter(TestCase, TestMixin):
self.router.send_header.assert_called_once_with('Content-type', 'text/html')
self.assertEqual(self.router.end_headers.call_count, 1, 'end_headers called once')
def serve_file_with_partial_params_test(self):
"""
Test the serve_file method with an existing file
"""
# GIVEN: mocked environment
self.router.send_response = MagicMock()
self.router.send_header = MagicMock()
self.router.end_headers = MagicMock()
self.router.wfile = MagicMock()
self.router.html_dir = os.path.normpath('test/dir')
self.router.template_vars = MagicMock()
with patch('openlp.core.lib.os.path.exists') as mocked_exists, \
patch('builtins.open', mock_open(read_data='123')):
mocked_exists.return_value = True
# WHEN: call serve_file with an existing html file
self.router.serve_file(os.path.normpath('test/dir/test'))
# THEN: it should return a 200 and the file
self.router.send_response.assert_called_once_with(200)
self.router.send_header.assert_called_once_with('Content-type', 'text/html')
self.assertEqual(self.router.end_headers.call_count, 1, 'end_headers called once')
def serve_thumbnail_without_params_test(self):
"""
Test the serve_thumbnail routine without params