Merge lp:~alisonken1/openlp/strings-templates2 into lp:openlp

Proposed by Ken Roberts
Status: Merged
Approved by: Tim Bentley
Approved revision: 2680
Merged at revision: 2675
Proposed branch: lp:~alisonken1/openlp/strings-templates2
Merge into: lp:openlp
Diff against target: 923 lines (+409/-398)
5 files modified
openlp/core/lib/htmlbuilder.py (+224/-226)
openlp/core/ui/firsttimeform.py (+3/-3)
openlp/plugins/bibles/forms/editbibledialog.py (+1/-1)
openlp/plugins/songs/lib/mediaitem.py (+1/-1)
tests/functional/openlp_core_lib/test_htmlbuilder.py (+180/-167)
To merge this branch: bzr merge lp:~alisonken1/openlp/strings-templates2
Reviewer Review Type Date Requested Status
Tim Bentley Approve
Tomas Groth Approve
Review via email: mp+296870@code.launchpad.net

This proposal supersedes a proposal from 2016-06-08.

Commit message

Convert htmlbuilder.py to use Template() strings for css

Description of the change

Convert htmlbuilder.py to use Template() strings for css

- Changed strings to use Template() instead of format() for css building
- Fix htmlbuilder strings tests
- Cleanup template variables and fix tests to match
- bug 1590386 - string format error in editbibledialog.py
- bug 1590475 - string format error in mediaitem.py
- Function call error in firsttimeform.py (missed label text variable)

--------------------------------
lp:~alisonken1/openlp/strings-templates2 (revision 2679)
[SUCCESS] https://ci.openlp.io/job/Branch-01-Pull/1609/
[SUCCESS] https://ci.openlp.io/job/Branch-02-Functional-Tests/1520/
[SUCCESS] https://ci.openlp.io/job/Branch-03-Interface-Tests/1458/
[SUCCESS] https://ci.openlp.io/job/Branch-04a-Windows_Functional_Tests/1230/
[SUCCESS] https://ci.openlp.io/job/Branch-04b-Windows_Interface_Tests/820/
[SUCCESS] https://ci.openlp.io/job/Branch-05a-Code_Analysis/888/
[SUCCESS] https://ci.openlp.io/job/Branch-05b-Test_Coverage/756/

To post a comment you must log in.
Revision history for this message
Tim Bentley (trb143) wrote : Posted in a previous version of this proposal

Looks good but one comment which is general across all the code.

review: Needs Fixing
Revision history for this message
Ken Roberts (alisonken1) wrote : Posted in a previous version of this proposal

Since this is HTML/css source and not just any text variable I followed the
formatting the original HTML SRC. Has something changed since the original
was put in?
On Jun 6, 2016 9:12 AM, "Tim Bentley" <email address hidden> wrote:

> Review: Needs Fixing
>
> Looks good but one comment which is general across all the code.
>
> Diff comments:
>
> > === modified file 'openlp/core/lib/htmlbuilder.py'
> > --- openlp/core/lib/htmlbuilder.py 2016-05-17 13:21:29 +0000
> > +++ openlp/core/lib/htmlbuilder.py 2016-06-06 15:26:06 +0000
> > @@ -538,15 +538,60 @@
> > </script>
> > </head>
> > <body>
> > -<img id="bgimage" class="size" %s />
> > -<img id="image" class="size" %s />
> > -%s
> > +<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("""
>
> Indent please.
> No real rule about indentation but Lyrics_src looks better!
>
> > +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;
> > +padding: 0;
> > +padding-bottom: ${bottom};
> > +padding-left: ${left}px;
> > +width: ${width}px;
> > +height: ${height}px;${font_style}${font_weight}
> > +""")
> >
> >
> > def build_html(item, screen, is_live, background, image=None,
> plugins=None):
>
>
> --
>
> https://code.launchpad.net/~alisonken1/openlp/strings-templates2/+merge/296567
> You are the owner of lp:~alisonken1/openlp/strings-templates2.
>

Revision history for this message
Tim Bentley (trb143) wrote : Posted in a previous version of this proposal

No it just looks a bit cramped and could do with a visit to a beauty spar😁
On 7 Jun 2016 1:42 a.m., "Ken Roberts" <email address hidden> wrote:

> Since this is HTML/css source and not just any text variable I followed the
> formatting the original HTML SRC. Has something changed since the original
> was put in?
> On Jun 6, 2016 9:12 AM, "Tim Bentley" <email address hidden> wrote:
>
> > Review: Needs Fixing
> >
> > Looks good but one comment which is general across all the code.
> >
> > Diff comments:
> >
> > > === modified file 'openlp/core/lib/htmlbuilder.py'
> > > --- openlp/core/lib/htmlbuilder.py 2016-05-17 13:21:29 +0000
> > > +++ openlp/core/lib/htmlbuilder.py 2016-06-06 15:26:06 +0000
> > > @@ -538,15 +538,60 @@
> > > </script>
> > > </head>
> > > <body>
> > > -<img id="bgimage" class="size" %s />
> > > -<img id="image" class="size" %s />
> > > -%s
> > > +<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("""
> >
> > Indent please.
> > No real rule about indentation but Lyrics_src looks better!
> >
> > > +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;
> > > +padding: 0;
> > > +padding-bottom: ${bottom};
> > > +padding-left: ${left}px;
> > > +width: ${width}px;
> > > +height: ${height}px;${font_style}${font_weight}
> > > +""")
> > >
> > >
> > > def build_html(item, screen, is_live, background, image=None,
> > plugins=None):
> >
> >
> > --
> >
> >
> https://code.launchpad.net/~alisonken1/openlp/strings-templates2/+merge/296567
> > You are the owner of lp:~alisonken1/openlp/strings-templates2.
> >
>
> --
>
> https://code.launchpad.net/~alisonken1/openlp/strings-templates2/+merge/296567
> You are reviewing the proposed merge of
> lp:~alisonken1/openlp/strings-templates2 into lp:openlp.
>

Revision history for this message
Tim Bentley (trb143) : Posted in a previous version of this proposal
review: Approve
2680. By Ken Roberts

String format oops

Revision history for this message
Ken Roberts (alisonken1) wrote :

Ignore last commit (2680) - fixed in strings_template and reverted in this branch

Revision history for this message
Tomas Groth (tomasgroth) wrote :

Looks ok to me

review: Approve
Revision history for this message
Tim Bentley (trb143) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'openlp/core/lib/htmlbuilder.py'
2--- openlp/core/lib/htmlbuilder.py 2016-05-17 13:21:29 +0000
3+++ openlp/core/lib/htmlbuilder.py 2016-06-09 02:57:58 +0000
4@@ -390,163 +390,207 @@
5 import logging
6
7 from PyQt5 import QtWebKit
8+from string import Template
9
10 from openlp.core.common import Settings
11 from openlp.core.lib.theme import BackgroundType, BackgroundGradientType, VerticalType, HorizontalType
12
13 log = logging.getLogger(__name__)
14
15-# TODO: Verify where this is used before converting to python3
16-HTMLSRC = """
17-<!DOCTYPE html>
18-<html>
19-<head>
20-<title>OpenLP Display</title>
21-<style>
22-*{
23+HTML_SRC = Template("""
24+ <!DOCTYPE html>
25+ <html>
26+ <head>
27+ <title>OpenLP Display</title>
28+ <style>
29+ *{
30+ margin: 0;
31+ padding: 0;
32+ border: 0;
33+ overflow: hidden;
34+ -webkit-user-select: none;
35+ }
36+ body {
37+ ${bg_css};
38+ }
39+ .size {
40+ position: absolute;
41+ left: 0px;
42+ top: 0px;
43+ width: 100%;
44+ height: 100%;
45+ }
46+ #black {
47+ z-index: 8;
48+ background-color: black;
49+ display: none;
50+ }
51+ #bgimage {
52+ z-index: 1;
53+ }
54+ #image {
55+ z-index: 2;
56+ }
57+ ${css_additions}
58+ #footer {
59+ position: absolute;
60+ z-index: 6;
61+ ${footer_css}
62+ }
63+ /* lyric css */${lyrics_css}
64+ sup {
65+ font-size: 0.6em;
66+ vertical-align: top;
67+ position: relative;
68+ top: -0.3em;
69+ }
70+ </style>
71+ <script>
72+ var timer = null;
73+ var transition = ${transitions};
74+ ${js_additions}
75+
76+ function show_image(src){
77+ var img = document.getElementById('image');
78+ img.src = src;
79+ if(src == '')
80+ img.style.display = 'none';
81+ else
82+ img.style.display = 'block';
83+ }
84+
85+ function show_blank(state){
86+ var black = 'none';
87+ var lyrics = '';
88+ switch(state){
89+ case 'theme':
90+ lyrics = 'hidden';
91+ break;
92+ case 'black':
93+ black = 'block';
94+ break;
95+ case 'desktop':
96+ break;
97+ }
98+ document.getElementById('black').style.display = black;
99+ document.getElementById('lyricsmain').style.visibility = lyrics;
100+ document.getElementById('image').style.visibility = lyrics;
101+ document.getElementById('footer').style.visibility = lyrics;
102+ }
103+
104+ function show_footer(footertext){
105+ document.getElementById('footer').innerHTML = footertext;
106+ }
107+
108+ function show_text(new_text){
109+ var match = /-webkit-text-fill-color:[^;\"]+/gi;
110+ if(timer != null)
111+ clearTimeout(timer);
112+ /*
113+ QtWebkit bug with outlines and justify causing outline alignment
114+ problems. (Bug 859950) Surround each word with a <span> to workaround,
115+ but only in this scenario.
116+ */
117+ var txt = document.getElementById('lyricsmain');
118+ if(window.getComputedStyle(txt).textAlign == 'justify'){
119+ if(window.getComputedStyle(txt).webkitTextStrokeWidth != '0px'){
120+ new_text = new_text.replace(/(\s|&nbsp;)+(?![^<]*>)/g,
121+ function(match) {
122+ return '</span>' + match + '<span>';
123+ });
124+ new_text = '<span>' + new_text + '</span>';
125+ }
126+ }
127+ text_fade('lyricsmain', new_text);
128+ }
129+
130+ function text_fade(id, new_text){
131+ /*
132+ Show the text.
133+ */
134+ var text = document.getElementById(id);
135+ if(text == null) return;
136+ if(!transition){
137+ text.innerHTML = new_text;
138+ return;
139+ }
140+ // Fade text out. 0.1 to minimize the time "nothing" is shown on the screen.
141+ text.style.opacity = '0.1';
142+ // Fade new text in after the old text has finished fading out.
143+ timer = window.setTimeout(function(){_show_text(text, new_text)}, 400);
144+ }
145+
146+ function _show_text(text, new_text) {
147+ /*
148+ Helper function to show the new_text delayed.
149+ */
150+ text.innerHTML = new_text;
151+ text.style.opacity = '1';
152+ // Wait until the text is completely visible. We want to save the timer id, to be able to call
153+ // clearTimeout(timer) when the text has changed before finishing fading.
154+ timer = window.setTimeout(function(){timer = null;}, 400);
155+ }
156+
157+ function show_text_completed(){
158+ return (timer == null);
159+ }
160+ </script>
161+ </head>
162+ <body>
163+ <img id="bgimage" class="size" ${bg_image} />
164+ <img id="image" class="size" ${image} />
165+ ${html_additions}
166+ <div class="lyricstable"><div id="lyricsmain" style="opacity:1" class="lyricscell lyricsmain"></div></div>
167+ <div id="footer" class="footer"></div>
168+ <div id="black" class="size"></div>
169+ </body>
170+ </html>
171+ """)
172+
173+LYRICS_SRC = Template("""
174+ .lyricstable {
175+ z-index: 5;
176+ position: absolute;
177+ display: table;
178+ ${stable}
179+ }
180+ .lyricscell {
181+ display: table-cell;
182+ word-wrap: break-word;
183+ -webkit-transition: opacity 0.4s ease;
184+ ${lyrics}
185+ }
186+ .lyricsmain {
187+ ${main}
188+ }
189+ """)
190+
191+FOOTER_SRC = Template("""
192+ left: ${left}px;
193+ bottom: ${bottom}px;
194+ width: ${width}px;
195+ font-family: ${family};
196+ font-size: ${size}pt;
197+ color: ${color};
198+ text-align: left;
199+ white-space: ${space};
200+ """)
201+
202+LYRICS_FORMAT_SRC = Template("""
203+ ${justify}word-wrap: break-word;
204+ text-align: ${align};
205+ vertical-align: ${valign};
206+ font-family: ${font};
207+ font-size: ${size}pt;
208+ color: ${color};
209+ line-height: ${line}%;
210 margin: 0;
211 padding: 0;
212- border: 0;
213- overflow: hidden;
214- -webkit-user-select: none;
215-}
216-body {
217- %s;
218-}
219-.size {
220- position: absolute;
221- left: 0px;
222- top: 0px;
223- width: 100%%;
224- height: 100%%;
225-}
226-#black {
227- z-index: 8;
228- background-color: black;
229- display: none;
230-}
231-#bgimage {
232- z-index: 1;
233-}
234-#image {
235- z-index: 2;
236-}
237-%s
238-#footer {
239- position: absolute;
240- z-index: 6;
241- %s
242-}
243-/* lyric css */
244-%s
245-sup {
246- font-size: 0.6em;
247- vertical-align: top;
248- position: relative;
249- top: -0.3em;
250-}
251-</style>
252-<script>
253- var timer = null;
254- var transition = %s;
255- %s
256-
257- function show_image(src){
258- var img = document.getElementById('image');
259- img.src = src;
260- if(src == '')
261- img.style.display = 'none';
262- else
263- img.style.display = 'block';
264- }
265-
266- function show_blank(state){
267- var black = 'none';
268- var lyrics = '';
269- switch(state){
270- case 'theme':
271- lyrics = 'hidden';
272- break;
273- case 'black':
274- black = 'block';
275- break;
276- case 'desktop':
277- break;
278- }
279- document.getElementById('black').style.display = black;
280- document.getElementById('lyricsmain').style.visibility = lyrics;
281- document.getElementById('image').style.visibility = lyrics;
282- document.getElementById('footer').style.visibility = lyrics;
283- }
284-
285- function show_footer(footertext){
286- document.getElementById('footer').innerHTML = footertext;
287- }
288-
289- function show_text(new_text){
290- var match = /-webkit-text-fill-color:[^;\"]+/gi;
291- if(timer != null)
292- clearTimeout(timer);
293- /*
294- QtWebkit bug with outlines and justify causing outline alignment
295- problems. (Bug 859950) Surround each word with a <span> to workaround,
296- but only in this scenario.
297- */
298- var txt = document.getElementById('lyricsmain');
299- if(window.getComputedStyle(txt).textAlign == 'justify'){
300- if(window.getComputedStyle(txt).webkitTextStrokeWidth != '0px'){
301- new_text = new_text.replace(/(\s|&nbsp;)+(?![^<]*>)/g,
302- function(match) {
303- return '</span>' + match + '<span>';
304- });
305- new_text = '<span>' + new_text + '</span>';
306- }
307- }
308- text_fade('lyricsmain', new_text);
309- }
310-
311- function text_fade(id, new_text){
312- /*
313- Show the text.
314- */
315- var text = document.getElementById(id);
316- if(text == null) return;
317- if(!transition){
318- text.innerHTML = new_text;
319- return;
320- }
321- // Fade text out. 0.1 to minimize the time "nothing" is shown on the screen.
322- text.style.opacity = '0.1';
323- // Fade new text in after the old text has finished fading out.
324- timer = window.setTimeout(function(){_show_text(text, new_text)}, 400);
325- }
326-
327- function _show_text(text, new_text) {
328- /*
329- Helper function to show the new_text delayed.
330- */
331- text.innerHTML = new_text;
332- text.style.opacity = '1';
333- // Wait until the text is completely visible. We want to save the timer id, to be able to call
334- // clearTimeout(timer) when the text has changed before finishing fading.
335- timer = window.setTimeout(function(){timer = null;}, 400);
336- }
337-
338- function show_text_completed(){
339- return (timer == null);
340- }
341-</script>
342-</head>
343-<body>
344-<img id="bgimage" class="size" %s />
345-<img id="image" class="size" %s />
346-%s
347-<div class="lyricstable"><div id="lyricsmain" style="opacity:1" class="lyricscell lyricsmain"></div></div>
348-<div id="footer" class="footer"></div>
349-<div id="black" class="size"></div>
350-</body>
351-</html>
352-"""
353+ padding-bottom: ${bottom};
354+ padding-left: ${left}px;
355+ width: ${width}px;
356+ height: ${height}px;${font_style}${font_weight}
357+ """)
358
359
360 def build_html(item, screen, is_live, background, image=None, plugins=None):
361@@ -582,18 +626,17 @@
362 css_additions += plugin.get_display_css()
363 js_additions += plugin.get_display_javascript()
364 html_additions += plugin.get_display_html()
365- html = HTMLSRC % (
366- build_background_css(item, width),
367- css_additions,
368- build_footer_css(item, height),
369- build_lyrics_css(item),
370- 'true' if theme_data and theme_data.display_slide_transition and is_live else 'false',
371- js_additions,
372- bgimage_src,
373- image_src,
374- html_additions
375- )
376- return html
377+ return HTML_SRC.substitute(bg_css=build_background_css(item, width),
378+ css_additions=css_additions,
379+ footer_css=build_footer_css(item, height),
380+ lyrics_css=build_lyrics_css(item),
381+ transitions='true' if (theme_data and
382+ theme_data.display_slide_transition and
383+ is_live) else 'false',
384+ js_additions=js_additions,
385+ bg_image=bgimage_src,
386+ image=image_src,
387+ html_additions=html_additions)
388
389
390 def webkit_version():
391@@ -650,24 +693,6 @@
392
393 :param item: Service Item containing theme and location information
394 """
395- # TODO: Verify this before converting to python3
396- style = """
397-.lyricstable {
398- z-index: 5;
399- position: absolute;
400- display: table;
401- %s
402-}
403-.lyricscell {
404- display: table-cell;
405- word-wrap: break-word;
406- -webkit-transition: opacity 0.4s ease;
407- %s
408-}
409-.lyricsmain {
410- %s
411-}
412-"""
413 theme_data = item.theme_data
414 lyricstable = ''
415 lyrics = ''
416@@ -680,8 +705,7 @@
417 lyricsmain += ' text-shadow: {theme} {shadow}px ' \
418 '{shadow}px;'.format(theme=theme_data.font_main_shadow_color,
419 shadow=theme_data.font_main_shadow_size)
420- lyrics_css = style % (lyricstable, lyrics, lyricsmain)
421- return lyrics_css
422+ return LYRICS_SRC.substitute(stable=lyricstable, lyrics=lyrics, main=lyricsmain)
423
424
425 def build_lyrics_outline_css(theme_data):
426@@ -710,38 +734,23 @@
427 """
428 align = HorizontalType.Names[theme_data.display_horizontal_align]
429 valign = VerticalType.Names[theme_data.display_vertical_align]
430- if theme_data.font_main_outline:
431- left_margin = int(theme_data.font_main_outline_size) * 2
432- else:
433- left_margin = 0
434- justify = 'white-space:pre-wrap;'
435+ left_margin = (int(theme_data.font_main_outline_size) * 2) if theme_data.font_main_outline else 0
436 # fix tag incompatibilities
437- if theme_data.display_horizontal_align == HorizontalType.Justify:
438- justify = ''
439- if theme_data.display_vertical_align == VerticalType.Bottom:
440- padding_bottom = '0.5em'
441- else:
442- padding_bottom = '0'
443- lyrics = '{justify} word-wrap: break-word; ' \
444- 'text-align: {align}; vertical-align: {valign}; font-family: {font}; ' \
445- 'font-size: {size}pt; color: {color}; line-height: {line:d}%; margin: 0;' \
446- 'padding: 0; padding-bottom: {bottom}; padding-left: {left}px; width: {width}px; ' \
447- 'height: {height}px; '.format(justify=justify,
448- align=align,
449- valign=valign,
450- font=theme_data.font_main_name,
451- size=theme_data.font_main_size,
452- color=theme_data.font_main_color,
453- line=100 + int(theme_data.font_main_line_adjustment),
454- bottom=padding_bottom,
455- left=left_margin,
456- width=width,
457- height=height)
458- if theme_data.font_main_italics:
459- lyrics += 'font-style:italic; '
460- if theme_data.font_main_bold:
461- lyrics += 'font-weight:bold; '
462- return lyrics
463+ justify = '' if (theme_data.display_horizontal_align == HorizontalType.Justify) else ' white-space: pre-wrap;\n'
464+ padding_bottom = '0.5em' if (theme_data.display_vertical_align == VerticalType.Bottom) else '0'
465+ return LYRICS_FORMAT_SRC.substitute(justify=justify,
466+ align=align,
467+ valign=valign,
468+ font=theme_data.font_main_name,
469+ size=theme_data.font_main_size,
470+ color=theme_data.font_main_color,
471+ line='{line:d}'.format(line=100 + int(theme_data.font_main_line_adjustment)),
472+ bottom=padding_bottom,
473+ left=left_margin,
474+ width=width,
475+ height=height,
476+ font_style='\n font-style: italic;' if theme_data.font_main_italics else '',
477+ font_weight='\n font-weight: bold;' if theme_data.font_main_bold else '')
478
479
480 def build_footer_css(item, height):
481@@ -751,22 +760,11 @@
482 :param item: Service Item to be processed.
483 :param height:
484 """
485- style = """
486- left: {left}px;
487- bottom: {bottom}px;
488- width: {width}px;
489- font-family: {family};
490- font-size: {size}pt;
491- color: {color};
492- text-align: left;
493- white-space: {space};
494- """
495 theme = item.theme_data
496 if not theme or not item.footer:
497 return ''
498 bottom = height - int(item.footer.y()) - int(item.footer.height())
499 whitespace = 'normal' if Settings().value('themes/wrap footer') else 'nowrap'
500- lyrics_html = style.format(left=item.footer.x(), bottom=bottom, width=item.footer.width(),
501- family=theme.font_footer_name, size=theme.font_footer_size,
502- color=theme.font_footer_color, space=whitespace)
503- return lyrics_html
504+ return FOOTER_SRC.substitute(left=item.footer.x(), bottom=bottom, width=item.footer.width(),
505+ family=theme.font_footer_name, size=theme.font_footer_size,
506+ color=theme.font_footer_color, space=whitespace)
507
508=== modified file 'openlp/core/ui/firsttimeform.py'
509--- openlp/core/ui/firsttimeform.py 2016-05-20 16:22:06 +0000
510+++ openlp/core/ui/firsttimeform.py 2016-06-09 02:57:58 +0000
511@@ -565,13 +565,13 @@
512 if self.has_run_wizard:
513 text = translate('OpenLP.FirstTimeWizard',
514 'Download complete. Click the {button} button to return to OpenLP.'
515- ).format(text=clean_button_text(self.buttonText(QtWidgets.QWizard.FinishButton)))
516+ ).format(button=clean_button_text(self.buttonText(QtWidgets.QWizard.FinishButton)))
517 self.progress_label.setText(text)
518 else:
519 text = translate('OpenLP.FirstTimeWizard',
520 'Download complete. Click the {button} button to start OpenLP.'
521 ).format(button=clean_button_text(self.buttonText(QtWidgets.QWizard.FinishButton)))
522- self.progress_label.setText()
523+ self.progress_label.setText(text)
524 else:
525 if self.has_run_wizard:
526 text = translate('OpenLP.FirstTimeWizard',
527@@ -582,7 +582,7 @@
528 text = translate('OpenLP.FirstTimeWizard',
529 'Click the {button} button to start OpenLP.'
530 ).format(button=clean_button_text(self.buttonText(QtWidgets.QWizard.FinishButton)))
531- self.progress_label.setText()
532+ self.progress_label.setText(text)
533 self.finish_button.setVisible(True)
534 self.finish_button.setEnabled(True)
535 self.cancel_button.setVisible(False)
536
537=== modified file 'openlp/plugins/bibles/forms/editbibledialog.py'
538--- openlp/plugins/bibles/forms/editbibledialog.py 2016-05-21 08:31:24 +0000
539+++ openlp/plugins/bibles/forms/editbibledialog.py 2016-06-09 02:57:58 +0000
540@@ -104,7 +104,7 @@
541 for book in BiblesResourcesDB.get_books():
542 self.book_name_label[book['abbreviation']] = QtWidgets.QLabel(self.book_name_widget)
543 self.book_name_label[book['abbreviation']].setObjectName(
544- 'book_name_label[{name}]'.format(book=book['abbreviation']))
545+ 'book_name_label[{book}]'.format(book=book['abbreviation']))
546 self.book_name_edit[book['abbreviation']] = QtWidgets.QLineEdit(self.book_name_widget)
547 self.book_name_edit[book['abbreviation']].setObjectName(
548 'book_name_edit[{name}]'.format(name=book['abbreviation']))
549
550=== modified file 'openlp/plugins/songs/lib/mediaitem.py'
551--- openlp/plugins/songs/lib/mediaitem.py 2016-05-27 08:13:14 +0000
552+++ openlp/plugins/songs/lib/mediaitem.py 2016-06-09 02:57:58 +0000
553@@ -603,7 +603,7 @@
554 else:
555 verse_index = VerseType.from_tag(verse[0]['type'])
556 verse_tag = VerseType.translated_tags[verse_index]
557- verse_def = '{tag}{label}'.format(tzg=verse_tag, text=verse[0]['label'])
558+ verse_def = '{tag}{text}'.format(tag=verse_tag, text=verse[0]['label'])
559 service_item.add_from_text(verse[1], verse_def)
560 service_item.title = song.title
561 author_list = self.generate_footer(service_item, song)
562
563=== modified file 'tests/functional/openlp_core_lib/test_htmlbuilder.py'
564--- tests/functional/openlp_core_lib/test_htmlbuilder.py 2016-05-31 21:40:13 +0000
565+++ tests/functional/openlp_core_lib/test_htmlbuilder.py 2016-06-09 02:57:58 +0000
566@@ -14,177 +14,190 @@
567 from tests.helpers.testmixin import TestMixin
568
569 HTML = """
570-<!DOCTYPE html>
571-<html>
572-<head>
573-<title>OpenLP Display</title>
574-<style>
575-*{
576- margin: 0;
577- padding: 0;
578- border: 0;
579- overflow: hidden;
580- -webkit-user-select: none;
581-}
582-body {
583- ;
584-}
585-.size {
586- position: absolute;
587- left: 0px;
588- top: 0px;
589- width: 100%;
590- height: 100%;
591-}
592-#black {
593- z-index: 8;
594- background-color: black;
595- display: none;
596-}
597-#bgimage {
598- z-index: 1;
599-}
600-#image {
601- z-index: 2;
602-}
603-plugin CSS
604-#footer {
605- position: absolute;
606- z-index: 6;
607- dummy: dummy;
608-}
609-/* lyric css */
610-
611-sup {
612- font-size: 0.6em;
613- vertical-align: top;
614- position: relative;
615- top: -0.3em;
616-}
617-</style>
618-<script>
619- var timer = null;
620- var transition = false;
621- plugin JS
622-
623- function show_image(src){
624- var img = document.getElementById('image');
625- img.src = src;
626- if(src == '')
627- img.style.display = 'none';
628- else
629- img.style.display = 'block';
630- }
631-
632- function show_blank(state){
633- var black = 'none';
634- var lyrics = '';
635- switch(state){
636- case 'theme':
637- lyrics = 'hidden';
638- break;
639- case 'black':
640- black = 'block';
641- break;
642- case 'desktop':
643- break;
644- }
645- document.getElementById('black').style.display = black;
646- document.getElementById('lyricsmain').style.visibility = lyrics;
647- document.getElementById('image').style.visibility = lyrics;
648- document.getElementById('footer').style.visibility = lyrics;
649- }
650-
651- function show_footer(footertext){
652- document.getElementById('footer').innerHTML = footertext;
653- }
654-
655- function show_text(new_text){
656- var match = /-webkit-text-fill-color:[^;"]+/gi;
657- if(timer != null)
658- clearTimeout(timer);
659- /*
660- QtWebkit bug with outlines and justify causing outline alignment
661- problems. (Bug 859950) Surround each word with a <span> to workaround,
662- but only in this scenario.
663- */
664- var txt = document.getElementById('lyricsmain');
665- if(window.getComputedStyle(txt).textAlign == 'justify'){
666- if(window.getComputedStyle(txt).webkitTextStrokeWidth != '0px'){
667- new_text = new_text.replace(/(\s|&nbsp;)+(?![^<]*>)/g,
668- function(match) {
669- return '</span>' + match + '<span>';
670- });
671- new_text = '<span>' + new_text + '</span>';
672- }
673- }
674- text_fade('lyricsmain', new_text);
675- }
676-
677- function text_fade(id, new_text){
678- /*
679- Show the text.
680- */
681- var text = document.getElementById(id);
682- if(text == null) return;
683- if(!transition){
684+ <!DOCTYPE html>
685+ <html>
686+ <head>
687+ <title>OpenLP Display</title>
688+ <style>
689+ *{
690+ margin: 0;
691+ padding: 0;
692+ border: 0;
693+ overflow: hidden;
694+ -webkit-user-select: none;
695+ }
696+ body {
697+ ;
698+ }
699+ .size {
700+ position: absolute;
701+ left: 0px;
702+ top: 0px;
703+ width: 100%;
704+ height: 100%;
705+ }
706+ #black {
707+ z-index: 8;
708+ background-color: black;
709+ display: none;
710+ }
711+ #bgimage {
712+ z-index: 1;
713+ }
714+ #image {
715+ z-index: 2;
716+ }
717+ plugin CSS
718+ #footer {
719+ position: absolute;
720+ z-index: 6;
721+ dummy: dummy;
722+ }
723+ /* lyric css */
724+ sup {
725+ font-size: 0.6em;
726+ vertical-align: top;
727+ position: relative;
728+ top: -0.3em;
729+ }
730+ </style>
731+ <script>
732+ var timer = null;
733+ var transition = false;
734+ plugin JS
735+
736+ function show_image(src){
737+ var img = document.getElementById('image');
738+ img.src = src;
739+ if(src == '')
740+ img.style.display = 'none';
741+ else
742+ img.style.display = 'block';
743+ }
744+
745+ function show_blank(state){
746+ var black = 'none';
747+ var lyrics = '';
748+ switch(state){
749+ case 'theme':
750+ lyrics = 'hidden';
751+ break;
752+ case 'black':
753+ black = 'block';
754+ break;
755+ case 'desktop':
756+ break;
757+ }
758+ document.getElementById('black').style.display = black;
759+ document.getElementById('lyricsmain').style.visibility = lyrics;
760+ document.getElementById('image').style.visibility = lyrics;
761+ document.getElementById('footer').style.visibility = lyrics;
762+ }
763+
764+ function show_footer(footertext){
765+ document.getElementById('footer').innerHTML = footertext;
766+ }
767+
768+ function show_text(new_text){
769+ var match = /-webkit-text-fill-color:[^;"]+/gi;
770+ if(timer != null)
771+ clearTimeout(timer);
772+ /*
773+ QtWebkit bug with outlines and justify causing outline alignment
774+ problems. (Bug 859950) Surround each word with a <span> to workaround,
775+ but only in this scenario.
776+ */
777+ var txt = document.getElementById('lyricsmain');
778+ if(window.getComputedStyle(txt).textAlign == 'justify'){
779+ if(window.getComputedStyle(txt).webkitTextStrokeWidth != '0px'){
780+ new_text = new_text.replace(/(\s|&nbsp;)+(?![^<]*>)/g,
781+ function(match) {
782+ return '</span>' + match + '<span>';
783+ });
784+ new_text = '<span>' + new_text + '</span>';
785+ }
786+ }
787+ text_fade('lyricsmain', new_text);
788+ }
789+
790+ function text_fade(id, new_text){
791+ /*
792+ Show the text.
793+ */
794+ var text = document.getElementById(id);
795+ if(text == null) return;
796+ if(!transition){
797+ text.innerHTML = new_text;
798+ return;
799+ }
800+ // Fade text out. 0.1 to minimize the time "nothing" is shown on the screen.
801+ text.style.opacity = '0.1';
802+ // Fade new text in after the old text has finished fading out.
803+ timer = window.setTimeout(function(){_show_text(text, new_text)}, 400);
804+ }
805+
806+ function _show_text(text, new_text) {
807+ /*
808+ Helper function to show the new_text delayed.
809+ */
810 text.innerHTML = new_text;
811- return;
812- }
813- // Fade text out. 0.1 to minimize the time "nothing" is shown on the screen.
814- text.style.opacity = '0.1';
815- // Fade new text in after the old text has finished fading out.
816- timer = window.setTimeout(function(){_show_text(text, new_text)}, 400);
817- }
818-
819- function _show_text(text, new_text) {
820- /*
821- Helper function to show the new_text delayed.
822- */
823- text.innerHTML = new_text;
824- text.style.opacity = '1';
825- // Wait until the text is completely visible. We want to save the timer id, to be able to call
826- // clearTimeout(timer) when the text has changed before finishing fading.
827- timer = window.setTimeout(function(){timer = null;}, 400);
828- }
829-
830- function show_text_completed(){
831- return (timer == null);
832- }
833-</script>
834-</head>
835-<body>
836-<img id="bgimage" class="size" style="display:none;" />
837-<img id="image" class="size" style="display:none;" />
838-plugin HTML
839-<div class="lyricstable"><div id="lyricsmain" style="opacity:1" class="lyricscell lyricsmain"></div></div>
840-<div id="footer" class="footer"></div>
841-<div id="black" class="size"></div>
842-</body>
843-</html>
844-"""
845+ text.style.opacity = '1';
846+ // Wait until the text is completely visible. We want to save the timer id, to be able to call
847+ // clearTimeout(timer) when the text has changed before finishing fading.
848+ timer = window.setTimeout(function(){timer = null;}, 400);
849+ }
850+
851+ function show_text_completed(){
852+ return (timer == null);
853+ }
854+ </script>
855+ </head>
856+ <body>
857+ <img id="bgimage" class="size" style="display:none;" />
858+ <img id="image" class="size" style="display:none;" />
859+ plugin HTML
860+ <div class="lyricstable"><div id="lyricsmain" style="opacity:1" class="lyricscell lyricsmain"></div></div>
861+ <div id="footer" class="footer"></div>
862+ <div id="black" class="size"></div>
863+ </body>
864+ </html>
865+ """
866 BACKGROUND_CSS_RADIAL = 'background: -webkit-gradient(radial, 5 50%, 100, 5 50%, 5, from(#000000), to(#FFFFFF)) fixed'
867 LYRICS_CSS = """
868-.lyricstable {
869- z-index: 5;
870- position: absolute;
871- display: table;
872- left: 10px; top: 20px;
873-}
874-.lyricscell {
875- display: table-cell;
876+ .lyricstable {
877+ z-index: 5;
878+ position: absolute;
879+ display: table;
880+ left: 10px; top: 20px;
881+ }
882+ .lyricscell {
883+ display: table-cell;
884+ word-wrap: break-word;
885+ -webkit-transition: opacity 0.4s ease;
886+ lyrics_format_css
887+ }
888+ .lyricsmain {
889+ text-shadow: #000000 5px 5px;
890+ }
891+ """
892+LYRICS_OUTLINE_CSS = ' -webkit-text-stroke: 0.125em #000000; -webkit-text-fill-color: #FFFFFF; '
893+LYRICS_FORMAT_CSS = """
894 word-wrap: break-word;
895- -webkit-transition: opacity 0.4s ease;
896- lyrics_format_css
897-}
898-.lyricsmain {
899- text-shadow: #000000 5px 5px;
900-}
901-"""
902-LYRICS_OUTLINE_CSS = ' -webkit-text-stroke: 0.125em #000000; -webkit-text-fill-color: #FFFFFF; '
903-LYRICS_FORMAT_CSS = ' word-wrap: break-word; text-align: justify; vertical-align: bottom; ' + \
904- 'font-family: Arial; font-size: 40pt; color: #FFFFFF; line-height: 108%; margin: 0;padding: 0; ' + \
905- 'padding-bottom: 0.5em; padding-left: 2px; width: 1580px; height: 810px; font-style:italic; font-weight:bold; '
906+ text-align: justify;
907+ vertical-align: bottom;
908+ font-family: Arial;
909+ font-size: 40pt;
910+ color: #FFFFFF;
911+ line-height: 108%;
912+ margin: 0;
913+ padding: 0;
914+ padding-bottom: 0.5em;
915+ padding-left: 2px;
916+ width: 1580px;
917+ height: 810px;
918+ font-style: italic;
919+ font-weight: bold;
920+ """
921 FOOTER_CSS_BASE = """
922 left: 10px;
923 bottom: 0px;