This commit is contained in:
Tim Bentley 2013-10-23 20:26:03 +01:00
commit 63d65da6c1
7 changed files with 751 additions and 156 deletions

View File

@ -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|&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" 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 @@ sup {
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 @@ sup {
*/
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|&nbsp;)+(?![^<]*>)/g,
function(match) {
@ -150,8 +506,6 @@ sup {
}
}
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 @@ sup {
<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 @@ def build_html(item, screen, is_live, background, image=None, plugins=None):
"""
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 @@ def build_html(item, screen, is_live, background, image=None, plugins=None):
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 @@ def build_background_css(item, width):
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 @@ def build_lyrics_css(item, webkit_ver):
%s
}
.lyricsmain {
%s
%s
}
.lyricsoutline {
%s
}
.lyricsshadow {
%s
}
"""
theme = item.themedata
"""
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 ''
return ''
def build_lyrics_format_css(theme, width, height):
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 @@ def build_lyrics_format_css(theme, width, height):
``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 @@ def build_lyrics_format_css(theme, width, height):
'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

View File

@ -243,8 +243,6 @@ class MainDisplay(Display):
# 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):
"""

View File

@ -46,36 +46,22 @@ from openlp.core.ui.media.mediaplayer import MediaPlayer
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;
'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']
}
#video1 {
background-color: %(bgcolor)s;
z-index:4;
}
#video2 {
background-color: %(bgcolor)s;
z-index:4;
}
"""
class PhononPlayer(MediaPlayer):
@ -269,8 +255,7 @@ class PhononPlayer(MediaPlayer):
"""
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):
"""

View File

@ -30,9 +30,9 @@
Package to test the openlp.core.lib.settings package.
"""
import os
from unittest import TestCase
from tempfile import mkstemp
from unittest import TestCase
from PyQt4 import QtGui
from openlp.core.common import Settings

View File

@ -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
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|&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" 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 == 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.'

View File

@ -30,8 +30,8 @@
Package to test the openlp.core.ui package.
"""
import os
from unittest import TestCase
from unittest import TestCase
from PyQt4 import QtGui
from openlp.core.lib import Registry, ImageManager, ScreenList

View File

@ -32,10 +32,13 @@ Package to test the openlp.core.lib package.
import os
from unittest import TestCase
from openlp.core.lib import ItemCapabilities, ServiceItem, Registry
from tests.functional import MagicMock, patch
from tests.utils import assert_length, convert_file_service_item
from openlp.core.lib import ItemCapabilities, ServiceItem, Registry
VERSE = 'The Lord said to {r}Noah{/r}: \n'\
'There\'s gonna be a {su}floody{/su}, {sb}floody{/sb}\n'\
'The Lord said to {g}Noah{/g}:\n'\