- Merged trunk on 24.7.16

- Added superflys startup traceback fix to my code
- Resolved conflicts
This commit is contained in:
suutari-olli 2016-07-24 23:20:25 +03:00
commit aa1cd8fa91
260 changed files with 3885 additions and 2453 deletions

17
nose2.cfg Normal file
View File

@ -0,0 +1,17 @@
[unittest]
verbose = True
[log-capture]
always-on = True
clear-handlers = True
filter = -nose
log-level = ERROR
[test-result]
always-on = True
descriptions = True
[coverage]
always-on = False
coverage = openlp
coverage-report = html

View File

@ -195,7 +195,7 @@ def verify_ip_address(addr):
return True if verify_ipv4(addr) else verify_ipv6(addr) return True if verify_ipv4(addr) else verify_ipv6(addr)
def md5_hash(salt, data=None): def md5_hash(salt=None, data=None):
""" """
Returns the hashed output of md5sum on salt,data Returns the hashed output of md5sum on salt,data
using Python3 hashlib using Python3 hashlib
@ -205,8 +205,11 @@ def md5_hash(salt, data=None):
:returns: str :returns: str
""" """
log.debug('md5_hash(salt="{text}")'.format(text=salt)) log.debug('md5_hash(salt="{text}")'.format(text=salt))
if not salt and not data:
return None
hash_obj = hashlib.new('md5') hash_obj = hashlib.new('md5')
hash_obj.update(salt) if salt:
hash_obj.update(salt)
if data: if data:
hash_obj.update(data) hash_obj.update(data)
hash_value = hash_obj.hexdigest() hash_value = hash_obj.hexdigest()
@ -214,22 +217,30 @@ def md5_hash(salt, data=None):
return hash_value return hash_value
def qmd5_hash(salt, data=None): def qmd5_hash(salt=None, data=None):
""" """
Returns the hashed output of MD5Sum on salt, data Returns the hashed output of MD5Sum on salt, data
using PyQt5.QCryptographicHash. using PyQt5.QCryptographicHash. Function returns a
QByteArray instead of a text string.
If you need a string instead, call with
result = str(qmd5_hash(salt=..., data=...), encoding='ascii')
:param salt: Initial salt :param salt: Initial salt
:param data: OPTIONAL Data to hash :param data: OPTIONAL Data to hash
:returns: str :returns: QByteArray
""" """
log.debug('qmd5_hash(salt="{text}"'.format(text=salt)) log.debug('qmd5_hash(salt="{text}"'.format(text=salt))
if salt is None and data is None:
return None
hash_obj = QHash(QHash.Md5) hash_obj = QHash(QHash.Md5)
hash_obj.addData(salt) if salt:
hash_obj.addData(data) hash_obj.addData(salt)
if data:
hash_obj.addData(data)
hash_value = hash_obj.result().toHex() hash_value = hash_obj.result().toHex()
log.debug('qmd5_hash() returning "{text}"'.format(text=hash_value)) log.debug('qmd5_hash() returning "{hash}"'.format(hash=hash_value))
return hash_value.data() return hash_value
def clean_button_text(button_text): def clean_button_text(button_text):

View File

@ -138,7 +138,7 @@ class CategoryList(object):
for category in self.categories: for category in self.categories:
if category.name == key: if category.name == key:
return category return category
raise KeyError('Category "{keY}" does not exist.'.format(key=key)) raise KeyError('Category "{key}" does not exist.'.format(key=key))
def __len__(self): def __len__(self):
""" """

View File

@ -22,11 +22,12 @@
""" """
The :mod:`db` module provides helper functions for database related methods. The :mod:`db` module provides helper functions for database related methods.
""" """
import sqlalchemy
import logging import logging
from copy import deepcopy from copy import deepcopy
import sqlalchemy
log = logging.getLogger(__name__) log = logging.getLogger(__name__)

View File

@ -168,7 +168,7 @@ def format_time(text, local_time):
""" """
return local_time.strftime(match.group()) return local_time.strftime(match.group())
return re.sub('\%[a-zA-Z]', match_formatting, text) return re.sub(r'\%[a-zA-Z]', match_formatting, text)
def get_locale_key(string): def get_locale_key(string):

View File

@ -55,6 +55,7 @@ class Registry(object):
registry = cls() registry = cls()
registry.service_list = {} registry.service_list = {}
registry.functions_list = {} registry.functions_list = {}
registry.working_flags = {}
# Allow the tests to remove Registry entries but not the live system # Allow the tests to remove Registry entries but not the live system
registry.running_under_test = 'nose' in sys.argv[0] registry.running_under_test = 'nose' in sys.argv[0]
registry.initialising = True registry.initialising = True
@ -90,8 +91,7 @@ class Registry(object):
def remove(self, key): def remove(self, key):
""" """
Removes the registry value from the list based on the key passed in (Only valid and active for testing Removes the registry value from the list based on the key passed in.
framework).
:param key: The service to be deleted. :param key: The service to be deleted.
""" """
@ -145,3 +145,34 @@ class Registry(object):
trace_error_handler(log) trace_error_handler(log)
log.error("Event {event} called but not registered".format(event=event)) log.error("Event {event} called but not registered".format(event=event))
return results return results
def get_flag(self, key):
"""
Extracts the working_flag value from the list based on the key passed in
:param key: The flag to be retrieved.
"""
if key in self.working_flags:
return self.working_flags[key]
else:
trace_error_handler(log)
log.error('Working Flag {key} not found in list'.format(key=key))
raise KeyError('Working Flag {key} not found in list'.format(key=key))
def set_flag(self, key, reference):
"""
Sets a working_flag based on the key passed in.
:param key: The working_flag to be created this is usually a major class like "renderer" or "main_window" .
:param reference: The data to be saved.
"""
self.working_flags[key] = reference
def remove_flag(self, key):
"""
Removes the working flags value from the list based on the key passed.
:param key: The working_flag to be deleted.
"""
if key in self.working_flags:
del self.working_flags[key]

View File

@ -26,7 +26,7 @@ import datetime
import logging import logging
import os import os
from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5 import QtCore, QtGui
from openlp.core.common import ThemeLevel, SlideLimits, UiStrings, is_win, is_linux from openlp.core.common import ThemeLevel, SlideLimits, UiStrings, is_win, is_linux
@ -129,7 +129,7 @@ class Settings(QtCore.QSettings):
'advanced/recent file count': 4, 'advanced/recent file count': 4,
'advanced/save current plugin': False, 'advanced/save current plugin': False,
'advanced/slide limits': SlideLimits.End, 'advanced/slide limits': SlideLimits.End,
'advanced/slide max height': 0, 'advanced/slide max height': -4,
'advanced/single click preview': False, 'advanced/single click preview': False,
'advanced/single click service preview': False, 'advanced/single click service preview': False,
'advanced/x11 bypass wm': X11_BYPASS_DEFAULT, 'advanced/x11 bypass wm': X11_BYPASS_DEFAULT,

View File

@ -69,7 +69,7 @@ class UiStrings(object):
self.Default = translate('OpenLP.Ui', 'Default') self.Default = translate('OpenLP.Ui', 'Default')
self.DefaultColor = translate('OpenLP.Ui', 'Default Color:') self.DefaultColor = translate('OpenLP.Ui', 'Default Color:')
self.DefaultServiceName = translate('OpenLP.Ui', 'Service %Y-%m-%d %H-%M', self.DefaultServiceName = translate('OpenLP.Ui', 'Service %Y-%m-%d %H-%M',
'This may not contain any of the following characters: /\\?*|<>\[\]":+\n' 'This may not contain any of the following characters: /\\?*|<>[]":+\n'
'See http://docs.python.org/library/datetime' 'See http://docs.python.org/library/datetime'
'.html#strftime-strptime-behavior for more information.') '.html#strftime-strptime-behavior for more information.')
self.Delete = translate('OpenLP.Ui', '&Delete') self.Delete = translate('OpenLP.Ui', '&Delete')

View File

@ -10,10 +10,10 @@ from datetime import datetime
from distutils.version import LooseVersion from distutils.version import LooseVersion
from subprocess import Popen, PIPE from subprocess import Popen, PIPE
from openlp.core.common import AppLocation, Settings
from PyQt5 import QtCore from PyQt5 import QtCore
from openlp.core.common import AppLocation, Settings
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
APPLICATION_VERSION = {} APPLICATION_VERSION = {}

View File

@ -24,13 +24,12 @@ The :mod:`lib` module contains most of the components and libraries that make
OpenLP work. OpenLP work.
""" """
from distutils.version import LooseVersion
import logging import logging
import os import os
from distutils.version import LooseVersion
from PyQt5 import QtCore, QtGui, Qt, QtWidgets from PyQt5 import QtCore, QtGui, Qt, QtWidgets
from openlp.core.common import translate from openlp.core.common import translate
log = logging.getLogger(__name__ + '.__init__') log = logging.getLogger(__name__ + '.__init__')
@ -96,7 +95,7 @@ def get_text_file_string(text_file):
content = None content = None
try: try:
file_handle = open(text_file, 'r', encoding='utf-8') file_handle = open(text_file, 'r', encoding='utf-8')
if not file_handle.read(3) == '\xEF\xBB\xBF': if file_handle.read(3) != '\xEF\xBB\xBF':
# no BOM was found # no BOM was found
file_handle.seek(0) file_handle.seek(0)
content = file_handle.read() content = file_handle.read()
@ -342,7 +341,6 @@ from .exceptions import ValidationError
from .filedialog import FileDialog from .filedialog import FileDialog
from .screen import ScreenList from .screen import ScreenList
from .formattingtags import FormattingTags from .formattingtags import FormattingTags
from .spelltextedit import SpellTextEdit
from .plugin import PluginStatus, StringContent, Plugin from .plugin import PluginStatus, StringContent, Plugin
from .pluginmanager import PluginManager from .pluginmanager import PluginManager
from .settingstab import SettingsTab from .settingstab import SettingsTab

View File

@ -122,6 +122,21 @@ def get_upgrade_op(session):
return Operations(context) return Operations(context)
class BaseModel(object):
"""
BaseModel provides a base object with a set of generic functions
"""
@classmethod
def populate(cls, **kwargs):
"""
Creates an instance of a class and populates it, returning the instance
"""
instance = cls()
for key, value in kwargs.items():
instance.__setattr__(key, value)
return instance
def upgrade_db(url, upgrade): def upgrade_db(url, upgrade):
""" """
Upgrade a database. Upgrade a database.
@ -178,9 +193,9 @@ def upgrade_db(url, upgrade):
version_meta = Metadata.populate(key='version', value=int(upgrade.__version__)) version_meta = Metadata.populate(key='version', value=int(upgrade.__version__))
session.commit() session.commit()
upgrade_version = upgrade.__version__ upgrade_version = upgrade.__version__
version_meta = int(version_meta.value) version = int(version_meta.value)
session.close() session.close()
return version_meta, upgrade_version return version, upgrade_version
def delete_database(plugin_name, db_file_name=None): def delete_database(plugin_name, db_file_name=None):
@ -197,21 +212,6 @@ def delete_database(plugin_name, db_file_name=None):
return delete_file(db_file_path) return delete_file(db_file_path)
class BaseModel(object):
"""
BaseModel provides a base object with a set of generic functions
"""
@classmethod
def populate(cls, **kwargs):
"""
Creates an instance of a class and populates it, returning the instance
"""
instance = cls()
for key, value in kwargs.items():
instance.__setattr__(key, value)
return instance
class Manager(object): class Manager(object):
""" """
Provide generic object persistence management Provide generic object persistence management

View File

@ -389,6 +389,7 @@ is the function which has to be called from outside. The generated and returned
""" """
import logging import logging
from string import Template
from PyQt5 import QtWebKit from PyQt5 import QtWebKit
from openlp.core.common import Settings from openlp.core.common import Settings
@ -396,157 +397,200 @@ from openlp.core.lib.theme import BackgroundType, BackgroundGradientType, Vertic
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
# TODO: Verify where this is used before converting to python3 HTML_SRC = Template("""
HTMLSRC = """ <!DOCTYPE html>
<!DOCTYPE html> <html>
<html> <head>
<head> <title>OpenLP Display</title>
<title>OpenLP Display</title> <style>
<style> *{
*{ margin: 0;
padding: 0;
border: 0;
overflow: hidden;
-webkit-user-select: none;
}
body {
${bg_css};
}
.size {
position: absolute;
left: 0px;
top: 0px;
width: 100%;
height: 100%;
}
#black {
z-index: 8;
background-color: black;
display: none;
}
#bgimage {
z-index: 1;
}
#image {
z-index: 2;
}
${css_additions}
#footer {
position: absolute;
z-index: 6;
${footer_css}
}
/* lyric css */${lyrics_css}
sup {
font-size: 0.6em;
vertical-align: top;
position: relative;
top: -0.3em;
}
</style>
<script>
var timer = null;
var transition = ${transitions};
${js_additions}
function show_image(src){
var img = document.getElementById('image');
img.src = src;
if(src == '')
img.style.display = 'none';
else
img.style.display = 'block';
}
function show_blank(state){
var black = 'none';
var lyrics = '';
switch(state){
case 'theme':
lyrics = 'hidden';
break;
case 'black':
black = 'block';
break;
case 'desktop':
break;
}
document.getElementById('black').style.display = black;
document.getElementById('lyricsmain').style.visibility = lyrics;
document.getElementById('image').style.visibility = lyrics;
document.getElementById('footer').style.visibility = lyrics;
}
function show_footer(footertext){
document.getElementById('footer').innerHTML = footertext;
}
function show_text(new_text){
var match = /-webkit-text-fill-color:[^;\"]+/gi;
if(timer != null)
clearTimeout(timer);
/*
QtWebkit bug with outlines and justify causing outline alignment
problems. (Bug 859950) Surround each word with a <span> to workaround,
but only in this scenario.
*/
var txt = document.getElementById('lyricsmain');
if(window.getComputedStyle(txt).textAlign == 'justify'){
if(window.getComputedStyle(txt).webkitTextStrokeWidth != '0px'){
new_text = new_text.replace(/(\s|&nbsp;)+(?![^<]*>)/g,
function(match) {
return '</span>' + match + '<span>';
});
new_text = '<span>' + new_text + '</span>';
}
}
text_fade('lyricsmain', new_text);
}
function text_fade(id, new_text){
/*
Show the text.
*/
var text = document.getElementById(id);
if(text == null) return;
if(!transition){
text.innerHTML = new_text;
return;
}
// Fade text out. 0.1 to minimize the time "nothing" is shown on the screen.
text.style.opacity = '0.1';
// Fade new text in after the old text has finished fading out.
timer = window.setTimeout(function(){_show_text(text, new_text)}, 400);
}
function _show_text(text, new_text) {
/*
Helper function to show the new_text delayed.
*/
text.innerHTML = new_text;
text.style.opacity = '1';
// Wait until the text is completely visible. We want to save the timer id, to be able to call
// clearTimeout(timer) when the text has changed before finishing fading.
timer = window.setTimeout(function(){timer = null;}, 400);
}
function show_text_completed(){
return (timer == null);
}
</script>
</head>
<body>
<img id="bgimage" class="size" ${bg_image} />
<img id="image" class="size" ${image} />
${html_additions}
<div class="lyricstable"><div id="lyricsmain" style="opacity:1" class="lyricscell lyricsmain"></div></div>
<div id="footer" class="footer"></div>
<div id="black" class="size"></div>
</body>
</html>
""")
LYRICS_SRC = Template("""
.lyricstable {
z-index: 5;
position: absolute;
display: table;
${stable}
}
.lyricscell {
display: table-cell;
word-wrap: break-word;
-webkit-transition: opacity 0.4s ease;
${lyrics}
}
.lyricsmain {
${main}
}
""")
FOOTER_SRC = Template("""
left: ${left}px;
bottom: ${bottom}px;
width: ${width}px;
font-family: ${family};
font-size: ${size}pt;
color: ${color};
text-align: left;
white-space: ${space};
""")
LYRICS_FORMAT_SRC = Template("""
${justify}word-wrap: break-word;
text-align: ${align};
vertical-align: ${valign};
font-family: ${font};
font-size: ${size}pt;
color: ${color};
line-height: ${line}%;
margin: 0; margin: 0;
padding: 0; padding: 0;
border: 0; padding-bottom: ${bottom};
overflow: hidden; padding-left: ${left}px;
-webkit-user-select: none; width: ${width}px;
} height: ${height}px;${font_style}${font_weight}
body { """)
%s;
}
.size {
position: absolute;
left: 0px;
top: 0px;
width: 100%%;
height: 100%%;
}
#black {
z-index: 8;
background-color: black;
display: none;
}
#bgimage {
z-index: 1;
}
#image {
z-index: 2;
}
%s
#footer {
position: absolute;
z-index: 6;
%s
}
/* lyric css */
%s
sup {
font-size: 0.6em;
vertical-align: top;
position: relative;
top: -0.3em;
}
</style>
<script>
var timer = null;
var transition = %s;
%s
function show_image(src){
var img = document.getElementById('image');
img.src = src;
if(src == '')
img.style.display = 'none';
else
img.style.display = 'block';
}
function show_blank(state){
var black = 'none';
var lyrics = '';
switch(state){
case 'theme':
lyrics = 'hidden';
break;
case 'black':
black = 'block';
break;
case 'desktop':
break;
}
document.getElementById('black').style.display = black;
document.getElementById('lyricsmain').style.visibility = lyrics;
document.getElementById('image').style.visibility = lyrics;
document.getElementById('footer').style.visibility = lyrics;
}
function show_footer(footertext){
document.getElementById('footer').innerHTML = footertext;
}
function show_text(new_text){
var match = /-webkit-text-fill-color:[^;\"]+/gi;
if(timer != null)
clearTimeout(timer);
/*
QtWebkit bug with outlines and justify causing outline alignment
problems. (Bug 859950) Surround each word with a <span> to workaround,
but only in this scenario.
*/
var txt = document.getElementById('lyricsmain');
if(window.getComputedStyle(txt).textAlign == 'justify'){
if(window.getComputedStyle(txt).webkitTextStrokeWidth != '0px'){
new_text = new_text.replace(/(\s|&nbsp;)+(?![^<]*>)/g,
function(match) {
return '</span>' + match + '<span>';
});
new_text = '<span>' + new_text + '</span>';
}
}
text_fade('lyricsmain', new_text);
}
function text_fade(id, new_text){
/*
Show the text.
*/
var text = document.getElementById(id);
if(text == null) return;
if(!transition){
text.innerHTML = new_text;
return;
}
// Fade text out. 0.1 to minimize the time "nothing" is shown on the screen.
text.style.opacity = '0.1';
// Fade new text in after the old text has finished fading out.
timer = window.setTimeout(function(){_show_text(text, new_text)}, 400);
}
function _show_text(text, new_text) {
/*
Helper function to show the new_text delayed.
*/
text.innerHTML = new_text;
text.style.opacity = '1';
// Wait until the text is completely visible. We want to save the timer id, to be able to call
// clearTimeout(timer) when the text has changed before finishing fading.
timer = window.setTimeout(function(){timer = null;}, 400);
}
function show_text_completed(){
return (timer == null);
}
</script>
</head>
<body>
<img id="bgimage" class="size" %s />
<img id="image" class="size" %s />
%s
<div class="lyricstable"><div id="lyricsmain" style="opacity:1" class="lyricscell lyricsmain"></div></div>
<div id="footer" class="footer"></div>
<div id="black" class="size"></div>
</body>
</html>
"""
def build_html(item, screen, is_live, background, image=None, plugins=None): def build_html(item, screen, is_live, background, image=None, plugins=None):
@ -582,18 +626,17 @@ def build_html(item, screen, is_live, background, image=None, plugins=None):
css_additions += plugin.get_display_css() css_additions += plugin.get_display_css()
js_additions += plugin.get_display_javascript() js_additions += plugin.get_display_javascript()
html_additions += plugin.get_display_html() html_additions += plugin.get_display_html()
html = HTMLSRC % ( return HTML_SRC.substitute(bg_css=build_background_css(item, width),
build_background_css(item, width), css_additions=css_additions,
css_additions, footer_css=build_footer_css(item, height),
build_footer_css(item, height), lyrics_css=build_lyrics_css(item),
build_lyrics_css(item), transitions='true' if (theme_data and
'true' if theme_data and theme_data.display_slide_transition and is_live else 'false', theme_data.display_slide_transition and
js_additions, is_live) else 'false',
bgimage_src, js_additions=js_additions,
image_src, bg_image=bgimage_src,
html_additions image=image_src,
) html_additions=html_additions)
return html
def webkit_version(): def webkit_version():
@ -604,7 +647,7 @@ def webkit_version():
webkit_ver = float(QtWebKit.qWebKitVersion()) webkit_ver = float(QtWebKit.qWebKitVersion())
log.debug('Webkit version = {version}'.format(version=webkit_ver)) log.debug('Webkit version = {version}'.format(version=webkit_ver))
except AttributeError: except AttributeError:
webkit_ver = 0 webkit_ver = 0.0
return webkit_ver return webkit_ver
@ -650,24 +693,6 @@ def build_lyrics_css(item):
:param item: Service Item containing theme and location information :param item: Service Item containing theme and location information
""" """
# TODO: Verify this before converting to python3
style = """
.lyricstable {
z-index: 5;
position: absolute;
display: table;
%s
}
.lyricscell {
display: table-cell;
word-wrap: break-word;
-webkit-transition: opacity 0.4s ease;
%s
}
.lyricsmain {
%s
}
"""
theme_data = item.theme_data theme_data = item.theme_data
lyricstable = '' lyricstable = ''
lyrics = '' lyrics = ''
@ -680,8 +705,7 @@ def build_lyrics_css(item):
lyricsmain += ' text-shadow: {theme} {shadow}px ' \ lyricsmain += ' text-shadow: {theme} {shadow}px ' \
'{shadow}px;'.format(theme=theme_data.font_main_shadow_color, '{shadow}px;'.format(theme=theme_data.font_main_shadow_color,
shadow=theme_data.font_main_shadow_size) shadow=theme_data.font_main_shadow_size)
lyrics_css = style % (lyricstable, lyrics, lyricsmain) return LYRICS_SRC.substitute(stable=lyricstable, lyrics=lyrics, main=lyricsmain)
return lyrics_css
def build_lyrics_outline_css(theme_data): def build_lyrics_outline_css(theme_data):
@ -710,38 +734,23 @@ def build_lyrics_format_css(theme_data, width, height):
""" """
align = HorizontalType.Names[theme_data.display_horizontal_align] align = HorizontalType.Names[theme_data.display_horizontal_align]
valign = VerticalType.Names[theme_data.display_vertical_align] valign = VerticalType.Names[theme_data.display_vertical_align]
if theme_data.font_main_outline: left_margin = (int(theme_data.font_main_outline_size) * 2) if theme_data.font_main_outline else 0
left_margin = int(theme_data.font_main_outline_size) * 2
else:
left_margin = 0
justify = 'white-space:pre-wrap;'
# fix tag incompatibilities # fix tag incompatibilities
if theme_data.display_horizontal_align == HorizontalType.Justify: justify = '' if (theme_data.display_horizontal_align == HorizontalType.Justify) else ' white-space: pre-wrap;\n'
justify = '' padding_bottom = '0.5em' if (theme_data.display_vertical_align == VerticalType.Bottom) else '0'
if theme_data.display_vertical_align == VerticalType.Bottom: return LYRICS_FORMAT_SRC.substitute(justify=justify,
padding_bottom = '0.5em' align=align,
else: valign=valign,
padding_bottom = '0' font=theme_data.font_main_name,
lyrics = '{justify} word-wrap: break-word; ' \ size=theme_data.font_main_size,
'text-align: {align}; vertical-align: {valign}; font-family: {font}; ' \ color=theme_data.font_main_color,
'font-size: {size}pt; color: {color}; line-height: {line:d}%; margin: 0;' \ line='{line:d}'.format(line=100 + int(theme_data.font_main_line_adjustment)),
'padding: 0; padding-bottom: {bottom}; padding-left: {left}px; width: {width}px; ' \ bottom=padding_bottom,
'height: {height}px; '.format(justify=justify, left=left_margin,
align=align, width=width,
valign=valign, height=height,
font=theme_data.font_main_name, font_style='\n font-style: italic;' if theme_data.font_main_italics else '',
size=theme_data.font_main_size, font_weight='\n font-weight: bold;' if theme_data.font_main_bold else '')
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:
lyrics += 'font-weight:bold; '
return lyrics
def build_footer_css(item, height): def build_footer_css(item, height):
@ -751,22 +760,11 @@ def build_footer_css(item, height):
:param item: Service Item to be processed. :param item: Service Item to be processed.
:param height: :param height:
""" """
style = """
left: {left}px;
bottom: {bottom}px;
width: {width}px;
font-family: {family};
font-size: {size}pt;
color: {color};
text-align: left;
white-space: {space};
"""
theme = item.theme_data theme = item.theme_data
if not theme or not item.footer: if not theme or not item.footer:
return '' return ''
bottom = height - int(item.footer.y()) - int(item.footer.height()) bottom = height - int(item.footer.y()) - int(item.footer.height())
whitespace = 'normal' if Settings().value('themes/wrap footer') else 'nowrap' whitespace = 'normal' if Settings().value('themes/wrap footer') else 'nowrap'
lyrics_html = style.format(left=item.footer.x(), bottom=bottom, width=item.footer.width(), return FOOTER_SRC.substitute(left=item.footer.x(), bottom=bottom, width=item.footer.width(),
family=theme.font_footer_name, size=theme.font_footer_size, family=theme.font_footer_name, size=theme.font_footer_size,
color=theme.font_footer_color, space=whitespace) color=theme.font_footer_color, space=whitespace)
return lyrics_html

View File

@ -272,7 +272,7 @@ class ImageManager(QtCore.QObject):
Add image to cache if it is not already there. Add image to cache if it is not already there.
""" """
log.debug('add_image {path}'.format(path=path)) log.debug('add_image {path}'.format(path=path))
if not (path, source, width, height) in self._cache: if (path, source, width, height) not in self._cache:
image = Image(path, source, background, width, height) image = Image(path, source, background, width, height)
self._cache[(path, source, width, height)] = image self._cache[(path, source, width, height)] = image
self._conversion_queue.put((image.priority, image.secondary_priority, image)) self._conversion_queue.put((image.priority, image.secondary_priority, image))

View File

@ -23,7 +23,6 @@
Provide plugin management Provide plugin management
""" """
import os import os
import sys
import imp import imp
from openlp.core.lib import Plugin, PluginStatus from openlp.core.lib import Plugin, PluginStatus

View File

@ -40,13 +40,12 @@ log.debug('projector.lib.db module loaded')
from sqlalchemy import Column, ForeignKey, Integer, MetaData, String, and_ from sqlalchemy import Column, ForeignKey, Integer, MetaData, String, and_
from sqlalchemy.ext.declarative import declarative_base, declared_attr from sqlalchemy.ext.declarative import declarative_base, declared_attr
from sqlalchemy.orm import backref, relationship from sqlalchemy.orm import relationship
from openlp.core.lib.db import Manager, init_db, init_url from openlp.core.lib.db import Manager, init_db, init_url
from openlp.core.lib.projector.constants import PJLINK_DEFAULT_CODES from openlp.core.lib.projector.constants import PJLINK_DEFAULT_CODES
metadata = MetaData() Base = declarative_base(MetaData())
Base = declarative_base(metadata)
class CommonBase(object): class CommonBase(object):
@ -54,8 +53,8 @@ class CommonBase(object):
Base class to automate table name and ID column. Base class to automate table name and ID column.
""" """
@declared_attr @declared_attr
def __tablename__(cls): def __tablename__(self):
return cls.__name__.lower() return self.__name__.lower()
id = Column(Integer, primary_key=True) id = Column(Integer, primary_key=True)
@ -131,7 +130,7 @@ class Source(CommonBase, Base):
""" """
Return basic representation of Source table entry. 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, code=self.pjlink_code,
text=self.text) text=self.text)
model_id = Column(Integer, ForeignKey('model.id')) model_id = Column(Integer, ForeignKey('model.id'))
@ -257,7 +256,7 @@ class ProjectorDB(Manager):
projector = self.get_object_filtered(Projector, Projector.id == dbid) projector = self.get_object_filtered(Projector, Projector.id == dbid)
if projector is None: if projector is None:
# Not found # Not found
log.warn('get_projector_by_id() did not find {data}'.format(data=id)) log.warning('get_projector_by_id() did not find {data}'.format(data=id))
return None return None
log.debug('get_projectorby_id() returning 1 entry for "{entry}" id="{data}"'.format(entry=dbid, log.debug('get_projectorby_id() returning 1 entry for "{entry}" id="{data}"'.format(entry=dbid,
data=projector.id)) data=projector.id))
@ -290,7 +289,7 @@ class ProjectorDB(Manager):
projector = self.get_object_filtered(Projector, Projector.ip == ip) projector = self.get_object_filtered(Projector, Projector.ip == ip)
if projector is None: if projector is None:
# Not found # Not found
log.warn('get_projector_by_ip() did not find {ip}'.format(ip=ip)) log.warning('get_projector_by_ip() did not find {ip}'.format(ip=ip))
return None return None
log.debug('get_projectorby_ip() returning 1 entry for "{ip}" id="{data}"'.format(ip=ip, log.debug('get_projectorby_ip() returning 1 entry for "{ip}" id="{data}"'.format(ip=ip,
data=projector.id)) data=projector.id))
@ -307,7 +306,7 @@ class ProjectorDB(Manager):
projector = self.get_object_filtered(Projector, Projector.name == name) projector = self.get_object_filtered(Projector, Projector.name == name)
if projector is None: if projector is None:
# Not found # Not found
log.warn('get_projector_by_name() did not find "{name}"'.format(name=name)) log.warning('get_projector_by_name() did not find "{name}"'.format(name=name))
return None return None
log.debug('get_projector_by_name() returning one entry for "{name}" id="{data}"'.format(name=name, log.debug('get_projector_by_name() returning one entry for "{name}" id="{data}"'.format(name=name,
data=projector.id)) data=projector.id))
@ -324,7 +323,7 @@ class ProjectorDB(Manager):
""" """
old_projector = self.get_object_filtered(Projector, Projector.ip == projector.ip) old_projector = self.get_object_filtered(Projector, Projector.ip == projector.ip)
if old_projector is not None: if old_projector is not None:
log.warn('add_new() skipping entry ip="{ip}" (Already saved)'.format(ip=old_projector.ip)) log.warning('add_new() skipping entry ip="{ip}" (Already saved)'.format(ip=old_projector.ip))
return False return False
log.debug('add_new() saving new entry') log.debug('add_new() saving new entry')
log.debug('ip="{ip}", name="{name}", location="{location}"'.format(ip=projector.ip, log.debug('ip="{ip}", name="{name}", location="{location}"'.format(ip=projector.ip,
@ -408,10 +407,10 @@ class ProjectorDB(Manager):
:param source: ProjectorSource id :param source: ProjectorSource id
:returns: ProjetorSource instance or None :returns: ProjetorSource instance or None
""" """
source_entry = self.get_object_filtered(ProjetorSource, ProjectorSource.id == source) source_entry = self.get_object_filtered(ProjectorSource, ProjectorSource.id == source)
if source_entry is None: if source_entry is None:
# Not found # Not found
log.warn('get_source_by_id() did not find "{source}"'.format(source=source)) log.warning('get_source_by_id() did not find "{source}"'.format(source=source))
return None return None
log.debug('get_source_by_id() returning one entry for "{source}""'.format(source=source)) log.debug('get_source_by_id() returning one entry for "{source}""'.format(source=source))
return source_entry return source_entry
@ -430,8 +429,8 @@ class ProjectorDB(Manager):
if source_entry is None: if source_entry is None:
# Not found # Not found
log.warn('get_source_by_id() not found') log.warning('get_source_by_id() not found')
log.warn('code="{code}" projector_id="{data}"'.format(code=code, data=projector_id)) log.warning('code="{code}" projector_id="{data}"'.format(code=code, data=projector_id))
return None return None
log.debug('get_source_by_id() returning one entry') log.debug('get_source_by_id() returning one entry')
log.debug('code="{code}" projector_id="{data}"'.format(code=code, data=projector_id)) log.debug('code="{code}" projector_id="{data}"'.format(code=code, data=projector_id))

View File

@ -58,7 +58,7 @@ SocketSTate = QAbstractSocket.SocketState
PJLINK_PREFIX = '%' PJLINK_PREFIX = '%'
PJLINK_CLASS = '1' PJLINK_CLASS = '1'
PJLINK_HEADER = '%s%s' % (PJLINK_PREFIX, PJLINK_CLASS) PJLINK_HEADER = '{prefix}{linkclass}'.format(prefix=PJLINK_PREFIX, linkclass=PJLINK_CLASS)
PJLINK_SUFFIX = CR PJLINK_SUFFIX = CR
@ -160,8 +160,10 @@ class PJLink1(QTcpSocket):
self.source = None self.source = None
self.other_info = None self.other_info = None
if hasattr(self, 'timer'): if hasattr(self, 'timer'):
log.debug('({ip}): Calling timer.stop()'.format(ip=self.ip))
self.timer.stop() self.timer.stop()
if hasattr(self, 'socket_timer'): if hasattr(self, 'socket_timer'):
log.debug('({ip}): Calling socket_timer.stop()'.format(ip=self.ip))
self.socket_timer.stop() self.socket_timer.stop()
self.send_queue = [] self.send_queue = []
self.send_busy = False self.send_busy = False
@ -295,6 +297,8 @@ class PJLink1(QTcpSocket):
Processes the initial connection and authentication (if needed). Processes the initial connection and authentication (if needed).
Starts poll timer if connection is established. Starts poll timer if connection is established.
NOTE: Qt md5 hash function doesn't work with projector authentication. Use the python md5 hash function.
:param data: Optional data if called from another routine :param data: Optional data if called from another routine
""" """
log.debug('({ip}) check_login(data="{data}")'.format(ip=self.ip, data=data)) log.debug('({ip}) check_login(data="{data}")'.format(ip=self.ip, data=data))
@ -308,10 +312,10 @@ class PJLink1(QTcpSocket):
read = self.readLine(self.maxSize) read = self.readLine(self.maxSize)
dontcare = self.readLine(self.maxSize) # Clean out the trailing \r\n dontcare = self.readLine(self.maxSize) # Clean out the trailing \r\n
if read is None: if read is None:
log.warn('({ip}) read is None - socket error?'.format(ip=self.ip)) log.warning('({ip}) read is None - socket error?'.format(ip=self.ip))
return return
elif len(read) < 8: elif len(read) < 8:
log.warn('({ip}) Not enough data read)'.format(ip=self.ip)) log.warning('({ip}) Not enough data read)'.format(ip=self.ip))
return return
data = decode(read, 'ascii') data = decode(read, 'ascii')
# Possibility of extraneous data on input when reading. # Possibility of extraneous data on input when reading.
@ -342,23 +346,33 @@ class PJLink1(QTcpSocket):
return return
elif data_check[1] == '0' and self.pin is not None: elif data_check[1] == '0' and self.pin is not None:
# Pin set and no authentication needed # Pin set and no authentication needed
log.warning('({ip}) Regular connection but PIN set'.format(ip=self.name))
self.disconnect_from_host() self.disconnect_from_host()
self.change_status(E_AUTHENTICATION) self.change_status(E_AUTHENTICATION)
log.debug('({ip}) emitting projectorNoAuthentication() signal'.format(ip=self.name)) log.debug('({ip}) Emitting projectorNoAuthentication() signal'.format(ip=self.name))
self.projectorNoAuthentication.emit(self.name) self.projectorNoAuthentication.emit(self.name)
return return
elif data_check[1] == '1': elif data_check[1] == '1':
# Authenticated login with salt # Authenticated login with salt
log.debug('({ip}) Setting hash with salt="{data}"'.format(ip=self.ip, data=data_check[2])) if self.pin is None:
log.debug('({ip}) pin="{data}"'.format(ip=self.ip, data=self.pin)) log.warning('({ip}) Authenticated connection but no pin set'.format(ip=self.name))
salt = qmd5_hash(salt=data_check[2].encode('ascii'), data=self.pin.encode('ascii')) self.disconnect_from_host()
self.change_status(E_AUTHENTICATION)
log.debug('({ip}) Emitting projectorAuthentication() signal'.format(ip=self.name))
self.projectorAuthentication.emit(self.name)
return
else:
log.debug('({ip}) Setting hash with salt="{data}"'.format(ip=self.ip, data=data_check[2]))
log.debug('({ip}) pin="{data}"'.format(ip=self.ip, data=self.pin))
data_hash = str(qmd5_hash(salt=data_check[2].encode('utf-8'), data=self.pin.encode('utf-8')),
encoding='ascii')
else: else:
salt = None data_hash = None
# We're connected at this point, so go ahead and do regular I/O # We're connected at this point, so go ahead and setup regular I/O
self.readyRead.connect(self.get_data) self.readyRead.connect(self.get_data)
self.projectorReceivedData.connect(self._send_command) self.projectorReceivedData.connect(self._send_command)
# Initial data we should know about # Initial data we should know about
self.send_command(cmd='CLSS', salt=salt) self.send_command(cmd='CLSS', salt=data_hash)
self.waitForReadyRead() self.waitForReadyRead()
if (not self.no_poll) and (self.state() == self.ConnectedState): if (not self.no_poll) and (self.state() == self.ConnectedState):
log.debug('({ip}) Starting timer'.format(ip=self.ip)) log.debug('({ip}) Starting timer'.format(ip=self.ip))
@ -400,7 +414,7 @@ class PJLink1(QTcpSocket):
self.projectorReceivedData.emit() self.projectorReceivedData.emit()
return return
elif '=' not in data: elif '=' not in data:
log.warn('({ip}) get_data(): Invalid packet received'.format(ip=self.ip)) log.warning('({ip}) get_data(): Invalid packet received'.format(ip=self.ip))
self.send_busy = False self.send_busy = False
self.projectorReceivedData.emit() self.projectorReceivedData.emit()
return return
@ -408,15 +422,15 @@ class PJLink1(QTcpSocket):
try: try:
(prefix, class_, cmd, data) = (data_split[0][0], data_split[0][1], data_split[0][2:], data_split[1]) (prefix, class_, cmd, data) = (data_split[0][0], data_split[0][1], data_split[0][2:], data_split[1])
except ValueError as e: except ValueError as e:
log.warn('({ip}) get_data(): Invalid packet - expected header + command + data'.format(ip=self.ip)) log.warning('({ip}) get_data(): Invalid packet - expected header + command + data'.format(ip=self.ip))
log.warn('({ip}) get_data(): Received data: "{data}"'.format(ip=self.ip, data=data_in.strip())) log.warning('({ip}) get_data(): Received data: "{data}"'.format(ip=self.ip, data=data_in.strip()))
self.change_status(E_INVALID_DATA) self.change_status(E_INVALID_DATA)
self.send_busy = False self.send_busy = False
self.projectorReceivedData.emit() self.projectorReceivedData.emit()
return return
if not (self.pjlink_class in PJLINK_VALID_CMD and cmd in PJLINK_VALID_CMD[self.pjlink_class]): if not (self.pjlink_class in PJLINK_VALID_CMD and cmd in PJLINK_VALID_CMD[self.pjlink_class]):
log.warn('({ip}) get_data(): Invalid packet - unknown command "{data}"'.format(ip=self.ip, data=cmd)) log.warning('({ip}) get_data(): Invalid packet - unknown command "{data}"'.format(ip=self.ip, data=cmd))
self.send_busy = False self.send_busy = False
self.projectorReceivedData.emit() self.projectorReceivedData.emit()
return return
@ -459,7 +473,7 @@ class PJLink1(QTcpSocket):
:param queue: Option to force add to queue rather than sending directly :param queue: Option to force add to queue rather than sending directly
""" """
if self.state() != self.ConnectedState: if self.state() != self.ConnectedState:
log.warn('({ip}) send_command(): Not connected - returning'.format(ip=self.ip)) log.warning('({ip}) send_command(): Not connected - returning'.format(ip=self.ip))
self.send_queue = [] self.send_queue = []
return return
self.projectorNetwork.emit(S_NETWORK_SENDING) self.projectorNetwork.emit(S_NETWORK_SENDING)
@ -575,7 +589,7 @@ class PJLink1(QTcpSocket):
if cmd in self.PJLINK1_FUNC: if cmd in self.PJLINK1_FUNC:
self.PJLINK1_FUNC[cmd](data) self.PJLINK1_FUNC[cmd](data)
else: else:
log.warn('({ip}) Invalid command {data}'.format(ip=self.ip, data=cmd)) log.warning('({ip}) Invalid command {data}'.format(ip=self.ip, data=cmd))
self.send_busy = False self.send_busy = False
self.projectorReceivedData.emit() self.projectorReceivedData.emit()
@ -594,7 +608,7 @@ class PJLink1(QTcpSocket):
fill = {'Hours': int(data_dict[0]), 'On': False if data_dict[1] == '0' else True} fill = {'Hours': int(data_dict[0]), 'On': False if data_dict[1] == '0' else True}
except ValueError: except ValueError:
# In case of invalid entry # In case of invalid entry
log.warn('({ip}) process_lamp(): Invalid data "{data}"'.format(ip=self.ip, data=data)) log.warning('({ip}) process_lamp(): Invalid data "{data}"'.format(ip=self.ip, data=data))
return return
lamps.append(fill) lamps.append(fill)
data_dict.pop(0) # Remove lamp hours data_dict.pop(0) # Remove lamp hours
@ -621,7 +635,7 @@ class PJLink1(QTcpSocket):
self.send_command('INST') self.send_command('INST')
else: else:
# Log unknown status response # Log unknown status response
log.warn('({ip}) Unknown power response: {data}'.format(ip=self.ip, data=data)) log.warning('({ip}) Unknown power response: {data}'.format(ip=self.ip, data=data))
return return
def process_avmt(self, data): def process_avmt(self, data):
@ -646,7 +660,7 @@ class PJLink1(QTcpSocket):
shutter = True shutter = True
mute = True mute = True
else: else:
log.warn('({ip}) Unknown shutter response: {data}'.format(ip=self.ip, data=data)) log.warning('({ip}) Unknown shutter response: {data}'.format(ip=self.ip, data=data))
update_icons = shutter != self.shutter update_icons = shutter != self.shutter
update_icons = update_icons or mute != self.mute update_icons = update_icons or mute != self.mute
self.shutter = shutter self.shutter = shutter
@ -795,7 +809,7 @@ class PJLink1(QTcpSocket):
Initiate connection to projector. Initiate connection to projector.
""" """
if self.state() == self.ConnectedState: if self.state() == self.ConnectedState:
log.warn('({ip}) connect_to_host(): Already connected - returning'.format(ip=self.ip)) log.warning('({ip}) connect_to_host(): Already connected - returning'.format(ip=self.ip))
return return
self.change_status(S_CONNECTING) self.change_status(S_CONNECTING)
self.connectToHost(self.ip, self.port if type(self.port) is int else int(self.port)) self.connectToHost(self.ip, self.port if type(self.port) is int else int(self.port))
@ -807,9 +821,9 @@ class PJLink1(QTcpSocket):
""" """
if abort or self.state() != self.ConnectedState: if abort or self.state() != self.ConnectedState:
if abort: if abort:
log.warn('({ip}) disconnect_from_host(): Aborting connection'.format(ip=self.ip)) log.warning('({ip}) disconnect_from_host(): Aborting connection'.format(ip=self.ip))
else: else:
log.warn('({ip}) disconnect_from_host(): Not connected - returning'.format(ip=self.ip)) log.warning('({ip}) disconnect_from_host(): Not connected - returning'.format(ip=self.ip))
self.reset_information() self.reset_information()
self.disconnectFromHost() self.disconnectFromHost()
try: try:

View File

@ -531,7 +531,7 @@ def words_split(line):
:param line: Line to be split :param line: Line to be split
""" """
# this parse we are to be wordy # this parse we are to be wordy
return re.split('\s+', line) return re.split(r'\s+', line)
def get_start_tags(raw_text): def get_start_tags(raw_text):

View File

@ -34,7 +34,7 @@ import ntpath
from PyQt5 import QtGui from PyQt5 import QtGui
from openlp.core.common import RegistryProperties, Settings, translate, AppLocation, md5_hash from openlp.core.common import RegistryProperties, Settings, translate, AppLocation, md5_hash
from openlp.core.lib import ImageSource, build_icon, clean_tags, expand_tags, create_thumb from openlp.core.lib import ImageSource, build_icon, clean_tags, expand_tags
log = logging.getLogger(__name__) log = logging.getLogger(__name__)

View File

@ -23,7 +23,6 @@
Provide the theme XML and handling functions for OpenLP v2 themes. Provide the theme XML and handling functions for OpenLP v2 themes.
""" """
import os import os
import re
import logging import logging
import json import json
@ -165,6 +164,7 @@ class ThemeXML(object):
jsn = get_text_file_string(json_file) jsn = get_text_file_string(json_file)
jsn = json.loads(jsn) jsn = json.loads(jsn)
self.expand_json(jsn) self.expand_json(jsn)
self.background_filename = None
def expand_json(self, var, prev=None): def expand_json(self, var, prev=None):
""" """
@ -474,15 +474,16 @@ class ThemeXML(object):
if element.startswith('shadow') or element.startswith('outline'): if element.startswith('shadow') or element.startswith('outline'):
master = 'font_main' master = 'font_main'
# fix bold font # fix bold font
ret_value = None
if element == 'weight': if element == 'weight':
element = 'bold' element = 'bold'
if value == 'Normal': if value == 'Normal':
value = False ret_value = False
else: else:
value = True ret_value = True
if element == 'proportion': if element == 'proportion':
element = 'size' element = 'size'
return False, master, element, value return False, master, element, ret_value if ret_value is not None else value
def _create_attr(self, master, element, value): def _create_attr(self, master, element, value):
""" """

View File

@ -179,5 +179,4 @@ def get_web_page(url, header=None, update_openlp=False):
return page return page
__all__ = ['get_application_version', 'check_latest_version', __all__ = ['get_web_page']
'get_web_page']

View File

@ -88,7 +88,7 @@ class UiAboutDialog(object):
:param about_dialog: The QDialog object to translate :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( self.about_text_edit.setPlainText(
translate('OpenLP.AboutForm', translate('OpenLP.AboutForm',
'OpenLP <version><revision> - Open Source Lyrics Projection\n' 'OpenLP <version><revision> - Open Source Lyrics Projection\n'
@ -200,115 +200,115 @@ class UiAboutDialog(object):
' bring this software to you for free because\n' ' bring this software to you for free because\n'
' He has set us free.') ' He has set us free.')
self.credits_text_edit.setPlainText( self.credits_text_edit.setPlainText(
'%s\n' '{titleLead}\n'
' %s\n' ' {nameLead}\n'
'\n' '\n'
'%s\n' '{titleDevs}\n'
' %s\n' ' {nameDevs}\n'
'\n' '\n'
'%s\n' '{titleContrib}\n'
' %s\n' ' {nameContrib}\n'
'\n' '\n'
'%s\n' '{titleTesters}\n'
' %s\n' ' {nameTesters}\n'
'\n' '\n'
'%s\n' '{titlePackagers}\n'
' %s\n' ' {namePackagers}\n'
'\n' '\n'
'%s\n' '{titleTranslators}\n'
' %s\n' ' {titleAF}\n'
' %s\n' ' {nameAF}\n'
' %s\n' ' {titleCS}\n'
' %s\n' ' {nameCS}\n'
' %s\n' ' {titleDA}\n'
' %s\n' ' {nameDA}\n'
' %s\n' ' {titleDE}\n'
' %s\n' ' {nameDE}\n'
' %s\n' ' {titleEL}\n'
' %s\n' ' {nameEL}\n'
' %s\n' ' {titleGB}\n'
' %s\n' ' {nameGB}\n'
' %s\n' ' {titleENZA}\n'
' %s\n' ' {nameENZA}\n'
' %s\n' ' {titleES}\n'
' %s\n' ' {nameES}\n'
' %s\n' ' {titleET}\n'
' %s\n' ' {nameET}\n'
' %s\n' ' {titleFI}\n'
' %s\n' ' {nameFI}\n'
' %s\n' ' {titleFR}\n'
' %s\n' ' {nameFR}\n'
' %s\n' ' {titleHU}\n'
' %s\n' ' {nameHU}\n'
' %s\n' ' {titleIND}\n'
' %s\n' ' {nameIND}\n'
' %s\n' ' {titleJA}\n'
' %s\n' ' {nameJA}\n'
' %s\n' ' {titleNB}\n'
' %s\n' ' {nameNB}\n'
' %s\n' ' {titleNL}\n'
' %s\n' ' {nameNL}\n'
' %s\n' ' {titlePL}\n'
' %s\n' ' {namePL}\n'
' %s\n' ' {titlePTBR}\n'
' %s\n' ' {namePTBR}\n'
' %s\n' ' {titleRU}\n'
' %s\n' ' {nameRU}\n'
' %s\n' ' {titleSV}\n'
' %s\n' ' {nameSV}\n'
' %s\n' ' {titleTALK}\n'
' %s\n' ' {nameTALK}\n'
' %s\n' ' {titleZHCN}\n'
' %s\n' ' {nameZHCN}\n'
'\n' '\n'
'%s\n' '{titleDOCS}\n'
' %s\n' ' {nameDOCS}\n'
'\n' '\n'
'%s\n%s' % '{build}\n{final}'.format(titleLead=project_lead, nameLead=lead,
(project_lead, lead, titleDevs=devs, nameDevs='\n '.join(developers),
devs, '\n '.join(developers), titleContrib=cons, nameContrib='\n '.join(contributors),
cons, '\n '.join(contributors), titleTesters=tests, nameTesters='\n '.join(testers),
tests, '\n '.join(testers), titlePackagers=packs, namePackagers='\n '.join(packagers),
packs, '\n '.join(packagers), titleTranslators=laters,
laters, titleAF=af, nameAF='\n '.join(translators['af']),
af, '\n '.join(translators['af']), titleCS=cs, nameCS='\n '.join(translators['cs']),
cs, '\n '.join(translators['cs']), titleDA=da, nameDA='\n '.join(translators['da']),
da, '\n '.join(translators['da']), titleDE=de, nameDE='\n '.join(translators['de']),
de, '\n '.join(translators['de']), titleEL=el, nameEL='\n '.join(translators['el']),
el, '\n '.join(translators['el']), titleGB=gb, nameGB='\n '.join(translators['en_GB']),
gb, '\n '.join(translators['en_GB']), titleENZA=enza, nameENZA='\n '.join(translators['en_ZA']),
enza, '\n '.join(translators['en_ZA']), titleES=es, nameES='\n '.join(translators['es']),
es, '\n '.join(translators['es']), titleET=et, nameET='\n '.join(translators['et']),
et, '\n '.join(translators['et']), titleFI=fi, nameFI='\n '.join(translators['fi']),
fi, '\n '.join(translators['fi']), titleFR=fr, nameFR='\n '.join(translators['fr']),
fr, '\n '.join(translators['fr']), titleHU=hu, nameHU='\n '.join(translators['hu']),
hu, '\n '.join(translators['hu']), titleIND=ind, nameIND='\n '.join(translators['id']),
ind, '\n '.join(translators['id']), titleJA=ja, nameJA='\n '.join(translators['ja']),
ja, '\n '.join(translators['ja']), titleNB=nb, nameNB='\n '.join(translators['nb']),
nb, '\n '.join(translators['nb']), titleNL=nl, nameNL='\n '.join(translators['nl']),
nl, '\n '.join(translators['nl']), titlePL=pl, namePL='\n '.join(translators['pl']),
pl, '\n '.join(translators['pl']), titlePTBR=ptbr, namePTBR='\n '.join(translators['pt_BR']),
ptbr, '\n '.join(translators['pt_BR']), titleRU=ru, nameRU='\n '.join(translators['ru']),
ru, '\n '.join(translators['ru']), titleSV=sv, nameSV='\n '.join(translators['sv']),
sv, '\n '.join(translators['sv']), titleTALK=talk, nameTALK='\n '.join(translators['ta_LK']),
talk, '\n '.join(translators['ta_LK']), titleZHCN=zhcn, nameZHCN='\n '.join(translators['zh_CN']),
zhcn, '\n '.join(translators['zh_CN']), titleDOCS=documentation, nameDOCS='\n '.join(documentors),
documentation, '\n '.join(documentors), build=built_with,
built_with, final_credit)) final=final_credit))
self.about_notebook.setTabText(self.about_notebook.indexOf(self.credits_tab), self.about_notebook.setTabText(self.about_notebook.indexOf(self.credits_tab),
translate('OpenLP.AboutForm', 'Credits')) 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_note = translate('OpenLP.AboutForm',
'Copyright \xa9 2004-2016 %s\n' 'Copyright \xa9 2004-2016 {cr}\n\n'
'Portions copyright \xa9 2004-2016 %s') % \ 'Portions copyright \xa9 2004-2016 {others}').format(cr='Raoul Snyman',
('Raoul Snyman', others=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, Simon Scudder, Jeffrey Smith, Maikel Stuivenberg, '
'Martin Thompson, Jon Tibble, Dave Warnock, Frode Woldsund, '
'Martin Zibricky, Patrick Zimmermann')
licence = translate('OpenLP.AboutForm', licence = translate('OpenLP.AboutForm',
'This program is free software; you can redistribute it and/or ' 'This program is free software; you can redistribute it and/or '
'modify it under the terms of the GNU General Public License as ' '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 ' 'linking proprietary applications with the library. If this is '
'what you want to do, use the GNU Lesser General Public License ' 'what you want to do, use the GNU Lesser General Public License '
'instead of this 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), self.about_notebook.setTabText(self.about_notebook.indexOf(self.license_tab),
translate('OpenLP.AboutForm', 'License')) translate('OpenLP.AboutForm', 'License'))
self.volunteer_button.setText(translate('OpenLP.AboutForm', 'Volunteer')) 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 = self.about_text_edit.toPlainText()
about_text = about_text.replace('<version>', application_version['version']) about_text = about_text.replace('<version>', application_version['version'])
if application_version['build']: 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: else:
build_text = '' build_text = ''
about_text = about_text.replace('<revision>', build_text) about_text = about_text.replace('<revision>', build_text)

View File

@ -87,11 +87,14 @@ class AdvancedTab(SettingsTab):
self.ui_layout.addRow(self.expand_service_item_check_box) self.ui_layout.addRow(self.expand_service_item_check_box)
self.slide_max_height_label = QtWidgets.QLabel(self.ui_group_box) self.slide_max_height_label = QtWidgets.QLabel(self.ui_group_box)
self.slide_max_height_label.setObjectName('slide_max_height_label') self.slide_max_height_label.setObjectName('slide_max_height_label')
self.slide_max_height_spin_box = QtWidgets.QSpinBox(self.ui_group_box) self.slide_max_height_combo_box = QtWidgets.QComboBox(self.ui_group_box)
self.slide_max_height_spin_box.setObjectName('slide_max_height_spin_box') self.slide_max_height_combo_box.addItem('', userData=0)
self.slide_max_height_spin_box.setRange(0, 1000) self.slide_max_height_combo_box.addItem('', userData=-4)
self.slide_max_height_spin_box.setSingleStep(20) # Generate numeric values for combo box dynamically
self.ui_layout.addRow(self.slide_max_height_label, self.slide_max_height_spin_box) for px in range(60, 801, 5):
self.slide_max_height_combo_box.addItem(str(px) + 'px', userData=px)
self.slide_max_height_combo_box.setObjectName('slide_max_height_combo_box')
self.ui_layout.addRow(self.slide_max_height_label, self.slide_max_height_combo_box)
self.autoscroll_label = QtWidgets.QLabel(self.ui_group_box) self.autoscroll_label = QtWidgets.QLabel(self.ui_group_box)
self.autoscroll_label.setObjectName('autoscroll_label') self.autoscroll_label.setObjectName('autoscroll_label')
self.autoscroll_combo_box = QtWidgets.QComboBox(self.ui_group_box) self.autoscroll_combo_box = QtWidgets.QComboBox(self.ui_group_box)
@ -265,7 +268,8 @@ class AdvancedTab(SettingsTab):
'Expand new Service items on creation')) 'Expand new Service items on creation'))
self.slide_max_height_label.setText(translate('OpenLP.AdvancedTab', self.slide_max_height_label.setText(translate('OpenLP.AdvancedTab',
'Max height for non-text slides\nin slide controller:')) 'Max height for non-text slides\nin slide controller:'))
self.slide_max_height_spin_box.setSpecialValueText(translate('OpenLP.AdvancedTab', 'Disabled')) self.slide_max_height_combo_box.setItemText(0, translate('OpenLP.AdvancedTab', 'Disabled'))
self.slide_max_height_combo_box.setItemText(1, translate('OpenLP.AdvancedTab', 'Automatic'))
self.autoscroll_label.setText(translate('OpenLP.AdvancedTab', self.autoscroll_label.setText(translate('OpenLP.AdvancedTab',
'When changing slides:')) 'When changing slides:'))
self.autoscroll_combo_box.setItemText(0, translate('OpenLP.AdvancedTab', 'Do not auto-scroll')) self.autoscroll_combo_box.setItemText(0, translate('OpenLP.AdvancedTab', 'Do not auto-scroll'))
@ -308,8 +312,8 @@ class AdvancedTab(SettingsTab):
self.service_name_label.setText(translate('OpenLP.AdvancedTab', 'Name:')) 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_edit.setToolTip(translate('OpenLP.AdvancedTab', 'Consult the OpenLP manual for usage.'))
self.service_name_revert_button.setToolTip( self.service_name_revert_button.setToolTip(
translate('OpenLP.AdvancedTab', 'Revert to the default service name "%s".') % translate('OpenLP.AdvancedTab',
UiStrings().DefaultServiceName) 'Revert to the default service name "{name}".').format(name=UiStrings().DefaultServiceName))
self.service_name_example_label.setText(translate('OpenLP.AdvancedTab', 'Example:')) self.service_name_example_label.setText(translate('OpenLP.AdvancedTab', 'Example:'))
self.hide_mouse_group_box.setTitle(translate('OpenLP.AdvancedTab', 'Mouse Cursor')) 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')) self.hide_mouse_check_box.setText(translate('OpenLP.AdvancedTab', 'Hide mouse cursor when over display window'))
@ -355,10 +359,13 @@ class AdvancedTab(SettingsTab):
self.single_click_preview_check_box.setChecked(settings.value('single click preview')) self.single_click_preview_check_box.setChecked(settings.value('single click preview'))
self.single_click_service_preview_check_box.setChecked(settings.value('single click service preview')) self.single_click_service_preview_check_box.setChecked(settings.value('single click service preview'))
self.expand_service_item_check_box.setChecked(settings.value('expand service item')) self.expand_service_item_check_box.setChecked(settings.value('expand service item'))
self.slide_max_height_spin_box.setValue(settings.value('slide max height')) slide_max_height_value = settings.value('slide max height')
for i in range(0, self.slide_max_height_combo_box.count()):
if self.slide_max_height_combo_box.itemData(i) == slide_max_height_value:
self.slide_max_height_combo_box.setCurrentIndex(i)
autoscroll_value = settings.value('autoscrolling') autoscroll_value = settings.value('autoscrolling')
for i in range(0, len(self.autoscroll_map)): for i in range(0, len(self.autoscroll_map)):
if self.autoscroll_map[i] == autoscroll_value: if self.autoscroll_map[i] == autoscroll_value and i < self.autoscroll_combo_box.count():
self.autoscroll_combo_box.setCurrentIndex(i) self.autoscroll_combo_box.setCurrentIndex(i)
self.enable_auto_close_check_box.setChecked(settings.value('enable exit confirmation')) self.enable_auto_close_check_box.setChecked(settings.value('enable exit confirmation'))
self.hide_mouse_check_box.setChecked(settings.value('hide mouse')) self.hide_mouse_check_box.setChecked(settings.value('hide mouse'))
@ -391,16 +398,16 @@ class AdvancedTab(SettingsTab):
# Since data location can be changed, make sure the path is present. # Since data location can be changed, make sure the path is present.
self.current_data_path = AppLocation.get_data_path() self.current_data_path = AppLocation.get_data_path()
if not os.path.exists(self.current_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( answer = QtWidgets.QMessageBox.critical(
self, translate('OpenLP.AdvancedTab', 'Data Directory Error'), 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 ' 'This data directory was previously changed from the OpenLP '
'default location. If the new location was on removable ' 'default location. If the new location was on removable '
'media, that media needs to be made available.\n\n' '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 "No" to stop loading OpenLP. allowing you to fix the the problem.\n\n'
'Click "Yes" to reset the data directory to the default ' '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.StandardButtons(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No),
QtWidgets.QMessageBox.No) QtWidgets.QMessageBox.No)
if answer == QtWidgets.QMessageBox.No: if answer == QtWidgets.QMessageBox.No:
@ -410,7 +417,7 @@ class AdvancedTab(SettingsTab):
# Set data location to default. # Set data location to default.
settings.remove('advanced/data path') settings.remove('advanced/data path')
self.current_data_path = AppLocation.get_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)) self.data_directory_label.setText(os.path.abspath(self.current_data_path))
# Don't allow data directory move if running portable. # Don't allow data directory move if running portable.
if settings.value('advanced/is portable'): if settings.value('advanced/is portable'):
@ -439,7 +446,9 @@ class AdvancedTab(SettingsTab):
settings.setValue('single click preview', self.single_click_preview_check_box.isChecked()) settings.setValue('single click preview', self.single_click_preview_check_box.isChecked())
settings.setValue('single click service preview', self.single_click_service_preview_check_box.isChecked()) settings.setValue('single click service preview', self.single_click_service_preview_check_box.isChecked())
settings.setValue('expand service item', self.expand_service_item_check_box.isChecked()) settings.setValue('expand service item', self.expand_service_item_check_box.isChecked())
settings.setValue('slide max height', self.slide_max_height_spin_box.value()) slide_max_height_index = self.slide_max_height_combo_box.currentIndex()
slide_max_height_value = self.slide_max_height_combo_box.itemData(slide_max_height_index)
settings.setValue('slide max height', slide_max_height_value)
settings.setValue('autoscrolling', self.autoscroll_map[self.autoscroll_combo_box.currentIndex()]) settings.setValue('autoscrolling', self.autoscroll_map[self.autoscroll_combo_box.currentIndex()])
settings.setValue('enable exit confirmation', self.enable_auto_close_check_box.isChecked()) settings.setValue('enable exit confirmation', self.enable_auto_close_check_box.isChecked())
settings.setValue('hide mouse', self.hide_mouse_check_box.isChecked()) settings.setValue('hide mouse', self.hide_mouse_check_box.isChecked())
@ -542,9 +551,9 @@ class AdvancedTab(SettingsTab):
# Make sure they want to change the data. # Make sure they want to change the data.
answer = QtWidgets.QMessageBox.question(self, translate('OpenLP.AdvancedTab', 'Confirm Data Directory Change'), answer = QtWidgets.QMessageBox.question(self, translate('OpenLP.AdvancedTab', 'Confirm Data Directory Change'),
translate('OpenLP.AdvancedTab', 'Are you sure you want to change the ' translate('OpenLP.AdvancedTab', 'Are you sure you want to change the '
'location of the OpenLP data directory to:\n\n%s\n\nThe data ' 'location of the OpenLP data directory to:\n\n{path}'
'directory will be changed when OpenLP is closed.'). '\n\nThe data directory will be changed when OpenLP is '
replace('%s', new_data_path), 'closed.').format(path=new_data_path),
QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes |
QtWidgets.QMessageBox.No), QtWidgets.QMessageBox.No),
QtWidgets.QMessageBox.No) QtWidgets.QMessageBox.No)
@ -608,10 +617,10 @@ class AdvancedTab(SettingsTab):
answer = QtWidgets.QMessageBox.warning(self, answer = QtWidgets.QMessageBox.warning(self,
translate('OpenLP.AdvancedTab', 'Overwrite Existing Data'), translate('OpenLP.AdvancedTab', 'Overwrite Existing Data'),
translate('OpenLP.AdvancedTab', translate('OpenLP.AdvancedTab',
'WARNING: \n\nThe location you have selected \n\n%s\n\n' 'WARNING: \n\nThe location you have selected \n\n{path}'
'appears to contain OpenLP data files. Do you wish to ' '\n\nappears to contain OpenLP data files. Do you wish to '
'replace these files with the current data files?'). 'replace these files with the current data '
replace('%s', os.path.abspath(data_path,)), 'files?').format(path=os.path.abspath(data_path,)),
QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes |
QtWidgets.QMessageBox.No), QtWidgets.QMessageBox.No),
QtWidgets.QMessageBox.No) QtWidgets.QMessageBox.No)

View File

@ -32,8 +32,6 @@ import sqlalchemy
from PyQt5 import Qt, QtCore, QtGui, QtWebKit, QtWidgets from PyQt5 import Qt, QtCore, QtGui, QtWebKit, QtWidgets
from lxml import etree from lxml import etree
from openlp.core.common import RegistryProperties, is_linux
try: try:
import migrate import migrate
MIGRATE_VERSION = getattr(migrate, '__version__', '< 0.7') MIGRATE_VERSION = getattr(migrate, '__version__', '< 0.7')
@ -74,6 +72,7 @@ except ImportError:
from openlp.core.common import Settings, UiStrings, translate from openlp.core.common import Settings, UiStrings, translate
from openlp.core.common.versionchecker import get_application_version from openlp.core.common.versionchecker import get_application_version
from openlp.core.common import RegistryProperties, is_linux
from .exceptiondialog import Ui_ExceptionDialog from .exceptiondialog import Ui_ExceptionDialog
@ -91,6 +90,7 @@ class ExceptionForm(QtWidgets.QDialog, Ui_ExceptionDialog, RegistryProperties):
super(ExceptionForm, self).__init__(None, QtCore.Qt.WindowSystemMenuHint | QtCore.Qt.WindowTitleHint) super(ExceptionForm, self).__init__(None, QtCore.Qt.WindowSystemMenuHint | QtCore.Qt.WindowTitleHint)
self.setupUi(self) self.setupUi(self)
self.settings_section = 'crashreport' 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' \ self.report_text = '**OpenLP Bug Report**\n' \
'Version: %s\n\n' \ 'Version: %s\n\n' \
'--- Details of the Exception. ---\n\n%s\n\n ' \ '--- Details of the Exception. ---\n\n%s\n\n ' \
@ -114,21 +114,17 @@ class ExceptionForm(QtWidgets.QDialog, Ui_ExceptionDialog, RegistryProperties):
openlp_version = get_application_version() openlp_version = get_application_version()
description = self.description_text_edit.toPlainText() description = self.description_text_edit.toPlainText()
traceback = self.exception_text_edit.toPlainText() traceback = self.exception_text_edit.toPlainText()
system = translate('OpenLP.ExceptionForm', 'Platform: %s\n') % platform.platform() system = translate('OpenLP.ExceptionForm', 'Platform: {platform}\n').format(platform=platform.platform())
libraries = 'Python: %s\n' % platform.python_version() + \ libraries = ('Python: {python}\nQt5: {qt5}\nPyQt5: {pyqt5}\nQtWebkit: {qtwebkit}\nSQLAlchemy: {sqalchemy}\n'
'Qt5: %s\n' % Qt.qVersion() + \ 'SQLAlchemy Migrate: {migrate}\nBeautifulSoup: {soup}\nlxml: {etree}\nChardet: {chardet}\n'
'PyQt5: %s\n' % Qt.PYQT_VERSION_STR + \ 'PyEnchant: {enchant}\nMako: {mako}\npyICU: {icu}\npyUNO bridge: {uno}\n'
'QtWebkit: %s\n' % WEBKIT_VERSION + \ 'VLC: {vlc}\n').format(python=platform.python_version(), qt5=Qt.qVersion(),
'SQLAlchemy: %s\n' % sqlalchemy.__version__ + \ pyqt5=Qt.PYQT_VERSION_STR, qtwebkit=WEBKIT_VERSION,
'SQLAlchemy Migrate: %s\n' % MIGRATE_VERSION + \ sqalchemy=sqlalchemy.__version__, migrate=MIGRATE_VERSION,
'BeautifulSoup: %s\n' % bs4.__version__ + \ soup=bs4.__version__, etree=etree.__version__, chardet=CHARDET_VERSION,
'lxml: %s\n' % etree.__version__ + \ enchant=ENCHANT_VERSION, mako=MAKO_VERSION, icu=ICU_VERSION,
'Chardet: %s\n' % CHARDET_VERSION + \ uno=self._pyuno_import(), vlc=VLC_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
if is_linux(): if is_linux():
if os.environ.get('KDE_FULL_SESSION') == 'true': if os.environ.get('KDE_FULL_SESSION') == 'true':
system += 'Desktop: KDE SC\n' system += 'Desktop: KDE SC\n'
@ -178,9 +174,10 @@ class ExceptionForm(QtWidgets.QDialog, Ui_ExceptionDialog, RegistryProperties):
source = re.sub(r'.*[/\\]openlp[/\\](.*)".*', r'\1', line) source = re.sub(r'.*[/\\]openlp[/\\](.*)".*', r'\1', line)
if ':' in line: if ':' in line:
exception = line.split('\n')[-1].split(':')[0] 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 = QtCore.QUrlQuery()
mail_urlquery.addQueryItem('subject', subject) 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) mail_urlquery.addQueryItem('body', self.report_text % content)
if self.file_attachment: if self.file_attachment:
mail_urlquery.addQueryItem('attach', self.file_attachment) mail_urlquery.addQueryItem('attach', self.file_attachment)
@ -211,7 +208,7 @@ class ExceptionForm(QtWidgets.QDialog, Ui_ExceptionDialog, RegistryProperties):
'Select Attachment'), 'Select Attachment'),
Settings().value(self.settings_section + Settings().value(self.settings_section +
'/last directory'), '/last directory'),
'%s (*)' % UiStrings().AllFiles) '{text} (*)'.format(text=UiStrings().AllFiles))
log.info('New files(s) %s', str(files)) log.info('New files(s) %s', str(files))
if files: if files:
self.file_attachment = str(files) self.file_attachment = str(files)

View File

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

View File

@ -228,12 +228,13 @@ class UiFirstTimeWizard(object):
:param first_time_wizard: The wizard form :param first_time_wizard: The wizard form
""" """
first_time_wizard.setWindowTitle(translate('OpenLP.FirstTimeWizard', 'First Time Wizard')) 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>' % text = translate('OpenLP.FirstTimeWizard', 'Welcome to the First Time Wizard')
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( first_time_wizard.information_label.setText(
translate('OpenLP.FirstTimeWizard', 'This wizard will help you to configure OpenLP for initial use. ' translate('OpenLP.FirstTimeWizard', 'This wizard will help you to configure OpenLP for initial use. '
'Click the %s button below to start.') % 'Click the {button} button below to start.').format(button=button))
clean_button_text(first_time_wizard.buttonText(QtWidgets.QWizard.NextButton)))
self.download_page.setTitle(translate('OpenLP.FirstTimeWizard', 'Downloading Resource Index')) self.download_page.setTitle(translate('OpenLP.FirstTimeWizard', 'Downloading Resource Index'))
self.download_page.setSubTitle(translate('OpenLP.FirstTimeWizard', 'Please wait while the resource index is ' self.download_page.setSubTitle(translate('OpenLP.FirstTimeWizard', 'Please wait while the resource index is '
'downloaded.')) 'downloaded.'))
@ -264,18 +265,19 @@ class UiFirstTimeWizard(object):
self.no_internet_page.setTitle(translate('OpenLP.FirstTimeWizard', 'No Internet Connection')) self.no_internet_page.setTitle(translate('OpenLP.FirstTimeWizard', 'No Internet Connection'))
self.no_internet_page.setSubTitle( self.no_internet_page.setSubTitle(
translate('OpenLP.FirstTimeWizard', 'Unable to detect an Internet connection.')) 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', self.no_internet_text = translate('OpenLP.FirstTimeWizard',
'No Internet connection was found. The First Time Wizard needs an Internet ' '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.' '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 ' '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 ' 'data at a later time, check your Internet connection and re-run this '
'wizard by selecting "Tools/Re-run First Time Wizard" from OpenLP.') % \ 'wizard by selecting "Tools/Re-run First Time Wizard" from OpenLP.'
clean_button_text(first_time_wizard.buttonText(QtWidgets.QWizard.FinishButton)) ).format(button=button)
button = clean_button_text(first_time_wizard.buttonText(QtWidgets.QWizard.CancelButton))
self.cancel_wizard_text = translate('OpenLP.FirstTimeWizard', self.cancel_wizard_text = translate('OpenLP.FirstTimeWizard',
'\n\nTo cancel the First Time Wizard completely (and not start OpenLP), ' '\n\nTo cancel the First Time Wizard completely (and not start OpenLP), '
'click the %s button now.') % \ 'click the {button} button now.').format(button=button)
clean_button_text(first_time_wizard.buttonText(QtWidgets.QWizard.CancelButton))
self.songs_page.setTitle(translate('OpenLP.FirstTimeWizard', 'Sample Songs')) self.songs_page.setTitle(translate('OpenLP.FirstTimeWizard', 'Sample Songs'))
self.songs_page.setSubTitle(translate('OpenLP.FirstTimeWizard', 'Select and download public domain songs.')) self.songs_page.setSubTitle(translate('OpenLP.FirstTimeWizard', 'Select and download public domain songs.'))
self.bibles_page.setTitle(translate('OpenLP.FirstTimeWizard', 'Sample Bibles')) 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): for line_number, html1 in enumerate(self.protected_tags):
if self._strip(html1['start tag']) == tag: 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: 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): for line_number, html1 in enumerate(self.custom_tags):
if self._strip(html1['start tag']) == tag: 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: 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 = { tag = {
'desc': desc, 'desc': desc,
'start tag': '{%s}' % tag, 'start tag': '{{{tag}}}'.format(tag=tag),
'start html': start_html, 'start html': start_html,
'end tag': '{/%s}' % tag, 'end tag': '{{{tag}}}'.format(tag=tag),
'end html': end_html, 'end html': end_html,
'protected': False, 'protected': False,
'temporary': False 'temporary': False
@ -130,6 +130,7 @@ class FormattingTagController(object):
elif not match.group('empty'): elif not match.group('empty'):
end_tags.append(tag) end_tags.append(tag)
match = self.html_tag_regex.search(start_html, match.end()) 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))) return ''.join(map(lambda tag: '</%s>' % tag, reversed(end_tags)))
def start_tag_changed(self, start_html, end_html): 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) end = self.start_html_to_end_html(start_html)
if not end_html: if not end_html:
if not end: 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, end
return None, None return None, None
@ -165,7 +167,8 @@ class FormattingTagController(object):
if not end_html: if not end_html:
return None, end return None, end
if end and end != end_html: if end and end != end_html:
return translate('OpenLP.FormattingTagForm', return (translate('OpenLP.FormattingTagForm',
'End tag %(end)s does not match end tag for start tag %(start)s') % \ 'End tag {end} does not match end tag for start tag {start}').format(end=end,
{'end': end, 'start': start_html}, None start=start_html),
None)
return None, None return None, None

View File

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

View File

@ -401,7 +401,7 @@ class GeneralTab(SettingsTab):
""" """
Select the logo file 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, filename, filter_used = QtWidgets.QFileDialog.getOpenFileName(self,
translate('OpenLP.AdvancedTab', 'Open File'), '', translate('OpenLP.AdvancedTab', 'Open File'), '',
file_filters) file_filters)

View File

@ -28,6 +28,7 @@ from .dockwidget import OpenLPDockWidget
from .wizard import OpenLPWizard, WizardStrings from .wizard import OpenLPWizard, WizardStrings
from .mediadockmanager import MediaDockManager from .mediadockmanager import MediaDockManager
from .listpreviewwidget import ListPreviewWidget from .listpreviewwidget import ListPreviewWidget
from .spelltextedit import SpellTextEdit
__all__ = ['ColorButton', 'ListPreviewWidget', 'ListWidgetWithDnD', 'OpenLPToolbar', 'OpenLPDockWidget', __all__ = ['ColorButton', 'ListPreviewWidget', 'ListWidgetWithDnD', 'OpenLPToolbar', 'OpenLPDockWidget',
'OpenLPWizard', 'WizardStrings', 'MediaDockManager', 'ListPreviewWidget'] 'OpenLPWizard', 'WizardStrings', 'MediaDockManager', 'ListPreviewWidget', 'SpellTextEdit']

View File

@ -63,6 +63,7 @@ class ListPreviewWidget(QtWidgets.QTableWidget, RegistryProperties):
# Initialize variables. # Initialize variables.
self.service_item = ServiceItem() self.service_item = ServiceItem()
self.screen_ratio = screen_ratio self.screen_ratio = screen_ratio
self.auto_row_height = 100
# Connect signals # Connect signals
self.verticalHeader().sectionResized.connect(self.row_resized) self.verticalHeader().sectionResized.connect(self.row_resized)
@ -87,8 +88,14 @@ class ListPreviewWidget(QtWidgets.QTableWidget, RegistryProperties):
height = self.viewport().width() // self.screen_ratio height = self.viewport().width() // self.screen_ratio
max_img_row_height = Settings().value('advanced/slide max height') max_img_row_height = Settings().value('advanced/slide max height')
# Adjust for row height cap if in use. # Adjust for row height cap if in use.
if isinstance(max_img_row_height, int) and max_img_row_height > 0 and height > max_img_row_height: if isinstance(max_img_row_height, int):
height = max_img_row_height if max_img_row_height > 0 and height > max_img_row_height:
height = max_img_row_height
elif max_img_row_height < 0:
# If auto setting, show that number of slides, or if the resulting slides too small, 100px.
# E.g. If setting is -4, 4 slides will be visible, unless those slides are < 100px high.
self.auto_row_height = max(self.viewport().height() / (-1 * max_img_row_height), 100)
height = min(height, self.auto_row_height)
# Apply new height to slides # Apply new height to slides
for frame_number in range(len(self.service_item.get_frames())): for frame_number in range(len(self.service_item.get_frames())):
self.setRowHeight(frame_number, height) self.setRowHeight(frame_number, height)
@ -99,7 +106,7 @@ class ListPreviewWidget(QtWidgets.QTableWidget, RegistryProperties):
""" """
# Only for non-text slides when row height cap in use # Only for non-text slides when row height cap in use
max_img_row_height = Settings().value('advanced/slide max height') max_img_row_height = Settings().value('advanced/slide max height')
if self.service_item.is_text() or not isinstance(max_img_row_height, int) or max_img_row_height <= 0: if self.service_item.is_text() or not isinstance(max_img_row_height, int) or max_img_row_height == 0:
return return
# Get and validate label widget containing slide & adjust max width # Get and validate label widget containing slide & adjust max width
try: try:
@ -165,11 +172,15 @@ class ListPreviewWidget(QtWidgets.QTableWidget, RegistryProperties):
slide_height = width // self.screen_ratio slide_height = width // self.screen_ratio
# Setup and validate row height cap if in use. # Setup and validate row height cap if in use.
max_img_row_height = Settings().value('advanced/slide max height') max_img_row_height = Settings().value('advanced/slide max height')
if isinstance(max_img_row_height, int) and max_img_row_height > 0: if isinstance(max_img_row_height, int) and max_img_row_height != 0:
if slide_height > max_img_row_height: if max_img_row_height > 0 and slide_height > max_img_row_height:
# Manual Setting
slide_height = max_img_row_height slide_height = max_img_row_height
label.setMaximumWidth(max_img_row_height * self.screen_ratio) elif max_img_row_height < 0 and slide_height > self.auto_row_height:
label.resize(max_img_row_height * self.screen_ratio, max_img_row_height) # Auto Setting
slide_height = self.auto_row_height
label.setMaximumWidth(slide_height * self.screen_ratio)
label.resize(slide_height * self.screen_ratio, slide_height)
# Build widget with stretch padding # Build widget with stretch padding
container = QtWidgets.QWidget() container = QtWidgets.QWidget()
hbox = QtWidgets.QHBoxLayout() hbox = QtWidgets.QHBoxLayout()

View File

@ -142,6 +142,7 @@ class SpellTextEdit(QtWidgets.QPlainTextEdit):
""" """
Replaces the selected text with word. Replaces the selected text with word.
""" """
tag = tag.replace('&', '')
for html in FormattingTags.get_html_tags(): for html in FormattingTags.get_html_tags():
if tag == html['desc']: if tag == html['desc']:
cursor = self.textCursor() cursor = self.textCursor()
@ -163,7 +164,7 @@ class Highlighter(QtGui.QSyntaxHighlighter):
""" """
Provides a text highlighter for pointing out spelling errors in text. Provides a text highlighter for pointing out spelling errors in text.
""" """
WORDS = '(?iu)[\w\']+' WORDS = r'(?iu)[\w\']+'
def __init__(self, *args): def __init__(self, *args):
""" """

View File

@ -33,7 +33,7 @@ import html
import logging import logging
import os import os
from PyQt5 import QtCore, QtWidgets, QtWebKit, QtWebKitWidgets, QtOpenGL, QtGui, QtMultimedia from PyQt5 import QtCore, QtWidgets, QtWebKit, QtWebKitWidgets, QtGui, QtMultimedia
from openlp.core.common import AppLocation, Registry, RegistryProperties, OpenLPMixin, Settings, translate,\ from openlp.core.common import AppLocation, Registry, RegistryProperties, OpenLPMixin, Settings, translate,\
is_macosx, is_win is_macosx, is_win
@ -468,9 +468,9 @@ class MainDisplay(OpenLPMixin, Display, RegistryProperties):
self.service_item.theme_data.background_filename, ImageSource.Theme) self.service_item.theme_data.background_filename, ImageSource.Theme)
if image_path: if image_path:
image_bytes = self.image_manager.get_image_bytes(image_path, ImageSource.ImagePlugin) image_bytes = self.image_manager.get_image_bytes(image_path, ImageSource.ImagePlugin)
html = build_html(self.service_item, self.screen, self.is_live, background, image_bytes, created_html = build_html(self.service_item, self.screen, self.is_live, background, image_bytes,
plugins=self.plugin_manager.plugins) plugins=self.plugin_manager.plugins)
self.web_view.setHtml(html) self.web_view.setHtml(created_html)
if service_item.foot_text: if service_item.foot_text:
self.footer(service_item.foot_text) self.footer(service_item.foot_text)
# if was hidden keep it hidden # if was hidden keep it hidden

View File

@ -46,7 +46,6 @@ from openlp.core.ui.firsttimeform import FirstTimeForm
from openlp.core.ui.media import MediaController from openlp.core.ui.media import MediaController
from openlp.core.ui.printserviceform import PrintServiceForm from openlp.core.ui.printserviceform import PrintServiceForm
from openlp.core.ui.projector.manager import ProjectorManager from openlp.core.ui.projector.manager import ProjectorManager
from openlp.core.ui.lib.toolbar import OpenLPToolbar
from openlp.core.ui.lib.dockwidget import OpenLPDockWidget from openlp.core.ui.lib.dockwidget import OpenLPDockWidget
from openlp.core.ui.lib.mediadockmanager import MediaDockManager from openlp.core.ui.lib.mediadockmanager import MediaDockManager
@ -472,7 +471,8 @@ class Ui_MainWindow(object):
self.web_site_item.setText(translate('OpenLP.MainWindow', '&Web Site')) self.web_site_item.setText(translate('OpenLP.MainWindow', '&Web Site'))
for item in self.language_group.actions(): for item in self.language_group.actions():
item.setText(item.objectName()) 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.setText(translate('OpenLP.MainWindow', '&Autodetect'))
self.auto_language_item.setStatusTip(translate('OpenLP.MainWindow', 'Use the system language, if available.')) 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...')) self.tools_add_tool_item.setText(translate('OpenLP.MainWindow', 'Add &Tool...'))
@ -1337,8 +1337,10 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow, RegistryProperties):
for file_id, filename in enumerate(recent_files_to_display): for file_id, filename in enumerate(recent_files_to_display):
log.debug('Recent file name: {name}'.format(name=filename)) log.debug('Recent file name: {name}'.format(name=filename))
# TODO: Verify ''.format() before committing # TODO: Verify ''.format() before committing
action = create_action(self, '', text='&%d %s' % (file_id + 1, action = create_action(self, '',
os.path.splitext(os.path.basename(str(filename)))[0]), data=filename, 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) triggers=self.service_manager_contents.on_recent_service_clicked)
self.recent_files_menu.addAction(action) self.recent_files_menu.addAction(action)
clear_recent_files_action = create_action(self, '', clear_recent_files_action = create_action(self, '',

View File

@ -24,10 +24,10 @@ The :mod:`~openlp.core.ui.media` module contains classes and objects for media p
""" """
import logging import logging
from openlp.core.common import Settings
from PyQt5 import QtCore from PyQt5 import QtCore
from openlp.core.common import Settings
log = logging.getLogger(__name__ + '.__init__') log = logging.getLogger(__name__ + '.__init__')
@ -134,6 +134,7 @@ def format_milliseconds(milliseconds):
:param milliseconds: Milliseconds to format :param milliseconds: Milliseconds to format
:return: Time string in format: hh.mm.ss,ttt :return: Time string in format: hh.mm.ss,ttt
""" """
milliseconds = int(milliseconds)
seconds, millis = divmod(milliseconds, 1000) seconds, millis = divmod(milliseconds, 1000)
minutes, seconds = divmod(seconds, 60) minutes, seconds = divmod(seconds, 60)
hours, minutes = divmod(minutes, 60) hours, minutes = divmod(minutes, 60)

View File

@ -38,7 +38,6 @@ from openlp.core.ui.media.mediaplayer import MediaPlayer
from openlp.core.ui.media import MediaState, MediaInfo, MediaType, get_media_players, set_media_players,\ from openlp.core.ui.media import MediaState, MediaInfo, MediaType, get_media_players, set_media_players,\
parse_optical_path parse_optical_path
from openlp.core.ui.lib.toolbar import OpenLPToolbar from openlp.core.ui.lib.toolbar import OpenLPToolbar
from openlp.core.ui.lib.dockwidget import OpenLPDockWidget
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -175,7 +174,7 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties):
log.debug('_check_available_media_players') log.debug('_check_available_media_players')
controller_dir = os.path.join(AppLocation.get_directory(AppLocation.AppDir), 'core', 'ui', 'media') controller_dir = os.path.join(AppLocation.get_directory(AppLocation.AppDir), 'core', 'ui', 'media')
for filename in os.listdir(controller_dir): for filename in os.listdir(controller_dir):
if filename.endswith('player.py') and not filename == 'mediaplayer.py': if filename.endswith('player.py') and filename != 'mediaplayer.py':
path = os.path.join(controller_dir, filename) path = os.path.join(controller_dir, filename)
if os.path.isfile(path): if os.path.isfile(path):
module_name = 'openlp.core.ui.media.' + os.path.splitext(filename)[0] module_name = 'openlp.core.ui.media.' + os.path.splitext(filename)[0]
@ -554,7 +553,7 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties):
default_player = [used_players[0]] default_player = [used_players[0]]
if service_item.processor and service_item.processor != UiStrings().Automatic: if service_item.processor and service_item.processor != UiStrings().Automatic:
# check to see if the player is usable else use the default one. # check to see if the player is usable else use the default one.
if not service_item.processor.lower() in used_players: if service_item.processor.lower() not in used_players:
used_players = default_player used_players = default_player
else: else:
used_players = [service_item.processor.lower()] used_players = [service_item.processor.lower()]

View File

@ -224,9 +224,11 @@ class PlayerTab(SettingsTab):
self.settings_form.register_post_process('mediaitem_media_rebuild') self.settings_form.register_post_process('mediaitem_media_rebuild')
self.settings_form.register_post_process('config_screen_changed') self.settings_form.register_post_process('config_screen_changed')
def post_set_up(self): def post_set_up(self, post_update=False):
""" """
Late setup for players as the MediaController has to be initialised first. Late setup for players as the MediaController has to be initialised first.
:param post_update: Indicates if called before or after updates.
""" """
for key, player in self.media_players.items(): for key, player in self.media_players.items():
player = self.media_players[key] player = self.media_players[key]

View File

@ -112,7 +112,6 @@ def get_vlc():
# This needs to happen on module load and not in get_vlc(), otherwise it can cause crashes on some DE on some setups # This needs to happen on module load and not in get_vlc(), otherwise it can cause crashes on some DE on some setups
# (reported on Gnome3, Unity, Cinnamon, all GTK+ based) when using native filedialogs... # (reported on Gnome3, Unity, Cinnamon, all GTK+ based) when using native filedialogs...
if is_linux() and 'nose' not in sys.argv[0] and get_vlc(): if is_linux() and 'nose' not in sys.argv[0] and get_vlc():
import ctypes
try: try:
try: try:
x11 = ctypes.cdll.LoadLibrary('libX11.so.6') x11 = ctypes.cdll.LoadLibrary('libX11.so.6')
@ -233,7 +232,7 @@ class VlcPlayer(MediaPlayer):
""" """
vlc = get_vlc() vlc = get_vlc()
start = datetime.now() start = datetime.now()
while not media_state == display.vlc_media.get_state(): while media_state != display.vlc_media.get_state():
if display.vlc_media.get_state() == vlc.State.Error: if display.vlc_media.get_state() == vlc.State.Error:
return False return False
self.application.process_events() self.application.process_events()

View File

@ -22,10 +22,10 @@
""" """
The :mod:`~openlp.core.ui.media.webkit` module contains our WebKit video player The :mod:`~openlp.core.ui.media.webkit` module contains our WebKit video player
""" """
from PyQt5 import QtGui, QtWebKitWidgets
import logging import logging
from PyQt5 import QtGui, QtWebKitWidgets
from openlp.core.common import Settings from openlp.core.common import Settings
from openlp.core.lib import translate from openlp.core.lib import translate
from openlp.core.ui.media import MediaState from openlp.core.ui.media import MediaState

View File

@ -74,6 +74,6 @@ class Ui_PluginViewDialog(object):
""" """
plugin_view_dialog.setWindowTitle(translate('OpenLP.PluginForm', 'Manage Plugins')) plugin_view_dialog.setWindowTitle(translate('OpenLP.PluginForm', 'Manage Plugins'))
self.plugin_info_group_box.setTitle(translate('OpenLP.PluginForm', 'Plugin Details')) self.plugin_info_group_box.setTitle(translate('OpenLP.PluginForm', 'Plugin Details'))
self.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_label.setText(translate('OpenLP.PluginForm', 'Status:'))
self.status_checkbox.setText(translate('OpenLP.PluginForm', 'Active')) self.status_checkbox.setText(translate('OpenLP.PluginForm', 'Active'))

View File

@ -60,6 +60,7 @@ class PluginForm(QtWidgets.QDialog, Ui_PluginViewDialog, RegistryProperties):
self._clear_details() self._clear_details()
self.programatic_change = True self.programatic_change = True
plugin_list_width = 0 plugin_list_width = 0
# TODO: See how to use format() with variables
for plugin in self.plugin_manager.plugins: for plugin in self.plugin_manager.plugins:
item = QtWidgets.QListWidgetItem(self.plugin_list_widget) item = QtWidgets.QListWidgetItem(self.plugin_list_widget)
# We do this just to make 100% sure the status is an integer as # We do this just to make 100% sure the status is an integer as
@ -94,7 +95,7 @@ class PluginForm(QtWidgets.QDialog, Ui_PluginViewDialog, RegistryProperties):
""" """
Set the details of the currently selected plugin Set the details of the currently selected plugin
""" """
log.debug('PluginStatus: %s', str(self.active_plugin.status)) log.debug('PluginStatus: {status}'.format(status=str(self.active_plugin.status)))
self.about_text_browser.setHtml(self.active_plugin.about()) self.about_text_browser.setHtml(self.active_plugin.about())
self.programatic_change = True self.programatic_change = True
if self.active_plugin.status != PluginStatus.Disabled: if self.active_plugin.status != PluginStatus.Disabled:
@ -136,6 +137,7 @@ class PluginForm(QtWidgets.QDialog, Ui_PluginViewDialog, RegistryProperties):
self.active_plugin.app_startup() self.active_plugin.app_startup()
else: else:
self.active_plugin.toggle_status(PluginStatus.Inactive) self.active_plugin.toggle_status(PluginStatus.Inactive)
# TODO: Verify using format() with a variable
status_text = translate('OpenLP.PluginForm', '%s (Inactive)') status_text = translate('OpenLP.PluginForm', '%s (Inactive)')
if self.active_plugin.status == PluginStatus.Active: if self.active_plugin.status == PluginStatus.Active:
status_text = translate('OpenLP.PluginForm', '%s (Active)') status_text = translate('OpenLP.PluginForm', '%s (Active)')

View File

@ -25,7 +25,8 @@ The UI widgets of the print service dialog.
from PyQt5 import QtCore, QtWidgets, QtPrintSupport from PyQt5 import QtCore, QtWidgets, QtPrintSupport
from openlp.core.common import UiStrings, translate from openlp.core.common import UiStrings, translate
from openlp.core.lib import SpellTextEdit, build_icon from openlp.core.lib import build_icon
from openlp.core.ui.lib import SpellTextEdit
class ZoomSize(object): class ZoomSize(object):

View File

@ -141,23 +141,23 @@ def Build_Tab(group, source_key, default, projector, projectordb, edit=False):
return widget, button_count, buttonchecked return widget, button_count, buttonchecked
def set_button_tooltip(bar): def set_button_tooltip(button_bar):
""" """
Set the toolip for the standard buttons used Set the toolip for the standard buttons used
:param bar: QDialogButtonBar instance to update :param button_bar: QDialogButtonBar instance to update
""" """
for button in bar.buttons(): for button in button_bar.buttons():
if bar.standardButton(button) == QDialogButtonBox.Cancel: if button_bar.standardButton(button) == QDialogButtonBox.Cancel:
button.setToolTip(translate('OpenLP.SourceSelectForm', button.setToolTip(translate('OpenLP.SourceSelectForm',
'Ignoring current changes and return to OpenLP')) 'Ignoring current changes and return to OpenLP'))
elif bar.standardButton(button) == QDialogButtonBox.Reset: elif button_bar.standardButton(button) == QDialogButtonBox.Reset:
button.setToolTip(translate('OpenLP.SourceSelectForm', button.setToolTip(translate('OpenLP.SourceSelectForm',
'Delete all user-defined text and revert to PJLink default text')) 'Delete all user-defined text and revert to PJLink default text'))
elif bar.standardButton(button) == QDialogButtonBox.Discard: elif button_bar.standardButton(button) == QDialogButtonBox.Discard:
button.setToolTip(translate('OpenLP.SourceSelectForm', button.setToolTip(translate('OpenLP.SourceSelectForm',
'Discard changes and reset to previous user-defined text')) 'Discard changes and reset to previous user-defined text'))
elif bar.standardButton(button) == QDialogButtonBox.Ok: elif button_bar.standardButton(button) == QDialogButtonBox.Ok:
button.setToolTip(translate('OpenLP.SourceSelectForm', button.setToolTip(translate('OpenLP.SourceSelectForm',
'Save changes and return to OpenLP')) 'Save changes and return to OpenLP'))
else: else:

View File

@ -133,7 +133,7 @@ class ProjectorTab(SettingsTab):
settings.setValue('socket timeout', self.socket_timeout_spin_box.value()) settings.setValue('socket timeout', self.socket_timeout_spin_box.value())
settings.setValue('poll time', self.socket_poll_spin_box.value()) settings.setValue('poll time', self.socket_poll_spin_box.value())
settings.setValue('source dialog type', self.dialog_type_combo_box.currentIndex()) settings.setValue('source dialog type', self.dialog_type_combo_box.currentIndex())
settings.endGroup settings.endGroup()
def on_dialog_type_combo_box_changed(self): def on_dialog_type_combo_box_changed(self):
self.dialog_type = self.dialog_type_combo_box.currentIndex() self.dialog_type = self.dialog_type_combo_box.currentIndex()

View File

@ -118,7 +118,7 @@ class Ui_ServiceManager(object):
tooltip=translate('OpenLP.ServiceManager', 'Save this service.'), tooltip=translate('OpenLP.ServiceManager', 'Save this service.'),
triggers=self.decide_save_method) triggers=self.decide_save_method)
self.toolbar.addSeparator() 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.setContentsMargins(3, 3, 3, 3)
self.theme_label.setObjectName('theme_label') self.theme_label.setObjectName('theme_label')
self.toolbar.add_toolbar_widget(self.theme_label) self.toolbar.add_toolbar_widget(self.theme_label)
@ -480,9 +480,10 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa
:return: service array :return: service array
""" """
service = [] service = []
core = {'lite-service': self._save_lite, core = {
'service-theme': self.service_theme 'lite-service': self._save_lite,
} 'service-theme': self.service_theme
}
service.append({'openlp_core': core}) service.append({'openlp_core': core})
return service return service
@ -503,8 +504,8 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa
path_file_name = str(self.file_name()) path_file_name = str(self.file_name())
path, file_name = os.path.split(path_file_name) path, file_name = os.path.split(path_file_name)
base_name = os.path.splitext(file_name)[0] base_name = os.path.splitext(file_name)[0]
service_file_name = '%s.osj' % base_name service_file_name = '{name}.osj'.format(name=base_name)
self.log_debug('ServiceManager.save_file - %s' % path_file_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) Settings().setValue(self.main_window.service_manager_settings_section + '/last directory', path)
service = self.create_basic_service() service = self.create_basic_service()
write_list = [] write_list = []
@ -530,8 +531,9 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa
self.application.set_normal_cursor() self.application.set_normal_cursor()
title = translate('OpenLP.ServiceManager', 'Service File(s) Missing') title = translate('OpenLP.ServiceManager', 'Service File(s) Missing')
message = translate('OpenLP.ServiceManager', message = translate('OpenLP.ServiceManager',
'The following file(s) in the service are missing: %s\n\n' 'The following file(s) in the service are missing: {name}\n\n'
'These files will be removed if you continue to save.') % "\n\t".join(missing_list) 'These files will be removed if you continue to save.'
).format(name="\n\t".join(missing_list))
answer = QtWidgets.QMessageBox.critical(self, title, message, answer = QtWidgets.QMessageBox.critical(self, title, message,
QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Ok |
QtWidgets.QMessageBox.Cancel)) QtWidgets.QMessageBox.Cancel))
@ -561,7 +563,7 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa
service_content = json.dumps(service) service_content = json.dumps(service)
# Usual Zip file cannot exceed 2GiB, file with Zip64 cannot be extracted using unzip in UNIX. # 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)) 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 zip_file = None
success = True success = True
self.main_window.increment_progress_bar() self.main_window.increment_progress_bar()
@ -584,7 +586,7 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa
shutil.copy(audio_from, save_file) shutil.copy(audio_from, save_file)
zip_file.write(audio_from, audio_to) zip_file.write(audio_from, audio_to)
except IOError: 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'), self.main_window.error_message(translate('OpenLP.ServiceManager', 'Error Saving File'),
translate('OpenLP.ServiceManager', 'There was an error saving your file.')) translate('OpenLP.ServiceManager', 'There was an error saving your file.'))
success = False success = False
@ -596,12 +598,12 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa
if success: if success:
try: try:
shutil.copy(temp_file_name, path_file_name) shutil.copy(temp_file_name, path_file_name)
except shutil.Error: except (shutil.Error, PermissionError):
return self.save_file_as() return self.save_file_as()
except OSError as ose: except OSError as ose:
QtWidgets.QMessageBox.critical(self, translate('OpenLP.ServiceManager', 'Error Saving File'), QtWidgets.QMessageBox.critical(self, translate('OpenLP.ServiceManager', 'Error Saving File'),
translate('OpenLP.ServiceManager', 'An error occurred while writing the ' 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)) QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Ok))
success = False success = False
self.main_window.add_recent_file(path_file_name) self.main_window.add_recent_file(path_file_name)
@ -623,8 +625,8 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa
path_file_name = str(self.file_name()) path_file_name = str(self.file_name())
path, file_name = os.path.split(path_file_name) path, file_name = os.path.split(path_file_name)
base_name = os.path.splitext(file_name)[0] base_name = os.path.splitext(file_name)[0]
service_file_name = '%s.osj' % base_name service_file_name = '{name}.osj'.format(name=base_name)
self.log_debug('ServiceManager.save_file - %s' % path_file_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) Settings().setValue(self.main_window.service_manager_settings_section + '/last directory', path)
service = self.create_basic_service() service = self.create_basic_service()
self.application.set_busy_cursor() self.application.set_busy_cursor()
@ -645,7 +647,7 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa
# First we add service contents. # First we add service contents.
zip_file.writestr(service_file_name, service_content) zip_file.writestr(service_file_name, service_content)
except IOError: 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'), self.main_window.error_message(translate('OpenLP.ServiceManager', 'Error Saving File'),
translate('OpenLP.ServiceManager', 'There was an error saving your file.')) translate('OpenLP.ServiceManager', 'There was an error saving your file.'))
success = False success = False
@ -657,7 +659,7 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa
if success: if success:
try: try:
shutil.copy(temp_file_name, path_file_name) shutil.copy(temp_file_name, path_file_name)
except shutil.Error: except (shutil.Error, PermissionError):
return self.save_file_as() return self.save_file_as()
self.main_window.add_recent_file(path_file_name) self.main_window.add_recent_file(path_file_name)
self.set_modified(False) self.set_modified(False)
@ -740,13 +742,13 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa
try: try:
ucs_file = zip_info.filename ucs_file = zip_info.filename
except UnicodeDecodeError: 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', critical_error_message_box(message=translate('OpenLP.ServiceManager',
'File is not a valid service.\n The content encoding is not UTF-8.')) 'File is not a valid service.\n The content encoding is not UTF-8.'))
continue continue
os_file = ucs_file.replace('/', os.path.sep) os_file = ucs_file.replace('/', os.path.sep)
os_file = os.path.basename(os_file) 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_info.filename = os_file
zip_file.extract(zip_info, self.service_path) zip_file.extract(zip_info, self.service_path)
if os_file.endswith('osj') or os_file.endswith('osd'): if os_file.endswith('osj') or os_file.endswith('osd'):
@ -773,19 +775,19 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa
else: else:
critical_error_message_box(message=translate('OpenLP.ServiceManager', 'File is not a valid service.')) critical_error_message_box(message=translate('OpenLP.ServiceManager', 'File is not a valid service.'))
self.log_error('File contains no service data') self.log_error('File contains no service data')
except (IOError, NameError, zipfile.BadZipfile): except (IOError, NameError):
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', critical_error_message_box(message=translate('OpenLP.ServiceManager',
'File could not be opened because it is corrupt.')) 'File could not be opened because it is corrupt.'))
except zipfile.BadZipfile: except zipfile.BadZipfile:
if os.path.getsize(file_name) == 0: 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'), QtWidgets.QMessageBox.information(self, translate('OpenLP.ServiceManager', 'Empty File'),
translate('OpenLP.ServiceManager', translate('OpenLP.ServiceManager',
'This service file does not contain ' 'This service file does not contain '
'any data.')) 'any data.'))
else: 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'), QtWidgets.QMessageBox.information(self, translate('OpenLP.ServiceManager', 'Corrupt File'),
translate('OpenLP.ServiceManager', translate('OpenLP.ServiceManager',
'This file is either corrupt or it is not an OpenLP 2 ' 'This file is either corrupt or it is not an OpenLP 2 '
@ -874,7 +876,7 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa
self.auto_play_slides_loop.setChecked(service_item['service_item'].auto_play_slides_loop) 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) self.timed_slide_interval.setChecked(service_item['service_item'].timed_slide_interval > 0)
if 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: else:
delay_suffix = ' ...' delay_suffix = ' ...'
self.timed_slide_interval.setText( self.timed_slide_interval.setText(
@ -1268,14 +1270,17 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa
tree_widget_item.setText(0, service_item_from_item.get_display_title()) tree_widget_item.setText(0, service_item_from_item.get_display_title())
tips = [] tips = []
if service_item_from_item.temporary_edit: if service_item_from_item.temporary_edit:
tips.append('<strong>%s:</strong> <em>%s</em>' % (translate('OpenLP.ServiceManager', 'Edit'), text1 = translate('OpenLP.ServiceManager', 'Edit')
(translate('OpenLP.ServiceManager', 'Service copy only')))) 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: if service_item_from_item.theme and service_item_from_item.theme != -1:
tips.append('<strong>%s:</strong> <em>%s</em>' % text = translate('OpenLP.ServiceManager', 'Slide theme')
(translate('OpenLP.ServiceManager', 'Slide theme'), service_item_from_item.theme)) tips.append('<strong>{text1}:</strong> <em>{text2}</em>'.format(text1=text,
text2=service_item_from_item.theme))
if service_item_from_item.notes: if service_item_from_item.notes:
tips.append('<strong>%s: </strong> %s' % text1 = translate('OpenLP.ServiceManager', 'Notes')
(translate('OpenLP.ServiceManager', 'Notes'), html.escape(service_item_from_item.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): if item['service_item'].is_capable(ItemCapabilities.HasVariableStartTime):
tips.append(item['service_item'].get_media_time()) tips.append(item['service_item'].get_media_time())
tree_widget_item.setToolTip(0, '<br>'.join(tips)) tree_widget_item.setToolTip(0, '<br>'.join(tips))
@ -1323,9 +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. 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 visible = self.renderer.theme_level != ThemeLevel.Global
self.theme_label.setVisible(visible) self.toolbar.actions['theme_combo_box'].setVisible(visible)
self.theme_combo_box.setVisible(visible) self.toolbar.actions['theme_label'].setVisible(visible)
self.regenerate_service_items() self.regenerate_service_items()
def regenerate_service_items(self, changed=False): def regenerate_service_items(self, changed=False):
@ -1637,7 +1642,7 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa
replace = True replace = True
else: else:
self.drop_position = get_parent_item_data(item) - 1 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): def update_theme_list(self, theme_list):
""" """

View File

@ -25,7 +25,7 @@ The :mod:`~openlp.core.ui.servicenoteform` module contains the `ServiceNoteForm`
from PyQt5 import QtCore, QtWidgets from PyQt5 import QtCore, QtWidgets
from openlp.core.common import Registry, RegistryProperties, translate from openlp.core.common import Registry, RegistryProperties, translate
from openlp.core.lib import SpellTextEdit from openlp.core.ui.lib import SpellTextEdit
from openlp.core.lib.ui import create_button_box from openlp.core.lib.ui import create_button_box

View File

@ -85,7 +85,7 @@ class SettingsForm(QtWidgets.QDialog, Ui_SettingsDialog, RegistryProperties):
:param tab_widget: The widget to add :param tab_widget: The widget to add
:param is_visible: If this tab should be visible :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 # add the tab to get it to display in the correct part of the screen
self.stacked_layout.addWidget(tab_widget) self.stacked_layout.addWidget(tab_widget)
if is_visible: if is_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]: if changing_action.shortcutContext() in [QtCore.Qt.WindowShortcut, QtCore.Qt.ApplicationShortcut]:
is_valid = False is_valid = False
if not is_valid: 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'), self.main_window.warning_message(translate('OpenLP.ShortcutListDialog', 'Duplicate Shortcut'),
translate('OpenLP.ShortcutListDialog', text, for_display=True)
'The shortcut "%s" is already assigned to another action, please'
' use a different shortcut.') %
self.get_shortcut_string(key_sequence, for_display=True))
self.dialog_was_shown = True self.dialog_was_shown = True
return is_valid return is_valid

View File

@ -37,7 +37,6 @@ from openlp.core.lib import ItemCapabilities, ServiceItem, ImageSource, ServiceI
build_html build_html
from openlp.core.lib.ui import create_action from openlp.core.lib.ui import create_action
from openlp.core.ui.lib.toolbar import OpenLPToolbar from openlp.core.ui.lib.toolbar import OpenLPToolbar
from openlp.core.ui.lib.dockwidget import OpenLPDockWidget
from openlp.core.ui.lib.listpreviewwidget import ListPreviewWidget from openlp.core.ui.lib.listpreviewwidget import ListPreviewWidget
from openlp.core.ui import HideMode, MainDisplay, Display, DisplayControllerType from openlp.core.ui import HideMode, MainDisplay, Display, DisplayControllerType
@ -98,7 +97,7 @@ class DisplayController(QtWidgets.QWidget):
""" """
sender = self.sender().objectName() if self.sender().objectName() else self.sender().text() sender = self.sender().objectName() if self.sender().objectName() else self.sender().text()
controller = self controller = self
Registry().execute('%s' % sender, [controller, args]) Registry().execute('{text}'.format(text=sender), [controller, args])
class InfoLabel(QtWidgets.QLabel): class InfoLabel(QtWidgets.QLabel):
@ -395,7 +394,7 @@ class SlideController(DisplayController, RegistryProperties):
{'key': 'O', 'configurable': True, 'text': translate('OpenLP.SlideController', 'Go to "Other"')} {'key': 'O', 'configurable': True, 'text': translate('OpenLP.SlideController', 'Go to "Other"')}
] ]
shortcuts.extend([{'key': str(number)} for number in range(10)]) 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'), text=s.get('text'),
can_shortcuts=True, can_shortcuts=True,
context=QtCore.Qt.WidgetWithChildrenShortcut, context=QtCore.Qt.WidgetWithChildrenShortcut,
@ -417,14 +416,20 @@ class SlideController(DisplayController, RegistryProperties):
self.preview_widget.doubleClicked.connect(self.on_preview_double_click) self.preview_widget.doubleClicked.connect(self.on_preview_double_click)
self.toolbar.set_widget_visible(['editSong'], False) self.toolbar.set_widget_visible(['editSong'], False)
self.controller.addActions([self.next_item, self.previous_item]) 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_{text}_stop_loop'.format(text=self.type_prefix),
Registry().register_function('slidecontroller_%s_change' % self.type_prefix, self.on_slide_change) self.on_stop_loop)
Registry().register_function('slidecontroller_%s_blank' % self.type_prefix, self.on_slide_blank) Registry().register_function('slidecontroller_{text}_change'.format(text=self.type_prefix),
Registry().register_function('slidecontroller_%s_unblank' % self.type_prefix, self.on_slide_unblank) 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) 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_{text}_set'.format(text=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_{text}_next'.format(text=self.type_prefix)).connect(self.on_slide_selected_next)
getattr(self, 'slidecontroller_%s_previous' % self.type_prefix).connect(self.on_slide_selected_previous) # 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): def _slide_shortcut_activated(self):
""" """
@ -841,7 +846,8 @@ class SlideController(DisplayController, RegistryProperties):
self.service_item = copy.copy(service_item) self.service_item = copy.copy(service_item)
if self.service_item.is_command(): if self.service_item.is_command():
Registry().execute( 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 # Reset blanking if needed
if old_item and self.is_live and (old_item.is_capable(ItemCapabilities.ProvidesOwnDisplay) or if old_item and self.is_live and (old_item.is_capable(ItemCapabilities.ProvidesOwnDisplay) or
self.service_item.is_capable(ItemCapabilities.ProvidesOwnDisplay)): self.service_item.is_capable(ItemCapabilities.ProvidesOwnDisplay)):
@ -879,8 +885,8 @@ class SlideController(DisplayController, RegistryProperties):
if frame['verseTag']: if frame['verseTag']:
# These tags are already translated. # These tags are already translated.
verse_def = frame['verseTag'] verse_def = frame['verseTag']
verse_def = '%s%s' % (verse_def[0], verse_def[1:]) verse_def = '{def1}{def2}'.format(def1=verse_def[0], def2=verse_def[1:])
two_line_def = '%s\n%s' % (verse_def[0], verse_def[1:]) two_line_def = '{def1}\n{def2}'.format(def1=verse_def[0], def2=verse_def[1:])
row = two_line_def row = two_line_def
if verse_def not in self.slide_list: if verse_def not in self.slide_list:
self.slide_list[verse_def] = frame_number self.slide_list[verse_def] = frame_number
@ -915,10 +921,10 @@ class SlideController(DisplayController, RegistryProperties):
# close the previous, so make sure we don't close the new one. # 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 \ 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(): 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(): if old_item.is_media() and not self.service_item.is_media():
self.on_media_close() 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): def on_slide_selected_index(self, message):
""" """
@ -930,7 +936,8 @@ class SlideController(DisplayController, RegistryProperties):
if not self.service_item: if not self.service_item:
return return
if self.service_item.is_command(): 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.update_preview()
self.selected_row = index self.selected_row = index
else: else:
@ -975,7 +982,7 @@ class SlideController(DisplayController, RegistryProperties):
""" """
if checked is None: if checked is None:
checked = self.blank_screen.isChecked() 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.hide_menu.setDefaultAction(self.blank_screen)
self.blank_screen.setChecked(checked) self.blank_screen.setChecked(checked)
self.theme_screen.setChecked(False) self.theme_screen.setChecked(False)
@ -996,7 +1003,7 @@ class SlideController(DisplayController, RegistryProperties):
""" """
if checked is None: if checked is None:
checked = self.theme_screen.isChecked() 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.hide_menu.setDefaultAction(self.theme_screen)
self.blank_screen.setChecked(False) self.blank_screen.setChecked(False)
self.theme_screen.setChecked(checked) self.theme_screen.setChecked(checked)
@ -1017,7 +1024,7 @@ class SlideController(DisplayController, RegistryProperties):
""" """
if checked is None: if checked is None:
checked = self.desktop_screen.isChecked() 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.hide_menu.setDefaultAction(self.desktop_screen)
self.blank_screen.setChecked(False) self.blank_screen.setChecked(False)
self.theme_screen.setChecked(False) self.theme_screen.setChecked(False)
@ -1035,17 +1042,18 @@ class SlideController(DisplayController, RegistryProperties):
Blank/Hide the display screen within a plugin if required. Blank/Hide the display screen within a plugin if required.
""" """
hide_mode = self.hide_mode() 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 self.service_item is not None:
if hide_mode: if hide_mode:
if not self.service_item.is_command(): if not self.service_item.is_command():
Registry().execute('live_display_hide', hide_mode) Registry().execute('live_display_hide', hide_mode)
Registry().execute('%s_blank' % Registry().execute('{text}_blank'.format(text=self.service_item.name.lower()),
self.service_item.name.lower(), [self.service_item, self.is_live, hide_mode]) [self.service_item, self.is_live, hide_mode])
else: else:
if not self.service_item.is_command(): if not self.service_item.is_command():
Registry().execute('live_display_show') 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: else:
if hide_mode: if hide_mode:
Registry().execute('live_display_hide', hide_mode) Registry().execute('live_display_hide', hide_mode)
@ -1056,15 +1064,17 @@ class SlideController(DisplayController, RegistryProperties):
""" """
Tell the plugin to hide the display screen. 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 self.service_item is not None:
if hide: if hide:
Registry().execute('live_display_hide', HideMode.Screen) 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: else:
if not self.service_item.is_command(): if not self.service_item.is_command():
Registry().execute('live_display_show') 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: else:
if hide: if hide:
Registry().execute('live_display_hide', HideMode.Screen) Registry().execute('live_display_hide', HideMode.Screen)
@ -1099,8 +1109,8 @@ class SlideController(DisplayController, RegistryProperties):
if -1 < row < self.preview_widget.slide_count(): if -1 < row < self.preview_widget.slide_count():
if self.service_item.is_command(): if self.service_item.is_command():
if self.is_live and not start: if self.is_live and not start:
Registry().execute('%s_slide' % Registry().execute('{text}_slide'.format(text=self.service_item.name.lower()),
self.service_item.name.lower(), [self.service_item, self.is_live, row]) [self.service_item, self.is_live, row])
else: else:
to_display = self.service_item.get_rendered_frame(row) to_display = self.service_item.get_rendered_frame(row)
if self.service_item.is_text(): if self.service_item.is_text():
@ -1133,7 +1143,7 @@ class SlideController(DisplayController, RegistryProperties):
""" """
This updates the preview frame, for example after changing a slide or using *Blank to Theme*. 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): if self.service_item and self.service_item.is_capable(ItemCapabilities.ProvidesOwnDisplay):
if self.is_live: if self.is_live:
# If live, grab screen-cap of main display now # If live, grab screen-cap of main display now
@ -1185,7 +1195,8 @@ class SlideController(DisplayController, RegistryProperties):
if not self.service_item: if not self.service_item:
return return
if self.service_item.is_command(): 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: if self.is_live:
self.update_preview() self.update_preview()
else: else:
@ -1213,7 +1224,8 @@ class SlideController(DisplayController, RegistryProperties):
if not self.service_item: if not self.service_item:
return return
if self.service_item.is_command(): 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: if self.is_live:
self.update_preview() self.update_preview()
else: else:
@ -1265,7 +1277,7 @@ class SlideController(DisplayController, RegistryProperties):
checked = self.play_slides_loop.isChecked() checked = self.play_slides_loop.isChecked()
else: else:
self.play_slides_loop.setChecked(checked) 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: if checked:
self.play_slides_loop.setIcon(build_icon(':/media/media_stop.png')) self.play_slides_loop.setIcon(build_icon(':/media/media_stop.png'))
self.play_slides_loop.setText(UiStrings().StopPlaySlidesInLoop) self.play_slides_loop.setText(UiStrings().StopPlaySlidesInLoop)
@ -1288,7 +1300,7 @@ class SlideController(DisplayController, RegistryProperties):
checked = self.play_slides_once.isChecked() checked = self.play_slides_once.isChecked()
else: else:
self.play_slides_once.setChecked(checked) 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: if checked:
self.play_slides_once.setIcon(build_icon(':/media/media_stop.png')) self.play_slides_once.setIcon(build_icon(':/media/media_stop.png'))
self.play_slides_once.setText(UiStrings().StopPlaySlidesToEnd) self.play_slides_once.setText(UiStrings().StopPlaySlidesToEnd)
@ -1354,7 +1366,8 @@ class SlideController(DisplayController, RegistryProperties):
# Live and Preview have issues if we have video or presentations # Live and Preview have issues if we have video or presentations
# playing in both at the same time. # playing in both at the same time.
if self.service_item.is_command(): 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(): if self.service_item.is_media():
self.on_media_close() self.on_media_close()
self.on_go_live() 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.hour_finish_spin_box.setValue(hours)
self.minute_finish_spin_box.setValue(minutes) self.minute_finish_spin_box.setValue(minutes)
self.second_finish_spin_box.setValue(seconds) self.second_finish_spin_box.setValue(seconds)
self.hour_finish_label.setText('%s%s' % (str(hour), UiStrings().Hours)) self.hour_finish_label.setText('{val:d}{text}'.format(val=hour, text=UiStrings().Hours))
self.minute_finish_label.setText('%s%s' % (str(minutes), UiStrings().Minutes)) self.minute_finish_label.setText('{val:d}{text}'.format(val=minutes, text=UiStrings().Minutes))
self.second_finish_label.setText('%s%s' % (str(seconds), UiStrings().Seconds)) self.second_finish_label.setText('{val:d}{text}'.format(val=seconds, text=UiStrings().Seconds))
return QtWidgets.QDialog.exec(self) return QtWidgets.QDialog.exec(self)
def accept(self): def accept(self):

View File

@ -249,7 +249,7 @@ class ThemeForm(QtWidgets.QWizard, Ui_ThemeWizard, RegistryProperties):
NOTE the font_main_override is the inverse of the check box value NOTE the font_main_override is the inverse of the check box value
""" """
if self.update_theme_allowed: if self.update_theme_allowed:
self.theme.font_main_override = not (value == QtCore.Qt.Checked) self.theme.font_main_override = (value != QtCore.Qt.Checked)
def on_footer_position_check_box_state_changed(self, value): def on_footer_position_check_box_state_changed(self, value):
""" """
@ -257,13 +257,13 @@ class ThemeForm(QtWidgets.QWizard, Ui_ThemeWizard, RegistryProperties):
NOTE the font_footer_override is the inverse of the check box value NOTE the font_footer_override is the inverse of the check box value
""" """
if self.update_theme_allowed: if self.update_theme_allowed:
self.theme.font_footer_override = not (value == QtCore.Qt.Checked) self.theme.font_footer_override = (value != QtCore.Qt.Checked)
def exec(self, edit=False): def exec(self, edit=False):
""" """
Run the wizard. 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.temp_background_filename = ''
self.update_theme_allowed = False self.update_theme_allowed = False
self.set_defaults() self.set_defaults()
@ -272,7 +272,8 @@ class ThemeForm(QtWidgets.QWizard, Ui_ThemeWizard, RegistryProperties):
self.theme_name_edit.setVisible(not edit) self.theme_name_edit.setVisible(not edit)
self.edit_mode = edit self.edit_mode = edit
if 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() self.next()
else: else:
self.setWindowTitle(UiStrings().NewTheme) self.setWindowTitle(UiStrings().NewTheme)
@ -282,7 +283,7 @@ class ThemeForm(QtWidgets.QWizard, Ui_ThemeWizard, RegistryProperties):
""" """
Set up the pages for Initial run through dialog 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) wizard_page = self.page(page_id)
if wizard_page == self.background_page: if wizard_page == self.background_page:
self.set_background_page_values() self.set_background_page_values()
@ -445,7 +446,7 @@ class ThemeForm(QtWidgets.QWizard, Ui_ThemeWizard, RegistryProperties):
Background Image button pushed. Background Image button pushed.
""" """
images_filter = get_images_filter() 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( filename, filter_used = QtWidgets.QFileDialog.getOpenFileName(
self, translate('OpenLP.ThemeWizard', 'Select Image'), self, translate('OpenLP.ThemeWizard', 'Select Image'),
self.image_file_edit.text(), images_filter) self.image_file_edit.text(), images_filter)
@ -463,6 +464,7 @@ class ThemeForm(QtWidgets.QWizard, Ui_ThemeWizard, RegistryProperties):
""" """
Background video button pushed. Background video button pushed.
""" """
# TODO: Check this before converting
visible_formats = '(%s)' % '; '.join(VIDEO_EXT) visible_formats = '(%s)' % '; '.join(VIDEO_EXT)
actual_formats = '(%s)' % ' '.join(VIDEO_EXT) actual_formats = '(%s)' % ' '.join(VIDEO_EXT)
video_filter = '{trans} {visible} {actual}'.format(trans=translate('OpenLP', 'Video Files'), 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 Change the global theme when it is changed through the Themes settings tab
""" """
self.global_theme = Settings().value(self.settings_section + '/global theme') 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()): for count in range(0, self.theme_list_widget.count()):
# reset the old name # reset the old name
item = self.theme_list_widget.item(count) 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) self.theme_list_widget.item(count).setText(new_name)
# Set the new name # Set the new name
if self.global_theme == 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.theme_list_widget.item(count).setText(name)
self.delete_toolbar_action.setVisible(item not in self.theme_list_widget.selectedItems()) 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 # Set the new name
if count == selected_row: if count == selected_row:
self.global_theme = self.theme_list_widget.item(count).text() 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) self.theme_list_widget.item(count).setText(name)
Settings().setValue(self.settings_section + '/global theme', self.global_theme) Settings().setValue(self.settings_section + '/global theme', self.global_theme)
Registry().execute('theme_update_global') 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 Renames an existing theme to a new name
:param field: :param field:
""" """
# TODO: Check for delayed format() conversions
if self._validate_theme_action(translate('OpenLP.ThemeManager', 'You must select a theme to rename.'), if self._validate_theme_action(translate('OpenLP.ThemeManager', 'You must select a theme to rename.'),
translate('OpenLP.ThemeManager', 'Rename Confirmation'), translate('OpenLP.ThemeManager', 'Rename Confirmation'),
translate('OpenLP.ThemeManager', 'Rename %s theme?'), False, False): 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() item = self.theme_list_widget.currentItem()
old_theme_name = item.data(QtCore.Qt.UserRole) old_theme_name = item.data(QtCore.Qt.UserRole)
self.file_rename_form.file_name_edit.setText(translate('OpenLP.ThemeManager', 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): if self.file_rename_form.exec(True):
new_theme_name = self.file_rename_form.file_name_edit.text() new_theme_name = self.file_rename_form.file_name_edit.text()
if self.check_if_theme_exists(new_theme_name): 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. Delete a theme triggered by the UI.
:param field: :param field:
""" """
# TODO: Verify delayed format() conversions
if self._validate_theme_action(translate('OpenLP.ThemeManager', 'You must select a theme to delete.'), if self._validate_theme_action(translate('OpenLP.ThemeManager', 'You must select a theme to delete.'),
translate('OpenLP.ThemeManager', 'Delete Confirmation'), translate('OpenLP.ThemeManager', 'Delete Confirmation'),
translate('OpenLP.ThemeManager', 'Delete %s theme?')): translate('OpenLP.ThemeManager', 'Delete %s theme?')):
@ -351,7 +354,7 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage
:param theme: The theme to delete. :param theme: The theme to delete.
""" """
self.theme_list.remove(theme) 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.path, thumb))
delete_file(os.path.join(self.thumb_path, thumb)) delete_file(os.path.join(self.thumb_path, thumb))
try: try:
@ -363,7 +366,7 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage
shutil.rmtree(os.path.join(self.path, theme).encode(encoding)) shutil.rmtree(os.path.join(self.path, theme).encode(encoding))
except OSError as os_error: except OSError as os_error:
shutil.Error = 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): def on_export_theme(self, field=None):
""" """
@ -376,7 +379,8 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage
return return
theme = item.data(QtCore.Qt.UserRole) theme = item.data(QtCore.Qt.UserRole)
path = QtWidgets.QFileDialog.getExistingDirectory(self, 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 + Settings().value(self.settings_section +
'/last directory export')) '/last directory export'))
self.application.set_busy_cursor() self.application.set_busy_cursor()
@ -409,7 +413,7 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage
self.log_exception('Export Theme Failed') self.log_exception('Export Theme Failed')
critical_error_message_box(translate('OpenLP.ThemeManager', 'Theme Export Failed'), critical_error_message_box(translate('OpenLP.ThemeManager', 'Theme Export Failed'),
translate('OpenLP.ThemeManager', 'The theme export failed because this error ' translate('OpenLP.ThemeManager', 'The theme export failed because this error '
'occurred: %s') % ose.strerror) 'occurred: {err}').format(err=ose.strerror))
if theme_zip: if theme_zip:
theme_zip.close() theme_zip.close()
shutil.rmtree(theme_path, True) shutil.rmtree(theme_path, True)
@ -425,7 +429,7 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage
translate('OpenLP.ThemeManager', 'Select Theme Import File'), translate('OpenLP.ThemeManager', 'Select Theme Import File'),
Settings().value(self.settings_section + '/last directory import'), Settings().value(self.settings_section + '/last directory import'),
translate('OpenLP.ThemeManager', 'OpenLP Themes (*.otz)')) 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: if not files:
return return
self.application.set_busy_cursor() self.application.set_busy_cursor()
@ -472,10 +476,10 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage
if os.path.exists(theme): if os.path.exists(theme):
text_name = os.path.splitext(name)[0] text_name = os.path.splitext(name)[0]
if text_name == self.global_theme: 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: else:
name = text_name 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) item_name = QtWidgets.QListWidgetItem(name)
if validate_thumb(theme, thumb): if validate_thumb(theme, thumb):
icon = build_icon(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 :param theme_name: Name of the theme to load from file
:return: The theme object. :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_file = os.path.join(self.path, str(theme_name), str(theme_name) + '.xml')
xml = get_text_file_string(xml_file) xml = get_text_file_string(xml_file)
if not xml: 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'), ret = QtWidgets.QMessageBox.question(self, translate('OpenLP.ThemeManager', 'Theme Already Exists'),
translate('OpenLP.ThemeManager', translate('OpenLP.ThemeManager',
'Theme %s already exists. Do you want to replace it?') 'Theme {name} already exists. '
.replace('%s', theme_name), 'Do you want to replace it?').format(name=theme_name),
QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes |
QtWidgets.QMessageBox.No), QtWidgets.QMessageBox.No),
QtWidgets.QMessageBox.No) QtWidgets.QMessageBox.No)
@ -538,7 +542,7 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage
:param file_name: :param file_name:
:param directory: :param directory:
""" """
self.log_debug('Unzipping theme %s' % file_name) self.log_debug('Unzipping theme {name}'.format(name=file_name))
theme_zip = None theme_zip = None
out_file = None out_file = None
file_xml = None file_xml = None
@ -547,7 +551,7 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage
theme_zip = zipfile.ZipFile(file_name) theme_zip = zipfile.ZipFile(file_name)
xml_file = [name for name in theme_zip.namelist() if os.path.splitext(name)[1].lower() == '.xml'] xml_file = [name for name in theme_zip.namelist() if os.path.splitext(name)[1].lower() == '.xml']
if len(xml_file) != 1: 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 raise ValidationError
xml_tree = ElementTree(element=XML(theme_zip.read(xml_file[0]))).getroot() xml_tree = ElementTree(element=XML(theme_zip.read(xml_file[0]))).getroot()
theme_version = xml_tree.get('version', default=None) 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.write(theme_zip.read(name))
out_file.close() out_file.close()
except (IOError, zipfile.BadZipfile): 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 raise ValidationError
except ValidationError: except ValidationError:
critical_error_message_box(translate('OpenLP.ThemeManager', 'Validation Error'), 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( critical_error_message_box(
translate('OpenLP.ThemeManager', 'Validation Error'), translate('OpenLP.ThemeManager', 'Validation Error'),
translate('OpenLP.ThemeManager', 'File is not a valid theme.')) 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): 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): if os.path.exists(sample_path_name):
os.unlink(sample_path_name) os.unlink(sample_path_name)
frame.save(sample_path_name, 'png') 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) create_thumb(sample_path_name, thumb, False)
def update_preview_images(self): def update_preview_images(self):
@ -760,14 +764,17 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage
for plugin in self.plugin_manager.plugins: for plugin in self.plugin_manager.plugins:
used_count = plugin.uses_theme(theme) used_count = plugin.uses_theme(theme)
if used_count: if used_count:
plugin_usage = "%s%s" % (plugin_usage, (translate('OpenLP.ThemeManager', plugin_usage = "{plug}{text}".format(plug=plugin_usage,
'%(count)s time(s) by %(plugin)s') % text=(translate('OpenLP.ThemeManager',
{'count': used_count, 'plugin': plugin.name})) '{count} time(s) by {plugin}'
).format(name=used_count,
plugin=plugin.name)))
plugin_usage = "%s\n" % plugin_usage plugin_usage = "%s\n" % plugin_usage
if plugin_usage: if plugin_usage:
critical_error_message_box(translate('OpenLP.ThemeManager', 'Unable to delete theme'), critical_error_message_box(translate('OpenLP.ThemeManager', 'Unable to delete theme'),
translate('OpenLP.ThemeManager', 'Theme is currently used \n\n%s') % translate('OpenLP.ThemeManager',
plugin_usage) 'Theme is currently used \n\n{text}'
).format(text=plugin_usage))
return False return False
return True return True

View File

@ -405,8 +405,8 @@ class Ui_ThemeWizard(object):
Translate the UI on the fly Translate the UI on the fly
""" """
theme_wizard.setWindowTitle(translate('OpenLP.ThemeWizard', 'Theme Wizard')) theme_wizard.setWindowTitle(translate('OpenLP.ThemeWizard', 'Theme Wizard'))
self.title_label.setText('<span style="font-size:14pt; font-weight:600;">%s</span>' % text = translate('OpenLP.ThemeWizard', 'Welcome to the Theme Wizard')
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( self.information_label.setText(
translate('OpenLP.ThemeWizard', 'This wizard will help you to create and edit your themes. Click the next ' 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.')) '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, self.gradient_combo_box.setItemText(BackgroundGradientType.LeftBottom,
translate('OpenLP.ThemeWizard', 'Bottom Left - Top Right')) translate('OpenLP.ThemeWizard', 'Bottom Left - Top Right'))
self.image_color_label.setText(translate('OpenLP.ThemeWizard', 'Background color:')) 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_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.setTitle(translate('OpenLP.ThemeWizard', 'Main Area Font Details'))
self.main_area_page.setSubTitle(translate('OpenLP.ThemeWizard', 'Define the font and display ' self.main_area_page.setSubTitle(translate('OpenLP.ThemeWizard', 'Define the font and display '
'characteristics for the Display text')) 'characteristics for the Display text'))

View File

@ -88,6 +88,7 @@ JAVASCRIPT = """
} }
} }
""" """
# TODO: Verify format() with variable templates
CSS = """ CSS = """
#alert { #alert {
position: absolute; position: absolute;
@ -244,6 +245,9 @@ class AlertsPlugin(Plugin):
:param frame: The Web frame holding the page. :param frame: The Web frame holding the page.
""" """
align = VerticalType.Names[self.settings_tab.location] align = VerticalType.Names[self.settings_tab.location]
frame.evaluateJavaScript('update_css("%s", "%s", "%s", "%s", "%s")' % frame.evaluateJavaScript('update_css("{align}", "{face}", "{size}", "{color}", '
(align, self.settings_tab.font_face, self.settings_tab.font_size, '"{background}")'.format(align=align,
self.settings_tab.font_color, self.settings_tab.background_color)) face=self.settings_tab.font_face,
size=self.settings_tab.font_size,
color=self.settings_tab.font_color,
background=self.settings_tab.background_color))

View File

@ -62,7 +62,7 @@ class AlertsManager(OpenLPMixin, RegistryMixin, QtCore.QObject, RegistryProperti
:param text: The text to display :param text: The text to display
""" """
self.log_debug('display alert called %s' % text) self.log_debug('display alert called {text}'.format(text=text))
if text: if text:
self.alert_list.append(text) self.alert_list.append(text)
if self.timer_id != 0: if self.timer_id != 0:

View File

@ -197,5 +197,6 @@ class AlertsTab(SettingsTab):
font.setBold(True) font.setBold(True)
font.setPointSize(self.font_size) font.setPointSize(self.font_size)
self.font_preview.setFont(font) self.font_preview.setFont(font)
self.font_preview.setStyleSheet('background-color: %s; color: %s' % (self.background_color, self.font_color)) self.font_preview.setStyleSheet('background-color: {back}; color: {front}'.format(back=self.background_color,
front=self.font_color))
self.changed = True self.changed = True

View File

@ -593,22 +593,27 @@ class BibleImportForm(OpenLPWizard):
""" """
Show the file open dialog for the books CSV file. Show the file open dialog for the books CSV file.
""" """
# TODO: Verify format() with varible template
self.get_file_name( self.get_file_name(
WizardStrings.OpenTypeFile % WizardStrings.CSV, self.csv_books_edit, 'last directory import', '%s (*.csv)' % WizardStrings.OpenTypeFile % WizardStrings.CSV,
translate('BiblesPlugin.ImportWizardForm', 'CSV File')) self.csv_books_edit,
'last directory import',
'{name} (*.csv)'.format(name=translate('BiblesPlugin.ImportWizardForm', 'CSV File')))
def on_csv_verses_browse_button_clicked(self): def on_csv_verses_browse_button_clicked(self):
""" """
Show the file open dialog for the verses CSV file. Show the file open dialog for the verses CSV file.
""" """
# TODO: Verify format() with variable template
self.get_file_name(WizardStrings.OpenTypeFile % WizardStrings.CSV, self.csv_verses_edit, self.get_file_name(WizardStrings.OpenTypeFile % WizardStrings.CSV, self.csv_verses_edit,
'last directory import', '%s (*.csv)' % 'last directory import',
translate('BiblesPlugin.ImportWizardForm', 'CSV File')) '{name} (*.csv)'.format(name=translate('BiblesPlugin.ImportWizardForm', 'CSV File')))
def on_open_song_browse_button_clicked(self): def on_open_song_browse_button_clicked(self):
""" """
Show the file open dialog for the OpenSong file. Show the file open dialog for the OpenSong file.
""" """
# TODO: Verify format() with variable template
self.get_file_name(WizardStrings.OpenTypeFile % WizardStrings.OS, self.open_song_file_edit, self.get_file_name(WizardStrings.OpenTypeFile % WizardStrings.OS, self.open_song_file_edit,
'last directory import') 'last directory import')
@ -616,6 +621,7 @@ class BibleImportForm(OpenLPWizard):
""" """
Show the file open dialog for the Zefania file. Show the file open dialog for the Zefania file.
""" """
# TODO: Verify format() with variable template
self.get_file_name(WizardStrings.OpenTypeFile % WizardStrings.ZEF, self.zefania_file_edit, self.get_file_name(WizardStrings.OpenTypeFile % WizardStrings.ZEF, self.zefania_file_edit,
'last directory import') 'last directory import')
@ -631,6 +637,7 @@ class BibleImportForm(OpenLPWizard):
self.web_progress_bar.setVisible(True) self.web_progress_bar.setVisible(True)
self.web_progress_bar.setValue(0) self.web_progress_bar.setValue(0)
proxy_server = self.field('proxy_server') proxy_server = self.field('proxy_server')
# TODO: Where does critical_error_message_box get %s string from?
for (download_type, extractor) in ((WebDownload.Crosswalk, CWExtract(proxy_server)), for (download_type, extractor) in ((WebDownload.Crosswalk, CWExtract(proxy_server)),
(WebDownload.BibleGateway, BGExtract(proxy_server)), (WebDownload.BibleGateway, BGExtract(proxy_server)),
(WebDownload.Bibleserver, BSExtract(proxy_server))): (WebDownload.Bibleserver, BSExtract(proxy_server))):

View File

@ -209,7 +209,7 @@ class BibleUpgradeForm(OpenLPWizard):
for number, filename in enumerate(self.files): for number, filename in enumerate(self.files):
bible = OldBibleDB(self.media_item, path=self.path, file=filename[0]) bible = OldBibleDB(self.media_item, path=self.path, file=filename[0])
self.checkBox[number] = QtWidgets.QCheckBox(self.scrollAreaContents) self.checkBox[number] = QtWidgets.QCheckBox(self.scrollAreaContents)
self.checkBox[number].setObjectName('checkBox[%d]' % number) self.checkBox[number].setObjectName('checkBox[{count:d}]'.format(count=number))
self.checkBox[number].setText(bible.get_name()) self.checkBox[number].setText(bible.get_name())
self.checkBox[number].setCheckState(QtCore.Qt.Checked) self.checkBox[number].setCheckState(QtCore.Qt.Checked)
self.formLayout.addWidget(self.checkBox[number]) self.formLayout.addWidget(self.checkBox[number])
@ -364,7 +364,10 @@ class BibleUpgradeForm(OpenLPWizard):
name = filename[1] name = filename[1]
self.progress_label.setText( self.progress_label.setText(
translate('BiblesPlugin.UpgradeWizardForm', translate('BiblesPlugin.UpgradeWizardForm',
'Upgrading Bible %s of %s: "%s"\nUpgrading ...') % (number + 1, max_bibles, name)) 'Upgrading Bible {count} of {total}: "{name}"\n'
'Upgrading ...').format(count=number + 1,
total=max_bibles,
name=name))
self.new_bibles[number] = BibleDB(self.media_item, path=self.path, name=name, file=filename[0]) self.new_bibles[number] = BibleDB(self.media_item, path=self.path, name=name, file=filename[0])
self.new_bibles[number].register(self.plugin.upgrade_wizard) self.new_bibles[number].register(self.plugin.upgrade_wizard)
metadata = old_bible.get_metadata() metadata = old_bible.get_metadata()
@ -394,17 +397,19 @@ class BibleUpgradeForm(OpenLPWizard):
handler = BSExtract(proxy_server) handler = BSExtract(proxy_server)
books = handler.get_books_from_http(meta_data['download_name']) books = handler.get_books_from_http(meta_data['download_name'])
if not books: if not books:
log.error('Upgrading books from %s - download name: "%s" failed' % ( log.error('Upgrading books from {uri} - '
meta_data['download_source'], meta_data['download_name'])) 'download name: "{name}" failed'.format(uri=meta_data['download_source'],
name=meta_data['download_name']))
self.new_bibles[number].session.close() self.new_bibles[number].session.close()
del self.new_bibles[number] del self.new_bibles[number]
critical_error_message_box( critical_error_message_box(
translate('BiblesPlugin.UpgradeWizardForm', 'Download Error'), translate('BiblesPlugin.UpgradeWizardForm', 'Download Error'),
translate('BiblesPlugin.UpgradeWizardForm', translate('BiblesPlugin.UpgradeWizardForm',
'To upgrade your Web Bibles an Internet connection is required.')) 'To upgrade your Web Bibles an Internet connection is required.'))
self.increment_progress_bar(translate( text = translate('BiblesPlugin.UpgradeWizardForm',
'BiblesPlugin.UpgradeWizardForm', 'Upgrading Bible %s of %s: "%s"\nFailed') % 'Upgrading Bible {count} of {total}: "{name}"\n'
(number + 1, max_bibles, name), self.progress_bar.maximum() - self.progress_bar.value()) 'Failed').format(count=number + 1, total=max_bibles, name=name)
self.increment_progress_bar(text, self.progress_bar.maximum() - self.progress_bar.value())
self.success[number] = False self.success[number] = False
continue continue
bible = BiblesResourcesDB.get_webbible( bible = BiblesResourcesDB.get_webbible(
@ -416,12 +421,13 @@ class BibleUpgradeForm(OpenLPWizard):
else: else:
language_id = self.new_bibles[number].get_language(name) language_id = self.new_bibles[number].get_language(name)
if not language_id: if not language_id:
log.warning('Upgrading from "%s" failed' % filename[0]) log.warning('Upgrading from "{name}" failed'.format(name=filename[0]))
self.new_bibles[number].session.close() self.new_bibles[number].session.close()
del self.new_bibles[number] del self.new_bibles[number]
self.increment_progress_bar( self.increment_progress_bar(
translate('BiblesPlugin.UpgradeWizardForm', translate('BiblesPlugin.UpgradeWizardForm',
'Upgrading Bible %s of %s: "%s"\nFailed') % (number + 1, max_bibles, name), 'Upgrading Bible {count} of {total}: "{name}"\n'
'Failed').format(count=number + 1, total=max_bibles, name=name),
self.progress_bar.maximum() - self.progress_bar.value()) self.progress_bar.maximum() - self.progress_bar.value())
self.success[number] = False self.success[number] = False
continue continue
@ -432,13 +438,15 @@ class BibleUpgradeForm(OpenLPWizard):
break break
self.increment_progress_bar( self.increment_progress_bar(
translate('BiblesPlugin.UpgradeWizardForm', translate('BiblesPlugin.UpgradeWizardForm',
'Upgrading Bible %s of %s: "%s"\nUpgrading %s ...') % 'Upgrading Bible {count} of {total}: "{name}"\n'
(number + 1, max_bibles, name, book)) 'Upgrading {book} ...').format(count=number + 1, total=max_bibles,
name=name, book=book))
book_ref_id = self.new_bibles[number].\ book_ref_id = self.new_bibles[number].\
get_book_ref_id_by_name(book, len(books), language_id) get_book_ref_id_by_name(book, len(books), language_id)
if not book_ref_id: if not book_ref_id:
log.warning('Upgrading books from %s - download name: "%s" aborted by user' % ( log.warning('Upgrading books from {source} - download name: "{name}" '
meta_data['download_source'], meta_data['download_name'])) 'aborted by user'.format(source=meta_data['download_source'],
name=meta_data['download_name']))
self.new_bibles[number].session.close() self.new_bibles[number].session.close()
del self.new_bibles[number] del self.new_bibles[number]
self.success[number] = False self.success[number] = False
@ -450,7 +458,7 @@ class BibleUpgradeForm(OpenLPWizard):
if oldbook: if oldbook:
verses = old_bible.get_verses(oldbook['id']) verses = old_bible.get_verses(oldbook['id'])
if not verses: if not verses:
log.warning('No verses found to import for book "%s"', book) log.warning('No verses found to import for book "{book}"'.format(book=book))
continue continue
for verse in verses: for verse in verses:
if self.stop_import_flag: if self.stop_import_flag:
@ -465,12 +473,13 @@ class BibleUpgradeForm(OpenLPWizard):
if not language_id: if not language_id:
language_id = self.new_bibles[number].get_language(name) language_id = self.new_bibles[number].get_language(name)
if not language_id: if not language_id:
log.warning('Upgrading books from "%s" failed' % name) log.warning('Upgrading books from "{name}" failed'.format(name=name))
self.new_bibles[number].session.close() self.new_bibles[number].session.close()
del self.new_bibles[number] del self.new_bibles[number]
self.increment_progress_bar( self.increment_progress_bar(
translate('BiblesPlugin.UpgradeWizardForm', translate('BiblesPlugin.UpgradeWizardForm',
'Upgrading Bible %s of %s: "%s"\nFailed') % (number + 1, max_bibles, name), 'Upgrading Bible {count} of {total}: "{name}"\n'
'Failed').format(count=number + 1, total=max_bibles, name=name),
self.progress_bar.maximum() - self.progress_bar.value()) self.progress_bar.maximum() - self.progress_bar.value())
self.success[number] = False self.success[number] = False
continue continue
@ -482,11 +491,12 @@ class BibleUpgradeForm(OpenLPWizard):
break break
self.increment_progress_bar( self.increment_progress_bar(
translate('BiblesPlugin.UpgradeWizardForm', translate('BiblesPlugin.UpgradeWizardForm',
'Upgrading Bible %s of %s: "%s"\nUpgrading %s ...') % 'Upgrading Bible {count} of {total}: "{name}"\n'
(number + 1, max_bibles, name, book['name'])) 'Upgrading {book} ...').format(count=number + 1, total=max_bibles,
name=name, book=book['name']))
book_ref_id = self.new_bibles[number].get_book_ref_id_by_name(book['name'], len(books), language_id) book_ref_id = self.new_bibles[number].get_book_ref_id_by_name(book['name'], len(books), language_id)
if not book_ref_id: if not book_ref_id:
log.warning('Upgrading books from %s " failed - aborted by user' % name) log.warning('Upgrading books from {name} " failed - aborted by user'.format(name=name))
self.new_bibles[number].session.close() self.new_bibles[number].session.close()
del self.new_bibles[number] del self.new_bibles[number]
self.success[number] = False self.success[number] = False
@ -496,7 +506,7 @@ class BibleUpgradeForm(OpenLPWizard):
book_details['testament_id']) book_details['testament_id'])
verses = old_bible.get_verses(book['id']) verses = old_bible.get_verses(book['id'])
if not verses: if not verses:
log.warning('No verses found to import for book "%s"', book['name']) log.warning('No verses found to import for book "{book}"'.format(book=book['name']))
self.new_bibles[number].delete_book(db_book) self.new_bibles[number].delete_book(db_book)
continue continue
for verse in verses: for verse in verses:
@ -510,14 +520,16 @@ class BibleUpgradeForm(OpenLPWizard):
if not self.success.get(number, True): if not self.success.get(number, True):
self.increment_progress_bar( self.increment_progress_bar(
translate('BiblesPlugin.UpgradeWizardForm', translate('BiblesPlugin.UpgradeWizardForm',
'Upgrading Bible %s of %s: "%s"\nFailed') % (number + 1, max_bibles, name), 'Upgrading Bible {count} of {total}: "{name}"\n'
'Failed').format(count=number + 1, total=max_bibles, name=name),
self.progress_bar.maximum() - self.progress_bar.value()) self.progress_bar.maximum() - self.progress_bar.value())
else: else:
self.success[number] = True self.success[number] = True
self.new_bibles[number].save_meta('name', name) self.new_bibles[number].save_meta('name', name)
self.increment_progress_bar( self.increment_progress_bar(
translate('BiblesPlugin.UpgradeWizardForm', translate('BiblesPlugin.UpgradeWizardForm',
'Upgrading Bible %s of %s: "%s"\nComplete') % (number + 1, max_bibles, name)) 'Upgrading Bible {count} of {total}: "{name}"\n'
'Complete').format(count=number + 1, total=max_bibles, name=name))
if number in self.new_bibles: if number in self.new_bibles:
self.new_bibles[number].session.close() self.new_bibles[number].session.close()
# Close the last bible's connection if possible. # Close the last bible's connection if possible.
@ -540,20 +552,22 @@ class BibleUpgradeForm(OpenLPWizard):
# Copy not upgraded bible back. # Copy not upgraded bible back.
shutil.move(os.path.join(self.temp_dir, filename[0]), self.path) shutil.move(os.path.join(self.temp_dir, filename[0]), self.path)
if failed_import > 0: if failed_import > 0:
failed_import_text = translate('BiblesPlugin.UpgradeWizardForm', ', %s failed') % failed_import failed_import_text = translate('BiblesPlugin.UpgradeWizardForm',
', {name} failed').format(name=failed_import)
else: else:
failed_import_text = '' failed_import_text = ''
if successful_import > 0: if successful_import > 0:
if self.includeWebBible: if self.includeWebBible:
self.progress_label.setText( self.progress_label.setText(
translate('BiblesPlugin.UpgradeWizardForm', translate('BiblesPlugin.UpgradeWizardForm',
'Upgrading Bible(s): %(success)d successful%(failed_text)s\nPlease note that verses ' 'Upgrading Bible(s): {count:d} successful{failed}\nPlease note that verses '
'from Web Bibles will be downloaded on demand and so an Internet connection is required.') 'from Web Bibles will be downloaded on demand and so an Internet connection is required.'
% {'success': successful_import, 'failed_text': failed_import_text}) ).format(count=successful_import, failed=failed_import_text))
else: else:
self.progress_label.setText( self.progress_label.setText(
translate('BiblesPlugin.UpgradeWizardForm', 'Upgrading Bible(s): %s successful%s') % ( translate('BiblesPlugin.UpgradeWizardForm',
successful_import, failed_import_text)) 'Upgrading Bible(s): {count:d} successful{failed}').format(count=successful_import,
failed=failed_import_text))
else: else:
self.progress_label.setText(translate('BiblesPlugin.UpgradeWizardForm', 'Upgrade failed.')) self.progress_label.setText(translate('BiblesPlugin.UpgradeWizardForm', 'Upgrade failed.'))
# Remove temp directory. # Remove temp directory.

View File

@ -103,9 +103,11 @@ class Ui_EditBibleDialog(object):
self.book_name_edit = {} self.book_name_edit = {}
for book in BiblesResourcesDB.get_books(): for book in BiblesResourcesDB.get_books():
self.book_name_label[book['abbreviation']] = QtWidgets.QLabel(self.book_name_widget) self.book_name_label[book['abbreviation']] = QtWidgets.QLabel(self.book_name_widget)
self.book_name_label[book['abbreviation']].setObjectName('book_name_label[%s]' % book['abbreviation']) self.book_name_label[book['abbreviation']].setObjectName(
'book_name_label[{book}]'.format(book=book['abbreviation']))
self.book_name_edit[book['abbreviation']] = QtWidgets.QLineEdit(self.book_name_widget) self.book_name_edit[book['abbreviation']] = QtWidgets.QLineEdit(self.book_name_widget)
self.book_name_edit[book['abbreviation']].setObjectName('book_name_edit[%s]' % book['abbreviation']) self.book_name_edit[book['abbreviation']].setObjectName(
'book_name_edit[{name}]'.format(name=book['abbreviation']))
self.book_name_widget_layout.addRow( self.book_name_widget_layout.addRow(
self.book_name_label[book['abbreviation']], self.book_name_label[book['abbreviation']],
self.book_name_edit[book['abbreviation']]) self.book_name_edit[book['abbreviation']])
@ -148,4 +150,5 @@ class Ui_EditBibleDialog(object):
self.bible_tab_widget.indexOf(self.book_name_tab), self.bible_tab_widget.indexOf(self.book_name_tab),
translate('SongsPlugin.EditBibleForm', 'Custom Book Names')) translate('SongsPlugin.EditBibleForm', 'Custom Book Names'))
for book in BiblesResourcesDB.get_books(): for book in BiblesResourcesDB.get_books():
self.book_name_label[book['abbreviation']].setText('%s:' % str(self.book_names[book['abbreviation']])) self.book_name_label[book['abbreviation']].setText(
'{text}:'.format(text=self.book_names[book['abbreviation']]))

View File

@ -39,7 +39,7 @@ class EditBibleForm(QtWidgets.QDialog, Ui_EditBibleDialog, RegistryProperties):
""" """
Class to manage the editing of a bible Class to manage the editing of a bible
""" """
log.info('%s EditBibleForm loaded', __name__) log.info('{name} EditBibleForm loaded'.format(name=__name__))
def __init__(self, media_item, parent, manager): def __init__(self, media_item, parent, manager):
""" """
@ -168,16 +168,17 @@ class EditBibleForm(QtWidgets.QDialog, Ui_EditBibleDialog, RegistryProperties):
self.book_name_edit[abbreviation].setFocus() self.book_name_edit[abbreviation].setFocus()
critical_error_message_box( critical_error_message_box(
UiStrings().EmptyField, UiStrings().EmptyField,
translate('BiblesPlugin.BibleEditForm', 'You need to specify a book name for "%s".') % translate('BiblesPlugin.BibleEditForm',
self.book_names[abbreviation]) 'You need to specify a book name for "{text}".').format(text=self.book_names[abbreviation]))
return False return False
elif not book_regex.match(new_book_name): elif not book_regex.match(new_book_name):
self.book_name_edit[abbreviation].setFocus() self.book_name_edit[abbreviation].setFocus()
critical_error_message_box( critical_error_message_box(
UiStrings().EmptyField, UiStrings().EmptyField,
translate('BiblesPlugin.BibleEditForm', translate('BiblesPlugin.BibleEditForm',
'The book name "%s" is not correct.\nNumbers can only be used at the beginning and must\nbe ' 'The book name "{name}" is not correct.\n'
'followed by one or more non-numeric characters.') % new_book_name) 'Numbers can only be used at the beginning and must\nbe '
'followed by one or more non-numeric characters.').format(name=new_book_name))
return False return False
for abbr, book in self.books.items(): for abbr, book in self.books.items():
if book: if book:
@ -187,7 +188,7 @@ class EditBibleForm(QtWidgets.QDialog, Ui_EditBibleDialog, RegistryProperties):
self.book_name_edit[abbreviation].setFocus() self.book_name_edit[abbreviation].setFocus()
critical_error_message_box( critical_error_message_box(
translate('BiblesPlugin.BibleEditForm', 'Duplicate Book Name'), translate('BiblesPlugin.BibleEditForm', 'Duplicate Book Name'),
translate('BiblesPlugin.BibleEditForm', 'The Book Name "%s" has been entered more than once.') translate('BiblesPlugin.BibleEditForm',
% new_book_name) 'The Book Name "{name}" has been entered more than once.').format(name=new_book_name))
return False return False
return True return True

View File

@ -86,7 +86,7 @@ class CSVBible(BibleDB):
success = True success = True
language_id = self.get_language(bible_name) language_id = self.get_language(bible_name)
if not language_id: if not language_id:
log.error('Importing books from "%s" failed' % self.filename) log.error('Importing books from "{name}" failed'.format(name=self.filename))
return False return False
books_file = None books_file = None
book_list = {} book_list = {}
@ -98,11 +98,11 @@ class CSVBible(BibleDB):
for line in books_reader: for line in books_reader:
if self.stop_import_flag: if self.stop_import_flag:
break break
self.wizard.increment_progress_bar(translate('BiblesPlugin.CSVBible', 'Importing books... %s') self.wizard.increment_progress_bar(translate('BiblesPlugin.CSVBible',
% line[2]) 'Importing books... {text}').format(text=line[2]))
book_ref_id = self.get_book_ref_id_by_name(line[2], 67, language_id) book_ref_id = self.get_book_ref_id_by_name(line[2], 67, language_id)
if not book_ref_id: if not book_ref_id:
log.error('Importing books from "%s" failed' % self.books_file) log.error('Importing books from "{name}" failed'.format(name=self.books_file))
return False return False
book_details = BiblesResourcesDB.get_book_by_id(book_ref_id) book_details = BiblesResourcesDB.get_book_by_id(book_ref_id)
self.create_book(line[2], book_ref_id, book_details['testament_id']) self.create_book(line[2], book_ref_id, book_details['testament_id'])
@ -134,9 +134,11 @@ class CSVBible(BibleDB):
if book_ptr != line_book: if book_ptr != line_book:
book = self.get_book(line_book) book = self.get_book(line_book)
book_ptr = book.name book_ptr = book.name
# TODO: Check out this conversion in translations
self.wizard.increment_progress_bar( self.wizard.increment_progress_bar(
translate('BiblesPlugin.CSVBible', translate('BiblesPlugin.CSVBible',
'Importing verses from %s...' % book.name, 'Importing verses from <book name>...')) 'Importing verses from {name}...'.format(name=book.name),
'Importing verses from <book name>...'))
self.session.commit() self.session.commit()
verse_text = line[3] verse_text = line[3]
self.create_verse(book.id, line[1], line[2], verse_text) self.create_verse(book.id, line[1], line[2], verse_text)

View File

@ -185,7 +185,7 @@ class BibleDB(Manager, RegistryProperties):
:param testament: *Defaults to 1.* The testament_reference_id from :param testament: *Defaults to 1.* The testament_reference_id from
bibles_resources.sqlite of the testament this book belongs to. bibles_resources.sqlite of the testament this book belongs to.
""" """
log.debug('BibleDB.create_book("%s", "%s")' % (name, bk_ref_id)) log.debug('BibleDB.create_book("{name}", "{number}")'.format(name=name, number=bk_ref_id))
book = Book.populate(name=name, book_reference_id=bk_ref_id, testament_reference_id=testament) book = Book.populate(name=name, book_reference_id=bk_ref_id, testament_reference_id=testament)
self.save_object(book) self.save_object(book)
return book return book
@ -196,7 +196,7 @@ class BibleDB(Manager, RegistryProperties):
:param book: The book object :param book: The book object
""" """
log.debug('BibleDB.update_book("%s")' % book.name) log.debug('BibleDB.update_book("{name}")'.format(name=book.name))
return self.save_object(book) return self.save_object(book)
def delete_book(self, db_book): def delete_book(self, db_book):
@ -205,7 +205,7 @@ class BibleDB(Manager, RegistryProperties):
:param db_book: The book object. :param db_book: The book object.
""" """
log.debug('BibleDB.delete_book("%s")' % db_book.name) log.debug('BibleDB.delete_book("{name}")'.format(name=db_book.name))
if self.delete_object(Book, db_book.id): if self.delete_object(Book, db_book.id):
return True return True
return False return False
@ -219,7 +219,7 @@ class BibleDB(Manager, RegistryProperties):
:param text_list: A dict of the verses to be inserted. The key is the verse number, and the value is the :param text_list: A dict of the verses to be inserted. The key is the verse number, and the value is the
verse text. verse text.
""" """
log.debug('BibleDBcreate_chapter("%s", "%s")' % (book_id, chapter)) log.debug('BibleDBcreate_chapter("{number}", "{chapter}")'.format(number=book_id, chapter=chapter))
# Text list has book and chapter as first two elements of the array. # Text list has book and chapter as first two elements of the array.
for verse_number, verse_text in text_list.items(): for verse_number, verse_text in text_list.items():
verse = Verse.populate( verse = Verse.populate(
@ -266,7 +266,7 @@ class BibleDB(Manager, RegistryProperties):
""" """
if not isinstance(value, str): if not isinstance(value, str):
value = str(value) value = str(value)
log.debug('BibleDB.save_meta("%s/%s")' % (key, value)) log.debug('BibleDB.save_meta("{key}/{val}")'.format(key=key, val=value))
meta = self.get_object(BibleMeta, key) meta = self.get_object(BibleMeta, key)
if meta: if meta:
meta.value = value meta.value = value
@ -280,7 +280,7 @@ class BibleDB(Manager, RegistryProperties):
:param book: The name of the book to return. :param book: The name of the book to return.
""" """
log.debug('BibleDB.get_book("%s")' % book) log.debug('BibleDB.get_book("{book}")'.format(book=book))
return self.get_object_filtered(Book, Book.name.like(book + '%')) return self.get_object_filtered(Book, Book.name.like(book + '%'))
def get_books(self): def get_books(self):
@ -297,11 +297,11 @@ class BibleDB(Manager, RegistryProperties):
:param ref_id: The reference id of the book to return. :param ref_id: The reference id of the book to return.
""" """
log.debug('BibleDB.get_book_by_book_ref_id("%s")' % ref_id) log.debug('BibleDB.get_book_by_book_ref_id("{ref}")'.format(ref=ref_id))
return self.get_object_filtered(Book, Book.book_reference_id.like(ref_id)) return self.get_object_filtered(Book, Book.book_reference_id.like(ref_id))
def get_book_ref_id_by_name(self, book, maxbooks, language_id=None): def get_book_ref_id_by_name(self, book, maxbooks, language_id=None):
log.debug('BibleDB.get_book_ref_id_by_name:("%s", "%s")' % (book, language_id)) log.debug('BibleDB.get_book_ref_id_by_name:("{book}", "{lang}")'.format(book=book, lang=language_id))
book_id = None book_id = None
if BiblesResourcesDB.get_book(book, True): if BiblesResourcesDB.get_book(book, True):
book_temp = BiblesResourcesDB.get_book(book, True) book_temp = BiblesResourcesDB.get_book(book, True)
@ -327,13 +327,14 @@ class BibleDB(Manager, RegistryProperties):
:param book: The name of the book, according to the selected language. :param book: The name of the book, according to the selected language.
:param language_selection: The language selection the user has chosen in the settings section of the Bible. :param language_selection: The language selection the user has chosen in the settings section of the Bible.
""" """
log.debug('get_book_ref_id_by_localised_name("%s", "%s")' % (book, language_selection)) log.debug('get_book_ref_id_by_localised_name("{book}", "{lang}")'.format(book=book, lang=language_selection))
from openlp.plugins.bibles.lib import LanguageSelection, BibleStrings from openlp.plugins.bibles.lib import LanguageSelection, BibleStrings
book_names = BibleStrings().BookNames book_names = BibleStrings().BookNames
# escape reserved characters # escape reserved characters
book_escaped = book book_escaped = book
for character in RESERVED_CHARACTERS: for character in RESERVED_CHARACTERS:
book_escaped = book_escaped.replace(character, '\\' + character) book_escaped = book_escaped.replace(character, '\\' + character)
# TODO: Verify regex patters before using format()
regex_book = re.compile('\s*%s\s*' % '\s*'.join( regex_book = re.compile('\s*%s\s*' % '\s*'.join(
book_escaped.split()), re.UNICODE | re.IGNORECASE) book_escaped.split()), re.UNICODE | re.IGNORECASE)
if language_selection == LanguageSelection.Bible: if language_selection == LanguageSelection.Bible:
@ -374,14 +375,14 @@ class BibleDB(Manager, RegistryProperties):
[('35', 1, 1, 1), ('35', 2, 2, 3)] [('35', 1, 1, 1), ('35', 2, 2, 3)]
:param show_error: :param show_error:
""" """
log.debug('BibleDB.get_verses("%s")' % reference_list) log.debug('BibleDB.get_verses("{ref}")'.format(ref=reference_list))
verse_list = [] verse_list = []
book_error = False book_error = False
for book_id, chapter, start_verse, end_verse in reference_list: for book_id, chapter, start_verse, end_verse in reference_list:
db_book = self.get_book_by_book_ref_id(book_id) db_book = self.get_book_by_book_ref_id(book_id)
if db_book: if db_book:
book_id = db_book.book_reference_id book_id = db_book.book_reference_id
log.debug('Book name corrected to "%s"' % db_book.name) log.debug('Book name corrected to "{book}"'.format(book=db_book.name))
if end_verse == -1: if end_verse == -1:
end_verse = self.get_verse_count(book_id, chapter) end_verse = self.get_verse_count(book_id, chapter)
verses = self.session.query(Verse) \ verses = self.session.query(Verse) \
@ -393,7 +394,7 @@ class BibleDB(Manager, RegistryProperties):
.all() .all()
verse_list.extend(verses) verse_list.extend(verses)
else: else:
log.debug('OpenLP failed to find book with id "%s"' % book_id) log.debug('OpenLP failed to find book with id "{book}"'.format(book=book_id))
book_error = True book_error = True
if book_error and show_error: if book_error and show_error:
critical_error_message_box( critical_error_message_box(
@ -412,8 +413,9 @@ class BibleDB(Manager, RegistryProperties):
contains spaces, it will split apart and AND'd on the list of contains spaces, it will split apart and AND'd on the list of
values. values.
""" """
log.debug('BibleDB.verse_search("%s")' % text) log.debug('BibleDB.verse_search("{text}")'.format(text=text))
verses = self.session.query(Verse) verses = self.session.query(Verse)
# TODO: Find out what this is doing before converting to format()
if text.find(',') > -1: if text.find(',') > -1:
keywords = ['%%%s%%' % keyword.strip() for keyword in text.split(',')] keywords = ['%%%s%%' % keyword.strip() for keyword in text.split(',')]
or_clause = [Verse.text.like(keyword) for keyword in keywords] or_clause = [Verse.text.like(keyword) for keyword in keywords]
@ -431,7 +433,7 @@ class BibleDB(Manager, RegistryProperties):
:param book: The book object to get the chapter count for. :param book: The book object to get the chapter count for.
""" """
log.debug('BibleDB.get_chapter_count("%s")' % book.name) log.debug('BibleDB.get_chapter_count("{book}")'.format(book=book.name))
count = self.session.query(func.max(Verse.chapter)).join(Book).filter( count = self.session.query(func.max(Verse.chapter)).join(Book).filter(
Book.book_reference_id == book.book_reference_id).scalar() Book.book_reference_id == book.book_reference_id).scalar()
if not count: if not count:
@ -445,7 +447,7 @@ class BibleDB(Manager, RegistryProperties):
:param book_ref_id: The book reference id. :param book_ref_id: The book reference id.
:param chapter: The chapter to get the verse count for. :param chapter: The chapter to get the verse count for.
""" """
log.debug('BibleDB.get_verse_count("%s", "%s")' % (book_ref_id, chapter)) log.debug('BibleDB.get_verse_count("{ref}", "{chapter}")'.format(ref=book_ref_id, chapter=chapter))
count = self.session.query(func.max(Verse.verse)).join(Book) \ count = self.session.query(func.max(Verse.verse)).join(Book) \
.filter(Book.book_reference_id == book_ref_id) \ .filter(Book.book_reference_id == book_ref_id) \
.filter(Verse.chapter == chapter) \ .filter(Verse.chapter == chapter) \
@ -551,7 +553,7 @@ class BiblesResourcesDB(QtCore.QObject, Manager):
:param name: The name or abbreviation of the book. :param name: The name or abbreviation of the book.
:param lower: True if the comparison should be only lowercase :param lower: True if the comparison should be only lowercase
""" """
log.debug('BiblesResourcesDB.get_book("%s")' % name) log.debug('BiblesResourcesDB.get_book("{name}")'.format(name=name))
if not isinstance(name, str): if not isinstance(name, str):
name = str(name) name = str(name)
if lower: if lower:
@ -580,7 +582,7 @@ class BiblesResourcesDB(QtCore.QObject, Manager):
:param string: The string to search for in the book names or abbreviations. :param string: The string to search for in the book names or abbreviations.
""" """
log.debug('BiblesResourcesDB.get_book_like("%s")' % string) log.debug('BiblesResourcesDB.get_book_like("{text}")'.format(text=string))
if not isinstance(string, str): if not isinstance(string, str):
name = str(string) name = str(string)
books = BiblesResourcesDB.run_sql( books = BiblesResourcesDB.run_sql(
@ -605,7 +607,7 @@ class BiblesResourcesDB(QtCore.QObject, Manager):
:param book_id: The id of the book. :param book_id: The id of the book.
""" """
log.debug('BiblesResourcesDB.get_book_by_id("%s")' % book_id) log.debug('BiblesResourcesDB.get_book_by_id("{book}")'.format(book=book_id))
if not isinstance(book_id, int): if not isinstance(book_id, int):
book_id = int(book_id) book_id = int(book_id)
books = BiblesResourcesDB.run_sql( books = BiblesResourcesDB.run_sql(
@ -629,7 +631,7 @@ class BiblesResourcesDB(QtCore.QObject, Manager):
:param book_ref_id: The id of a book. :param book_ref_id: The id of a book.
:param chapter: The chapter number. :param chapter: The chapter number.
""" """
log.debug('BiblesResourcesDB.get_chapter("%s", "%s")' % (book_ref_id, chapter)) log.debug('BiblesResourcesDB.get_chapter("{book}", "{ref}")'.format(book=book_ref_id, ref=chapter))
if not isinstance(chapter, int): if not isinstance(chapter, int):
chapter = int(chapter) chapter = int(chapter)
chapters = BiblesResourcesDB.run_sql( chapters = BiblesResourcesDB.run_sql(
@ -652,7 +654,7 @@ class BiblesResourcesDB(QtCore.QObject, Manager):
:param book_ref_id: The id of the book. :param book_ref_id: The id of the book.
""" """
log.debug('BiblesResourcesDB.get_chapter_count("%s")' % book_ref_id) log.debug('BiblesResourcesDB.get_chapter_count("{ref}")'.format(ref=book_ref_id))
details = BiblesResourcesDB.get_book_by_id(book_ref_id) details = BiblesResourcesDB.get_book_by_id(book_ref_id)
if details: if details:
return details['chapters'] return details['chapters']
@ -666,7 +668,7 @@ class BiblesResourcesDB(QtCore.QObject, Manager):
:param book_ref_id: The id of the book. :param book_ref_id: The id of the book.
:param chapter: The number of the chapter. :param chapter: The number of the chapter.
""" """
log.debug('BiblesResourcesDB.get_verse_count("%s", "%s")' % (book_ref_id, chapter)) log.debug('BiblesResourcesDB.get_verse_count("{ref}", "{chapter}")'.format(ref=book_ref_id, chapter=chapter))
details = BiblesResourcesDB.get_chapter(book_ref_id, chapter) details = BiblesResourcesDB.get_chapter(book_ref_id, chapter)
if details: if details:
return details['verse_count'] return details['verse_count']
@ -679,7 +681,7 @@ class BiblesResourcesDB(QtCore.QObject, Manager):
:param source: The name or abbreviation of the book. :param source: The name or abbreviation of the book.
""" """
log.debug('BiblesResourcesDB.get_download_source("%s")' % source) log.debug('BiblesResourcesDB.get_download_source("{source}")'.format(source=source))
if not isinstance(source, str): if not isinstance(source, str):
source = str(source) source = str(source)
source = source.title() source = source.title()
@ -700,7 +702,7 @@ class BiblesResourcesDB(QtCore.QObject, Manager):
:param source: The source of the web_bible. :param source: The source of the web_bible.
""" """
log.debug('BiblesResourcesDB.get_webbibles("%s")' % source) log.debug('BiblesResourcesDB.get_webbibles("{source}")'.format(source=source))
if not isinstance(source, str): if not isinstance(source, str):
source = str(source) source = str(source)
source = BiblesResourcesDB.get_download_source(source) source = BiblesResourcesDB.get_download_source(source)
@ -725,7 +727,7 @@ class BiblesResourcesDB(QtCore.QObject, Manager):
:param abbreviation: The abbreviation of the web_bible. :param abbreviation: The abbreviation of the web_bible.
:param source: The source of the web_bible. :param source: The source of the web_bible.
""" """
log.debug('BiblesResourcesDB.get_webbibles("%s", "%s")' % (abbreviation, source)) log.debug('BiblesResourcesDB.get_webbibles("{text}", "{source}")'.format(text=abbreviation, source=source))
if not isinstance(abbreviation, str): if not isinstance(abbreviation, str):
abbreviation = str(abbreviation) abbreviation = str(abbreviation)
if not isinstance(source, str): if not isinstance(source, str):
@ -753,7 +755,7 @@ class BiblesResourcesDB(QtCore.QObject, Manager):
:param name: The name to search the id. :param name: The name to search the id.
:param language_id: The language_id for which language should be searched :param language_id: The language_id for which language should be searched
""" """
log.debug('BiblesResourcesDB.get_alternative_book_name("%s", "%s")' % (name, language_id)) log.debug('BiblesResourcesDB.get_alternative_book_name("{name}", "{lang}")'.format(name=name, lang=language_id))
if language_id: if language_id:
books = BiblesResourcesDB.run_sql( books = BiblesResourcesDB.run_sql(
'SELECT book_reference_id, name FROM alternative_book_names WHERE language_id = ? ORDER BY id', 'SELECT book_reference_id, name FROM alternative_book_names WHERE language_id = ? ORDER BY id',
@ -772,7 +774,7 @@ class BiblesResourcesDB(QtCore.QObject, Manager):
:param name: The name or abbreviation of the language. :param name: The name or abbreviation of the language.
""" """
log.debug('BiblesResourcesDB.get_language("%s")' % name) log.debug('BiblesResourcesDB.get_language("{name}")'.format(name=name))
if not isinstance(name, str): if not isinstance(name, str):
name = str(name) name = str(name)
language = BiblesResourcesDB.run_sql( language = BiblesResourcesDB.run_sql(
@ -868,7 +870,7 @@ class AlternativeBookNamesDB(QtCore.QObject, Manager):
:param name: The name to search the id. :param name: The name to search the id.
:param language_id: The language_id for which language should be searched :param language_id: The language_id for which language should be searched
""" """
log.debug('AlternativeBookNamesDB.get_book_reference_id("%s", "%s")' % (name, language_id)) log.debug('AlternativeBookNamesDB.get_book_reference_id("{name}", "{ref}")'.format(name=name, ref=language_id))
if language_id: if language_id:
books = AlternativeBookNamesDB.run_sql( books = AlternativeBookNamesDB.run_sql(
'SELECT book_reference_id, name FROM alternative_book_names WHERE language_id = ?', (language_id, )) 'SELECT book_reference_id, name FROM alternative_book_names WHERE language_id = ?', (language_id, ))
@ -889,8 +891,8 @@ class AlternativeBookNamesDB(QtCore.QObject, Manager):
:param book_reference_id: The book_reference_id of the book. :param book_reference_id: The book_reference_id of the book.
:param language_id: The language to which the alternative book name belong. :param language_id: The language to which the alternative book name belong.
""" """
log.debug('AlternativeBookNamesDB.create_alternative_book_name("%s", "%s", "%s")' % log.debug('AlternativeBookNamesDB.create_alternative_book_name("{name}", '
(name, book_reference_id, language_id)) '"{ref}", "{lang}")'.format(name=name, ref=book_reference_id, lang=language_id))
return AlternativeBookNamesDB.run_sql( return AlternativeBookNamesDB.run_sql(
'INSERT INTO alternative_book_names(book_reference_id, language_id, name) ' 'INSERT INTO alternative_book_names(book_reference_id, language_id, name) '
'VALUES (?, ?, ?)', (book_reference_id, language_id, name), True) 'VALUES (?, ?, ?)', (book_reference_id, language_id, name), True)

View File

@ -90,7 +90,7 @@ class BGExtract(RegistryProperties):
Extract verses from BibleGateway Extract verses from BibleGateway
""" """
def __init__(self, proxy_url=None): def __init__(self, proxy_url=None):
log.debug('BGExtract.init("%s")', proxy_url) log.debug('BGExtract.init("{url}")'.format(url=proxy_url))
self.proxy_url = proxy_url self.proxy_url = proxy_url
socket.setdefaulttimeout(30) socket.setdefaulttimeout(30)
@ -188,7 +188,7 @@ class BGExtract(RegistryProperties):
if len(verse_parts) > 1: if len(verse_parts) > 1:
verse = int(verse_parts[0]) verse = int(verse_parts[0])
except TypeError: except TypeError:
log.warning('Illegal verse number: %s', str(verse)) log.warning('Illegal verse number: {verse:d}'.format(verse=verse))
verses.append((verse, text)) verses.append((verse, text))
verse_list = {} verse_list = {}
for verse, text in verses[::-1]: for verse, text in verses[::-1]:
@ -221,7 +221,7 @@ class BGExtract(RegistryProperties):
if len(verse_parts) > 1: if len(verse_parts) > 1:
clean_verse_num = int(verse_parts[0]) clean_verse_num = int(verse_parts[0])
except TypeError: except TypeError:
log.warning('Illegal verse number: %s', str(raw_verse_num)) log.warning('Illegal verse number: {verse:d}'.format(verse=raw_verse_num))
if clean_verse_num: if clean_verse_num:
verse_text = raw_verse_num.next_element verse_text = raw_verse_num.next_element
part = raw_verse_num.next_element.next_element part = raw_verse_num.next_element.next_element
@ -244,11 +244,15 @@ class BGExtract(RegistryProperties):
:param book_name: Name of the Book. :param book_name: Name of the Book.
:param chapter: Chapter number. :param chapter: Chapter number.
""" """
log.debug('BGExtract.get_bible_chapter("%s", "%s", "%s")', version, book_name, chapter) log.debug('BGExtract.get_bible_chapter("{version}", "{name}", "{chapter}")'.format(version=version,
name=book_name,
chapter=chapter))
url_book_name = urllib.parse.quote(book_name.encode("utf-8")) url_book_name = urllib.parse.quote(book_name.encode("utf-8"))
url_params = 'search=%s+%s&version=%s' % (url_book_name, chapter, version) url_params = 'search={name}+{chapter}&version={version}'.format(name=url_book_name,
chapter=chapter,
version=version)
soup = get_soup_for_bible_ref( soup = get_soup_for_bible_ref(
'http://legacy.biblegateway.com/passage/?%s' % url_params, 'http://legacy.biblegateway.com/passage/?{url}'.format(url=url_params),
pre_parse_regex=r'<meta name.*?/>', pre_parse_substitute='') pre_parse_regex=r'<meta name.*?/>', pre_parse_substitute='')
if not soup: if not soup:
return None return None
@ -257,7 +261,7 @@ class BGExtract(RegistryProperties):
return None return None
self._clean_soup(div) self._clean_soup(div)
span_list = div.find_all('span', 'text') span_list = div.find_all('span', 'text')
log.debug('Span list: %s', span_list) log.debug('Span list: {span}'.format(span=span_list))
if not span_list: if not span_list:
# If we don't get any spans then we must have the old HTML format # If we don't get any spans then we must have the old HTML format
verse_list = self._extract_verses_old(div) verse_list = self._extract_verses_old(div)
@ -275,9 +279,9 @@ class BGExtract(RegistryProperties):
:param version: The version of the Bible like NIV for New International Version :param version: The version of the Bible like NIV for New International Version
""" """
log.debug('BGExtract.get_books_from_http("%s")', version) log.debug('BGExtract.get_books_from_http("{version}")'.format(version=version))
url_params = urllib.parse.urlencode({'action': 'getVersionInfo', 'vid': '%s' % version}) url_params = urllib.parse.urlencode({'action': 'getVersionInfo', 'vid': '{version}'.format(version=version)})
reference_url = 'http://legacy.biblegateway.com/versions/?%s#books' % url_params reference_url = 'http://legacy.biblegateway.com/versions/?{url}#books'.format(url=url_params)
page = get_web_page(reference_url) page = get_web_page(reference_url)
if not page: if not page:
send_error_message('download') send_error_message('download')
@ -353,7 +357,7 @@ class BSExtract(RegistryProperties):
Extract verses from Bibleserver.com Extract verses from Bibleserver.com
""" """
def __init__(self, proxy_url=None): def __init__(self, proxy_url=None):
log.debug('BSExtract.init("%s")', proxy_url) log.debug('BSExtract.init("{url}")'.format(url=proxy_url))
self.proxy_url = proxy_url self.proxy_url = proxy_url
socket.setdefaulttimeout(30) socket.setdefaulttimeout(30)
@ -365,10 +369,14 @@ class BSExtract(RegistryProperties):
:param book_name: Text name of bible book e.g. Genesis, 1. John, 1John or Offenbarung :param book_name: Text name of bible book e.g. Genesis, 1. John, 1John or Offenbarung
:param chapter: Chapter number :param chapter: Chapter number
""" """
log.debug('BSExtract.get_bible_chapter("%s", "%s", "%s")', version, book_name, chapter) log.debug('BSExtract.get_bible_chapter("{version}", "{book}", "{chapter}")'.format(version=version,
book=book_name,
chapter=chapter))
url_version = urllib.parse.quote(version.encode("utf-8")) url_version = urllib.parse.quote(version.encode("utf-8"))
url_book_name = urllib.parse.quote(book_name.encode("utf-8")) url_book_name = urllib.parse.quote(book_name.encode("utf-8"))
chapter_url = 'http://m.bibleserver.com/text/%s/%s%d' % (url_version, url_book_name, chapter) chapter_url = 'http://m.bibleserver.com/text/{version}/{name}{chapter:d}'.format(version=url_version,
name=url_book_name,
chapter=chapter)
header = ('Accept-Language', 'en') header = ('Accept-Language', 'en')
soup = get_soup_for_bible_ref(chapter_url, header) soup = get_soup_for_bible_ref(chapter_url, header)
if not soup: if not soup:
@ -393,9 +401,9 @@ class BSExtract(RegistryProperties):
:param version: The version of the Bible like NIV for New International Version :param version: The version of the Bible like NIV for New International Version
""" """
log.debug('BSExtract.get_books_from_http("%s")', version) log.debug('BSExtract.get_books_from_http("{version}")'.format(version=version))
url_version = urllib.parse.quote(version.encode("utf-8")) url_version = urllib.parse.quote(version.encode("utf-8"))
chapter_url = 'http://m.bibleserver.com/overlay/selectBook?translation=%s' % url_version chapter_url = 'http://m.bibleserver.com/overlay/selectBook?translation={version}'.format(version=url_version)
soup = get_soup_for_bible_ref(chapter_url) soup = get_soup_for_bible_ref(chapter_url)
if not soup: if not soup:
return None return None
@ -450,7 +458,7 @@ class CWExtract(RegistryProperties):
Extract verses from CrossWalk/BibleStudyTools Extract verses from CrossWalk/BibleStudyTools
""" """
def __init__(self, proxy_url=None): def __init__(self, proxy_url=None):
log.debug('CWExtract.init("%s")', proxy_url) log.debug('CWExtract.init("{url}")'.format(url=proxy_url))
self.proxy_url = proxy_url self.proxy_url = proxy_url
socket.setdefaulttimeout(30) socket.setdefaulttimeout(30)
@ -462,11 +470,15 @@ class CWExtract(RegistryProperties):
:param book_name: Text name of in english e.g. 'gen' for Genesis :param book_name: Text name of in english e.g. 'gen' for Genesis
:param chapter: Chapter number :param chapter: Chapter number
""" """
log.debug('CWExtract.get_bible_chapter("%s", "%s", "%s")', version, book_name, chapter) log.debug('CWExtract.get_bible_chapter("{version}", "{book}", "{chapter}")'.format(version=version,
book=book_name,
chapter=chapter))
url_book_name = book_name.replace(' ', '-') url_book_name = book_name.replace(' ', '-')
url_book_name = url_book_name.lower() url_book_name = url_book_name.lower()
url_book_name = urllib.parse.quote(url_book_name.encode("utf-8")) url_book_name = urllib.parse.quote(url_book_name.encode("utf-8"))
chapter_url = 'http://www.biblestudytools.com/%s/%s/%s.html' % (version, url_book_name, chapter) chapter_url = 'http://www.biblestudytools.com/{version}/{book}/{chapter}.html'.format(version=version,
book=url_book_name,
chapter=chapter)
soup = get_soup_for_bible_ref(chapter_url) soup = get_soup_for_bible_ref(chapter_url)
if not soup: if not soup:
return None return None
@ -499,8 +511,8 @@ class CWExtract(RegistryProperties):
:param version: The version of the bible like NIV for New International Version :param version: The version of the bible like NIV for New International Version
""" """
log.debug('CWExtract.get_books_from_http("%s")', version) log.debug('CWExtract.get_books_from_http("{version}")'.format(version=version))
chapter_url = 'http://www.biblestudytools.com/%s/' % version chapter_url = 'http://www.biblestudytools.com/{version}/'.format(version=version)
soup = get_soup_for_bible_ref(chapter_url) soup = get_soup_for_bible_ref(chapter_url)
if not soup: if not soup:
return None return None
@ -559,7 +571,7 @@ class CWExtract(RegistryProperties):
class HTTPBible(BibleDB, RegistryProperties): class HTTPBible(BibleDB, RegistryProperties):
log.info('%s HTTPBible loaded', __name__) log.info('{name} HTTPBible loaded'.format(name=__name__))
def __init__(self, parent, **kwargs): def __init__(self, parent, **kwargs):
""" """
@ -615,8 +627,8 @@ class HTTPBible(BibleDB, RegistryProperties):
handler = BSExtract(self.proxy_server) handler = BSExtract(self.proxy_server)
books = handler.get_books_from_http(self.download_name) books = handler.get_books_from_http(self.download_name)
if not books: if not books:
log.error('Importing books from %s - download name: "%s" failed' % log.error('Importing books from {source} - download name: "{name}" '
(self.download_source, self.download_name)) 'failed'.format(source=self.download_source, name=self.download_name))
return False return False
self.wizard.progress_bar.setMaximum(len(books) + 2) self.wizard.progress_bar.setMaximum(len(books) + 2)
self.wizard.increment_progress_bar(translate('BiblesPlugin.HTTPBible', 'Registering Language...')) self.wizard.increment_progress_bar(translate('BiblesPlugin.HTTPBible', 'Registering Language...'))
@ -625,21 +637,24 @@ class HTTPBible(BibleDB, RegistryProperties):
else: else:
self.language_id = self.get_language(bible_name) self.language_id = self.get_language(bible_name)
if not self.language_id: if not self.language_id:
log.error('Importing books from %s failed' % self.filename) log.error('Importing books from {name} failed'.format(name=self.filename))
return False return False
for book in books: for book in books:
if self.stop_import_flag: if self.stop_import_flag:
break break
self.wizard.increment_progress_bar(translate( self.wizard.increment_progress_bar(translate('BiblesPlugin.HTTPBible',
'BiblesPlugin.HTTPBible', 'Importing %s...', 'Importing <book name>...') % book) 'Importing {book}...',
'Importing <book name>...').format(book=book))
book_ref_id = self.get_book_ref_id_by_name(book, len(books), self.language_id) book_ref_id = self.get_book_ref_id_by_name(book, len(books), self.language_id)
if not book_ref_id: if not book_ref_id:
log.error('Importing books from %s - download name: "%s" failed' % log.error('Importing books from {source} - download name: "{name}" '
(self.download_source, self.download_name)) 'failed'.format(source=self.download_source, name=self.download_name))
return False return False
book_details = BiblesResourcesDB.get_book_by_id(book_ref_id) book_details = BiblesResourcesDB.get_book_by_id(book_ref_id)
log.debug('Book details: Name:%s; id:%s; testament_id:%s', log.debug('Book details: Name:{book}; id:{ref}; '
book, book_ref_id, book_details['testament_id']) 'testament_id:{detail}'.format(book=book,
ref=book_ref_id,
detail=book_details['testament_id']))
self.create_book(book, book_ref_id, book_details['testament_id']) self.create_book(book, book_ref_id, book_details['testament_id'])
if self.stop_import_flag: if self.stop_import_flag:
return False return False
@ -664,7 +679,7 @@ class HTTPBible(BibleDB, RegistryProperties):
[('35', 1, 1, 1), ('35', 2, 2, 3)] [('35', 1, 1, 1), ('35', 2, 2, 3)]
""" """
log.debug('HTTPBible.get_verses("%s")', reference_list) log.debug('HTTPBible.get_verses("{ref}")'.format(ref=reference_list))
for reference in reference_list: for reference in reference_list:
book_id = reference[0] book_id = reference[0]
db_book = self.get_book_by_book_ref_id(book_id) db_book = self.get_book_by_book_ref_id(book_id)
@ -698,8 +713,8 @@ class HTTPBible(BibleDB, RegistryProperties):
""" """
Receive the request and call the relevant handler methods. Receive the request and call the relevant handler methods.
""" """
log.debug('HTTPBible.get_chapter("%s", "%s")', book, chapter) log.debug('HTTPBible.get_chapter("{book}", "{chapter}")'.format(book=book, chapter=chapter))
log.debug('source = %s', self.download_source) log.debug('source = {source}'.format(source=self.download_source))
if self.download_source.lower() == 'crosswalk': if self.download_source.lower() == 'crosswalk':
handler = CWExtract(self.proxy_server) handler = CWExtract(self.proxy_server)
elif self.download_source.lower() == 'biblegateway': elif self.download_source.lower() == 'biblegateway':
@ -712,7 +727,7 @@ class HTTPBible(BibleDB, RegistryProperties):
""" """
Return the list of books. Return the list of books.
""" """
log.debug('HTTPBible.get_books("%s")', Book.name) log.debug('HTTPBible.get_books("{name}")'.format(name=Book.name))
return self.get_all_objects(Book, order_by_ref=Book.id) return self.get_all_objects(Book, order_by_ref=Book.id)
def get_chapter_count(self, book): def get_chapter_count(self, book):
@ -721,7 +736,7 @@ class HTTPBible(BibleDB, RegistryProperties):
:param book: The book object to get the chapter count for. :param book: The book object to get the chapter count for.
""" """
log.debug('HTTPBible.get_chapter_count("%s")', book.name) log.debug('HTTPBible.get_chapter_count("{name}")'.format(name=book.name))
return BiblesResourcesDB.get_chapter_count(book.book_reference_id) return BiblesResourcesDB.get_chapter_count(book.book_reference_id)
def get_verse_count(self, book_id, chapter): def get_verse_count(self, book_id, chapter):
@ -731,7 +746,7 @@ class HTTPBible(BibleDB, RegistryProperties):
:param book_id: The name of the book. :param book_id: The name of the book.
:param chapter: The chapter whose verses are being counted. :param chapter: The chapter whose verses are being counted.
""" """
log.debug('HTTPBible.get_verse_count("%s", %s)', book_id, chapter) log.debug('HTTPBible.get_verse_count("{ref}", {chapter})'.format(ref=book_id, chapter=chapter))
return BiblesResourcesDB.get_verse_count(book_id, chapter) return BiblesResourcesDB.get_verse_count(book_id, chapter)

View File

@ -122,7 +122,7 @@ class BibleManager(RegistryProperties):
files = AppLocation.get_files(self.settings_section, self.suffix) files = AppLocation.get_files(self.settings_section, self.suffix)
if 'alternative_book_names.sqlite' in files: if 'alternative_book_names.sqlite' in files:
files.remove('alternative_book_names.sqlite') files.remove('alternative_book_names.sqlite')
log.debug('Bible Files %s', files) log.debug('Bible Files {text}'.format(text=files))
self.db_cache = {} self.db_cache = {}
self.old_bible_databases = [] self.old_bible_databases = []
for filename in files: for filename in files:
@ -135,7 +135,7 @@ class BibleManager(RegistryProperties):
bible.session.close() bible.session.close()
delete_file(os.path.join(self.path, filename)) delete_file(os.path.join(self.path, filename))
continue continue
log.debug('Bible Name: "%s"', name) log.debug('Bible Name: "{name}"'.format(name=name))
self.db_cache[name] = bible self.db_cache[name] = bible
# Look to see if lazy load bible exists and get create getter. # Look to see if lazy load bible exists and get create getter.
source = self.db_cache[name].get_object(BibleMeta, 'download_source') source = self.db_cache[name].get_object(BibleMeta, 'download_source')
@ -177,7 +177,7 @@ class BibleManager(RegistryProperties):
:param name: The name of the bible. :param name: The name of the bible.
""" """
log.debug('BibleManager.delete_bible("%s")', name) log.debug('BibleManager.delete_bible("{name}")'.format(name=name))
bible = self.db_cache[name] bible = self.db_cache[name]
bible.session.close() bible.session.close()
bible.session = None bible.session = None
@ -196,7 +196,7 @@ class BibleManager(RegistryProperties):
:param bible: Unicode. The Bible to get the list of books from. :param bible: Unicode. The Bible to get the list of books from.
""" """
log.debug('BibleManager.get_books("%s")', bible) log.debug('BibleManager.get_books("{bible}")'.format(bible=bible))
return [ return [
{ {
'name': book.name, 'name': book.name,
@ -213,7 +213,7 @@ class BibleManager(RegistryProperties):
:param bible: Unicode. The Bible to get the list of books from. :param bible: Unicode. The Bible to get the list of books from.
:param id: Unicode. The book_reference_id to get the book for. :param id: Unicode. The book_reference_id to get the book for.
""" """
log.debug('BibleManager.get_book_by_id("%s", "%s")', bible, id) log.debug('BibleManager.get_book_by_id("{bible}", "{ref}")'.format(bible=bible, ref=id))
return self.db_cache[bible].get_book_by_book_ref_id(id) return self.db_cache[bible].get_book_by_book_ref_id(id)
def get_chapter_count(self, bible, book): def get_chapter_count(self, bible, book):
@ -223,14 +223,16 @@ class BibleManager(RegistryProperties):
:param bible: Unicode. The Bible to get the list of books from. :param bible: Unicode. The Bible to get the list of books from.
:param book: The book object to get the chapter count for. :param book: The book object to get the chapter count for.
""" """
log.debug('BibleManager.get_book_chapter_count ("%s", "%s")', bible, book.name) log.debug('BibleManager.get_book_chapter_count ("{bible}", "{name}")'.format(bible=bible, name=book.name))
return self.db_cache[bible].get_chapter_count(book) return self.db_cache[bible].get_chapter_count(book)
def get_verse_count(self, bible, book, chapter): def get_verse_count(self, bible, book, chapter):
""" """
Returns all the number of verses for a given book and chapterMaxBibleBookVerses. Returns all the number of verses for a given book and chapterMaxBibleBookVerses.
""" """
log.debug('BibleManager.get_verse_count("%s", "%s", %s)', bible, book, chapter) log.debug('BibleManager.get_verse_count("{bible}", "{book}", {chapter})'.format(bible=bible,
book=book,
chapter=chapter))
language_selection = self.get_language_selection(bible) language_selection = self.get_language_selection(bible)
book_ref_id = self.db_cache[bible].get_book_ref_id_by_localised_name(book, language_selection) book_ref_id = self.db_cache[bible].get_book_ref_id_by_localised_name(book, language_selection)
return self.db_cache[bible].get_verse_count(book_ref_id, chapter) return self.db_cache[bible].get_verse_count(book_ref_id, chapter)
@ -240,7 +242,8 @@ class BibleManager(RegistryProperties):
Returns all the number of verses for a given Returns all the number of verses for a given
book_ref_id and chapterMaxBibleBookVerses. book_ref_id and chapterMaxBibleBookVerses.
""" """
log.debug('BibleManager.get_verse_count_by_book_ref_id("%s", "%s", "%s")', bible, book_ref_id, chapter) log.debug('BibleManager.get_verse_count_by_book_ref_id("{bible}", '
'"{book}", "{chapter}")'.format(bible=bible, book=book_ref_id, chapter=chapter))
return self.db_cache[bible].get_verse_count(book_ref_id, chapter) return self.db_cache[bible].get_verse_count(book_ref_id, chapter)
def get_verses(self, bible, verse_text, book_ref_id=False, show_error=True): def get_verses(self, bible, verse_text, book_ref_id=False, show_error=True):
@ -264,7 +267,7 @@ class BibleManager(RegistryProperties):
For second bible this is necessary. For second bible this is necessary.
:param show_error: :param show_error:
""" """
log.debug('BibleManager.get_verses("%s", "%s")', bible, verse_text) log.debug('BibleManager.get_verses("{bible}", "{verse}")'.format(bible=bible, verse=verse_text))
if not bible: if not bible:
if show_error: if show_error:
self.main_window.information_message( self.main_window.information_message(
@ -308,7 +311,7 @@ class BibleManager(RegistryProperties):
:param bible: Unicode. The Bible to get the language selection from. :param bible: Unicode. The Bible to get the language selection from.
""" """
log.debug('BibleManager.get_language_selection("%s")', bible) log.debug('BibleManager.get_language_selection("{bible}")'.format(bible=bible))
language_selection = self.get_meta_data(bible, 'book_name_language') language_selection = self.get_meta_data(bible, 'book_name_language')
if not language_selection or language_selection.value == "None" or language_selection.value == "-1": if not language_selection or language_selection.value == "None" or language_selection.value == "-1":
# If None is returned, it's not the singleton object but a # If None is returned, it's not the singleton object but a
@ -330,7 +333,7 @@ class BibleManager(RegistryProperties):
:param second_bible: The second bible (unicode). We do not search in this bible. :param second_bible: The second bible (unicode). We do not search in this bible.
:param text: The text to search for (unicode). :param text: The text to search for (unicode).
""" """
log.debug('BibleManager.verse_search("%s", "%s")', bible, text) log.debug('BibleManager.verse_search("{bible}", "{text}")'.format(bible=bible, text=text))
if not bible: if not bible:
self.main_window.information_message( self.main_window.information_message(
translate('BiblesPlugin.BibleManager', 'No Bibles Available'), translate('BiblesPlugin.BibleManager', 'No Bibles Available'),
@ -365,7 +368,10 @@ class BibleManager(RegistryProperties):
""" """
Saves the bibles meta data. Saves the bibles meta data.
""" """
log.debug('save_meta data %s, %s, %s, %s', bible, version, copyright, permissions) log.debug('save_meta data {bible}, {version}, {copyright}, {perms}'.format(bible=bible,
version=version,
copyright=copyright,
perms=permissions))
self.db_cache[bible].save_meta('name', version) self.db_cache[bible].save_meta('name', version)
self.db_cache[bible].save_meta('copyright', copyright) self.db_cache[bible].save_meta('copyright', copyright)
self.db_cache[bible].save_meta('permissions', permissions) self.db_cache[bible].save_meta('permissions', permissions)
@ -375,14 +381,14 @@ class BibleManager(RegistryProperties):
""" """
Returns the meta data for a given key. Returns the meta data for a given key.
""" """
log.debug('get_meta %s,%s', bible, key) log.debug('get_meta {bible},{key}'.format(bible=bible, key=key))
return self.db_cache[bible].get_object(BibleMeta, key) return self.db_cache[bible].get_object(BibleMeta, key)
def update_book(self, bible, book): def update_book(self, bible, book):
""" """
Update a book of the bible. Update a book of the bible.
""" """
log.debug('BibleManager.update_book("%s", "%s")', bible, book.name) log.debug('BibleManager.update_book("{bible}", "{name}")'.format(bible=bible, name=book.name))
self.db_cache[bible].update_book(book) self.db_cache[bible].update_book(book)
def exists(self, name): def exists(self, name):
@ -392,7 +398,7 @@ class BibleManager(RegistryProperties):
if not isinstance(name, str): if not isinstance(name, str):
name = str(name) name = str(name)
for bible in list(self.db_cache.keys()): for bible in list(self.db_cache.keys()):
log.debug('Bible from cache in is_new_bible %s', bible) log.debug('Bible from cache in is_new_bible {bible}'.format(bible=bible))
if not isinstance(bible, str): if not isinstance(bible, str):
bible = str(bible) bible = str(bible)
if bible == name: if bible == name:

View File

@ -280,7 +280,7 @@ class BibleMediaItem(MediaManagerItem):
def retranslateUi(self): def retranslateUi(self):
log.debug('retranslateUi') log.debug('retranslateUi')
self.quick_search_label.setText(translate('BiblesPlugin.MediaItem', 'Find:')) self.quick_search_label.setText(translate('BiblesPlugin.MediaItem', 'Find:'))
self.quickVersionLabel.setText('%s:' % UiStrings().Version) self.quickVersionLabel.setText('{version}:'.format(version=UiStrings().Version))
self.quickSecondLabel.setText(translate('BiblesPlugin.MediaItem', 'Second:')) self.quickSecondLabel.setText(translate('BiblesPlugin.MediaItem', 'Second:'))
self.quickStyleLabel.setText(UiStrings().LayoutStyle) self.quickStyleLabel.setText(UiStrings().LayoutStyle)
self.quickStyleComboBox.setItemText(LayoutStyle.VersePerSlide, UiStrings().VersePerSlide) self.quickStyleComboBox.setItemText(LayoutStyle.VersePerSlide, UiStrings().VersePerSlide)
@ -294,7 +294,7 @@ class BibleMediaItem(MediaManagerItem):
self.advanced_verse_label.setText(translate('BiblesPlugin.MediaItem', 'Verse:')) self.advanced_verse_label.setText(translate('BiblesPlugin.MediaItem', 'Verse:'))
self.advanced_from_label.setText(translate('BiblesPlugin.MediaItem', 'From:')) self.advanced_from_label.setText(translate('BiblesPlugin.MediaItem', 'From:'))
self.advanced_to_label.setText(translate('BiblesPlugin.MediaItem', 'To:')) self.advanced_to_label.setText(translate('BiblesPlugin.MediaItem', 'To:'))
self.advancedVersionLabel.setText('%s:' % UiStrings().Version) self.advancedVersionLabel.setText('{version}:'.format(version=UiStrings().Version))
self.advancedSecondLabel.setText(translate('BiblesPlugin.MediaItem', 'Second:')) self.advancedSecondLabel.setText(translate('BiblesPlugin.MediaItem', 'Second:'))
self.advancedStyleLabel.setText(UiStrings().LayoutStyle) self.advancedStyleLabel.setText(UiStrings().LayoutStyle)
self.advancedStyleComboBox.setItemText(LayoutStyle.VersePerSlide, UiStrings().VersePerSlide) self.advancedStyleComboBox.setItemText(LayoutStyle.VersePerSlide, UiStrings().VersePerSlide)
@ -316,7 +316,8 @@ class BibleMediaItem(MediaManagerItem):
translate('BiblesPlugin.MediaItem', 'Text Search'), translate('BiblesPlugin.MediaItem', 'Text Search'),
translate('BiblesPlugin.MediaItem', 'Search Text...')) translate('BiblesPlugin.MediaItem', 'Search Text...'))
]) ])
self.quick_search_edit.set_current_search_type(Settings().value('%s/last search type' % self.settings_section)) text = self.settings_section
self.quick_search_edit.set_current_search_type(Settings().value('{text}/last search type'.format(text=text)))
self.config_update() self.config_update()
log.debug('bible manager initialise complete') log.debug('bible manager initialise complete')
@ -364,7 +365,7 @@ class BibleMediaItem(MediaManagerItem):
:param bible: The bible to initialise (unicode). :param bible: The bible to initialise (unicode).
:param last_book_id: The "book reference id" of the book which is chosen at the moment. (int) :param last_book_id: The "book reference id" of the book which is chosen at the moment. (int)
""" """
log.debug('initialise_advanced_bible %s, %s', bible, last_book_id) log.debug('initialise_advanced_bible {bible}, {ref}'.format(bible=bible, ref=last_book_id))
book_data = self.plugin.manager.get_books(bible) book_data = self.plugin.manager.get_books(bible)
second_bible = self.advancedSecondComboBox.currentText() second_bible = self.advancedSecondComboBox.currentText()
if second_bible != '': if second_bible != '':
@ -406,7 +407,7 @@ class BibleMediaItem(MediaManagerItem):
self.initialise_chapter_verse(bible, first_book['name'], first_book['book_reference_id']) self.initialise_chapter_verse(bible, first_book['name'], first_book['book_reference_id'])
def initialise_chapter_verse(self, bible, book, book_ref_id): def initialise_chapter_verse(self, bible, book, book_ref_id):
log.debug('initialise_chapter_verse %s, %s, %s', bible, book, book_ref_id) log.debug('initialise_chapter_verse {bible}, {book}, {ref}'.format(bible=bible, book=book, ref=book_ref_id))
book = self.plugin.manager.get_book_by_id(bible, book_ref_id) book = self.plugin.manager.get_book_by_id(bible, book_ref_id)
self.chapter_count = self.plugin.manager.get_chapter_count(bible, book) self.chapter_count = self.plugin.manager.get_chapter_count(bible, book)
verse_count = self.plugin.manager.get_verse_count_by_book_ref_id(bible, book_ref_id, 1) verse_count = self.plugin.manager.get_verse_count_by_book_ref_id(bible, book_ref_id, 1)
@ -427,9 +428,11 @@ class BibleMediaItem(MediaManagerItem):
""" """
log.debug('update_auto_completer') log.debug('update_auto_completer')
# Save the current search type to the configuration. # Save the current search type to the configuration.
Settings().setValue('%s/last search type' % self.settings_section, self.quick_search_edit.current_search_type()) Settings().setValue('{section}/last search type'.format(section=self.settings_section),
self.quick_search_edit.current_search_type())
# Save the current bible to the configuration. # Save the current bible to the configuration.
Settings().setValue(self.settings_section + '/quick bible', self.quickVersionComboBox.currentText()) Settings().setValue('{section}/quick bible'.format(section=self.settings_section),
self.quickVersionComboBox.currentText())
books = [] books = []
# We have to do a 'Reference Search'. # We have to do a 'Reference Search'.
if self.quick_search_edit.current_search_type() == BibleSearch.Reference: if self.quick_search_edit.current_search_type() == BibleSearch.Reference:
@ -502,9 +505,10 @@ class BibleMediaItem(MediaManagerItem):
if bible: if bible:
if QtWidgets.QMessageBox.question( if QtWidgets.QMessageBox.question(
self, UiStrings().ConfirmDelete, self, UiStrings().ConfirmDelete,
translate('BiblesPlugin.MediaItem', 'Are you sure you want to completely delete "%s" Bible from ' translate('BiblesPlugin.MediaItem',
'OpenLP?\n\nYou will need to re-import this Bible to use it ' 'Are you sure you want to completely delete "{bible}" Bible '
'again.') % bible, 'from OpenLP?\n\nYou will need to re-import this Bible to use it '
'again.').format(bible=bible),
QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No), QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No),
QtWidgets.QMessageBox.Yes) == QtWidgets.QMessageBox.No: QtWidgets.QMessageBox.Yes) == QtWidgets.QMessageBox.No:
return return
@ -606,7 +610,7 @@ class BibleMediaItem(MediaManagerItem):
:param combo: The combo box itself (QComboBox). :param combo: The combo box itself (QComboBox).
:param restore: If True, then the combo's currentText will be restored after adjusting (if possible). :param restore: If True, then the combo's currentText will be restored after adjusting (if possible).
""" """
log.debug('adjust_combo_box %s, %s, %s', combo, range_from, range_to) log.debug('adjust_combo_box {box}, {start}, {end}'.format(box=combo, start=range_from, end=range_to))
if restore: if restore:
old_text = combo.currentText() old_text = combo.currentText()
combo.clear() combo.clear()
@ -633,7 +637,7 @@ class BibleMediaItem(MediaManagerItem):
range_separator = get_reference_separator('sep_r_display') range_separator = get_reference_separator('sep_r_display')
verse_range = chapter_from + verse_separator + verse_from + range_separator + chapter_to + \ verse_range = chapter_from + verse_separator + verse_from + range_separator + chapter_to + \
verse_separator + verse_to verse_separator + verse_to
verse_text = '%s %s' % (book, verse_range) verse_text = '{book} {verse}'.format(book=book, verse=verse_range)
self.application.set_busy_cursor() self.application.set_busy_cursor()
self.search_results = self.plugin.manager.get_verses(bible, verse_text, book_ref_id) self.search_results = self.plugin.manager.get_verses(bible, verse_text, book_ref_id)
if second_bible: if second_bible:
@ -678,8 +682,8 @@ class BibleMediaItem(MediaManagerItem):
for verse in self.search_results: for verse in self.search_results:
db_book = bibles[second_bible].get_book_by_book_ref_id(verse.book.book_reference_id) db_book = bibles[second_bible].get_book_by_book_ref_id(verse.book.book_reference_id)
if not db_book: if not db_book:
log.debug('Passage "%s %d:%d" not found in Second Bible' % log.debug('Passage "{name} {chapter:d}:{verse:d}" not found in '
(verse.book.name, verse.chapter, verse.verse)) 'Second Bible'.format(name=verse.book.name, chapter=verse.chapter, verse=verse.verse))
passage_not_found = True passage_not_found = True
count += 1 count += 1
continue continue
@ -688,9 +692,10 @@ class BibleMediaItem(MediaManagerItem):
if passage_not_found: if passage_not_found:
QtWidgets.QMessageBox.information( QtWidgets.QMessageBox.information(
self, translate('BiblesPlugin.MediaItem', 'Information'), self, translate('BiblesPlugin.MediaItem', 'Information'),
translate('BiblesPlugin.MediaItem', 'The second Bible does not contain all the verses ' translate('BiblesPlugin.MediaItem',
'that are in the main Bible. Only verses found in both Bibles will be shown. %d ' 'The second Bible does not contain all the verses that are in the main Bible. '
'verses have not been included in the results.') % count, 'Only verses found in both Bibles will be shown. {count:d} verses have not been '
'included in the results.').format(count=count),
QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Ok)) QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Ok))
self.search_results = new_search_results self.search_results = new_search_results
self.second_search_results = bibles[second_bible].get_verses(text) self.second_search_results = bibles[second_bible].get_verses(text)
@ -767,10 +772,19 @@ class BibleMediaItem(MediaManagerItem):
except TypeError: except TypeError:
log.exception('The second_search_results does not have this book.') log.exception('The second_search_results does not have this book.')
break break
bible_text = '%s %d%s%d (%s, %s)' % (book, verse.chapter, verse_separator, verse.verse, version, bible_text = ('{book} {chapter:d}{sep}{verse:d} '
second_version) '({version1}, {version2})').format(book=book,
chapter=verse.chapter,
sep=verse_separator,
verse=verse.verse,
version1=version,
version2=second_version)
else: else:
bible_text = '%s %d%s%d (%s)' % (book, verse.chapter, verse_separator, verse.verse, version) bible_text = '{book} {chapter:d}{sep}{verse:d} ({version})'.format(book=book,
chapter=verse.chapter,
sep=verse_separator,
verse=verse.verse,
version=version)
bible_verse = QtWidgets.QListWidgetItem(bible_text) bible_verse = QtWidgets.QListWidgetItem(bible_text)
bible_verse.setData(QtCore.Qt.UserRole, data) bible_verse.setData(QtCore.Qt.UserRole, data)
items.append(bible_verse) items.append(bible_verse)
@ -817,20 +831,22 @@ class BibleMediaItem(MediaManagerItem):
verses.add(book, chapter, verse, version, copyright, permissions) verses.add(book, chapter, verse, version, copyright, permissions)
verse_text = self.format_verse(old_chapter, chapter, verse) verse_text = self.format_verse(old_chapter, chapter, verse)
if second_bible: if second_bible:
bible_text = '%s%s\n\n%s&nbsp;%s' % (verse_text, text, verse_text, second_text) bible_text = '{verse}{text1}\n\n{verse}&nbsp;{text2}'.format(verse=verse_text,
text1=text,
text2=second_text)
raw_slides.append(bible_text.rstrip()) raw_slides.append(bible_text.rstrip())
bible_text = '' bible_text = ''
# If we are 'Verse Per Slide' then create a new slide. # If we are 'Verse Per Slide' then create a new slide.
elif self.settings.layout_style == LayoutStyle.VersePerSlide: elif self.settings.layout_style == LayoutStyle.VersePerSlide:
bible_text = '%s%s' % (verse_text, text) bible_text = '{verse}{text}'.format(verse=verse_text, text=text)
raw_slides.append(bible_text.rstrip()) raw_slides.append(bible_text.rstrip())
bible_text = '' bible_text = ''
# If we are 'Verse Per Line' then force a new line. # If we are 'Verse Per Line' then force a new line.
elif self.settings.layout_style == LayoutStyle.VersePerLine: elif self.settings.layout_style == LayoutStyle.VersePerLine:
bible_text = '%s%s%s\n' % (bible_text, verse_text, text) bible_text = '{bible}{verse}{text}\n'.format(bible=bible_text, verse=verse_text, text=text)
# We have to be 'Continuous'. # We have to be 'Continuous'.
else: else:
bible_text = '%s %s%s\n' % (bible_text, verse_text, text) bible_text = '{bible} {verse}{text}\n'.format(bible=bible_text, verse=verse_text, text=text)
bible_text = bible_text.strip(' ') bible_text = bible_text.strip(' ')
if not old_item: if not old_item:
start_item = bitem start_item = bitem
@ -857,7 +873,7 @@ class BibleMediaItem(MediaManagerItem):
service_item.add_capability(ItemCapabilities.CanWordSplit) service_item.add_capability(ItemCapabilities.CanWordSplit)
service_item.add_capability(ItemCapabilities.CanEditTitle) service_item.add_capability(ItemCapabilities.CanEditTitle)
# Service Item: Title # Service Item: Title
service_item.title = '%s %s' % (verses.format_verses(), verses.format_versions()) service_item.title = '{verse} {version}'.format(verse=verses.format_verses(), version=verses.format_versions())
# Service Item: Theme # Service Item: Theme
if not self.settings.bible_theme: if not self.settings.bible_theme:
service_item.theme = None service_item.theme = None
@ -885,7 +901,7 @@ class BibleMediaItem(MediaManagerItem):
start_bible = self._decode_qt_object(start_bitem, 'bible') start_bible = self._decode_qt_object(start_bitem, 'bible')
start_second_bible = self._decode_qt_object(start_bitem, 'second_bible') start_second_bible = self._decode_qt_object(start_bitem, 'second_bible')
if start_second_bible: if start_second_bible:
bibles = '%s, %s' % (start_bible, start_second_bible) bibles = '{bible1}, {bible2}'.format(bible1=start_bible, bible2=start_second_bible)
else: else:
bibles = start_bible bibles = start_bible
if start_chapter == old_chapter: if start_chapter == old_chapter:
@ -896,7 +912,7 @@ class BibleMediaItem(MediaManagerItem):
else: else:
verse_range = start_chapter + verse_separator + start_verse + \ verse_range = start_chapter + verse_separator + start_verse + \
range_separator + old_chapter + verse_separator + old_verse range_separator + old_chapter + verse_separator + old_verse
return '%s %s (%s)' % (start_book, verse_range, bibles) return '{book} {verse} ({bible})'.format(book=start_book, verse=verse_range, bible=bibles)
def check_title(self, bitem, old_bitem): def check_title(self, bitem, old_bitem):
""" """
@ -949,12 +965,12 @@ class BibleMediaItem(MediaManagerItem):
else: else:
verse_text = str(verse) verse_text = str(verse)
if self.settings.display_style == DisplayStyle.Round: if self.settings.display_style == DisplayStyle.Round:
return '{su}(%s){/su}&nbsp;' % verse_text return '{{su}}({verse}){{/su}}&nbsp;'.format(verse=verse_text)
if self.settings.display_style == DisplayStyle.Curly: if self.settings.display_style == DisplayStyle.Curly:
return '{su}{%s}{/su}&nbsp;' % verse_text return '{{su}}{{{verse}}}{{/su}}&nbsp;'.format(verse=verse_text)
if self.settings.display_style == DisplayStyle.Square: if self.settings.display_style == DisplayStyle.Square:
return '{su}[%s]{/su}&nbsp;' % verse_text return '{{su}}[{verse}]{{/su}}&nbsp;'.format(verse=verse_text)
return '{su}%s{/su}&nbsp;' % verse_text return '{{su}}{verse}{{/su}}&nbsp;'.format(verse=verse_text)
def search(self, string, showError): def search(self, string, showError):
""" """

View File

@ -63,7 +63,7 @@ class OpenSongBible(BibleDB):
""" """
Loads a Bible from file. Loads a Bible from file.
""" """
log.debug('Starting OpenSong import from "%s"' % self.filename) log.debug('Starting OpenSong import from "{name}"'.format(name=self.filename))
if not isinstance(self.filename, str): if not isinstance(self.filename, str):
self.filename = str(self.filename, 'utf8') self.filename = str(self.filename, 'utf8')
import_file = None import_file = None
@ -84,14 +84,14 @@ class OpenSongBible(BibleDB):
# No language info in the opensong format, so ask the user # No language info in the opensong format, so ask the user
language_id = self.get_language(bible_name) language_id = self.get_language(bible_name)
if not language_id: if not language_id:
log.error('Importing books from "%s" failed' % self.filename) log.error('Importing books from "{name}" failed'.format(name=self.filename))
return False return False
for book in bible.b: for book in bible.b:
if self.stop_import_flag: if self.stop_import_flag:
break break
book_ref_id = self.get_book_ref_id_by_name(str(book.attrib['n']), len(bible.b), language_id) book_ref_id = self.get_book_ref_id_by_name(str(book.attrib['n']), len(bible.b), language_id)
if not book_ref_id: if not book_ref_id:
log.error('Importing books from "%s" failed' % self.filename) log.error('Importing books from "{name}" failed'.format(name=self.filename))
return False return False
book_details = BiblesResourcesDB.get_book_by_id(book_ref_id) book_details = BiblesResourcesDB.get_book_by_id(book_ref_id)
db_book = self.create_book(book.attrib['n'], book_ref_id, book_details['testament_id']) db_book = self.create_book(book.attrib['n'], book_ref_id, book_details['testament_id'])
@ -117,14 +117,14 @@ class OpenSongBible(BibleDB):
if len(verse_parts) > 1: if len(verse_parts) > 1:
number = int(verse_parts[0]) number = int(verse_parts[0])
except TypeError: except TypeError:
log.warning('Illegal verse number: %s', str(verse.attrib['n'])) log.warning('Illegal verse number: {verse:d}'.format(verse=verse.attrib['n']))
verse_number = number verse_number = number
else: else:
verse_number += 1 verse_number += 1
self.create_verse(db_book.id, chapter_number, verse_number, self.get_text(verse)) self.create_verse(db_book.id, chapter_number, verse_number, self.get_text(verse))
self.wizard.increment_progress_bar( self.wizard.increment_progress_bar(translate('BiblesPlugin.Opensong',
translate('BiblesPlugin.Opensong', 'Importing %(bookname)s %(chapter)s...') % 'Importing {name} {chapter}...'
{'bookname': db_book.name, 'chapter': chapter_number}) ).format(name=db_book.name, chapter=chapter_number))
self.session.commit() self.session.commit()
self.application.process_events() self.application.process_events()
except etree.XMLSyntaxError as inst: except etree.XMLSyntaxError as inst:

View File

@ -49,7 +49,7 @@ class OSISBible(BibleDB):
""" """
Loads a Bible from file. Loads a Bible from file.
""" """
log.debug('Starting OSIS import from "%s"' % self.filename) log.debug('Starting OSIS import from "{name}"'.format(name=self.filename))
if not isinstance(self.filename, str): if not isinstance(self.filename, str):
self.filename = str(self.filename, 'utf8') self.filename = str(self.filename, 'utf8')
import_file = None import_file = None
@ -69,7 +69,7 @@ class OSISBible(BibleDB):
if not language_id: if not language_id:
language_id = self.get_language(bible_name) language_id = self.get_language(bible_name)
if not language_id: if not language_id:
log.error('Importing books from "%s" failed' % self.filename) log.error('Importing books from "{name}" failed'.format(name=self.filename))
return False return False
self.save_meta('language_id', language_id) self.save_meta('language_id', language_id)
num_books = int(osis_bible_tree.xpath("count(//ns:div[@type='book'])", namespaces=namespace)) num_books = int(osis_bible_tree.xpath("count(//ns:div[@type='book'])", namespaces=namespace))
@ -127,9 +127,7 @@ class OSISBible(BibleDB):
etree.strip_tags(book, ('{http://www.bibletechnologies.net/2003/OSIS/namespace}div')) etree.strip_tags(book, ('{http://www.bibletechnologies.net/2003/OSIS/namespace}div'))
book_ref_id = self.get_book_ref_id_by_name(book.get('osisID'), num_books, language_id) book_ref_id = self.get_book_ref_id_by_name(book.get('osisID'), num_books, language_id)
if not book_ref_id: if not book_ref_id:
book_ref_id = self.get_book_ref_id_by_localised_name(book.get('osisID')) log.error('Importing books from "{name}" failed'.format(name=self.filename))
if not book_ref_id:
log.error('Importing books from "%s" failed' % self.filename)
return False return False
book_details = BiblesResourcesDB.get_book_by_id(book_ref_id) book_details = BiblesResourcesDB.get_book_by_id(book_ref_id)
db_book = self.create_book(book_details['name'], book_ref_id, book_details['testament_id']) db_book = self.create_book(book_details['name'], book_ref_id, book_details['testament_id'])
@ -187,7 +185,8 @@ class OSISBible(BibleDB):
trace_error_handler(log) trace_error_handler(log)
success = False success = False
critical_error_message_box(message=translate('BiblesPlugin.OsisImport', critical_error_message_box(message=translate('BiblesPlugin.OsisImport',
'The file is not a valid OSIS-XML file: \n%s' % e.msg)) 'The file is not a valid OSIS-XML file:'
'\n{text}').format(text=e.msg))
finally: finally:
if import_file: if import_file:
import_file.close() import_file.close()

View File

@ -51,7 +51,7 @@ class SwordBible(BibleDB):
""" """
Loads a Bible from SWORD module. Loads a Bible from SWORD module.
""" """
log.debug('Starting SWORD import from "%s"' % self.sword_key) log.debug('Starting SWORD import from "{key}"'.format(key=self.sword_key))
success = True success = True
try: try:
pysword_modules = modules.SwordModules(self.sword_path) pysword_modules = modules.SwordModules(self.sword_path)
@ -84,14 +84,14 @@ class SwordBible(BibleDB):
verse_number += 1 verse_number += 1
self.create_verse(db_book.id, chapter_number, verse_number, verse) self.create_verse(db_book.id, chapter_number, verse_number, verse)
self.wizard.increment_progress_bar( self.wizard.increment_progress_bar(
translate('BiblesPlugin.Sword', 'Importing %s...') % db_book.name) translate('BiblesPlugin.Sword', 'Importing {name}...').format(name=db_book.name))
self.session.commit() self.session.commit()
self.application.process_events() self.application.process_events()
except Exception as e: except Exception as e:
critical_error_message_box( critical_error_message_box(
message=translate('BiblesPlugin.SwordImport', 'An unexpected error happened while importing the SWORD ' message=translate('BiblesPlugin.SwordImport', 'An unexpected error happened while importing the SWORD '
'bible, please report this to the OpenLP developers.\n' 'bible, please report this to the OpenLP developers.\n'
'%s' % e)) '{error}').format(error=e))
log.exception(str(e)) log.exception(str(e))
success = False success = False
if self.stop_import_flag: if self.stop_import_flag:

View File

@ -101,7 +101,7 @@ def upgrade_1(session, metadata):
metadata_table.c.key == 'download source' metadata_table.c.key == 'download source'
) )
).scalar() ).scalar()
log.debug('download source: %s', value_count) log.debug('download source: {count}'.format(count=value_count))
if value_count > 0: if value_count > 0:
session.execute(insert(metadata_table).values( session.execute(insert(metadata_table).values(
key='download_source', key='download_source',
@ -121,7 +121,7 @@ def upgrade_1(session, metadata):
metadata_table.c.key == 'download name' metadata_table.c.key == 'download name'
) )
).scalar() ).scalar()
log.debug('download name: %s', value_count) log.debug('download name: {count}'.format(count=value_count))
if value_count > 0: if value_count > 0:
session.execute(insert(metadata_table).values( session.execute(insert(metadata_table).values(
key='download_name', key='download_name',
@ -141,7 +141,7 @@ def upgrade_1(session, metadata):
metadata_table.c.key == 'proxy server' metadata_table.c.key == 'proxy server'
) )
).scalar() ).scalar()
log.debug('proxy server: %s', value_count) log.debug('proxy server: {count}'.format(count=value_count))
if value_count > 0: if value_count > 0:
session.execute(insert(metadata_table).values( session.execute(insert(metadata_table).values(
key='proxy_server', key='proxy_server',
@ -161,7 +161,7 @@ def upgrade_1(session, metadata):
metadata_table.c.key == 'proxy username' metadata_table.c.key == 'proxy username'
) )
).scalar() ).scalar()
log.debug('proxy username: %s', value_count) log.debug('proxy username: {count}'.format(count=value_count))
if value_count > 0: if value_count > 0:
session.execute(insert(metadata_table).values( session.execute(insert(metadata_table).values(
key='proxy_username', key='proxy_username',
@ -181,7 +181,7 @@ def upgrade_1(session, metadata):
metadata_table.c.key == 'proxy password' metadata_table.c.key == 'proxy password'
) )
).scalar() ).scalar()
log.debug('proxy password: %s', value_count) log.debug('proxy password: {count}'.format(count=value_count))
if value_count > 0: if value_count > 0:
session.execute(insert(metadata_table).values( session.execute(insert(metadata_table).values(
key='proxy_password', key='proxy_password',

View File

@ -61,23 +61,29 @@ class VerseReferenceList(object):
result = '' result = ''
for index, verse in enumerate(self.verse_list): for index, verse in enumerate(self.verse_list):
if index == 0: if index == 0:
result = '%s %s%s%s' % (verse['book'], verse['chapter'], verse_sep, verse['start']) result = '{book} {chapter}{sep}{verse}'.format(book=verse['book'],
chapter=verse['chapter'],
sep=verse_sep,
verse=verse['start'])
if verse['start'] != verse['end']: if verse['start'] != verse['end']:
result = '%s%s%s' % (result, range_sep, verse['end']) result = '{result}{sep}{end}'.format(result=result, sep=range_sep, end=verse['end'])
continue continue
prev = index - 1 prev = index - 1
if self.verse_list[prev]['version'] != verse['version']: if self.verse_list[prev]['version'] != verse['version']:
result = '%s (%s)' % (result, self.verse_list[prev]['version']) result = '{result} ({version})'.format(result=result, version=self.verse_list[prev]['version'])
result += '%s ' % list_sep result += '{sep} '.format(sep=list_sep)
if self.verse_list[prev]['book'] != verse['book']: if self.verse_list[prev]['book'] != verse['book']:
result = '%s%s %s%s' % (result, verse['book'], verse['chapter'], verse_sep) result = '{result}{book} {chapter}{sep}'.format(result=result,
book=verse['book'],
chapter=verse['chapter'],
sep=verse_sep)
elif self.verse_list[prev]['chapter'] != verse['chapter']: elif self.verse_list[prev]['chapter'] != verse['chapter']:
result = '%s%s%s' % (result, verse['chapter'], verse_sep) result = '{result}{chapter}{sep}'.format(result=result, chapter=verse['chapter'], sep=verse_sep)
result += str(verse['start']) result += str(verse['start'])
if verse['start'] != verse['end']: if verse['start'] != verse['end']:
result = '%s%s%s' % (result, range_sep, verse['end']) result = '{result}{sep}{end}'.format(result=result, sep=range_sep, end=verse['end'])
if len(self.version_list) > 1: if len(self.version_list) > 1:
result = '%s (%s)' % (result, verse['version']) result = '{result} ({version})'.format(result=result, version=verse['version'])
return result return result
def format_versions(self, copyright=True, permission=True): def format_versions(self, copyright=True, permission=True):

View File

@ -48,7 +48,7 @@ class ZefaniaBible(BibleDB):
""" """
Loads a Bible from file. Loads a Bible from file.
""" """
log.debug('Starting Zefania import from "%s"' % self.filename) log.debug('Starting Zefania import from "{name}"'.format(name=self.filename))
if not isinstance(self.filename, str): if not isinstance(self.filename, str):
self.filename = str(self.filename, 'utf8') self.filename = str(self.filename, 'utf8')
import_file = None import_file = None
@ -67,7 +67,7 @@ class ZefaniaBible(BibleDB):
if not language_id: if not language_id:
language_id = self.get_language(bible_name) language_id = self.get_language(bible_name)
if not language_id: if not language_id:
log.error('Importing books from "%s" failed' % self.filename) log.error('Importing books from "{name}" failed'.format(name=self.filename))
return False return False
self.save_meta('language_id', language_id) self.save_meta('language_id', language_id)
num_books = int(zefania_bible_tree.xpath('count(//BIBLEBOOK)')) num_books = int(zefania_bible_tree.xpath('count(//BIBLEBOOK)'))
@ -86,13 +86,11 @@ class ZefaniaBible(BibleDB):
continue continue
if bname: if bname:
book_ref_id = self.get_book_ref_id_by_name(bname, num_books, language_id) book_ref_id = self.get_book_ref_id_by_name(bname, num_books, language_id)
if not book_ref_id:
book_ref_id = self.get_book_ref_id_by_localised_name(bname)
else: else:
log.debug('Could not find a name, will use number, basically a guess.') log.debug('Could not find a name, will use number, basically a guess.')
book_ref_id = int(bnumber) book_ref_id = int(bnumber)
if not book_ref_id: if not book_ref_id:
log.error('Importing books from "%s" failed' % self.filename) log.error('Importing books from "{name}" failed'.format(name=self.filename))
return False return False
book_details = BiblesResourcesDB.get_book_by_id(book_ref_id) book_details = BiblesResourcesDB.get_book_by_id(book_ref_id)
db_book = self.create_book(book_details['name'], book_ref_id, book_details['testament_id']) db_book = self.create_book(book_details['name'], book_ref_id, book_details['testament_id'])
@ -104,8 +102,9 @@ class ZefaniaBible(BibleDB):
verse_number = VERS.get("vnumber") verse_number = VERS.get("vnumber")
self.create_verse(db_book.id, chapter_number, verse_number, VERS.text.replace('<BR/>', '\n')) self.create_verse(db_book.id, chapter_number, verse_number, VERS.text.replace('<BR/>', '\n'))
self.wizard.increment_progress_bar( self.wizard.increment_progress_bar(
translate('BiblesPlugin.Zefnia', 'Importing %(bookname)s %(chapter)s...') % translate('BiblesPlugin.Zefnia',
{'bookname': db_book.name, 'chapter': chapter_number}) 'Importing {book} {chapter}...').format(book=db_book.name,
chapter=chapter_number))
self.session.commit() self.session.commit()
self.application.process_events() self.application.process_events()
except Exception as e: except Exception as e:

View File

@ -23,8 +23,9 @@
from PyQt5 import QtWidgets from PyQt5 import QtWidgets
from openlp.core.common import UiStrings, translate from openlp.core.common import UiStrings, translate
from openlp.core.lib import SpellTextEdit, build_icon from openlp.core.lib import build_icon
from openlp.core.lib.ui import create_button, create_button_box from openlp.core.lib.ui import create_button, create_button_box
from openlp.core.ui.lib import SpellTextEdit
class Ui_CustomSlideEditDialog(object): class Ui_CustomSlideEditDialog(object):

View File

@ -128,7 +128,7 @@ class CustomXMLParser(object):
try: try:
self.custom_xml = objectify.fromstring(xml) self.custom_xml = objectify.fromstring(xml)
except etree.XMLSyntaxError: except etree.XMLSyntaxError:
log.exception('Invalid xml %s', xml) log.exception('Invalid xml {xml}'.format(xml=xml))
def get_verses(self): def get_verses(self):
""" """

View File

@ -94,7 +94,7 @@ class CustomMediaItem(MediaManagerItem):
""" """
""" """
self.search_text_label.setText('%s:' % UiStrings().Search) self.search_text_label.setText('{text}:'.format(text=UiStrings().Search))
self.search_text_button.setText(UiStrings().Search) self.search_text_button.setText(UiStrings().Search)
def initialise(self): def initialise(self):
@ -105,7 +105,8 @@ class CustomMediaItem(MediaManagerItem):
[(CustomSearch.Titles, ':/songs/song_search_title.png', translate('SongsPlugin.MediaItem', 'Titles'), [(CustomSearch.Titles, ':/songs/song_search_title.png', translate('SongsPlugin.MediaItem', 'Titles'),
translate('SongsPlugin.MediaItem', 'Search Titles...')), translate('SongsPlugin.MediaItem', 'Search Titles...')),
(CustomSearch.Themes, ':/slides/slide_theme.png', UiStrings().Themes, UiStrings().SearchThemes)]) (CustomSearch.Themes, ':/slides/slide_theme.png', UiStrings().Themes, UiStrings().SearchThemes)])
self.search_text_edit.set_current_search_type(Settings().value('%s/last search type' % self.settings_section)) text = '{section}/last search type'.format(section=self.settings_section)
self.search_text_edit.set_current_search_type(Settings().value(text))
self.load_list(self.plugin.db_manager.get_all_objects(CustomSlide, order_by_ref=CustomSlide.title)) self.load_list(self.plugin.db_manager.get_all_objects(CustomSlide, order_by_ref=CustomSlide.title))
self.config_update() self.config_update()
@ -190,7 +191,8 @@ class CustomMediaItem(MediaManagerItem):
if QtWidgets.QMessageBox.question( if QtWidgets.QMessageBox.question(
self, UiStrings().ConfirmDelete, self, UiStrings().ConfirmDelete,
translate('CustomPlugin.MediaItem', translate('CustomPlugin.MediaItem',
'Are you sure you want to delete the "%d" selected custom slide(s)?') % len(items), 'Are you sure you want to delete the "{items:d}" '
'selected custom slide(s)?').format(items=len(items)),
QtWidgets.QMessageBox.StandardButtons( QtWidgets.QMessageBox.StandardButtons(
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No), QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No),
QtWidgets.QMessageBox.Yes) == QtWidgets.QMessageBox.No: QtWidgets.QMessageBox.Yes) == QtWidgets.QMessageBox.No:
@ -249,10 +251,11 @@ class CustomMediaItem(MediaManagerItem):
Search the plugin database Search the plugin database
""" """
# Save the current search type to the configuration. # Save the current search type to the configuration.
Settings().setValue('%s/last search type' % self.settings_section, self.search_text_edit.current_search_type()) Settings().setValue('{section}/last search type'.format(section=self.settings_section),
self.search_text_edit.current_search_type())
# Reload the list considering the new search type. # Reload the list considering the new search type.
search_type = self.search_text_edit.current_search_type() search_type = self.search_text_edit.current_search_type()
search_keywords = '%' + self.whitespace.sub(' ', self.search_text_edit.displayText()) + '%' search_keywords = '%{search}%'.format(search=self.whitespace.sub(' ', self.search_text_edit.displayText()))
if search_type == CustomSearch.Titles: if search_type == CustomSearch.Titles:
log.debug('Titles Search') log.debug('Titles Search')
search_results = self.plugin.db_manager.get_all_objects(CustomSlide, search_results = self.plugin.db_manager.get_all_objects(CustomSlide,
@ -347,7 +350,7 @@ class CustomMediaItem(MediaManagerItem):
:param string: The search string :param string: The search string
:param show_error: The error string to be show. :param show_error: The error string to be show.
""" """
search = '%' + string.lower() + '%' search = '%{search}%'.forma(search=string.lower())
search_results = self.plugin.db_manager.get_all_objects(CustomSlide, search_results = self.plugin.db_manager.get_all_objects(CustomSlide,
or_(func.lower(CustomSlide.title).like(search), or_(func.lower(CustomSlide.title).like(search),
func.lower(CustomSlide.text).like(search)), func.lower(CustomSlide.text).like(search)),

View File

@ -74,7 +74,7 @@ class ImageMediaItem(MediaManagerItem):
def retranslateUi(self): def retranslateUi(self):
self.on_new_prompt = translate('ImagePlugin.MediaItem', 'Select Image(s)') self.on_new_prompt = translate('ImagePlugin.MediaItem', 'Select Image(s)')
file_formats = get_images_filter() file_formats = get_images_filter()
self.on_new_file_masks = '%s;;%s (*)' % (file_formats, UiStrings().AllFiles) self.on_new_file_masks = '{formats};;{files} (*)'.format(formats=file_formats, files=UiStrings().AllFiles)
self.add_group_action.setText(UiStrings().AddGroupDot) self.add_group_action.setText(UiStrings().AddGroupDot)
self.add_group_action.setToolTip(UiStrings().AddGroupDot) self.add_group_action.setToolTip(UiStrings().AddGroupDot)
self.replace_action.setText(UiStrings().ReplaceBG) self.replace_action.setText(UiStrings().ReplaceBG)
@ -113,7 +113,7 @@ class ImageMediaItem(MediaManagerItem):
self.list_view = TreeWidgetWithDnD(self, self.plugin.name) self.list_view = TreeWidgetWithDnD(self, self.plugin.name)
self.list_view.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) self.list_view.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
self.list_view.setAlternatingRowColors(True) self.list_view.setAlternatingRowColors(True)
self.list_view.setObjectName('%sTreeView' % self.plugin.name) self.list_view.setObjectName('{name}TreeView'.format(name=self.plugin.name))
# Add to pageLayout # Add to pageLayout
self.page_layout.addWidget(self.list_view) self.page_layout.addWidget(self.list_view)
# define and add the context menu # define and add the context menu
@ -127,21 +127,21 @@ class ImageMediaItem(MediaManagerItem):
create_widget_action(self.list_view, separator=True) create_widget_action(self.list_view, separator=True)
create_widget_action( create_widget_action(
self.list_view, self.list_view,
'listView%s%sItem' % (self.plugin.name.title(), StringContent.Preview.title()), 'listView{name}{preview}Item'.format(name=self.plugin.name.title(), preview=StringContent.Preview.title()),
text=self.plugin.get_string(StringContent.Preview)['title'], text=self.plugin.get_string(StringContent.Preview)['title'],
icon=':/general/general_preview.png', icon=':/general/general_preview.png',
can_shortcuts=True, can_shortcuts=True,
triggers=self.on_preview_click) triggers=self.on_preview_click)
create_widget_action( create_widget_action(
self.list_view, self.list_view,
'listView%s%sItem' % (self.plugin.name.title(), StringContent.Live.title()), 'listView{name}{live}Item'.format(name=self.plugin.name.title(), live=StringContent.Live.title()),
text=self.plugin.get_string(StringContent.Live)['title'], text=self.plugin.get_string(StringContent.Live)['title'],
icon=':/general/general_live.png', icon=':/general/general_live.png',
can_shortcuts=True, can_shortcuts=True,
triggers=self.on_live_click) triggers=self.on_live_click)
create_widget_action( create_widget_action(
self.list_view, self.list_view,
'listView%s%sItem' % (self.plugin.name.title(), StringContent.Service.title()), 'listView{name}{service}Item'.format(name=self.plugin.name.title(), service=StringContent.Service.title()),
can_shortcuts=True, can_shortcuts=True,
text=self.plugin.get_string(StringContent.Service)['title'], text=self.plugin.get_string(StringContent.Service)['title'],
icon=':/general/general_add.png', icon=':/general/general_add.png',
@ -157,7 +157,7 @@ class ImageMediaItem(MediaManagerItem):
if self.has_delete_icon: if self.has_delete_icon:
create_widget_action( create_widget_action(
self.list_view, self.list_view,
'listView%s%sItem' % (self.plugin.name.title(), StringContent.Delete.title()), 'listView{name}{delete}Item'.format(name=self.plugin.name.title(), delete=StringContent.Delete.title()),
text=self.plugin.get_string(StringContent.Delete)['title'], text=self.plugin.get_string(StringContent.Delete)['title'],
icon=':/general/general_delete.png', icon=':/general/general_delete.png',
can_shortcuts=True, triggers=self.on_delete_click) can_shortcuts=True, triggers=self.on_delete_click)
@ -245,8 +245,8 @@ class ImageMediaItem(MediaManagerItem):
self.list_view.parent(), self.list_view.parent(),
translate('ImagePlugin.MediaItem', 'Remove group'), translate('ImagePlugin.MediaItem', 'Remove group'),
translate('ImagePlugin.MediaItem', translate('ImagePlugin.MediaItem',
'Are you sure you want to remove "%s" and everything in it?') % 'Are you sure you want to remove "{name}" and everything in it?'
item_data.group_name, ).format(name=item_data.group_name),
QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes |
QtWidgets.QMessageBox.No) QtWidgets.QMessageBox.No)
) == QtWidgets.QMessageBox.Yes: ) == QtWidgets.QMessageBox.Yes:
@ -355,7 +355,7 @@ class ImageMediaItem(MediaManagerItem):
# characters. # characters.
images.sort(key=lambda image_object: get_locale_key(os.path.split(str(image_object.filename))[1])) images.sort(key=lambda image_object: get_locale_key(os.path.split(str(image_object.filename))[1]))
for image_file in images: for image_file in images:
log.debug('Loading image: %s', image_file.filename) log.debug('Loading image: {name}'.format(name=image_file.filename))
filename = os.path.split(image_file.filename)[1] filename = os.path.split(image_file.filename)[1]
thumb = self.generate_thumbnail_path(image_file) thumb = self.generate_thumbnail_path(image_file)
if not os.path.exists(image_file.filename): if not os.path.exists(image_file.filename):
@ -481,7 +481,7 @@ class ImageMediaItem(MediaManagerItem):
for filename in images_list: for filename in images_list:
if not isinstance(filename, str): if not isinstance(filename, str):
continue continue
log.debug('Adding new image: %s', filename) log.debug('Adding new image: {name}'.format(name=filename))
image_file = ImageFilenames() image_file = ImageFilenames()
image_file.group_id = group_id image_file.group_id = group_id
image_file.filename = str(filename) image_file.filename = str(filename)
@ -589,14 +589,15 @@ class ImageMediaItem(MediaManagerItem):
if not remote: if not remote:
critical_error_message_box( critical_error_message_box(
translate('ImagePlugin.MediaItem', 'Missing Image(s)'), translate('ImagePlugin.MediaItem', 'Missing Image(s)'),
translate('ImagePlugin.MediaItem', 'The following image(s) no longer exist: %s') translate('ImagePlugin.MediaItem', 'The following image(s) no longer exist: {names}'
% '\n'.join(missing_items_file_names)) ).format(names='\n'.join(missing_items_file_names)))
return False return False
# We have missing as well as existing images. We ask what to do. # We have missing as well as existing images. We ask what to do.
elif missing_items_file_names and QtWidgets.QMessageBox.question( elif missing_items_file_names and QtWidgets.QMessageBox.question(
self, translate('ImagePlugin.MediaItem', 'Missing Image(s)'), self, translate('ImagePlugin.MediaItem', 'Missing Image(s)'),
translate('ImagePlugin.MediaItem', 'The following image(s) no longer exist: %s\n' translate('ImagePlugin.MediaItem', 'The following image(s) no longer exist: {names}\n'
'Do you want to add the other images anyway?') % '\n'.join(missing_items_file_names), 'Do you want to add the other images anyway?'
).format(names='\n'.join(missing_items_file_names)),
QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.No | QtWidgets.QMessageBox.Yes)) == \ QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.No | QtWidgets.QMessageBox.Yes)) == \
QtWidgets.QMessageBox.No: QtWidgets.QMessageBox.No:
return False return False
@ -688,7 +689,7 @@ class ImageMediaItem(MediaManagerItem):
critical_error_message_box( critical_error_message_box(
UiStrings().LiveBGError, UiStrings().LiveBGError,
translate('ImagePlugin.MediaItem', 'There was a problem replacing your background, ' translate('ImagePlugin.MediaItem', 'There was a problem replacing your background, '
'the image file "%s" no longer exists.') % filename) 'the image file "{name}" no longer exists.').format(name=filename))
def search(self, string, show_error=True): def search(self, string, show_error=True):
""" """

View File

@ -46,7 +46,7 @@ class MediaClipSelectorForm(QtWidgets.QDialog, Ui_MediaClipSelector, RegistryPro
""" """
Class to manage the clip selection Class to manage the clip selection
""" """
log.info('%s MediaClipSelectorForm loaded', __name__) log.info('{name} MediaClipSelectorForm loaded'.format(name=__name__))
def __init__(self, media_item, parent, manager): def __init__(self, media_item, parent, manager):
""" """
@ -265,7 +265,8 @@ class MediaClipSelectorForm(QtWidgets.QDialog, Ui_MediaClipSelector, RegistryPro
# Enable audio track combobox if anything is in it # Enable audio track combobox if anything is in it
if len(titles) > 0: if len(titles) > 0:
self.titles_combo_box.setDisabled(False) self.titles_combo_box.setDisabled(False)
log.debug('load_disc_button end - vlc_media_player state: %s' % self.vlc_media_player.get_state()) log.debug('load_disc_button end - '
'vlc_media_player state: {state}'.format(state=self.vlc_media_player.get_state()))
@QtCore.pyqtSlot(bool) @QtCore.pyqtSlot(bool)
def on_play_button_clicked(self, clicked): def on_play_button_clicked(self, clicked):
@ -374,7 +375,7 @@ class MediaClipSelectorForm(QtWidgets.QDialog, Ui_MediaClipSelector, RegistryPro
:param index: The index of the newly chosen title track. :param index: The index of the newly chosen title track.
""" """
log.debug('in on_titles_combo_box_changed, index: %d', index) log.debug('in on_titles_combo_box_changed, index: {index:d}'.format(index=index))
vlc = get_vlc() vlc = get_vlc()
if not self.vlc_media_player: if not self.vlc_media_player:
log.error('vlc_media_player was None') log.error('vlc_media_player was None')
@ -407,7 +408,7 @@ class MediaClipSelectorForm(QtWidgets.QDialog, Ui_MediaClipSelector, RegistryPro
self.vlc_media_player.audio_set_mute(True) self.vlc_media_player.audio_set_mute(True)
# Get audio tracks # Get audio tracks
audio_tracks = self.vlc_media_player.audio_get_track_description() audio_tracks = self.vlc_media_player.audio_get_track_description()
log.debug('number of audio tracks: %d' % len(audio_tracks)) log.debug('number of audio tracks: {tracks:d}'.format(tracks=len(audio_tracks)))
# Clear the audio track combobox, insert new tracks # Clear the audio track combobox, insert new tracks
self.audio_tracks_combobox.clear() self.audio_tracks_combobox.clear()
for audio_track in audio_tracks: for audio_track in audio_tracks:
@ -433,14 +434,14 @@ class MediaClipSelectorForm(QtWidgets.QDialog, Ui_MediaClipSelector, RegistryPro
self.toggle_disable_player(False) self.toggle_disable_player(False)
# Set media length info # Set media length info
self.playback_length = self.vlc_media_player.get_length() self.playback_length = self.vlc_media_player.get_length()
log.debug('playback_length: %d ms' % self.playback_length) log.debug('playback_length: {length:d} ms'.format(length=self.playback_length))
# if length is 0, wait a bit, maybe vlc will change its mind... # if length is 0, wait a bit, maybe vlc will change its mind...
loop_count = 0 loop_count = 0
while self.playback_length == 0 and loop_count < 20: while self.playback_length == 0 and loop_count < 20:
sleep(0.1) sleep(0.1)
self.playback_length = self.vlc_media_player.get_length() self.playback_length = self.vlc_media_player.get_length()
loop_count += 1 loop_count += 1
log.debug('in loop, playback_length: %d ms' % self.playback_length) log.debug('in loop, playback_length: {length:d} ms'.format(length=self.playback_length))
self.position_slider.setMaximum(self.playback_length) self.position_slider.setMaximum(self.playback_length)
# setup start and end time # setup start and end time
rounded_vlc_ms_length = int(round(self.playback_length / 100.0) * 100.0) rounded_vlc_ms_length = int(round(self.playback_length / 100.0) * 100.0)
@ -455,7 +456,8 @@ class MediaClipSelectorForm(QtWidgets.QDialog, Ui_MediaClipSelector, RegistryPro
sleep(0.1) sleep(0.1)
self.vlc_media_player.set_pause(1) self.vlc_media_player.set_pause(1)
loop_count += 1 loop_count += 1
log.debug('titles_combo_box end - vlc_media_player state: %s' % self.vlc_media_player.get_state()) log.debug('titles_combo_box end - '
'vlc_media_player state: {state}'.format(state=self.vlc_media_player.get_state()))
self.application.set_normal_cursor() self.application.set_normal_cursor()
@QtCore.pyqtSlot(int) @QtCore.pyqtSlot(int)
@ -468,7 +470,8 @@ class MediaClipSelectorForm(QtWidgets.QDialog, Ui_MediaClipSelector, RegistryPro
if not self.vlc_media_player: if not self.vlc_media_player:
return return
audio_track = self.audio_tracks_combobox.itemData(index) audio_track = self.audio_tracks_combobox.itemData(index)
log.debug('in on_audio_tracks_combobox_currentIndexChanged, index: %d audio_track: %s' % (index, audio_track)) log.debug('in on_audio_tracks_combobox_currentIndexChanged, '
'index: {index:d} audio_track: {tracks}'.format(index=index, tracks=audio_track))
if audio_track and int(audio_track) > 0: if audio_track and int(audio_track) > 0:
self.vlc_media_player.audio_set_track(int(audio_track)) self.vlc_media_player.audio_set_track(int(audio_track))
@ -566,7 +569,9 @@ class MediaClipSelectorForm(QtWidgets.QDialog, Ui_MediaClipSelector, RegistryPro
translate('MediaPlugin.MediaClipSelectorForm', translate('MediaPlugin.MediaClipSelectorForm',
'The CD was not loaded correctly, please re-load and try again.')) 'The CD was not loaded correctly, please re-load and try again.'))
return return
optical = 'optical:%d:-1:-1:%d:%d:' % (title, start_time_ms, end_time_ms) optical = 'optical:{title:d}:-1:-1:{start:d}:{end:d}:'.format(title=title,
start=start_time_ms,
end=end_time_ms)
else: else:
audio_track = self.audio_tracks_combobox.itemData(self.audio_tracks_combobox.currentIndex()) audio_track = self.audio_tracks_combobox.itemData(self.audio_tracks_combobox.currentIndex())
subtitle_track = self.subtitle_tracks_combobox.itemData(self.subtitle_tracks_combobox.currentIndex()) subtitle_track = self.subtitle_tracks_combobox.itemData(self.subtitle_tracks_combobox.currentIndex())
@ -577,7 +582,11 @@ class MediaClipSelectorForm(QtWidgets.QDialog, Ui_MediaClipSelector, RegistryPro
translate('MediaPlugin.MediaClipSelectorForm', translate('MediaPlugin.MediaClipSelectorForm',
'The DVD was not loaded correctly, please re-load and try again.')) 'The DVD was not loaded correctly, please re-load and try again.'))
return return
optical = 'optical:%d:%d:%d:%d:%d:' % (title, audio_track, subtitle_track, start_time_ms, end_time_ms) optical = 'optical:{title:d}:{audio:d}:{sub:d}:{start:d}:{end:d}:'.format(title=title,
audio=audio_track,
sub=subtitle_track,
start=start_time_ms,
end=end_time_ms)
# Ask for an alternative name for the mediaclip # Ask for an alternative name for the mediaclip
while True: while True:
new_optical_name, ok = QtWidgets.QInputDialog.getText(self, translate('MediaPlugin.MediaClipSelectorForm', new_optical_name, ok = QtWidgets.QInputDialog.getText(self, translate('MediaPlugin.MediaClipSelectorForm',
@ -634,10 +643,10 @@ class MediaClipSelectorForm(QtWidgets.QDialog, Ui_MediaClipSelector, RegistryPro
# use win api to find optical drives # use win api to find optical drives
fso = Dispatch('scripting.filesystemobject') fso = Dispatch('scripting.filesystemobject')
for drive in fso.Drives: for drive in fso.Drives:
log.debug('Drive %s has type %d' % (drive.DriveLetter, drive.DriveType)) log.debug('Drive {drive} has type {types:d}'.format(drive=drive.DriveLetter, types=drive.DriveType))
# if type is 4, it is a cd-rom drive # if type is 4, it is a cd-rom drive
if drive.DriveType == 4: if drive.DriveType == 4:
self.media_path_combobox.addItem('%s:\\' % drive.DriveLetter) self.media_path_combobox.addItem('{drive}:\\'.format(drive=drive.DriveLetter))
elif is_linux(): elif is_linux():
# Get disc devices from dbus and find the ones that are optical # Get disc devices from dbus and find the ones that are optical
bus = dbus.SystemBus() bus = dbus.SystemBus()

View File

@ -51,7 +51,7 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties):
""" """
media_go_live = QtCore.pyqtSignal(list) media_go_live = QtCore.pyqtSignal(list)
media_add_to_service = QtCore.pyqtSignal(list) media_add_to_service = QtCore.pyqtSignal(list)
log.info('%s MediaMediaItem loaded', __name__) log.info('{name} MediaMediaItem loaded'.format(name=__name__))
def __init__(self, parent, plugin): def __init__(self, parent, plugin):
self.setup() self.setup()
@ -232,7 +232,7 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties):
critical_error_message_box(UiStrings().LiveBGError, critical_error_message_box(UiStrings().LiveBGError,
translate('MediaPlugin.MediaItem', translate('MediaPlugin.MediaItem',
'There was a problem replacing your background, ' 'There was a problem replacing your background, '
'the media file "%s" no longer exists.') % filename) 'the media file "{name}" no longer exists.').format(name=filename))
def generate_slide_data(self, service_item, item=None, xml_version=False, remote=False, def generate_slide_data(self, service_item, item=None, xml_version=False, remote=False,
context=ServiceItemContext.Service): context=ServiceItemContext.Service):
@ -258,7 +258,8 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties):
# Optical disc is no longer present # Optical disc is no longer present
critical_error_message_box( critical_error_message_box(
translate('MediaPlugin.MediaItem', 'Missing Media File'), translate('MediaPlugin.MediaItem', 'Missing Media File'),
translate('MediaPlugin.MediaItem', 'The optical disc %s is no longer available.') % name) translate('MediaPlugin.MediaItem',
'The optical disc {name} is no longer available.').format(name=name))
return False return False
service_item.processor = self.display_type_combo_box.currentText() service_item.processor = self.display_type_combo_box.currentText()
service_item.add_from_command(filename, name, CLAPPERBOARD) service_item.add_from_command(filename, name, CLAPPERBOARD)
@ -275,7 +276,7 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties):
# File is no longer present # File is no longer present
critical_error_message_box( critical_error_message_box(
translate('MediaPlugin.MediaItem', 'Missing Media File'), translate('MediaPlugin.MediaItem', 'Missing Media File'),
translate('MediaPlugin.MediaItem', 'The file %s no longer exists.') % filename) translate('MediaPlugin.MediaItem', 'The file {name} no longer exists.').format(name=filename))
return False return False
(path, name) = os.path.split(filename) (path, name) = os.path.split(filename)
service_item.title = name service_item.title = name
@ -308,9 +309,11 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties):
Rebuild the tab in the media manager when changes are made in the settings. Rebuild the tab in the media manager when changes are made in the settings.
""" """
self.populate_display_types() self.populate_display_types()
self.on_new_file_masks = translate('MediaPlugin.MediaItem', 'Videos (%s);;Audio (%s);;%s (*)') % ( self.on_new_file_masks = translate('MediaPlugin.MediaItem',
' '.join(self.media_controller.video_extensions_list), 'Videos ({video});;Audio ({audio});;{files} '
' '.join(self.media_controller.audio_extensions_list), UiStrings().AllFiles) '(*)').format(video=' '.join(self.media_controller.video_extensions_list),
audio=' '.join(self.media_controller.audio_extensions_list),
files=UiStrings().AllFiles)
def populate_display_types(self): def populate_display_types(self):
""" """
@ -365,7 +368,9 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties):
item_name = QtWidgets.QListWidgetItem(clip_name) item_name = QtWidgets.QListWidgetItem(clip_name)
item_name.setIcon(self.optical_icon) item_name.setIcon(self.optical_icon)
item_name.setData(QtCore.Qt.UserRole, track) item_name.setData(QtCore.Qt.UserRole, track)
item_name.setToolTip('%s@%s-%s' % (file_name, format_milliseconds(start), format_milliseconds(end))) item_name.setToolTip('{name}@{start}-{end}'.format(name=file_name,
start=format_milliseconds(start),
end=format_milliseconds(end)))
elif not os.path.exists(track): elif not os.path.exists(track):
# File doesn't exist, mark as error. # File doesn't exist, mark as error.
file_name = os.path.split(str(track))[1] file_name = os.path.split(str(track))[1]
@ -377,7 +382,8 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties):
# Normal media file handling. # Normal media file handling.
file_name = os.path.split(str(track))[1] file_name = os.path.split(str(track))[1]
item_name = QtWidgets.QListWidgetItem(file_name) item_name = QtWidgets.QListWidgetItem(file_name)
if '*.%s' % (file_name.split('.')[-1].lower()) in self.media_controller.audio_extensions_list: search = file_name.split('.')[-1].lower()
if '*.{text}'.format(text=search) in self.media_controller.audio_extensions_list:
item_name.setIcon(self.audio_icon) item_name.setIcon(self.audio_icon)
else: else:
item_name.setIcon(self.video_icon) item_name.setIcon(self.video_icon)

View File

@ -49,7 +49,7 @@ class MediaPlugin(Plugin):
""" """
The media plugin adds the ability to playback audio and video content. The media plugin adds the ability to playback audio and video content.
""" """
log.info('%s MediaPlugin loaded', __name__) log.info('{name} MediaPlugin loaded'.format(name=__name__))
def __init__(self): def __init__(self):
super(MediaPlugin, self).__init__('media', __default_settings__, MediaMediaItem) super(MediaPlugin, self).__init__('media', __default_settings__, MediaMediaItem)

View File

@ -236,7 +236,7 @@ class ImpressDocument(PresentationDocument):
try: try:
self.document = desktop.loadComponentFromURL(url, '_blank', 0, properties) self.document = desktop.loadComponentFromURL(url, '_blank', 0, properties)
except: except:
log.warning('Failed to load presentation %s' % url) log.warning('Failed to load presentation {url}'.format(url=url))
return False return False
self.presentation = self.document.getPresentation() self.presentation = self.document.getPresentation()
self.presentation.Display = ScreenList().current['number'] + 1 self.presentation.Display = ScreenList().current['number'] + 1
@ -269,16 +269,16 @@ class ImpressDocument(PresentationDocument):
for index in range(pages.getCount()): for index in range(pages.getCount()):
page = pages.getByIndex(index) page = pages.getByIndex(index)
doc.getCurrentController().setCurrentPage(page) doc.getCurrentController().setCurrentPage(page)
url_path = '%s/%s.png' % (thumb_dir_url, str(index + 1)) url_path = '{path}/{name}.png'.format(path=thumb_dir_url, name=str(index + 1))
path = os.path.join(self.get_temp_folder(), str(index + 1) + '.png') path = os.path.join(self.get_temp_folder(), str(index + 1) + '.png')
try: try:
doc.storeToURL(url_path, properties) doc.storeToURL(url_path, properties)
self.convert_thumbnail(path, index + 1) self.convert_thumbnail(path, index + 1)
delete_file(path) delete_file(path)
except ErrorCodeIOException as exception: except ErrorCodeIOException as exception:
log.exception('ERROR! ErrorCodeIOException %d' % exception.ErrCode) log.exception('ERROR! ErrorCodeIOException {error:d}'.format(error=exception.ErrCode))
except: except:
log.exception('%s - Unable to store openoffice preview' % path) log.exception('{path} - Unable to store openoffice preview'.format(path=path))
def create_property(self, name, value): def create_property(self, name, value):
""" """

View File

@ -88,9 +88,10 @@ class PresentationMediaItem(MediaManagerItem):
file_types = self.controllers[controller].supports + self.controllers[controller].also_supports file_types = self.controllers[controller].supports + self.controllers[controller].also_supports
for file_type in file_types: for file_type in file_types:
if file_type not in file_type_string: if file_type not in file_type_string:
file_type_string += '*.%s ' % file_type file_type_string += '*.{text} '.format(text=file_type)
self.service_manager.supported_suffixes(file_type) self.service_manager.supported_suffixes(file_type)
self.on_new_file_masks = translate('PresentationPlugin.MediaItem', 'Presentations (%s)') % file_type_string self.on_new_file_masks = translate('PresentationPlugin.MediaItem',
'Presentations ({text})').format(text=file_type_string)
def required_icons(self): def required_icons(self):
""" """
@ -306,13 +307,13 @@ class PresentationMediaItem(MediaManagerItem):
os.path.join(doc.get_temp_folder(), 'mainslide001.png')): os.path.join(doc.get_temp_folder(), 'mainslide001.png')):
doc.load_presentation() doc.load_presentation()
i = 1 i = 1
image = os.path.join(doc.get_temp_folder(), 'mainslide%03d.png' % i) image = os.path.join(doc.get_temp_folder(), 'mainslide{number:0>3d}.png'.format(number=i))
thumbnail = os.path.join(doc.get_thumbnail_folder(), 'slide%d.png' % i) thumbnail = os.path.join(doc.get_thumbnail_folder(), 'slide%d.png' % i)
while os.path.isfile(image): while os.path.isfile(image):
service_item.add_from_image(image, name, thumbnail=thumbnail) service_item.add_from_image(image, name, thumbnail=thumbnail)
i += 1 i += 1
image = os.path.join(doc.get_temp_folder(), 'mainslide%03d.png' % i) image = os.path.join(doc.get_temp_folder(), 'mainslide{number:0>3d}.png'.format(number=i))
thumbnail = os.path.join(doc.get_thumbnail_folder(), 'slide%d.png' % i) thumbnail = os.path.join(doc.get_thumbnail_folder(), 'slide{number:d}.png'.format(number=i))
service_item.add_capability(ItemCapabilities.HasThumbnails) service_item.add_capability(ItemCapabilities.HasThumbnails)
doc.close_presentation() doc.close_presentation()
return True return True
@ -321,7 +322,8 @@ class PresentationMediaItem(MediaManagerItem):
if not remote: if not remote:
critical_error_message_box(translate('PresentationPlugin.MediaItem', 'Missing Presentation'), critical_error_message_box(translate('PresentationPlugin.MediaItem', 'Missing Presentation'),
translate('PresentationPlugin.MediaItem', translate('PresentationPlugin.MediaItem',
'The presentation %s no longer exists.') % filename) 'The presentation {name} no longer exists.'
).format(name=filename))
return False return False
else: else:
service_item.processor = self.display_type_combo_box.currentText() service_item.processor = self.display_type_combo_box.currentText()
@ -367,15 +369,16 @@ class PresentationMediaItem(MediaManagerItem):
critical_error_message_box(translate('PresentationPlugin.MediaItem', critical_error_message_box(translate('PresentationPlugin.MediaItem',
'Missing Presentation'), 'Missing Presentation'),
translate('PresentationPlugin.MediaItem', translate('PresentationPlugin.MediaItem',
'The presentation %s is incomplete, please reload.') 'The presentation {name} is incomplete, '
% filename) 'please reload.').format(name=filename))
return False return False
else: else:
# File is no longer present # File is no longer present
if not remote: if not remote:
critical_error_message_box(translate('PresentationPlugin.MediaItem', 'Missing Presentation'), critical_error_message_box(translate('PresentationPlugin.MediaItem', 'Missing Presentation'),
translate('PresentationPlugin.MediaItem', translate('PresentationPlugin.MediaItem',
'The presentation %s no longer exists.') % filename) 'The presentation {name} no longer exists.'
).format(name=filename))
return False return False
def find_controller_by_type(self, filename): def find_controller_by_type(self, filename):

View File

@ -28,7 +28,7 @@ from PyQt5 import QtCore
from openlp.core.common import Registry from openlp.core.common import Registry
from openlp.core.ui import HideMode from openlp.core.ui import HideMode
from openlp.core.lib import ServiceItemContext, ServiceItem from openlp.core.lib import ServiceItemContext
from openlp.plugins.presentations.lib.pdfcontroller import PDF_CONTROLLER_FILETYPES from openlp.plugins.presentations.lib.pdfcontroller import PDF_CONTROLLER_FILETYPES
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -48,14 +48,14 @@ class Controller(object):
self.is_live = live self.is_live = live
self.doc = None self.doc = None
self.hide_mode = None self.hide_mode = None
log.info('%s controller loaded' % live) log.info('{name} controller loaded'.format(name=live))
def add_handler(self, controller, file, hide_mode, slide_no): def add_handler(self, controller, file, hide_mode, slide_no):
""" """
Add a handler, which is an instance of a presentation and slidecontroller combination. If the slidecontroller Add a handler, which is an instance of a presentation and slidecontroller combination. If the slidecontroller
has a display then load the presentation. has a display then load the presentation.
""" """
log.debug('Live = %s, add_handler %s' % (self.is_live, file)) log.debug('Live = {live}, add_handler {handler}'.format(live=self.is_live, handler=file))
self.controller = controller self.controller = controller
if self.doc is not None: if self.doc is not None:
self.shutdown() self.shutdown()
@ -67,7 +67,7 @@ class Controller(object):
return return
self.doc.slidenumber = slide_no self.doc.slidenumber = slide_no
self.hide_mode = hide_mode self.hide_mode = hide_mode
log.debug('add_handler, slide_number: %d' % slide_no) log.debug('add_handler, slide_number: {slide:d}'.format(slide=slide_no))
if self.is_live: if self.is_live:
if hide_mode == HideMode.Screen: if hide_mode == HideMode.Screen:
Registry().execute('live_display_hide', HideMode.Screen) Registry().execute('live_display_hide', HideMode.Screen)
@ -87,14 +87,14 @@ class Controller(object):
""" """
Active the presentation, and show it on the screen. Use the last slide number. Active the presentation, and show it on the screen. Use the last slide number.
""" """
log.debug('Live = %s, activate' % self.is_live) log.debug('Live = {live}, activate'.format(live=self.is_live))
if not self.doc: if not self.doc:
return False return False
if self.doc.is_active(): if self.doc.is_active():
return True return True
if not self.doc.is_loaded(): if not self.doc.is_loaded():
if not self.doc.load_presentation(): if not self.doc.load_presentation():
log.warning('Failed to activate %s' % self.doc.file_path) log.warning('Failed to activate {path}'.format(path=self.doc.file_path))
return False return False
if self.is_live: if self.is_live:
self.doc.start_presentation() self.doc.start_presentation()
@ -105,14 +105,14 @@ class Controller(object):
if self.doc.is_active(): if self.doc.is_active():
return True return True
else: else:
log.warning('Failed to activate %s' % self.doc.file_path) log.warning('Failed to activate {path}'.format(path=self.doc.file_path))
return False return False
def slide(self, slide): def slide(self, slide):
""" """
Go to a specific slide Go to a specific slide
""" """
log.debug('Live = %s, slide' % self.is_live) log.debug('Live = {live}, slide'.format(live=self.is_live))
if not self.doc: if not self.doc:
return return
if not self.is_live: if not self.is_live:
@ -130,7 +130,7 @@ class Controller(object):
""" """
Based on the handler passed at startup triggers the first slide. Based on the handler passed at startup triggers the first slide.
""" """
log.debug('Live = %s, first' % self.is_live) log.debug('Live = {live}, first'.format(live=self.is_live))
if not self.doc: if not self.doc:
return return
if not self.is_live: if not self.is_live:
@ -148,7 +148,7 @@ class Controller(object):
""" """
Based on the handler passed at startup triggers the last slide. Based on the handler passed at startup triggers the last slide.
""" """
log.debug('Live = %s, last' % self.is_live) log.debug('Live = {live}, last'.format(live=self.is_live))
if not self.doc: if not self.doc:
return return
if not self.is_live: if not self.is_live:
@ -166,7 +166,7 @@ class Controller(object):
""" """
Based on the handler passed at startup triggers the next slide event. Based on the handler passed at startup triggers the next slide event.
""" """
log.debug('Live = %s, next' % self.is_live) log.debug('Live = {live}, next'.format(live=self.is_live))
if not self.doc: if not self.doc:
return return
if not self.is_live: if not self.is_live:
@ -191,7 +191,7 @@ class Controller(object):
""" """
Based on the handler passed at startup triggers the previous slide event. Based on the handler passed at startup triggers the previous slide event.
""" """
log.debug('Live = %s, previous' % self.is_live) log.debug('Live = {live}, previous'.formta(live=self.is_live))
if not self.doc: if not self.doc:
return return
if not self.is_live: if not self.is_live:
@ -212,7 +212,7 @@ class Controller(object):
""" """
Based on the handler passed at startup triggers slide show to shut down. Based on the handler passed at startup triggers slide show to shut down.
""" """
log.debug('Live = %s, shutdown' % self.is_live) log.debug('Live = {live}, shutdown'.format(live=self.is_live))
if not self.doc: if not self.doc:
return return
self.doc.close_presentation() self.doc.close_presentation()
@ -222,7 +222,7 @@ class Controller(object):
""" """
Instruct the controller to blank the presentation. Instruct the controller to blank the presentation.
""" """
log.debug('Live = %s, blank' % self.is_live) log.debug('Live = {live}, blank'.format(live=self.is_live))
self.hide_mode = hide_mode self.hide_mode = hide_mode
if not self.doc: if not self.doc:
return return
@ -243,7 +243,7 @@ class Controller(object):
""" """
Instruct the controller to stop and hide the presentation. Instruct the controller to stop and hide the presentation.
""" """
log.debug('Live = %s, stop' % self.is_live) log.debug('Live = {live}, stop'.format(live=self.is_live))
# The document has not been loaded yet, so don't do anything. This can happen when going live with a # The document has not been loaded yet, so don't do anything. This can happen when going live with a
# presentation while blanked to desktop. # presentation while blanked to desktop.
if not self.doc: if not self.doc:
@ -266,7 +266,7 @@ class Controller(object):
""" """
Instruct the controller to unblank the presentation. Instruct the controller to unblank the presentation.
""" """
log.debug('Live = %s, unblank' % self.is_live) log.debug('Live = {live}, unblank'.format(live=self.is_live))
self.hide_mode = None self.hide_mode = None
if not self.doc: if not self.doc:
return return
@ -321,7 +321,7 @@ class MessageListener(object):
""" """
Start of new presentation. Save the handler as any new presentations start here Start of new presentation. Save the handler as any new presentations start here
""" """
log.debug('Startup called with message %s' % message) log.debug('Startup called with message {text}'.format(text=message))
is_live = message[1] is_live = message[1]
item = message[0] item = message[0]
hide_mode = message[2] hide_mode = message[2]
@ -332,7 +332,7 @@ class MessageListener(object):
# the conversion has already been done at this point. # the conversion has already been done at this point.
file_type = os.path.splitext(file.lower())[1][1:] file_type = os.path.splitext(file.lower())[1][1:]
if file_type in PDF_CONTROLLER_FILETYPES: if file_type in PDF_CONTROLLER_FILETYPES:
log.debug('Converting from pdf/xps/oxps to images for serviceitem with file %s', file) log.debug('Converting from pdf/xps/oxps to images for serviceitem with file {name}'.format(name=file))
# Create a copy of the original item, and then clear the original item so it can be filled with images # Create a copy of the original item, and then clear the original item so it can be filled with images
item_cpy = copy.copy(item) item_cpy = copy.copy(item)
item.__init__(None) item.__init__(None)

View File

@ -80,14 +80,14 @@ class PdfController(PresentationController):
found_mutool = re.search('usage: mutool.*', decoded_line, re.IGNORECASE) found_mutool = re.search('usage: mutool.*', decoded_line, re.IGNORECASE)
if found_mutool: if found_mutool:
# Test that mutool contains mudraw # Test that mutool contains mudraw
if re.search('draw\s+--\s+convert document.*', runlog.decode(), re.IGNORECASE | re.MULTILINE): if re.search(r'draw\s+--\s+convert document.*', runlog.decode(), re.IGNORECASE | re.MULTILINE):
program_type = 'mutool' program_type = 'mutool'
break break
found_gs = re.search('GPL Ghostscript.*', decoded_line, re.IGNORECASE) found_gs = re.search('GPL Ghostscript.*', decoded_line, re.IGNORECASE)
if found_gs: if found_gs:
program_type = 'gs' program_type = 'gs'
break break
log.debug('in check_binary, found: %s', program_type) log.debug('in check_binary, found: {text}'.format(text=program_type))
return program_type return program_type
def check_available(self): def check_available(self):
@ -215,8 +215,8 @@ class PdfDocument(PresentationDocument):
height = 0.0 height = 0.0
for line in runlog.splitlines(): for line in runlog.splitlines():
try: try:
width = float(re.search('.*Size: x: (\d+\.?\d*), y: \d+.*', line.decode()).group(1)) width = float(re.search(r'.*Size: x: (\d+\.?\d*), y: \d+.*', line.decode()).group(1))
height = float(re.search('.*Size: x: \d+\.?\d*, y: (\d+\.?\d*).*', line.decode()).group(1)) height = float(re.search(r'.*Size: x: \d+\.?\d*, y: (\d+\.?\d*).*', line.decode()).group(1))
break break
except AttributeError: except AttributeError:
continue continue
@ -255,11 +255,13 @@ class PdfDocument(PresentationDocument):
os.makedirs(self.get_temp_folder()) os.makedirs(self.get_temp_folder())
if self.controller.mudrawbin: if self.controller.mudrawbin:
log.debug('loading presentation using mudraw') log.debug('loading presentation using mudraw')
# TODO: Find out where the string conversion actually happens
runlog = check_output([self.controller.mudrawbin, '-w', str(size.width()), '-h', str(size.height()), runlog = check_output([self.controller.mudrawbin, '-w', str(size.width()), '-h', str(size.height()),
'-o', os.path.join(self.get_temp_folder(), 'mainslide%03d.png'), self.file_path], '-o', os.path.join(self.get_temp_folder(), 'mainslide%03d.png'), self.file_path],
startupinfo=self.startupinfo) startupinfo=self.startupinfo)
elif self.controller.mutoolbin: elif self.controller.mutoolbin:
log.debug('loading presentation using mutool') log.debug('loading presentation using mutool')
# TODO: Find out where the string convertsion actually happens
runlog = check_output([self.controller.mutoolbin, 'draw', '-w', str(size.width()), '-h', runlog = check_output([self.controller.mutoolbin, 'draw', '-w', str(size.width()), '-h',
str(size.height()), str(size.height()),
'-o', os.path.join(self.get_temp_folder(), 'mainslide%03d.png'), self.file_path], '-o', os.path.join(self.get_temp_folder(), 'mainslide%03d.png'), self.file_path],
@ -267,6 +269,7 @@ class PdfDocument(PresentationDocument):
elif self.controller.gsbin: elif self.controller.gsbin:
log.debug('loading presentation using gs') log.debug('loading presentation using gs')
resolution = self.gs_get_resolution(size) resolution = self.gs_get_resolution(size)
# TODO: Find out where the string conversion actually happens
runlog = check_output([self.controller.gsbin, '-dSAFER', '-dNOPAUSE', '-dBATCH', '-sDEVICE=png16m', runlog = check_output([self.controller.gsbin, '-dSAFER', '-dNOPAUSE', '-dBATCH', '-sDEVICE=png16m',
'-r' + str(resolution), '-dTextAlphaBits=4', '-dGraphicsAlphaBits=4', '-r' + str(resolution), '-dTextAlphaBits=4', '-dGraphicsAlphaBits=4',
'-sOutputFile=' + os.path.join(self.get_temp_folder(), 'mainslide%03d.png'), '-sOutputFile=' + os.path.join(self.get_temp_folder(), 'mainslide%03d.png'),

View File

@ -179,7 +179,7 @@ class PowerpointDocument(PresentationDocument):
if not self.presentation.Slides(num + 1).SlideShowTransition.Hidden: if not self.presentation.Slides(num + 1).SlideShowTransition.Hidden:
self.index_map[key] = num + 1 self.index_map[key] = num + 1
self.presentation.Slides(num + 1).Export( self.presentation.Slides(num + 1).Export(
os.path.join(self.get_thumbnail_folder(), 'slide%d.png' % (key)), 'png', 320, 240) os.path.join(self.get_thumbnail_folder(), 'slide{key:d}.png'.format(key=key)), 'png', 320, 240)
key += 1 key += 1
self.slide_count = key - 1 self.slide_count = key - 1
@ -345,8 +345,9 @@ class PowerpointDocument(PresentationDocument):
# Find the presentation window and save the handle for later # Find the presentation window and save the handle for later
self.presentation_hwnd = None self.presentation_hwnd = None
if ppt_window: if ppt_window:
log.debug('main display size: y=%d, height=%d, x=%d, width=%d' log.debug('main display size: y={y:d}, height={height:d}, '
% (size.y(), size.height(), size.x(), size.width())) 'x={x:d}, width={width:d}'.format(y=size.y(), height=size.height(),
x=size.x(), width=size.width()))
win32gui.EnumWindows(self._window_enum_callback, size) win32gui.EnumWindows(self._window_enum_callback, size)
# Make sure powerpoint doesn't steal focus, unless we're on a single screen setup # Make sure powerpoint doesn't steal focus, unless we're on a single screen setup
if len(ScreenList().screen_list) > 1: if len(ScreenList().screen_list) > 1:
@ -361,10 +362,18 @@ class PowerpointDocument(PresentationDocument):
# it is the powerpoint presentation window. # it is the powerpoint presentation window.
(left, top, right, bottom) = win32gui.GetWindowRect(hwnd) (left, top, right, bottom) = win32gui.GetWindowRect(hwnd)
window_title = win32gui.GetWindowText(hwnd) window_title = win32gui.GetWindowText(hwnd)
log.debug('window size: left=%d, top=%d, right=%d, width=%d' % (left, top, right, bottom)) log.debug('window size: left={left:d}, top={top:d}, '
log.debug('compare size: %d and %d, %d and %d, %d and %d, %d and %d' 'right={right:d}, bottom={bottom:d}'.format(left=left, top=top, right=right, bottom=bottom))
% (size.y(), top, size.height(), (bottom - top), size.x(), left, size.width(), (right - left))) log.debug('compare size: {y:d} and {top:d}, {height:d} and {vertical:d}, '
log.debug('window title: %s' % window_title) '{x:d} and {left}, {width:d} and {horizontal:d}'.format(y=size.y(),
top=top,
height=size.height(),
vertical=(bottom - top),
x=size.x(),
left=left,
width=size.width(),
horizontal=(right - left)))
log.debug('window title: {title}'.format(title=window_title))
filename_root, filename_ext = os.path.splitext(os.path.basename(self.file_path)) filename_root, filename_ext = os.path.splitext(os.path.basename(self.file_path))
if size.y() == top and size.height() == (bottom - top) and size.x() == left and \ if size.y() == top and size.height() == (bottom - top) and size.x() == left and \
size.width() == (right - left) and filename_root in window_title: size.width() == (right - left) and filename_root in window_title:
@ -416,8 +425,8 @@ class PowerpointDocument(PresentationDocument):
and self.get_slide_number() == slide_no: and self.get_slide_number() == slide_no:
click_index = self.presentation.SlideShowWindow.View.GetClickIndex() click_index = self.presentation.SlideShowWindow.View.GetClickIndex()
click_count = self.presentation.SlideShowWindow.View.GetClickCount() click_count = self.presentation.SlideShowWindow.View.GetClickCount()
log.debug('We are already on this slide - go to next effect if any left, idx: %d, count: %d' log.debug('We are already on this slide - go to next effect if any left, idx: '
% (click_index, click_count)) '{index:d}, count: {count:d}'.format(index=click_index, count=click_count))
if click_index < click_count: if click_index < click_count:
self.next_step() self.next_step()
else: else:

View File

@ -148,7 +148,7 @@ class PptviewDocument(PresentationDocument):
return return
log.debug('create_thumbnails proceeding') log.debug('create_thumbnails proceeding')
for idx in range(self.get_slide_count()): for idx in range(self.get_slide_count()):
path = '%s\\slide%s.bmp' % (self.get_temp_folder(), str(idx + 1)) path = '{folder}\\slide{index}.bmp'.format(folder=self.get_temp_folder(), index=str(idx + 1))
self.convert_thumbnail(path, idx + 1) self.convert_thumbnail(path, idx + 1)
def create_titles_and_notes(self): def create_titles_and_notes(self):
@ -181,13 +181,13 @@ class PptviewDocument(PresentationDocument):
index = -1 index = -1
list_to_add = None list_to_add = None
# check if it is a slide # check if it is a slide
match = re.search("slides/slide(.+)\.xml", zip_info.filename) match = re.search(r'slides/slide(.+)\.xml', zip_info.filename)
if match: if match:
index = int(match.group(1)) - 1 index = int(match.group(1)) - 1
node_type = 'ctrTitle' node_type = 'ctrTitle'
list_to_add = titles list_to_add = titles
# or a note # or a note
match = re.search("notesSlides/notesSlide(.+)\.xml", zip_info.filename) match = re.search(r'notesSlides/notesSlide(.+)\.xml', zip_info.filename)
if match: if match:
index = int(match.group(1)) - 1 index = int(match.group(1)) - 1
node_type = 'body' node_type = 'body'

View File

@ -278,7 +278,7 @@ class PresentationDocument(object):
prefix = 'live' prefix = 'live'
else: else:
prefix = 'preview' prefix = 'preview'
Registry().execute('slidecontroller_%s_change' % prefix, self.slide_number - 1) Registry().execute('slidecontroller_{prefix}_change'.format(prefix=prefix), self.slide_number - 1)
def get_slide_text(self, slide_no): def get_slide_text(self, slide_no):
""" """
@ -312,7 +312,7 @@ class PresentationDocument(object):
log.exception('Failed to open/read existing titles file') log.exception('Failed to open/read existing titles file')
titles = [] titles = []
for slide_no, title in enumerate(titles, 1): for slide_no, title in enumerate(titles, 1):
notes_file = os.path.join(self.get_thumbnail_folder(), 'slideNotes%d.txt' % slide_no) notes_file = os.path.join(self.get_thumbnail_folder(), 'slideNotes{number:d}.txt'.format(number=slide_no))
note = '' note = ''
if os.path.exists(notes_file): if os.path.exists(notes_file):
try: try:
@ -335,7 +335,8 @@ class PresentationDocument(object):
fo.writelines(titles) fo.writelines(titles)
if notes: if notes:
for slide_no, note in enumerate(notes, 1): for slide_no, note in enumerate(notes, 1):
notes_file = os.path.join(self.get_thumbnail_folder(), 'slideNotes%d.txt' % slide_no) notes_file = os.path.join(self.get_thumbnail_folder(),
'slideNotes{number:d}.txt'.format(number=slide_no))
with open(notes_file, mode='wt', encoding='utf-8') as fn: with open(notes_file, mode='wt', encoding='utf-8') as fn:
fn.write(note) fn.write(note)

View File

@ -137,7 +137,8 @@ class PresentationTab(SettingsTab):
if checkbox.isEnabled(): if checkbox.isEnabled():
checkbox.setText(controller.name) checkbox.setText(controller.name)
else: else:
checkbox.setText(translate('PresentationPlugin.PresentationTab', '%s (unavailable)') % controller.name) checkbox.setText(translate('PresentationPlugin.PresentationTab',
'{name} (unavailable)').format(name=controller.name))
def load(self): def load(self):
""" """

View File

@ -124,15 +124,15 @@ class PresentationPlugin(Plugin):
log.debug('check_pre_conditions') log.debug('check_pre_conditions')
controller_dir = os.path.join(AppLocation.get_directory(AppLocation.PluginsDir), 'presentations', 'lib') controller_dir = os.path.join(AppLocation.get_directory(AppLocation.PluginsDir), 'presentations', 'lib')
for filename in os.listdir(controller_dir): for filename in os.listdir(controller_dir):
if filename.endswith('controller.py') and not filename == 'presentationcontroller.py': if filename.endswith('controller.py') and filename != 'presentationcontroller.py':
path = os.path.join(controller_dir, filename) path = os.path.join(controller_dir, filename)
if os.path.isfile(path): if os.path.isfile(path):
module_name = 'openlp.plugins.presentations.lib.' + os.path.splitext(filename)[0] module_name = 'openlp.plugins.presentations.lib.' + os.path.splitext(filename)[0]
log.debug('Importing controller %s', module_name) log.debug('Importing controller {name}'.format(name=module_name))
try: try:
__import__(module_name, globals(), locals(), []) __import__(module_name, globals(), locals(), [])
except ImportError: except ImportError:
log.warning('Failed to import %s on path %s', module_name, path) log.warning('Failed to import {name} on path {path}'.format(name=module_name, path=path))
controller_classes = PresentationController.__subclasses__() controller_classes = PresentationController.__subclasses__()
for controller_class in controller_classes: for controller_class in controller_classes:
controller = controller_class(self) controller = controller_class(self)

View File

@ -141,7 +141,8 @@ class HttpRouter(RegistryProperties):
""" """
Initialise the router stack and any other variables. Initialise the router stack and any other variables.
""" """
auth_code = "%s:%s" % (Settings().value('remotes/user id'), Settings().value('remotes/password')) auth_code = "{user}:{password}".format(user=Settings().value('remotes/user id'),
password=Settings().value('remotes/password'))
try: try:
self.auth = base64.b64encode(auth_code) self.auth = base64.b64encode(auth_code)
except TypeError: except TypeError:
@ -189,7 +190,7 @@ class HttpRouter(RegistryProperties):
if self.headers['Authorization'] is None: if self.headers['Authorization'] is None:
self.do_authorisation() self.do_authorisation()
self.wfile.write(bytes('no auth header received', 'UTF-8')) self.wfile.write(bytes('no auth header received', 'UTF-8'))
elif self.headers['Authorization'] == 'Basic %s' % self.auth: elif self.headers['Authorization'] == 'Basic {auth}'.format(auth=self.auth):
self.do_http_success() self.do_http_success()
self.call_function(function, *args) self.call_function(function, *args)
else: else:
@ -221,13 +222,17 @@ class HttpRouter(RegistryProperties):
self.request_data = None self.request_data = None
url_path_split = urlparse(url_path) url_path_split = urlparse(url_path)
url_query = parse_qs(url_path_split.query) url_query = parse_qs(url_path_split.query)
# GET # Get data from HTTP request
if 'data' in url_query.keys(): if self.command == 'GET':
self.request_data = url_query['data'][0] 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: for route, func in self.routes:
match = re.match(route, url_path_split.path) match = re.match(route, url_path_split.path)
if match: if match:
log.debug('Route "%s" matched "%s"', route, url_path) log.debug('Route "{route}" matched "{path}"'.format(route=route, path=url_path))
args = [] args = []
for param in match.groups(): for param in match.groups():
args.append(param) args.append(param)
@ -314,9 +319,9 @@ class HttpRouter(RegistryProperties):
remote = translate('RemotePlugin.Mobile', 'Remote') remote = translate('RemotePlugin.Mobile', 'Remote')
stage = translate('RemotePlugin.Mobile', 'Stage') stage = translate('RemotePlugin.Mobile', 'Stage')
self.template_vars = { self.template_vars = {
'app_title': "OpenLP | %s" % remote, 'app_title': "OpenLP | {remote}".format(remote=remote),
'stage_title': "OpenLP | %s" % stage, 'stage_title': "OpenLP | {stage}".format(stage=stage),
'live_title': "OpenLP | %s" % UiStrings().Live, 'live_title': "OpenLP | {live}".format(live=UiStrings().Live),
'service_manager': translate('RemotePlugin.Mobile', 'Service Manager'), 'service_manager': translate('RemotePlugin.Mobile', 'Service Manager'),
'slide_controller': translate('RemotePlugin.Mobile', 'Slide Controller'), 'slide_controller': translate('RemotePlugin.Mobile', 'Slide Controller'),
'alerts': translate('RemotePlugin.Mobile', 'Alerts'), 'alerts': translate('RemotePlugin.Mobile', 'Alerts'),
@ -349,7 +354,7 @@ class HttpRouter(RegistryProperties):
:param file_name: file name with path :param file_name: file name with path
:return: :return:
""" """
log.debug('serve file request %s' % file_name) log.debug('serve file request {name}'.format(name=file_name))
parts = file_name.split('/') parts = file_name.split('/')
if len(parts) == 1: if len(parts) == 1:
file_name = os.path.join(parts[0], 'stage.html') file_name = os.path.join(parts[0], 'stage.html')
@ -376,10 +381,10 @@ class HttpRouter(RegistryProperties):
content = Template(filename=path, input_encoding='utf-8', output_encoding='utf-8').render(**variables) content = Template(filename=path, input_encoding='utf-8', output_encoding='utf-8').render(**variables)
else: else:
file_handle = open(path, 'rb') file_handle = open(path, 'rb')
log.debug('Opened %s' % path) log.debug('Opened {path}'.format(path=path))
content = file_handle.read() content = file_handle.read()
except IOError: except IOError:
log.exception('Failed to open %s' % path) log.exception('Failed to open {path}'.format(path=path))
return self.do_not_found() return self.do_not_found()
finally: finally:
if file_handle: if file_handle:
@ -397,13 +402,11 @@ class HttpRouter(RegistryProperties):
Ultimately for i18n, this could first look for xx/file.html before falling back to file.html. Ultimately for i18n, this could first look for xx/file.html before falling back to file.html.
where xx is the language, e.g. 'en' where xx is the language, e.g. 'en'
""" """
log.debug('serve file request %s' % file_name) log.debug('serve file request {name}'.format(name=file_name))
if not file_name: if not file_name:
file_name = 'index.html' file_name = 'index.html'
elif file_name == 'stage': if '.' not in file_name:
file_name = 'stage.html' file_name += '.html'
elif file_name == 'main':
file_name = 'main.html'
if file_name.startswith('/'): if file_name.startswith('/'):
file_name = file_name[1:] file_name = file_name[1:]
path = os.path.normpath(os.path.join(self.html_dir, file_name)) path = os.path.normpath(os.path.join(self.html_dir, file_name))
@ -430,7 +433,9 @@ class HttpRouter(RegistryProperties):
:param dimensions: image size :param dimensions: image size
:param controller_name: controller to be called :param controller_name: controller to be called
""" """
log.debug('serve thumbnail %s/thumbnails%s/%s' % (controller_name, dimensions, file_name)) log.debug('serve thumbnail {cname}/thumbnails{dim}/{fname}'.format(cname=controller_name,
dim=dimensions,
fname=file_name))
supported_controllers = ['presentations', 'images'] supported_controllers = ['presentations', 'images']
# -1 means use the default dimension in ImageManager # -1 means use the default dimension in ImageManager
width = -1 width = -1
@ -536,7 +541,7 @@ class HttpRouter(RegistryProperties):
:param var: variable - not used :param var: variable - not used
""" """
log.debug("controller_text var = %s" % var) log.debug("controller_text var = {var}".format(var=var))
current_item = self.live_controller.service_item current_item = self.live_controller.service_item
data = [] data = []
if current_item: if current_item:
@ -591,7 +596,8 @@ class HttpRouter(RegistryProperties):
:param display_type: This is the type of slide controller, either ``preview`` or ``live``. :param display_type: This is the type of slide controller, either ``preview`` or ``live``.
:param action: The action to perform. :param action: The action to perform.
""" """
event = getattr(self.live_controller, 'slidecontroller_%s_%s' % (display_type, action)) event = getattr(self.live_controller, 'slidecontroller_{display}_{action}'.format(display=display_type,
action=action))
if self.request_data: if self.request_data:
try: try:
data = json.loads(self.request_data)['request']['id'] data = json.loads(self.request_data)['request']['id']
@ -620,7 +626,7 @@ class HttpRouter(RegistryProperties):
:param action: The action to perform. :param action: The action to perform.
""" """
event = getattr(self.service_manager, 'servicemanager_%s_item' % action) event = getattr(self.service_manager, 'servicemanager_{action}_item'.format(action=action))
if self.request_data: if self.request_data:
try: try:
data = int(json.loads(self.request_data)['request']['id']) data = int(json.loads(self.request_data)['request']['id'])
@ -677,7 +683,7 @@ class HttpRouter(RegistryProperties):
return self.do_http_error() return self.do_http_error()
plugin = self.plugin_manager.get_plugin_by_name(plugin_name) plugin = self.plugin_manager.get_plugin_by_name(plugin_name)
if plugin.status == PluginStatus.Active and plugin.media_item: if plugin.status == PluginStatus.Active and plugin.media_item:
getattr(plugin.media_item, '%s_go_live' % plugin_name).emit([request_id, True]) getattr(plugin.media_item, '{name}_go_live'.format(name=plugin_name)).emit([request_id, True])
return self.do_http_success() return self.do_http_success()
def add_to_service(self, plugin_name): def add_to_service(self, plugin_name):
@ -693,5 +699,5 @@ class HttpRouter(RegistryProperties):
plugin = self.plugin_manager.get_plugin_by_name(plugin_name) plugin = self.plugin_manager.get_plugin_by_name(plugin_name)
if plugin.status == PluginStatus.Active and plugin.media_item: if plugin.status == PluginStatus.Active and plugin.media_item:
item_id = plugin.media_item.create_item_from_id(request_id) item_id = plugin.media_item.create_item_from_id(request_id)
getattr(plugin.media_item, '%s_add_to_service' % plugin_name).emit([item_id, True]) getattr(plugin.media_item, '{name}_add_to_service'.format(name=plugin_name)).emit([item_id, True])
self.do_http_success() self.do_http_success()

View File

@ -136,11 +136,13 @@ class OpenLPServer(RegistryProperties):
while loop < 4: while loop < 4:
try: try:
self.httpd = server_class((address, port), CustomHandler) self.httpd = server_class((address, port), CustomHandler)
log.debug("Server started for class %s %s %d" % (server_class, address, port)) log.debug("Server started for class {name} {address} {port:d}".format(name=server_class,
address=address,
port=port))
break break
except OSError: except OSError:
log.debug("failed to start http server thread state %d %s" % log.debug("failed to start http server thread state "
(loop, self.http_thread.isRunning())) "{loop:d} {running}".format(loop=loop, running=self.http_thread.isRunning()))
loop += 1 loop += 1
time.sleep(0.1) time.sleep(0.1)
except: except:
@ -167,7 +169,6 @@ class HTTPSServer(HTTPServer):
local_data = AppLocation.get_directory(AppLocation.DataDir) local_data = AppLocation.get_directory(AppLocation.DataDir)
self.socket = ssl.SSLSocket( self.socket = ssl.SSLSocket(
sock=socket.socket(self.address_family, self.socket_type), sock=socket.socket(self.address_family, self.socket_type),
ssl_version=ssl.PROTOCOL_TLSv1_2,
certfile=os.path.join(local_data, 'remotes', 'openlp.crt'), certfile=os.path.join(local_data, 'remotes', 'openlp.crt'),
keyfile=os.path.join(local_data, 'remotes', 'openlp.key'), keyfile=os.path.join(local_data, 'remotes', 'openlp.key'),
server_side=True) server_side=True)

View File

@ -192,14 +192,14 @@ class RemoteTab(SettingsTab):
'Show thumbnails of non-text slides in remote and stage view.')) 'Show thumbnails of non-text slides in remote and stage view.'))
self.android_app_group_box.setTitle(translate('RemotePlugin.RemoteTab', 'Android App')) self.android_app_group_box.setTitle(translate('RemotePlugin.RemoteTab', 'Android App'))
self.android_qr_description_label.setText( self.android_qr_description_label.setText(
translate('RemotePlugin.RemoteTab', 'Scan the QR code or click <a href="%s">download</a> to install the ' translate('RemotePlugin.RemoteTab',
'Android app from Google Play.') % 'Scan the QR code or click <a href="{qr}">download</a> to install the Android app from Google '
'https://play.google.com/store/apps/details?id=org.openlp.android2') 'Play.').format(qr='https://play.google.com/store/apps/details?id=org.openlp.android2'))
self.ios_app_group_box.setTitle(translate('RemotePlugin.RemoteTab', 'iOS App')) self.ios_app_group_box.setTitle(translate('RemotePlugin.RemoteTab', 'iOS App'))
self.ios_qr_description_label.setText( self.ios_qr_description_label.setText(
translate('RemotePlugin.RemoteTab', 'Scan the QR code or click <a href="%s">download</a> to install the ' translate('RemotePlugin.RemoteTab',
'iOS app from the App Store.') % 'Scan the QR code or click <a href="{qr}">download</a> to install the iOS app from the App '
'https://itunes.apple.com/app/id1096218725') 'Store.').format(qr='https://itunes.apple.com/app/id1096218725'))
self.https_settings_group_box.setTitle(translate('RemotePlugin.RemoteTab', 'HTTPS Server')) self.https_settings_group_box.setTitle(translate('RemotePlugin.RemoteTab', 'HTTPS Server'))
self.https_error_label.setText( self.https_error_label.setText(
translate('RemotePlugin.RemoteTab', 'Could not find an SSL certificate. The HTTPS server will not be ' translate('RemotePlugin.RemoteTab', 'Could not find an SSL certificate. The HTTPS server will not be '
@ -217,18 +217,18 @@ class RemoteTab(SettingsTab):
Update the display based on the data input on the screen Update the display based on the data input on the screen
""" """
ip_address = self.get_ip_address(self.address_edit.text()) ip_address = self.get_ip_address(self.address_edit.text())
http_url = 'http://%s:%s/' % (ip_address, self.port_spin_box.value()) http_url = 'http://{url}:{text}/'.format(url=ip_address, text=self.port_spin_box.value())
https_url = 'https://%s:%s/' % (ip_address, self.https_port_spin_box.value()) https_url = 'https://{url}:{text}/'.format(url=ip_address, text=self.https_port_spin_box.value())
self.remote_url.setText('<a href="%s">%s</a>' % (http_url, http_url)) self.remote_url.setText('<a href="{url}">{url}</a>'.format(url=http_url))
self.remote_https_url.setText('<a href="%s">%s</a>' % (https_url, https_url)) self.remote_https_url.setText('<a href="{url}">{url}</a>'.format(url=https_url))
http_url_temp = http_url + 'stage' http_url_temp = http_url + 'stage'
https_url_temp = https_url + 'stage' https_url_temp = https_url + 'stage'
self.stage_url.setText('<a href="%s">%s</a>' % (http_url_temp, http_url_temp)) self.stage_url.setText('<a href="{url}">{url}</a>'.format(url=http_url_temp))
self.stage_https_url.setText('<a href="%s">%s</a>' % (https_url_temp, https_url_temp)) self.stage_https_url.setText('<a href="{url}">{url}</a>'.format(url=https_url_temp))
http_url_temp = http_url + 'main' http_url_temp = http_url + 'main'
https_url_temp = https_url + 'main' https_url_temp = https_url + 'main'
self.live_url.setText('<a href="%s">%s</a>' % (http_url_temp, http_url_temp)) self.live_url.setText('<a href="{url}">{url}</a>'.format(url=http_url_temp))
self.live_https_url.setText('<a href="%s">%s</a>' % (https_url_temp, https_url_temp)) self.live_https_url.setText('<a href="{url}">{url}</a>'.format(url=https_url_temp))
def get_ip_address(self, ip_address): def get_ip_address(self, ip_address):
""" """

View File

@ -130,6 +130,7 @@ class DuplicateSongRemovalForm(OpenLPWizard, RegistryProperties):
Song wizard localisation. Song wizard localisation.
""" """
self.setWindowTitle(translate('Wizard', 'Wizard')) self.setWindowTitle(translate('Wizard', 'Wizard'))
# TODO: Check format() using template strings
self.title_label.setText(WizardStrings.HeaderStyle % translate('OpenLP.Ui', self.title_label.setText(WizardStrings.HeaderStyle % translate('OpenLP.Ui',
'Welcome to the Duplicate Song Removal Wizard')) 'Welcome to the Duplicate Song Removal Wizard'))
self.information_label.setText( self.information_label.setText(
@ -148,8 +149,8 @@ class DuplicateSongRemovalForm(OpenLPWizard, RegistryProperties):
Set the wizard review page header text. Set the wizard review page header text.
""" """
self.review_page.setTitle( self.review_page.setTitle(
translate('Wizard', 'Review duplicate songs (%s/%s)') % translate('Wizard', 'Review duplicate songs ({current}/{total})').format(current=self.review_current_count,
(self.review_current_count, self.review_total_count)) total=self.review_total_count))
def custom_page_changed(self, page_id): def custom_page_changed(self, page_id):
""" """

View File

@ -50,7 +50,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
""" """
Class to manage the editing of a song Class to manage the editing of a song
""" """
log.info('%s EditSongForm loaded', __name__) log.info('{name} EditSongForm loaded'.format(name=__name__))
def __init__(self, media_item, parent, manager): def __init__(self, media_item, parent, manager):
""" """
@ -185,20 +185,23 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
verse = verse.data(QtCore.Qt.UserRole) verse = verse.data(QtCore.Qt.UserRole)
if verse not in verse_names: if verse not in verse_names:
verses.append(verse) verses.append(verse)
verse_names.append('%s%s' % (VerseType.translated_tag(verse[0]), verse[1:])) verse_names.append('{verse1}{verse2}'.format(verse1=VerseType.translated_tag(verse[0]),
verse2=verse[1:]))
for count, item in enumerate(order): for count, item in enumerate(order):
if item not in verses: if item not in verses:
invalid_verses.append(order_names[count]) invalid_verses.append(order_names[count])
if invalid_verses: if invalid_verses:
valid = create_separated_list(verse_names) valid = create_separated_list(verse_names)
if len(invalid_verses) > 1: if len(invalid_verses) > 1:
msg = translate('SongsPlugin.EditSongForm', 'There are no verses corresponding to "%(invalid)s". ' msg = translate('SongsPlugin.EditSongForm',
'Valid entries are %(valid)s.\nPlease enter the verses separated by spaces.') % \ 'There are no verses corresponding to "{invalid}". Valid entries are {valid}.\n'
{'invalid': ', '.join(invalid_verses), 'valid': valid} 'Please enter the verses separated by spaces.'
).format(invalid=', '.join(invalid_verses), valid=valid)
else: else:
msg = translate('SongsPlugin.EditSongForm', 'There is no verse corresponding to "%(invalid)s".' msg = translate('SongsPlugin.EditSongForm',
'Valid entries are %(valid)s.\nPlease enter the verses separated by spaces.') % \ 'There is no verse corresponding to "{invalid}". Valid entries are {valid}.\n'
{'invalid': invalid_verses[0], 'valid': valid} 'Please enter the verses separated by spaces.').format(invalid=invalid_verses[0],
valid=valid)
critical_error_message_box(title=translate('SongsPlugin.EditSongForm', 'Invalid Verse Order'), critical_error_message_box(title=translate('SongsPlugin.EditSongForm', 'Invalid Verse Order'),
message=msg) message=msg)
return len(invalid_verses) == 0 return len(invalid_verses) == 0
@ -242,23 +245,24 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
field = item.data(QtCore.Qt.UserRole) field = item.data(QtCore.Qt.UserRole)
verse_tags.append(field) verse_tags.append(field)
if not self._validate_tags(tags): if not self._validate_tags(tags):
misplaced_tags.append('%s %s' % (VerseType.translated_name(field[0]), field[1:])) misplaced_tags.append('{field1} {field2}'.format(field1=VerseType.translated_name(field[0]),
field2=field[1:]))
if misplaced_tags: if misplaced_tags:
critical_error_message_box( critical_error_message_box(
message=translate('SongsPlugin.EditSongForm', message=translate('SongsPlugin.EditSongForm',
'There are misplaced formatting tags in the following verses:\n\n%s\n\n' 'There are misplaced formatting tags in the following verses:\n\n{tag}\n\n'
'Please correct these tags before continuing.' % ', '.join(misplaced_tags))) 'Please correct these tags before continuing.').format(tag=', '.join(misplaced_tags)))
return False return False
for tag in verse_tags: for tag in verse_tags:
if verse_tags.count(tag) > 26: if verse_tags.count(tag) > 26:
# lp#1310523: OpenLyrics allows only a-z variants of one verse: # lp#1310523: OpenLyrics allows only a-z variants of one verse:
# http://openlyrics.info/dataformat.html#verse-name # http://openlyrics.info/dataformat.html#verse-name
critical_error_message_box(message=translate( critical_error_message_box(message=translate(
'SongsPlugin.EditSongForm', 'You have %(count)s verses named %(name)s %(number)s. ' 'SongsPlugin.EditSongForm',
'You can have at most 26 verses with the same name' % 'You have {count} verses named {name} {number}. You can have at most '
{'count': verse_tags.count(tag), '26 verses with the same name').format(count=verse_tags.count(tag),
'name': VerseType.translated_name(tag[0]), name=VerseType.translated_name(tag[0]),
'number': tag[1:]})) number=tag[1:]))
return False return False
return True return True
@ -313,7 +317,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
self.song.verse_order = re.sub('([' + verse.upper() + verse.lower() + '])(\W|$)', self.song.verse_order = re.sub('([' + verse.upper() + verse.lower() + '])(\W|$)',
r'\g<1>1\2', self.song.verse_order) r'\g<1>1\2', self.song.verse_order)
except: except:
log.exception('Problem processing song Lyrics \n%s', sxml.dump_xml()) log.exception('Problem processing song Lyrics \n{xml}'.forma(xml=sxml.dump_xml()))
raise raise
def keyPressEvent(self, event): def keyPressEvent(self, event):
@ -492,7 +496,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
verse[0]['type'] = VerseType.tags[index] verse[0]['type'] = VerseType.tags[index]
if verse[0]['label'] == '': if verse[0]['label'] == '':
verse[0]['label'] = '1' verse[0]['label'] = '1'
verse_def = '%s%s' % (verse[0]['type'], verse[0]['label']) verse_def = '{verse}{label}'.format(verse=verse[0]['type'], label=verse[0]['label'])
item = QtWidgets.QTableWidgetItem(verse[1]) item = QtWidgets.QTableWidgetItem(verse[1])
item.setData(QtCore.Qt.UserRole, verse_def) item.setData(QtCore.Qt.UserRole, verse_def)
self.verse_list_widget.setItem(count, 0, item) self.verse_list_widget.setItem(count, 0, item)
@ -501,7 +505,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
for count, verse in enumerate(verses): for count, verse in enumerate(verses):
self.verse_list_widget.setRowCount(self.verse_list_widget.rowCount() + 1) self.verse_list_widget.setRowCount(self.verse_list_widget.rowCount() + 1)
item = QtWidgets.QTableWidgetItem(verse) item = QtWidgets.QTableWidgetItem(verse)
verse_def = '%s%s' % (VerseType.tags[VerseType.Verse], str(count + 1)) verse_def = '{verse}{count:d}'.format(verse=VerseType.tags[VerseType.Verse], count=(count + 1))
item.setData(QtCore.Qt.UserRole, verse_def) item.setData(QtCore.Qt.UserRole, verse_def)
self.verse_list_widget.setItem(count, 0, item) self.verse_list_widget.setItem(count, 0, item)
if self.song.verse_order: if self.song.verse_order:
@ -514,7 +518,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
if verse_index is None: if verse_index is None:
verse_index = VerseType.from_tag(verse_def[0]) verse_index = VerseType.from_tag(verse_def[0])
verse_tag = VerseType.translated_tags[verse_index].upper() verse_tag = VerseType.translated_tags[verse_index].upper()
translated.append('%s%s' % (verse_tag, verse_def[1:])) translated.append('{tag}{verse}'.format(tag=verse_tag, verse=verse_def[1:]))
self.verse_order_edit.setText(' '.join(translated)) self.verse_order_edit.setText(' '.join(translated))
else: else:
self.verse_order_edit.setText('') self.verse_order_edit.setText('')
@ -554,7 +558,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
item = self.verse_list_widget.item(row, 0) item = self.verse_list_widget.item(row, 0)
verse_def = item.data(QtCore.Qt.UserRole) verse_def = item.data(QtCore.Qt.UserRole)
verse_tag = VerseType.translated_tag(verse_def[0]) verse_tag = VerseType.translated_tag(verse_def[0])
row_def = '%s%s' % (verse_tag, verse_def[1:]) row_def = '{tag}{verse}'.format(tag=verse_tag, verse=verse_def[1:])
row_label.append(row_def) row_label.append(row_def)
self.verse_list_widget.setVerticalHeaderLabels(row_label) self.verse_list_widget.setVerticalHeaderLabels(row_label)
self.verse_list_widget.resizeRowsToContents() self.verse_list_widget.resizeRowsToContents()
@ -742,7 +746,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
self.verse_form.set_verse('', True) self.verse_form.set_verse('', True)
if self.verse_form.exec(): if self.verse_form.exec():
after_text, verse_tag, verse_num = self.verse_form.get_verse() after_text, verse_tag, verse_num = self.verse_form.get_verse()
verse_def = '%s%s' % (verse_tag, verse_num) verse_def = '{tag}{number}'.format(tag=verse_tag, number=verse_num)
item = QtWidgets.QTableWidgetItem(after_text) item = QtWidgets.QTableWidgetItem(after_text)
item.setData(QtCore.Qt.UserRole, verse_def) item.setData(QtCore.Qt.UserRole, verse_def)
item.setText(after_text) item.setText(after_text)
@ -760,7 +764,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
self.verse_form.set_verse(temp_text, True, verse_id) self.verse_form.set_verse(temp_text, True, verse_id)
if self.verse_form.exec(): if self.verse_form.exec():
after_text, verse_tag, verse_num = self.verse_form.get_verse() after_text, verse_tag, verse_num = self.verse_form.get_verse()
verse_def = '%s%s' % (verse_tag, verse_num) verse_def = '{tag}{number}'.format(tag=verse_tag, number=verse_num)
item.setData(QtCore.Qt.UserRole, verse_def) item.setData(QtCore.Qt.UserRole, verse_def)
item.setText(after_text) item.setText(after_text)
# number of lines has changed, repaint the list moving the data # number of lines has changed, repaint the list moving the data
@ -793,7 +797,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
field = item.data(QtCore.Qt.UserRole) field = item.data(QtCore.Qt.UserRole)
verse_tag = VerseType.translated_name(field[0]) verse_tag = VerseType.translated_name(field[0])
verse_num = field[1:] verse_num = field[1:]
verse_list += '---[%s:%s]---\n' % (verse_tag, verse_num) verse_list += '---[{tag}:{number}]---\n'.format(tag=verse_tag, number=verse_num)
verse_list += item.text() verse_list += item.text()
verse_list += '\n' verse_list += '\n'
self.verse_form.set_verse(verse_list) self.verse_form.set_verse(verse_list)
@ -828,7 +832,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
verse_num = match.group(1) verse_num = match.group(1)
else: else:
verse_num = '1' verse_num = '1'
verse_def = '%s%s' % (verse_tag, verse_num) verse_def = '{tag}{number}'.format(tag=verse_tag, number=verse_num)
else: else:
if parts.endswith('\n'): if parts.endswith('\n'):
parts = parts.rstrip('\n') parts = parts.rstrip('\n')
@ -919,7 +923,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
""" """
Loads file(s) from the filesystem. Loads file(s) from the filesystem.
""" """
filters = '%s (*)' % UiStrings().AllFiles filters = '{text} (*)'.format(text=UiStrings().AllFiles)
file_names = FileDialog.getOpenFileNames(self, translate('SongsPlugin.EditSongForm', 'Open File(s)'), '', file_names = FileDialog.getOpenFileNames(self, translate('SongsPlugin.EditSongForm', 'Open File(s)'), '',
filters) filters)
for filename in file_names: for filename in file_names:
@ -1027,7 +1031,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
for item in order_text.split(): for item in order_text.split():
verse_tag = VerseType.tags[VerseType.from_translated_tag(item[0])] verse_tag = VerseType.tags[VerseType.from_translated_tag(item[0])]
verse_num = item[1:].lower() verse_num = item[1:].lower()
order.append('%s%s' % (verse_tag, verse_num)) order.append('{tag}{number}'.format(tag=verse_tag, number=verse_num))
self.song.verse_order = ' '.join(order) self.song.verse_order = ' '.join(order)
self.song.ccli_number = self.ccli_number_edit.text() self.song.ccli_number = self.ccli_number_edit.text()
theme_name = self.theme_combo_box.currentText() theme_name = self.theme_combo_box.currentText()
@ -1082,12 +1086,12 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
try: try:
os.remove(audio) os.remove(audio)
except: except:
log.exception('Could not remove file: %s', audio) log.exception('Could not remove file: {audio}'.format(audio=audio))
if not files: if not files:
try: try:
os.rmdir(save_path) os.rmdir(save_path)
except OSError: except OSError:
log.exception('Could not remove directory: %s', save_path) log.exception('Could not remove directory: {path}'.format(path=save_path))
clean_song(self.manager, self.song) clean_song(self.manager, self.song)
self.manager.save_object(self.song) self.manager.save_object(self.song)
self.media_item.auto_select_id = self.song.id self.media_item.auto_select_id = self.song.id

View File

@ -22,7 +22,8 @@
from PyQt5 import QtWidgets from PyQt5 import QtWidgets
from openlp.core.lib import SpellTextEdit, build_icon, translate from openlp.core.ui.lib import SpellTextEdit
from openlp.core.lib import build_icon, translate
from openlp.core.lib.ui import UiStrings, create_button_box from openlp.core.lib.ui import UiStrings, create_button_box
from openlp.plugins.songs.lib import VerseType from openlp.plugins.songs.lib import VerseType

View File

@ -59,7 +59,7 @@ class EditVerseForm(QtWidgets.QDialog, Ui_EditVerseDialog):
if self.verse_text_edit.textCursor().columnNumber() != 0: if self.verse_text_edit.textCursor().columnNumber() != 0:
self.verse_text_edit.insertPlainText('\n') self.verse_text_edit.insertPlainText('\n')
verse_tag = VerseType.translated_name(verse_tag) verse_tag = VerseType.translated_name(verse_tag)
self.verse_text_edit.insertPlainText('---[%s:%s]---\n' % (verse_tag, verse_num)) self.verse_text_edit.insertPlainText('---[{tag}:{number}]---\n'.format(tag=verse_tag, number=verse_num))
self.verse_text_edit.setFocus() self.verse_text_edit.setFocus()
def on_split_button_clicked(self): def on_split_button_clicked(self):
@ -107,7 +107,7 @@ class EditVerseForm(QtWidgets.QDialog, Ui_EditVerseDialog):
self.verse_type_combo_box.currentIndex()] self.verse_type_combo_box.currentIndex()]
if not text: if not text:
return return
position = text.rfind('---[%s' % verse_name, 0, position) position = text.rfind('---[{verse}'.format(verse=verse_name), 0, position)
if position == -1: if position == -1:
self.verse_number_box.setValue(1) self.verse_number_box.setValue(1)
return return
@ -124,7 +124,7 @@ class EditVerseForm(QtWidgets.QDialog, Ui_EditVerseDialog):
verse_num = 1 verse_num = 1
self.verse_number_box.setValue(verse_num) self.verse_number_box.setValue(verse_num)
def set_verse(self, text, single=False, tag='%s1' % VerseType.tags[VerseType.Verse]): def set_verse(self, text, single=False, tag='{verse}1'.format(verse=VerseType.tags[VerseType.Verse])):
""" """
Save the verse Save the verse
@ -142,7 +142,7 @@ class EditVerseForm(QtWidgets.QDialog, Ui_EditVerseDialog):
self.insert_button.setVisible(False) self.insert_button.setVisible(False)
else: else:
if not text: if not text:
text = '---[%s:1]---\n' % VerseType.translated_names[VerseType.Verse] text = '---[{tag}:1]---\n'.format(tag=VerseType.translated_names[VerseType.Verse])
self.verse_type_combo_box.setCurrentIndex(0) self.verse_type_combo_box.setCurrentIndex(0)
self.verse_number_box.setValue(1) self.verse_number_box.setValue(1)
self.insert_button.setVisible(True) self.insert_button.setVisible(True)
@ -167,5 +167,5 @@ class EditVerseForm(QtWidgets.QDialog, Ui_EditVerseDialog):
""" """
text = self.verse_text_edit.toPlainText() text = self.verse_text_edit.toPlainText()
if not text.startswith('---['): if not text.startswith('---['):
text = '---[%s:1]---\n%s' % (VerseType.translated_names[VerseType.Verse], text) text = '---[{tag}:1]---\n{text}'.format(tag=VerseType.translated_names[VerseType.Verse], text=text)
return text return text

View File

@ -34,7 +34,7 @@ class MediaFilesForm(QtWidgets.QDialog, Ui_MediaFilesDialog):
""" """
Class to show a list of files from the Class to show a list of files from the
""" """
log.info('%s MediaFilesForm loaded', __name__) log.info('{name} MediaFilesForm loaded'.format(name=__name__))
def __init__(self, parent): def __init__(self, parent):
super(MediaFilesForm, self).__init__(parent, QtCore.Qt.WindowSystemMenuHint | QtCore.Qt.WindowTitleHint) super(MediaFilesForm, self).__init__(parent, QtCore.Qt.WindowSystemMenuHint | QtCore.Qt.WindowTitleHint)

View File

@ -143,6 +143,7 @@ class SongExportForm(OpenLPWizard):
Song wizard localisation. Song wizard localisation.
""" """
self.setWindowTitle(translate('SongsPlugin.ExportWizardForm', 'Song Export Wizard')) self.setWindowTitle(translate('SongsPlugin.ExportWizardForm', 'Song Export Wizard'))
# TODO: Verify format() with template variables
self.title_label.setText(WizardStrings.HeaderStyle % self.title_label.setText(WizardStrings.HeaderStyle %
translate('OpenLP.Ui', 'Welcome to the Song Export Wizard')) translate('OpenLP.Ui', 'Welcome to the Song Export Wizard'))
self.information_label.setText( self.information_label.setText(
@ -151,7 +152,7 @@ class SongExportForm(OpenLPWizard):
self.available_songs_page.setTitle(translate('SongsPlugin.ExportWizardForm', 'Select Songs')) self.available_songs_page.setTitle(translate('SongsPlugin.ExportWizardForm', 'Select Songs'))
self.available_songs_page.setSubTitle(translate('SongsPlugin.ExportWizardForm', self.available_songs_page.setSubTitle(translate('SongsPlugin.ExportWizardForm',
'Check the songs you want to export.')) 'Check the songs you want to export.'))
self.search_label.setText('%s:' % UiStrings().Search) self.search_label.setText('{text}:'.format(text=UiStrings().Search))
self.uncheck_button.setText(translate('SongsPlugin.ExportWizardForm', 'Uncheck All')) self.uncheck_button.setText(translate('SongsPlugin.ExportWizardForm', 'Uncheck All'))
self.check_button.setText(translate('SongsPlugin.ExportWizardForm', 'Check All')) self.check_button.setText(translate('SongsPlugin.ExportWizardForm', 'Check All'))
self.export_song_page.setTitle(translate('SongsPlugin.ExportWizardForm', 'Select Directory')) self.export_song_page.setTitle(translate('SongsPlugin.ExportWizardForm', 'Select Directory'))
@ -223,7 +224,7 @@ class SongExportForm(OpenLPWizard):
if song.temporary: if song.temporary:
continue continue
authors = create_separated_list([author.display_name for author in song.authors]) authors = create_separated_list([author.display_name for author in song.authors])
title = '%s (%s)' % (str(song.title), authors) title = '{title} ({author})'.format(title=song.title, author=authors)
item = QtWidgets.QListWidgetItem(title) item = QtWidgets.QListWidgetItem(title)
item.setData(QtCore.Qt.UserRole, song) item.setData(QtCore.Qt.UserRole, song)
item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEnabled) item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEnabled)
@ -257,7 +258,7 @@ class SongExportForm(OpenLPWizard):
self.progress_label.setText(translate('SongsPlugin.SongExportForm', 'Your song export failed.')) self.progress_label.setText(translate('SongsPlugin.SongExportForm', 'Your song export failed.'))
except OSError as ose: except OSError as ose:
self.progress_label.setText(translate('SongsPlugin.SongExportForm', 'Your song export failed because this ' self.progress_label.setText(translate('SongsPlugin.SongExportForm', 'Your song export failed because this '
'error occurred: %s') % ose.strerror) 'error occurred: {error}').format(error=ose.strerror))
def on_search_line_edit_changed(self, text): def on_search_line_edit_changed(self, text):
""" """

View File

@ -132,6 +132,7 @@ class SongImportForm(OpenLPWizard, RegistryProperties):
Song wizard localisation. Song wizard localisation.
""" """
self.setWindowTitle(translate('SongsPlugin.ImportWizardForm', 'Song Import Wizard')) self.setWindowTitle(translate('SongsPlugin.ImportWizardForm', 'Song Import Wizard'))
# TODO: Verify format() with template variables
self.title_label.setText(WizardStrings.HeaderStyle % translate('OpenLP.Ui', self.title_label.setText(WizardStrings.HeaderStyle % translate('OpenLP.Ui',
'Welcome to the Song Import Wizard')) 'Welcome to the Song Import Wizard'))
self.information_label.setText( self.information_label.setText(
@ -236,7 +237,7 @@ class SongImportForm(OpenLPWizard, RegistryProperties):
""" """
if filters: if filters:
filters += ';;' filters += ';;'
filters += '%s (*)' % UiStrings().AllFiles filters += '{text} (*)'.format(text=UiStrings().AllFiles)
file_names = FileDialog.getOpenFileNames( file_names = FileDialog.getOpenFileNames(
self, title, self, title,
Settings().value(self.plugin.settings_section + '/last directory import'), filters) Settings().value(self.plugin.settings_section + '/last directory import'), filters)
@ -271,9 +272,11 @@ class SongImportForm(OpenLPWizard, RegistryProperties):
select_mode, format_name, ext_filter = SongFormat.get(this_format, 'selectMode', 'name', 'filter') select_mode, format_name, ext_filter = SongFormat.get(this_format, 'selectMode', 'name', 'filter')
file_path_edit = self.format_widgets[this_format]['file_path_edit'] file_path_edit = self.format_widgets[this_format]['file_path_edit']
if select_mode == SongFormatSelect.SingleFile: if select_mode == SongFormatSelect.SingleFile:
# TODO: Verify format() with template variables
self.get_file_name( self.get_file_name(
WizardStrings.OpenTypeFile % format_name, file_path_edit, 'last directory import', ext_filter) WizardStrings.OpenTypeFile % format_name, file_path_edit, 'last directory import', ext_filter)
elif select_mode == SongFormatSelect.SingleFolder: elif select_mode == SongFormatSelect.SingleFolder:
# TODO: Verify format() with template variables
self.get_folder(WizardStrings.OpenTypeFolder % format_name, file_path_edit, 'last directory import') self.get_folder(WizardStrings.OpenTypeFolder % format_name, file_path_edit, 'last directory import')
def on_add_button_clicked(self): def on_add_button_clicked(self):
@ -283,6 +286,7 @@ class SongImportForm(OpenLPWizard, RegistryProperties):
this_format = self.current_format this_format = self.current_format
select_mode, format_name, ext_filter, custom_title = \ select_mode, format_name, ext_filter, custom_title = \
SongFormat.get(this_format, 'selectMode', 'name', 'filter', 'getFilesTitle') SongFormat.get(this_format, 'selectMode', 'name', 'filter', 'getFilesTitle')
# TODO: Verify format() with template variables
title = custom_title if custom_title else WizardStrings.OpenTypeFile % format_name title = custom_title if custom_title else WizardStrings.OpenTypeFile % format_name
if select_mode == SongFormatSelect.MultipleFiles: if select_mode == SongFormatSelect.MultipleFiles:
self.get_files(title, self.format_widgets[this_format]['file_list_widget'], ext_filter) self.get_files(title, self.format_widgets[this_format]['file_list_widget'], ext_filter)

View File

@ -164,7 +164,8 @@ class SongMaintenanceForm(QtWidgets.QDialog, Ui_SongMaintenanceDialog, RegistryP
books = self.manager.get_all_objects(Book) books = self.manager.get_all_objects(Book)
books.sort(key=get_book_key) books.sort(key=get_book_key)
for book in books: for book in books:
book_name = QtWidgets.QListWidgetItem('%s (%s)' % (book.name, book.publisher)) book_name = QtWidgets.QListWidgetItem('{name} ({publisher})'.format(name=book.name,
publisher=book.publisher))
book_name.setData(QtCore.Qt.UserRole, book.id) book_name.setData(QtCore.Qt.UserRole, book.id)
self.song_books_list_widget.addItem(book_name) self.song_books_list_widget.addItem(book_name)
@ -310,11 +311,12 @@ class SongMaintenanceForm(QtWidgets.QDialog, Ui_SongMaintenanceDialog, RegistryP
else: else:
critical_error_message_box( critical_error_message_box(
message=translate('SongsPlugin.SongMaintenanceForm', 'Could not save your changes.')) message=translate('SongsPlugin.SongMaintenanceForm', 'Could not save your changes.'))
elif critical_error_message_box(message=translate( elif critical_error_message_box(
'SongsPlugin.SongMaintenanceForm', 'The author %s already exists. Would you like to make songs with ' message=translate(
'author %s use the existing author %s?') % 'SongsPlugin.SongMaintenanceForm',
(author.display_name, temp_display_name, author.display_name), parent=self, question=True) == \ 'The author {original} already exists. Would you like to make songs with author {new} use the '
QtWidgets.QMessageBox.Yes: 'existing author {original}?').format(original=author.display_name, new=temp_display_name),
parent=self, question=True) == QtWidgets.QMessageBox.Yes:
self._merge_objects(author, self.merge_authors, self.reset_authors) self._merge_objects(author, self.merge_authors, self.reset_authors)
else: else:
# We restore the author's old first and last name as well as # We restore the author's old first and last name as well as
@ -346,9 +348,10 @@ class SongMaintenanceForm(QtWidgets.QDialog, Ui_SongMaintenanceDialog, RegistryP
critical_error_message_box( critical_error_message_box(
message=translate('SongsPlugin.SongMaintenanceForm', 'Could not save your changes.')) message=translate('SongsPlugin.SongMaintenanceForm', 'Could not save your changes.'))
elif critical_error_message_box( elif critical_error_message_box(
message=translate('SongsPlugin.SongMaintenanceForm', message=translate('SongsPlugin.SongMaintenanceForm',
'The topic %s already exists. Would you like to make songs with topic %s use the ' 'The topic {original} already exists. Would you like to make songs with '
'existing topic %s?') % (topic.name, temp_name, topic.name), 'topic {new} use the existing topic {original}?').format(original=topic.name,
new=temp_name),
parent=self, question=True) == QtWidgets.QMessageBox.Yes: parent=self, question=True) == QtWidgets.QMessageBox.Yes:
self._merge_objects(topic, self.merge_topics, self.reset_topics) self._merge_objects(topic, self.merge_topics, self.reset_topics)
else: else:
@ -384,9 +387,10 @@ class SongMaintenanceForm(QtWidgets.QDialog, Ui_SongMaintenanceDialog, RegistryP
critical_error_message_box( critical_error_message_box(
message=translate('SongsPlugin.SongMaintenanceForm', 'Could not save your changes.')) message=translate('SongsPlugin.SongMaintenanceForm', 'Could not save your changes.'))
elif critical_error_message_box( elif critical_error_message_box(
message=translate('SongsPlugin.SongMaintenanceForm', message=translate('SongsPlugin.SongMaintenanceForm',
'The book %s already exists. Would you like to make ' 'The book {original} already exists. Would you like to make songs with '
'songs with book %s use the existing book %s?') % (book.name, temp_name, book.name), 'book {new} use the existing book {original}?').format(original=book.name,
new=temp_name),
parent=self, question=True) == QtWidgets.QMessageBox.Yes: parent=self, question=True) == QtWidgets.QMessageBox.Yes:
self._merge_objects(book, self.merge_song_books, self.reset_song_books) self._merge_objects(book, self.merge_song_books, self.reset_song_books)
else: else:

View File

@ -242,7 +242,8 @@ class Ui_SongSelectDialog(object):
self.search_label.setText(translate('SongsPlugin.SongSelectForm', 'Search Text:')) self.search_label.setText(translate('SongsPlugin.SongSelectForm', 'Search Text:'))
self.search_button.setText(translate('SongsPlugin.SongSelectForm', 'Search')) self.search_button.setText(translate('SongsPlugin.SongSelectForm', 'Search'))
self.stop_button.setText(translate('SongsPlugin.SongSelectForm', 'Stop')) self.stop_button.setText(translate('SongsPlugin.SongSelectForm', 'Stop'))
self.result_count_label.setText(translate('SongsPlugin.SongSelectForm', 'Found %s song(s)') % 0) self.result_count_label.setText(translate('SongsPlugin.SongSelectForm',
'Found {count:d} song(s)').format(count=0))
self.logout_button.setText(translate('SongsPlugin.SongSelectForm', 'Logout')) self.logout_button.setText(translate('SongsPlugin.SongSelectForm', 'Logout'))
self.view_button.setText(translate('SongsPlugin.SongSelectForm', 'View')) self.view_button.setText(translate('SongsPlugin.SongSelectForm', 'View'))
self.title_label.setText(translate('SongsPlugin.SongSelectForm', 'Title:')) self.title_label.setText(translate('SongsPlugin.SongSelectForm', 'Title:'))

View File

@ -305,7 +305,8 @@ class SongSelectForm(QtWidgets.QDialog, Ui_SongSelectDialog):
self.search_progress_bar.setValue(0) self.search_progress_bar.setValue(0)
self.set_progress_visible(True) self.set_progress_visible(True)
self.search_results_widget.clear() self.search_results_widget.clear()
self.result_count_label.setText(translate('SongsPlugin.SongSelectForm', 'Found %s song(s)') % self.song_count) self.result_count_label.setText(translate('SongsPlugin.SongSelectForm',
'Found {count:d} song(s)').format(count=self.song_count))
self.application.process_events() self.application.process_events()
self.song_count = 0 self.song_count = 0
search_history = self.search_combobox.getItems() search_history = self.search_combobox.getItems()
@ -343,7 +344,8 @@ class SongSelectForm(QtWidgets.QDialog, Ui_SongSelectDialog):
:param song: :param song:
""" """
self.song_count += 1 self.song_count += 1
self.result_count_label.setText(translate('SongsPlugin.SongSelectForm', 'Found %s song(s)') % self.song_count) self.result_count_label.setText(translate('SongsPlugin.SongSelectForm',
'Found {count:d} song(s)').format(count=self.song_count))
item_title = song['title'] + ' (' + ', '.join(song['authors']) + ')' item_title = song['title'] + ' (' + ', '.join(song['authors']) + ')'
song_item = QtWidgets.QListWidgetItem(item_title, self.search_results_widget) song_item = QtWidgets.QListWidgetItem(item_title, self.search_results_widget)
song_item.setData(QtCore.Qt.UserRole, song) song_item.setData(QtCore.Qt.UserRole, song)

Some files were not shown because too many files have changed in this diff Show More