openlp-core team mailing list archive
-
openlp-core team
-
Mailing list archive
-
Message #21732
[Merge] lp:~googol/openlp/html-clean-up into lp:openlp
Andreas Preikschat has proposed merging lp:~googol/openlp/html-clean-up into lp:openlp.
Requested reviews:
Tim Bentley (trb143)
For more details, see:
https://code.launchpad.net/~googol/openlp/html-clean-up/+merge/185062
Hello,
I started this sammmmme time ago and just found it...
- removed (outline/shaddow) workarounds from html builder
OS.......Version
----------------
Fedora...537.21
MAC......534.34
Arch.....537.21
Windows..534.34
The workaround were for 534.3 and below, so all major platforms should be ok with this change.
--
https://code.launchpad.net/~googol/openlp/html-clean-up/+merge/185062
Your team OpenLP Core is subscribed to branch lp:openlp.
=== modified file 'openlp/core/lib/htmlbuilder.py'
--- openlp/core/lib/htmlbuilder.py 2013-08-31 18:17:38 +0000
+++ openlp/core/lib/htmlbuilder.py 2013-09-11 14:24:14 +0000
@@ -26,7 +26,372 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
-
+"""
+This module is responsible for generating the HTML for :class:`~openlp.core.ui.maindisplay`. The ``build_html`` function
+is the function which has to be called from outside. The generated and returned HTML will look similar to this::
+
+ <!DOCTYPE html>
+ <html>
+ <head>
+ <title>OpenLP Display</title>
+ <style>
+ *{
+ margin: 0;
+ padding: 0;
+ border: 0;
+ overflow: hidden;
+ -webkit-user-select: none;
+ }
+ body {
+ background-color: #000000;
+ }
+ .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;
+ }
+
+ #videobackboard {
+ z-index:3;
+ background-color: #000000;
+ }
+ #video {
+ background-color: #000000;
+ z-index:4;
+ }
+
+ #flash {
+ z-index:5;
+ }
+
+ #alert {
+ position: absolute;
+ left: 0px;
+ top: 0px;
+ z-index: 10;
+ width: 100%;
+ vertical-align: bottom;
+ font-family: DejaVu Sans;
+ font-size: 40pt;
+ color: #ffffff;
+ background-color: #660000;
+ word-wrap: break-word;
+ }
+
+ #footer {
+ position: absolute;
+ z-index: 6;
+
+ left: 10px;
+ bottom: 0px;
+ width: 1580px;
+ font-family: Nimbus Sans L;
+ font-size: 12pt;
+ color: #FFFFFF;
+ text-align: left;
+ white-space: nowrap;
+
+ }
+ /* lyric css */
+
+ .lyricstable {
+ z-index: 5;
+ position: absolute;
+ display: table;
+ left: 10px; top: 0px;
+ }
+ .lyricscell {
+ display: table-cell;
+ word-wrap: break-word;
+ -webkit-transition: opacity 0.4s ease;
+ white-space:pre-wrap; word-wrap: break-word; text-align: left; vertical-align: top; font-family: Nimbus Sans L; font-size: 40pt; color: #FFFFFF; line-height: 100%; margin: 0;padding: 0; padding-bottom: 0; padding-left: 4px; width: 1580px; height: 810px;
+ }
+ .lyricsmain {
+ -webkit-text-stroke: 0.125em #000000; -webkit-text-fill-color: #FFFFFF; text-shadow: #000000 5px 5px;
+ }
+
+ sup {
+ font-size: 0.6em;
+ vertical-align: top;
+ position: relative;
+ top: -0.3em;
+ }
+ </style>
+ <script>
+ var timer = null;
+ var transition = false;
+
+ function show_video(state, path, volume, loop, variable_value){
+ // Sometimes video.currentTime stops slightly short of video.duration and video.ended is intermittent!
+
+ var video = document.getElementById('video');
+ if(volume != null){
+ video.volume = volume;
+ }
+ switch(state){
+ case 'load':
+ video.src = 'file:///' + path;
+ if(loop == true) {
+ video.loop = true;
+ }
+ video.load();
+ break;
+ case 'play':
+ video.play();
+ break;
+ case 'pause':
+ video.pause();
+ break;
+ case 'stop':
+ show_video('pause');
+ video.currentTime = 0;
+ break;
+ case 'close':
+ show_video('stop');
+ video.src = '';
+ break;
+ case 'length':
+ return video.duration;
+ case 'current_time':
+ return video.currentTime;
+ case 'seek':
+ video.currentTime = variable_value;
+ break;
+ case 'isEnded':
+ return video.ended;
+ case 'setVisible':
+ video.style.visibility = variable_value;
+ break;
+ case 'setBackBoard':
+ var back = document.getElementById('videobackboard');
+ back.style.visibility = variable_value;
+ break;
+ }
+ }
+
+ function getFlashMovieObject(movieName)
+ {
+ if (window.document[movieName]){
+ return window.document[movieName];
+ }
+ if (document.embeds && document.embeds[movieName]){
+ return document.embeds[movieName];
+ }
+ }
+
+ function show_flash(state, path, volume, variable_value){
+ var text = document.getElementById('flash');
+ var flashMovie = getFlashMovieObject("OpenLPFlashMovie");
+ var src = "src = 'file:///" + path + "'";
+ var view_parm = " wmode='opaque'" + " width='100%%'" + " height='100%%'";
+ var swf_parm = " name='OpenLPFlashMovie'" + " autostart='true' loop='false' play='true'" +
+ " hidden='false' swliveconnect='true' allowscriptaccess='always'" + " volume='" + volume + "'";
+
+ switch(state){
+ case 'load':
+ text.innerHTML = "<embed " + src + view_parm + swf_parm + "/>";
+ flashMovie = getFlashMovieObject("OpenLPFlashMovie");
+ flashMovie.Play();
+ break;
+ case 'play':
+ flashMovie.Play();
+ break;
+ case 'pause':
+ flashMovie.StopPlay();
+ break;
+ case 'stop':
+ flashMovie.StopPlay();
+ tempHtml = text.innerHTML;
+ text.innerHTML = '';
+ text.innerHTML = tempHtml;
+ break;
+ case 'close':
+ flashMovie.StopPlay();
+ text.innerHTML = '';
+ break;
+ case 'length':
+ return flashMovie.TotalFrames();
+ case 'current_time':
+ return flashMovie.CurrentFrame();
+ case 'seek':
+ // flashMovie.GotoFrame(variable_value);
+ break;
+ case 'isEnded':
+ //TODO check flash end
+ return false;
+ case 'setVisible':
+ text.style.visibility = variable_value;
+ break;
+ }
+ }
+
+ function show_alert(alerttext, position){
+ var text = document.getElementById('alert');
+ text.innerHTML = alerttext;
+ if(alerttext == '') {
+ text.style.visibility = 'hidden';
+ return 0;
+ }
+ if(position == ''){
+ position = getComputedStyle(text, '').verticalAlign;
+ }
+ switch(position)
+ {
+ case 'top':
+ text.style.top = '0px';
+ break;
+ case 'middle':
+ text.style.top = ((window.innerHeight - text.clientHeight) / 2)
+ + 'px';
+ break;
+ case 'bottom':
+ text.style.top = (window.innerHeight - text.clientHeight)
+ + 'px';
+ break;
+ }
+ text.style.visibility = 'visible';
+ return text.clientHeight;
+ }
+
+ function update_css(align, font, size, color, bgcolor){
+ var text = document.getElementById('alert');
+ text.style.fontSize = size + "pt";
+ text.style.fontFamily = font;
+ text.style.color = color;
+ text.style.backgroundColor = bgcolor;
+ switch(align)
+ {
+ case 'top':
+ text.style.top = '0px';
+ break;
+ case 'middle':
+ text.style.top = ((window.innerHeight - text.clientHeight) / 2)
+ + 'px';
+ break;
+ case 'bottom':
+ text.style.top = (window.innerHeight - text.clientHeight)
+ + 'px';
+ break;
+ }
+ }
+
+
+ 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| )+(?![^<]*>)/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" style="display:none;" />
+ <img id="image" class="size" style="display:none;" />
+
+ <div id="videobackboard" class="size" style="visibility:hidden"></div>
+ <video id="video" class="size" style="visibility:hidden" autobuffer preload></video>
+
+ <div id="flash" class="size" style="visibility:hidden"></div>
+
+ <div id="alert" style="visibility:hidden"></div>
+
+ <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>
+"""
import logging
from PyQt4 import QtWebKit
@@ -114,12 +479,6 @@
document.getElementById('black').style.display = black;
document.getElementById('lyricsmain').style.visibility = lyrics;
document.getElementById('image').style.visibility = lyrics;
- outline = document.getElementById('lyricsoutline')
- if(outline != null)
- outline.style.visibility = lyrics;
- shadow = document.getElementById('lyricsshadow')
- if(shadow != null)
- shadow.style.visibility = lyrics;
document.getElementById('footer').style.visibility = lyrics;
}
@@ -138,9 +497,6 @@
*/
var txt = document.getElementById('lyricsmain');
if(window.getComputedStyle(txt).textAlign == 'justify'){
- var outline = document.getElementById('lyricsoutline');
- if(outline != null)
- txt = outline;
if(window.getComputedStyle(txt).webkitTextStrokeWidth != '0px'){
new_text = new_text.replace(/(\s| )+(?![^<]*>)/g,
function(match) {
@@ -150,8 +506,6 @@
}
}
text_fade('lyricsmain', new_text);
- text_fade('lyricsoutline', new_text);
- text_fade('lyricsshadow', new_text.replace(match, ''));
}
function text_fade(id, new_text){
@@ -190,7 +544,7 @@
<img id="bgimage" class="size" %s />
<img id="image" class="size" %s />
%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>
@@ -222,8 +576,7 @@
"""
width = screen['size'].width()
height = screen['size'].height()
- theme = item.themedata
- webkit_ver = webkit_version()
+ theme_data = item.themedata
# Image generated and poked in
if background:
bgimage_src = 'src="data:image/png;base64,%s"' % background
@@ -247,12 +600,12 @@
build_background_css(item, width),
css_additions,
build_footer_css(item, height),
- build_lyrics_css(item, webkit_ver),
- 'true' if theme and theme.display_slide_transition and is_live else 'false',
+ build_lyrics_css(item),
+ 'true' if theme_data and theme_data.display_slide_transition and is_live else 'false',
js_additions,
- bgimage_src, image_src,
- html_additions,
- build_lyrics_html(item, webkit_ver)
+ bgimage_src,
+ image_src,
+ html_additions
)
return html
@@ -303,16 +656,13 @@
return background
-def build_lyrics_css(item, webkit_ver):
+def build_lyrics_css(item):
"""
Build the lyrics display css
``item``
Service Item containing theme and location information
- ``webkitvers``
- The version of qtwebkit we're using
-
"""
style = """
.lyricstable {
@@ -328,81 +678,44 @@
%s
}
.lyricsmain {
-%s
-}
-.lyricsoutline {
-%s
-}
-.lyricsshadow {
-%s
-}
- """
- theme = item.themedata
+ %s
+}
+"""
+ theme_data = item.themedata
lyricstable = ''
lyrics = ''
lyricsmain = ''
- outline = ''
- shadow = ''
- if theme and item.main:
+ if theme_data and item.main:
lyricstable = 'left: %spx; top: %spx;' % (item.main.x(), item.main.y())
- lyrics = build_lyrics_format_css(theme, item.main.width(), item.main.height())
- # For performance reasons we want to show as few DIV's as possible, especially when animating/transitions.
- # However some bugs in older versions of qtwebkit mean we need to perform workarounds and add extra divs. Only
- # do these when needed.
- #
- # Before 533.3 the webkit-text-fill colour wasn't displayed, only the stroke (outline) color. So put stroke
- # layer underneath the main text.
- #
- # Up to 534.3 the webkit-text-stroke was sometimes out of alignment with the fill, or normal text.
- # letter-spacing=1 is workaround https://bugs.webkit.org/show_bug.cgi?id=44403
- #
- # Up to 534.3 the text-shadow didn't get displayed when webkit-text-stroke was used. So use an offset text
- # layer underneath. https://bugs.webkit.org/show_bug.cgi?id=19728
- if webkit_ver >= 533.3:
- lyricsmain += build_lyrics_outline_css(theme)
- else:
- outline = build_lyrics_outline_css(theme)
- if theme.font_main_shadow:
- if theme.font_main_outline and webkit_ver <= 534.3:
- shadow = 'padding-left: %spx; padding-top: %spx;' % \
- (int(theme.font_main_shadow_size) + (int(theme.font_main_outline_size) * 2),
- theme.font_main_shadow_size)
- shadow += build_lyrics_outline_css(theme, True)
- else:
- lyricsmain += ' text-shadow: %s %spx %spx;' % \
- (theme.font_main_shadow_color, theme.font_main_shadow_size, theme.font_main_shadow_size)
- lyrics_css = style % (lyricstable, lyrics, lyricsmain, outline, shadow)
+ lyrics = build_lyrics_format_css(theme_data, item.main.width(), item.main.height())
+ lyricsmain += build_lyrics_outline_css(theme_data)
+ if theme_data.font_main_shadow:
+ lyricsmain += ' text-shadow: %s %spx %spx;' % \
+ (theme_data.font_main_shadow_color, theme_data.font_main_shadow_size, theme_data.font_main_shadow_size)
+ lyrics_css = style % (lyricstable, lyrics, lyricsmain)
return lyrics_css
-def build_lyrics_outline_css(theme, is_shadow=False):
+def build_lyrics_outline_css(theme_data):
"""
Build the css which controls the theme outline. Also used by renderer for splitting verses
- ``theme``
+ ``theme_data``
Object containing theme information
-
- ``is_shadow``
- If true, use the shadow colors instead
"""
- if theme.font_main_outline:
- size = float(theme.font_main_outline_size) / 16
- if is_shadow:
- fill_color = theme.font_main_shadow_color
- outline_color = theme.font_main_shadow_color
- else:
- fill_color = theme.font_main_color
- outline_color = theme.font_main_outline_color
+ if theme_data.font_main_outline:
+ size = float(theme_data.font_main_outline_size) / 16
+ fill_color = theme_data.font_main_color
+ outline_color = theme_data.font_main_outline_color
return ' -webkit-text-stroke: %sem %s; -webkit-text-fill-color: %s; ' % (size, outline_color, fill_color)
- else:
- return ''
-
-
-def build_lyrics_format_css(theme, width, height):
+ return ''
+
+
+def build_lyrics_format_css(theme_data, width, height):
"""
Build the css which controls the theme format. Also used by renderer for splitting verses
- ``theme``
+ ``theme_data``
Object containing theme information
``width``
@@ -411,17 +724,17 @@
``height``
Height of the lyrics block
"""
- align = HorizontalType.Names[theme.display_horizontal_align]
- valign = VerticalType.Names[theme.display_vertical_align]
- if theme.font_main_outline:
- left_margin = int(theme.font_main_outline_size) * 2
+ align = HorizontalType.Names[theme_data.display_horizontal_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
else:
left_margin = 0
justify = 'white-space:pre-wrap;'
# fix tag incompatibilities
- if theme.display_horizontal_align == HorizontalType.Justify:
+ if theme_data.display_horizontal_align == HorizontalType.Justify:
justify = ''
- if theme.display_vertical_align == VerticalType.Bottom:
+ if theme_data.display_vertical_align == VerticalType.Bottom:
padding_bottom = '0.5em'
else:
padding_bottom = '0'
@@ -429,41 +742,13 @@
'text-align: %s; vertical-align: %s; font-family: %s; ' \
'font-size: %spt; color: %s; line-height: %d%%; margin: 0;' \
'padding: 0; padding-bottom: %s; padding-left: %spx; width: %spx; height: %spx; ' % \
- (justify, align, valign, theme.font_main_name, theme.font_main_size,
- theme.font_main_color, 100 + int(theme.font_main_line_adjustment), padding_bottom, left_margin, width, height)
- if theme.font_main_outline:
- if webkit_version() <= 534.3:
- lyrics += ' letter-spacing: 1px;'
- if theme.font_main_italics:
- lyrics += ' font-style:italic; '
- if theme.font_main_bold:
- lyrics += ' font-weight:bold; '
- return lyrics
-
-
-def build_lyrics_html(item, webkitvers):
- """
- Build the HTML required to show the lyrics
-
- ``item``
- Service Item containing theme and location information
-
- ``webkitvers``
- The version of qtwebkit we're using
- """
- # Bugs in some versions of QtWebKit mean we sometimes need additional divs for outline and shadow, since the CSS
- # doesn't work. To support vertical alignment middle and bottom, nested div's using display:table/display:table-cell
- # are required for each lyric block.
- lyrics = ''
- theme = item.themedata
- if webkitvers <= 534.3 and theme and theme.font_main_outline:
- lyrics += '<div class="lyricstable"><div id="lyricsshadow" style="opacity:1" ' \
- 'class="lyricscell lyricsshadow"></div></div>'
- if webkitvers < 533.3:
- lyrics += '<div class="lyricstable"><div id="lyricsoutline" style="opacity:1" ' \
- 'class="lyricscell lyricsoutline"></div></div>'
- lyrics += '<div class="lyricstable"><div id="lyricsmain" style="opacity:1" ' \
- 'class="lyricscell lyricsmain"></div></div>'
+ (justify, align, valign, theme_data.font_main_name, theme_data.font_main_size,
+ theme_data.font_main_color, 100 + int(theme_data.font_main_line_adjustment), padding_bottom,
+ left_margin, width, height)
+ if theme_data.font_main_italics:
+ lyrics += 'font-style:italic; '
+ if theme_data.font_main_bold:
+ lyrics += 'font-weight:bold; '
return lyrics
=== modified file 'openlp/core/ui/maindisplay.py'
--- openlp/core/ui/maindisplay.py 2013-08-31 18:17:38 +0000
+++ openlp/core/ui/maindisplay.py 2013-09-11 14:24:14 +0000
@@ -243,8 +243,6 @@
# Windows if there are many items in the service to re-render.
# Setting the div elements direct seems to solve the issue
self.frame.findFirstElement("#lyricsmain").setInnerXml(slide)
- self.frame.findFirstElement("#lyricsoutline").setInnerXml(slide)
- self.frame.findFirstElement("#lyricsshadow").setInnerXml(slide)
def alert(self, text, location):
"""
=== modified file 'openlp/core/ui/media/phononplayer.py'
--- openlp/core/ui/media/phononplayer.py 2013-08-31 18:17:38 +0000
+++ openlp/core/ui/media/phononplayer.py 2013-09-11 14:24:14 +0000
@@ -45,36 +45,22 @@
log = logging.getLogger(__name__)
ADDITIONAL_EXT = {
- 'audio/ac3': ['.ac3'],
- 'audio/flac': ['.flac'],
- 'audio/x-m4a': ['.m4a'],
- 'audio/midi': ['.mid', '.midi'],
- 'audio/x-mp3': ['.mp3'],
- 'audio/mpeg': ['.mp3', '.mp2', '.mpga', '.mpega', '.m4a'],
- 'audio/qcelp': ['.qcp'],
- 'audio/x-wma': ['.wma'],
- 'audio/x-ms-wma': ['.wma'],
- 'video/x-flv': ['.flv'],
- 'video/x-matroska': ['.mpv', '.mkv'],
- 'video/x-wmv': ['.wmv'],
- 'video/x-mpg': ['.mpg'],
- 'video/mpeg': ['.mp4', '.mts', '.mov'],
- 'video/x-ms-wmv': ['.wmv']}
-
-VIDEO_CSS = """
-#videobackboard {
- z-index:3;
- background-color: %(bgcolor)s;
-}
-#video1 {
- background-color: %(bgcolor)s;
- z-index:4;
-}
-#video2 {
- background-color: %(bgcolor)s;
- z-index:4;
-}
-"""
+ 'audio/ac3': ['.ac3'],
+ 'audio/flac': ['.flac'],
+ 'audio/x-m4a': ['.m4a'],
+ 'audio/midi': ['.mid', '.midi'],
+ 'audio/x-mp3': ['.mp3'],
+ 'audio/mpeg': ['.mp3', '.mp2', '.mpga', '.mpega', '.m4a'],
+ 'audio/qcelp': ['.qcp'],
+ 'audio/x-wma': ['.wma'],
+ 'audio/x-ms-wma': ['.wma'],
+ 'video/x-flv': ['.flv'],
+ 'video/x-matroska': ['.mpv', '.mkv'],
+ 'video/x-wmv': ['.wmv'],
+ 'video/x-mpg': ['.mpg'],
+ 'video/mpeg': ['.mp4', '.mts', '.mov'],
+ 'video/x-ms-wmv': ['.wmv']
+}
class PhononPlayer(MediaPlayer):
@@ -268,8 +254,7 @@
"""
Add css style sheets to htmlbuilder
"""
- background = QtGui.QColor(Settings().value('players/background color')).name()
- return VIDEO_CSS % {'bgcolor': background}
+ return ''
def get_info(self):
"""
=== added file 'tests/functional/openlp_core_lib/test_htmlbuilder.py'
--- tests/functional/openlp_core_lib/test_htmlbuilder.py 1970-01-01 00:00:00 +0000
+++ tests/functional/openlp_core_lib/test_htmlbuilder.py 2013-09-11 14:24:14 +0000
@@ -0,0 +1,324 @@
+"""
+Package to test the openlp.core.lib.htmlbuilder module.
+"""
+
+from unittest import TestCase
+from mock import MagicMock, patch
+
+from PyQt4 import QtCore
+
+from openlp.core.lib.htmlbuilder import build_html, build_background_css, build_lyrics_css, build_lyrics_outline_css, \
+ build_lyrics_format_css, build_footer_css
+from openlp.core.lib.theme import HorizontalType, VerticalType
+
+
+BUILD_HTML = """
+<!DOCTYPE html>
+<html>
+<head>
+<title>OpenLP Display</title>
+<style>
+*{
+ margin: 0;
+ padding: 0;
+ border: 0;
+ overflow: hidden;
+ -webkit-user-select: none;
+}
+body {
+ ;
+}
+.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;
+}
+plugin CSS
+#footer {
+ position: absolute;
+ z-index: 6;
+ dummy: dummy;
+}
+/* lyric css */
+
+sup {
+ font-size: 0.6em;
+ vertical-align: top;
+ position: relative;
+ top: -0.3em;
+}
+</style>
+<script>
+ var timer = null;
+ var transition = false;
+ plugin JS
+
+ 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| )+(?![^<]*>)/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" style="display:none;" />
+<img id="image" class="size" style="display:none;" />
+plugin HTML
+<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>
+"""
+BACKGROUND_CSS_RADIAL = 'background: -webkit-gradient(radial, 5 50%, 100, 5 50%, 5, from(#000000), to(#FFFFFF)) fixed'
+LYRICS_CSS = """
+.lyricstable {
+ z-index: 5;
+ position: absolute;
+ display: table;
+ left: 10px; top: 20px;
+}
+.lyricscell {
+ display: table-cell;
+ word-wrap: break-word;
+ -webkit-transition: opacity 0.4s ease;
+ lyrics_format_css
+}
+.lyricsmain {
+ text-shadow: #000000 5px 5px;
+}
+"""
+LYRICS_OUTLINE_CSS = ' -webkit-text-stroke: 0.125em #000000; -webkit-text-fill-color: #FFFFFF; '
+LYRICS_FORMAT_CSS = ' word-wrap: break-word; text-align: justify; vertical-align: bottom; ' + \
+ 'font-family: Arial; font-size: 40pt; color: #FFFFFF; line-height: 108%; margin: 0;padding: 0; ' + \
+ 'padding-bottom: 0.5em; padding-left: 2px; width: 1580px; height: 810px; font-style:italic; font-weight:bold; '
+FOOTER_CSS = """
+ left: 10px;
+ bottom: 0px;
+ width: 1260px;
+ font-family: Arial;
+ font-size: 12pt;
+ color: #FFFFFF;
+ text-align: left;
+ white-space: nowrap;
+ """
+
+
+class Htmbuilder(TestCase):
+ def build_html_test(self):
+ """
+ Test the build_html() function
+ """
+ # GIVEN: Mocked arguments and function.
+ with patch('openlp.core.lib.htmlbuilder.build_background_css') as mocked_build_background_css, \
+ patch('openlp.core.lib.htmlbuilder.build_footer_css') as mocked_build_footer_css, \
+ patch('openlp.core.lib.htmlbuilder.build_lyrics_css') as mocked_build_lyrics_css:
+ # Mocked function.
+ mocked_build_background_css.return_value = ''
+ mocked_build_footer_css.return_value = 'dummy: dummy;'
+ mocked_build_lyrics_css.return_value = ''
+ # Mocked arguments.
+ item = MagicMock()
+ item.bg_image_bytes = None
+ screen = MagicMock()
+ is_live = False
+ background = None
+ plugin = MagicMock()
+ plugin.get_display_css = MagicMock(return_value='plugin CSS')
+ plugin.get_display_javascript = MagicMock(return_value='plugin JS')
+ plugin.get_display_html = MagicMock(return_value='plugin HTML')
+ plugins = [plugin]
+
+ # WHEN: Create the html.
+ html = build_html(item, screen, is_live, background, plugins=plugins)
+
+ # THEN: The returned html should match.
+ assert html == BUILD_HTML
+
+ def build_background_css_radial_test(self):
+ """
+ Test the build_background_css() function with a radial background
+ """
+ # GIVEN: Mocked arguments.
+ item = MagicMock()
+ item.themedata.background_start_color = '#000000'
+ item.themedata.background_end_color = '#FFFFFF'
+ width = 10
+
+ # WHEN: Create the css.
+ css = build_background_css(item, width)
+
+ # THEN: The returned css should match.
+ assert BACKGROUND_CSS_RADIAL == css, 'The background css should be equal.'
+
+ def build_lyrics_css_test(self):
+ """
+ Test the build_lyrics_css() function
+ """
+ # GIVEN: Mocked method and arguments.
+ with patch('openlp.core.lib.htmlbuilder.build_lyrics_format_css') as mocked_build_lyrics_format_css, \
+ patch('openlp.core.lib.htmlbuilder.build_lyrics_outline_css') as mocked_build_lyrics_outline_css:
+ mocked_build_lyrics_format_css.return_value = 'lyrics_format_css'
+ mocked_build_lyrics_outline_css.return_value = ''
+ item = MagicMock()
+ item.main = QtCore.QRect(10, 20, 10, 20)
+ item.themedata.font_main_shadow = True
+ item.themedata.font_main_shadow_color = '#000000'
+ item.themedata.font_main_shadow_size = 5
+
+ # WHEN: Create the css.
+ css = build_lyrics_css(item)
+
+ # THEN: The css should be equal.
+ assert LYRICS_CSS == css, 'The lyrics css should be equal.'
+
+ def build_lyrics_outline_css_test(self):
+ """
+ Test the build_lyrics_outline_css() function
+ """
+ # GIVEN: The mocked theme data.
+ theme_data = MagicMock()
+ theme_data.font_main_outline = True
+ theme_data.font_main_outline_size = 2
+ theme_data.font_main_color = '#FFFFFF'
+ theme_data.font_main_outline_color = '#000000'
+
+ # WHEN: Create the css.
+ css = build_lyrics_outline_css(theme_data)
+
+ # THEN: The css should be equal.
+ assert LYRICS_OUTLINE_CSS == css, 'The outline css should be equal.'
+
+ def build_lyrics_format_css_test(self):
+ """
+ Test the build_lyrics_format_css() function
+ """
+ # GIVEN: Mocked arguments.
+ theme_data = MagicMock()
+ theme_data.display_horizontal_align = HorizontalType.Justify
+ theme_data.display_vertical_align = VerticalType.Bottom
+ theme_data.font_main_name = 'Arial'
+ theme_data.font_main_size = 40
+ theme_data.font_main_color = '#FFFFFF'
+ theme_data.font_main_italics = True
+ theme_data.font_main_bold = True
+ theme_data.font_main_line_adjustment = 8
+ width = 1580
+ height = 810
+
+ # WHEN: Get the css.
+ css = build_lyrics_format_css(theme_data, width, height)
+
+ # THEN: They should be equal.
+ assert LYRICS_FORMAT_CSS == css, 'The lyrics format css should be equal.'
+
+ def build_footer_css_test(self):
+ """
+ Test the build_footer_css() function
+ """
+ # GIVEN: Create a theme.
+ item = MagicMock()
+ item.footer = QtCore.QRect(10, 921, 1260, 103)
+ item.themedata.font_footer_name = 'Arial'
+ item.themedata.font_footer_size = 12
+ item.themedata.font_footer_color = '#FFFFFF'
+ height = 1024
+
+ # WHEN: create the css.
+ css = build_footer_css(item, height)
+
+ # THEN: THE css should be the same.
+ assert FOOTER_CSS == css, 'The footer strings should be equal.'
+
=== modified file 'tests/functional/openlp_core_lib/test_image_manager.py'
--- tests/functional/openlp_core_lib/test_image_manager.py 2013-08-31 18:17:38 +0000
+++ tests/functional/openlp_core_lib/test_image_manager.py 2013-09-11 14:24:14 +0000
@@ -3,8 +3,8 @@
"""
import os
+
from unittest import TestCase
-
from PyQt4 import QtCore, QtGui
from openlp.core.lib import Registry, ImageManager, ScreenList
=== modified file 'tests/functional/openlp_core_lib/test_serviceitem.py'
--- tests/functional/openlp_core_lib/test_serviceitem.py 2013-08-31 18:17:38 +0000
+++ tests/functional/openlp_core_lib/test_serviceitem.py 2013-09-11 14:24:14 +0000
@@ -6,11 +6,12 @@
import os
import json
import tempfile
+
from unittest import TestCase
from mock import MagicMock, patch
+from lxml import objectify, etree
from openlp.core.lib import ItemCapabilities, ServiceItem, Registry
-from lxml import objectify, etree
VERSE = 'The Lord said to {r}Noah{/r}: \n'\
'There\'s gonna be a {su}floody{/su}, {sb}floody{/sb}\n'\
=== modified file 'tests/functional/openlp_core_lib/test_settings.py'
--- tests/functional/openlp_core_lib/test_settings.py 2013-08-31 18:17:38 +0000
+++ tests/functional/openlp_core_lib/test_settings.py 2013-09-11 14:24:14 +0000
@@ -2,13 +2,13 @@
Package to test the openlp.core.lib.settings package.
"""
import os
+from tempfile import mkstemp
+
from unittest import TestCase
-from tempfile import mkstemp
+from PyQt4 import QtGui
from openlp.core.lib import Settings
-from PyQt4 import QtGui
-
class TestSettings(TestCase):
"""
Follow ups