Even more pep8 fixes and removed the old htmlbuilder.

This commit is contained in:
Tomas Groth 2019-02-13 22:19:24 +01:00
parent 27f37df7e8
commit 5ac8bbc3f2
14 changed files with 8 additions and 1292 deletions

View File

@ -24,7 +24,6 @@ The :mod:`lib` module contains most of the components and libraries that make
OpenLP work. OpenLP work.
""" """
import logging import logging
import re
from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5 import QtCore, QtGui, QtWidgets

View File

@ -1,817 +0,0 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2018 OpenLP Developers #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
r"""
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;
}
/* Chords css */
.chordline {
line-height: 1.0em;
}
.chordline span.chord span {
position: relative;
}
.chordline span.chord span strong {
position: absolute;
top: -0.8em;
left: 0;
font-size: 75%;
font-weight: normal;
line-height: normal;
display: none;
}
.firstchordline {
line-height: 1.0em;
}
</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 string import Template
from PyQt5 import QtWebEngine
from openlp.core.common.settings import Settings
from openlp.core.lib.theme import BackgroundGradientType, BackgroundType, HorizontalType, VerticalType
log = logging.getLogger(__name__)
HTML_SRC = Template(r"""
<!DOCTYPE html>
<html>
<head>
<title>OpenLP Display</title>
<style>
*{
margin: 0;
padding: 0;
border: 0;
overflow: hidden;
-webkit-user-select: none;
}
body {
${bg_css};
}
.size {
position: absolute;
left: 0px;
top: 0px;
width: 100%;
height: 100%;
}
#black {
z-index: 8;
background-color: black;
display: none;
}
#bgimage {
z-index: 1;
}
#image {
z-index: 2;
}
${css_additions}
#footer {
position: absolute;
z-index: 6;
${footer_css}
}
/* lyric css */${lyrics_css}
sup {
font-size: 0.6em;
vertical-align: top;
position: relative;
top: -0.3em;
}
/* Chords css */${chords_css}
</style>
<script>
var timer = null;
var transition = ${transitions};
${js_additions}
function show_image(src){
var img = document.getElementById('image');
img.src = src;
if(src == '')
img.style.display = 'none';
else
img.style.display = 'block';
}
function show_blank(state){
var black = 'none';
var lyrics = '';
switch(state){
case 'theme':
lyrics = 'hidden';
break;
case 'black':
black = 'block';
break;
case 'desktop':
break;
}
document.getElementById('black').style.display = black;
document.getElementById('lyricsmain').style.visibility = lyrics;
document.getElementById('image').style.visibility = lyrics;
document.getElementById('footer').style.visibility = lyrics;
}
function show_footer(footertext){
document.getElementById('footer').innerHTML = footertext;
}
function show_text(new_text){
var match = /-webkit-text-fill-color:[^;\"]+/gi;
if(timer != null)
clearTimeout(timer);
/*
QtWebkit bug with outlines and justify causing outline alignment
problems. (Bug 859950) Surround each word with a <span> to workaround,
but only in this scenario.
*/
var txt = document.getElementById('lyricsmain');
if(window.getComputedStyle(txt).textAlign == 'justify'){
if(window.getComputedStyle(txt).webkitTextStrokeWidth != '0px'){
new_text = new_text.replace(/(\s|&nbsp;)+(?![^<]*>)/g,
function(match) {
return '</span>' + match + '<span>';
});
new_text = '<span>' + new_text + '</span>';
}
}
text_fade('lyricsmain', new_text);
}
function text_fade(id, new_text){
/*
Show the text.
*/
var text = document.getElementById(id);
if(text == null) return;
if(!transition){
text.innerHTML = new_text;
return;
}
// Fade text out. 0.1 to minimize the time "nothing" is shown on the screen.
text.style.opacity = '0.1';
// Fade new text in after the old text has finished fading out.
timer = window.setTimeout(function(){_show_text(text, new_text)}, 400);
}
function _show_text(text, new_text) {
/*
Helper function to show the new_text delayed.
*/
text.innerHTML = new_text;
text.style.opacity = '1';
// Wait until the text is completely visible. We want to save the timer id, to be able to call
// clearTimeout(timer) when the text has changed before finishing fading.
timer = window.setTimeout(function(){timer = null;}, 400);
}
function show_text_completed(){
return (timer == null);
}
</script>
</head>
<body>
<img id="bgimage" class="size" ${bg_image} />
<img id="image" class="size" ${image} />
${html_additions}
<div class="lyricstable"><div id="lyricsmain" style="opacity:1" class="lyricscell lyricsmain"></div></div>
<div id="footer" class="footer"></div>
<div id="black" class="size"></div>
</body>
</html>
""")
LYRICS_SRC = Template("""
.lyricstable {
z-index: 5;
position: absolute;
display: table;
${stable}
}
.lyricscell {
display: table-cell;
word-wrap: break-word;
-webkit-transition: opacity 0.4s ease;
${lyrics}
}
.lyricsmain {
${main}
}
""")
FOOTER_SRC = Template("""
left: ${left}px;
bottom: ${bottom}px;
width: ${width}px;
font-family: ${family};
font-size: ${size}pt;
color: ${color};
text-align: left;
white-space: ${space};
""")
LYRICS_FORMAT_SRC = Template("""
${justify}word-wrap: break-word;
text-align: ${align};
vertical-align: ${valign};
font-family: ${font};
font-size: ${size}pt;
color: ${color};
line-height: ${line}%;
margin: 0;
padding: 0;
padding-bottom: ${bottom};
padding-left: ${left}px;
width: ${width}px;
height: ${height}px;${font_style}${font_weight}
""")
CHORDS_FORMAT = Template("""
.chordline {
line-height: ${chord_line_height};
}
.chordline span.chord span {
position: relative;
}
.chordline span.chord span strong {
position: absolute;
top: -0.8em;
left: 0;
font-size: 75%;
font-weight: normal;
line-height: normal;
display: ${chords_display};
}
.firstchordline {
line-height: ${first_chord_line_height};
}
.ws {
display: ${chords_display};
white-space: pre-wrap;
}""")
def build_html(item, screen, is_live, background, image=None, plugins=None):
"""
Build the full web paged structure for display
:param item: Service Item to be displayed
:param screen: Current display information
:param is_live: Item is going live, rather than preview/theme building
:param background: Theme background image - bytes
:param image: Image media item - bytes
:param plugins: The List of available plugins
"""
width = screen['size'].width()
height = screen['size'].height()
theme_data = item.theme_data
# Image generated and poked in
if background:
bgimage_src = 'src="data:image/png;base64,{image}"'.format(image=background)
elif item.bg_image_bytes:
bgimage_src = 'src="data:image/png;base64,{image}"'.format(image=item.bg_image_bytes)
else:
bgimage_src = 'style="display:none;"'
if image:
image_src = 'src="data:image/png;base64,{image}"'.format(image=image)
else:
image_src = 'style="display:none;"'
css_additions = ''
js_additions = ''
html_additions = ''
if plugins:
for plugin in plugins:
css_additions += plugin.get_display_css()
js_additions += plugin.get_display_javascript()
html_additions += plugin.get_display_html()
return HTML_SRC.substitute(bg_css=build_background_css(item, width),
css_additions=css_additions,
footer_css=build_footer_css(item, height),
lyrics_css=build_lyrics_css(item),
transitions='true' if (theme_data and
theme_data.display_slide_transition and
is_live) else 'false',
js_additions=js_additions,
bg_image=bgimage_src,
image=image_src,
html_additions=html_additions,
chords_css=build_chords_css())
def build_background_css(item, width):
"""
Build the background css
:param item: Service Item containing theme and location information
:param width:
"""
width = int(width) // 2
theme = item.theme_data
background = 'background-color: black'
if theme:
if theme.background_type == BackgroundType.to_string(BackgroundType.Transparent):
background = ''
elif theme.background_type == BackgroundType.to_string(BackgroundType.Solid):
background = 'background-color: {theme}'.format(theme=theme.background_color)
else:
if theme.background_direction == BackgroundGradientType.to_string(BackgroundGradientType.Horizontal):
background = 'background: -webkit-gradient(linear, left top, left bottom, from({start}), to({end})) ' \
'fixed'.format(start=theme.background_start_color, end=theme.background_end_color)
elif theme.background_direction == BackgroundGradientType.to_string(BackgroundGradientType.LeftTop):
background = 'background: -webkit-gradient(linear, left top, right bottom, from({start}), to({end})) ' \
'fixed'.format(start=theme.background_start_color, end=theme.background_end_color)
elif theme.background_direction == BackgroundGradientType.to_string(BackgroundGradientType.LeftBottom):
background = 'background: -webkit-gradient(linear, left bottom, right top, from({start}), to({end})) ' \
'fixed'.format(start=theme.background_start_color, end=theme.background_end_color)
elif theme.background_direction == BackgroundGradientType.to_string(BackgroundGradientType.Vertical):
background = 'background: -webkit-gradient(linear, left top, right top, from({start}), to({end})) ' \
'fixed'.format(start=theme.background_start_color, end=theme.background_end_color)
else:
background = 'background: -webkit-gradient(radial, {width} 50%, 100, {width} 50%, {width}, ' \
'from({start}), to({end})) fixed'.format(width=width,
start=theme.background_start_color,
end=theme.background_end_color)
return background
def build_lyrics_css(item):
"""
Build the lyrics display css
:param item: Service Item containing theme and location information
"""
theme_data = item.theme_data
lyricstable = ''
lyrics = ''
lyricsmain = ''
if theme_data and item.main:
lyricstable = 'left: {left}px; top: {top}px;'.format(left=item.main.x(), top=item.main.y())
lyrics = build_lyrics_format_css(theme_data, item.main.width(), item.main.height())
lyricsmain += build_lyrics_outline_css(theme_data)
if theme_data.font_main_shadow:
lyricsmain += ' text-shadow: {theme} {shadow}px ' \
'{shadow}px;'.format(theme=theme_data.font_main_shadow_color,
shadow=theme_data.font_main_shadow_size)
return LYRICS_SRC.substitute(stable=lyricstable, lyrics=lyrics, main=lyricsmain)
def build_lyrics_outline_css(theme_data):
"""
Build the css which controls the theme outline. Also used by renderer for splitting verses
:param theme_data: Object containing theme information
"""
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: {size}em {color}; -webkit-text-fill-color: {fill}; '.format(size=size,
color=outline_color,
fill=fill_color)
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
:param theme_data: Object containing theme information
:param width: Width of the lyrics block
:param height: Height of the lyrics block
"""
align = HorizontalType.Names[theme_data.display_horizontal_align]
valign = VerticalType.Names[theme_data.display_vertical_align]
left_margin = (int(theme_data.font_main_outline_size) * 2) if theme_data.font_main_outline else 0
# fix tag incompatibilities
justify = '' if (theme_data.display_horizontal_align == HorizontalType.Justify) else ' white-space: pre-wrap;\n'
padding_bottom = '0.5em' if (theme_data.display_vertical_align == VerticalType.Bottom) else '0'
return LYRICS_FORMAT_SRC.substitute(justify=justify,
align=align,
valign=valign,
font=theme_data.font_main_name,
size=theme_data.font_main_size,
color=theme_data.font_main_color,
line='{line:d}'.format(line=100 + int(theme_data.font_main_line_adjustment)),
bottom=padding_bottom,
left=left_margin,
width=width,
height=height,
font_style='\n font-style: italic;' if theme_data.font_main_italics else '',
font_weight='\n font-weight: bold;' if theme_data.font_main_bold else '')
def build_footer_css(item, height):
"""
Build the display of the item footer
:param item: Service Item to be processed.
:param height:
"""
theme = item.theme_data
if not theme or not item.footer:
return ''
bottom = height - int(item.footer.y()) - int(item.footer.height())
whitespace = 'normal' if Settings().value('themes/wrap footer') else 'nowrap'
return FOOTER_SRC.substitute(left=item.footer.x(), bottom=bottom, width=item.footer.width(),
family=theme.font_footer_name, size=theme.font_footer_size,
color=theme.font_footer_color, space=whitespace)
def build_chords_css():
if Settings().value('songs/enable chords') and Settings().value('songs/mainview chords'):
chord_line_height = '2.0em'
chords_display = 'inline'
first_chord_line_height = '2.1em'
else:
chord_line_height = '1.0em'
chords_display = 'none'
first_chord_line_height = '1.0em'
return CHORDS_FORMAT.substitute(chord_line_height=chord_line_height, chords_display=chords_display,
first_chord_line_height=first_chord_line_height)

View File

@ -30,7 +30,7 @@ from lxml import etree, objectify
from openlp.core.common import de_hump from openlp.core.common import de_hump
from openlp.core.common.applocation import AppLocation from openlp.core.common.applocation import AppLocation
from openlp.core.common.json import OpenLPJsonDecoder, OpenLPJsonEncoder from openlp.core.common.json import OpenLPJsonDecoder, OpenLPJsonEncoder
from openlp.core.common.path import Path, str_to_path from openlp.core.common.path import Path
from openlp.core.display.screens import ScreenList from openlp.core.display.screens import ScreenList
from openlp.core.lib import get_text_file_string, str_to_bool from openlp.core.lib import get_text_file_string, str_to_bool

View File

@ -27,7 +27,7 @@ import platform
from PyQt5 import QtCore, QtWidgets from PyQt5 import QtCore, QtWidgets
from openlp.core.common.i18n import UiStrings, translate from openlp.core.common.i18n import UiStrings, translate
from openlp.core.common.registry import Registry # from openlp.core.common.registry import Registry
from openlp.core.common.settings import Settings from openlp.core.common.settings import Settings
from openlp.core.lib.settingstab import SettingsTab from openlp.core.lib.settingstab import SettingsTab
from openlp.core.lib.ui import create_button from openlp.core.lib.ui import create_button

View File

@ -36,7 +36,7 @@ from openlp.core.ui.advancedtab import AdvancedTab
from openlp.core.ui.generaltab import GeneralTab from openlp.core.ui.generaltab import GeneralTab
from openlp.core.ui.screenstab import ScreensTab from openlp.core.ui.screenstab import ScreensTab
from openlp.core.ui.themestab import ThemesTab from openlp.core.ui.themestab import ThemesTab
from openlp.core.ui.media.playertab import PlayerTab # from openlp.core.ui.media.playertab import PlayerTab
from openlp.core.ui.settingsdialog import Ui_SettingsDialog from openlp.core.ui.settingsdialog import Ui_SettingsDialog

View File

@ -295,7 +295,7 @@ class ThemeManager(QtWidgets.QWidget, RegistryBase, Ui_ThemeManager, LogMixin, R
for plugin in self.plugin_manager.plugins: for plugin in self.plugin_manager.plugins:
if plugin.uses_theme(old_theme_name): if plugin.uses_theme(old_theme_name):
plugin.rename_theme(old_theme_name, new_theme_name) plugin.rename_theme(old_theme_name, new_theme_name)
self.renderer.set_theme(self.get_theme_data(new_theme_data)) self.renderer.set_theme(self.get_theme_data(new_theme_name))
self.load_themes() self.load_themes()
def on_copy_theme(self, field=None): def on_copy_theme(self, field=None):

View File

@ -30,10 +30,8 @@ from openlp.core.state import State
from openlp.core.api.http import register_endpoint from openlp.core.api.http import register_endpoint
from openlp.core.common.i18n import translate from openlp.core.common.i18n import translate
from openlp.core.ui.icons import UiIcons from openlp.core.ui.icons import UiIcons
from openlp.core.common.path import Path
from openlp.core.lib import build_icon from openlp.core.lib import build_icon
from openlp.core.lib.plugin import Plugin, StringContent from openlp.core.lib.plugin import Plugin, StringContent
from openlp.core.ui.icons import UiIcons
from openlp.plugins.media.endpoint import api_media_endpoint, media_endpoint from openlp.plugins.media.endpoint import api_media_endpoint, media_endpoint
from openlp.plugins.media.lib.mediaitem import MediaMediaItem from openlp.plugins.media.lib.mediaitem import MediaMediaItem
from openlp.plugins.media.lib.mediatab import MediaTab from openlp.plugins.media.lib.mediatab import MediaTab

View File

@ -27,7 +27,7 @@ import faulthandler
import multiprocessing import multiprocessing
import sys import sys
from OpenGL import GL # from OpenGL import GL
from openlp.core.app import main from openlp.core.app import main
from openlp.core.common import is_macosx, is_win from openlp.core.common import is_macosx, is_win

View File

@ -57,7 +57,7 @@ import webbrowser
from argparse import ArgumentParser from argparse import ArgumentParser
from getpass import getpass from getpass import getpass
from lxml import etree, objectify from lxml import objectify
from PyQt5 import QtCore from PyQt5 import QtCore
SERVER_URL = 'http://www.transifex.com/api/2/project/openlp/resource/openlp-26x/' SERVER_URL = 'http://www.transifex.com/api/2/project/openlp/resource/openlp-26x/'

View File

@ -30,7 +30,6 @@ from openlp.core.state import State
# sys.modules['PyQt5.QtWebEngineWidgets'] = MagicMock() # sys.modules['PyQt5.QtWebEngineWidgets'] = MagicMock()
from openlp.core.api.endpoint.controller import controller_direction, controller_text from openlp.core.api.endpoint.controller import controller_direction, controller_text
from openlp.core.display.render import Renderer
from openlp.core.common.registry import Registry from openlp.core.common.registry import Registry
from openlp.core.display.screens import ScreenList from openlp.core.display.screens import ScreenList
from openlp.core.lib.serviceitem import ServiceItem from openlp.core.lib.serviceitem import ServiceItem

View File

@ -1,461 +0,0 @@
"""
Package to test the openlp.core.lib.htmlbuilder module.
"""
from unittest import TestCase
from unittest.mock import MagicMock, patch
from PyQt5 import QtCore
from openlp.core.common.settings import Settings
from openlp.core.lib.htmlbuilder import build_background_css, build_chords_css, build_footer_css, build_html, \
build_lyrics_css, build_lyrics_format_css, build_lyrics_outline_css
from openlp.core.lib.theme import HorizontalType, VerticalType
from tests.helpers.testmixin import TestMixin
HTML = r"""
<!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;
}
/* Chords css */
.chordline {
line-height: 1.0em;
}
.chordline span.chord span {
position: relative;
}
.chordline span.chord span strong {
position: absolute;
top: -0.8em;
left: 0;
font-size: 75%;
font-weight: normal;
line-height: normal;
display: none;
}
.firstchordline {
line-height: 1.0em;
}
.ws {
display: none;
white-space: pre-wrap;
}
</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_BASE = """
left: 10px;
bottom: 0px;
width: 1260px;
font-family: Arial;
font-size: 12pt;
color: #FFFFFF;
text-align: left;
white-space: %s;
"""
FOOTER_CSS = FOOTER_CSS_BASE % ('nowrap')
FOOTER_CSS_WRAP = FOOTER_CSS_BASE % ('normal')
FOOTER_CSS_INVALID = ''
CHORD_CSS_ENABLED = """
.chordline {
line-height: 2.0em;
}
.chordline span.chord span {
position: relative;
}
.chordline span.chord span strong {
position: absolute;
top: -0.8em;
left: 0;
font-size: 75%;
font-weight: normal;
line-height: normal;
display: inline;
}
.firstchordline {
line-height: 2.1em;
}
.ws {
display: inline;
white-space: pre-wrap;
}"""
__default_settings__ = {
'songs/mainview chords': False,
'songs/enable chords': True
}
class Htmbuilder(TestCase, TestMixin):
"""
Test the functions in the Htmlbuilder module
"""
def setUp(self):
"""
Create the UI
"""
self.build_settings()
Settings().extend_default_settings(__default_settings__)
def tearDown(self):
"""
Delete all the C++ objects at the end so that we don't have a segfault
"""
self.destroy_settings()
def test_build_html(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.return_value = 'plugin CSS'
plugin.get_display_javascript.return_value = 'plugin JS'
plugin.get_display_html.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, 'The returned html should match'
def test_build_background_css_radial(self):
"""
Test the build_background_css() function with a radial background
"""
# GIVEN: Mocked arguments.
item = MagicMock()
item.theme_data.background_start_color = '#000000'
item.theme_data.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 test_build_lyrics_css(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.theme_data.font_main_shadow = True
item.theme_data.font_main_shadow_color = '#000000'
item.theme_data.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 test_build_lyrics_outline_css(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 test_build_lyrics_format_css(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 test_build_footer_css(self):
"""
Test the build_footer_css() function
"""
# GIVEN: Create a theme.
item = MagicMock()
item.footer = QtCore.QRect(10, 921, 1260, 103)
item.theme_data.font_footer_name = 'Arial'
item.theme_data.font_footer_size = 12
item.theme_data.font_footer_color = '#FFFFFF'
height = 1024
# WHEN: create the css with default settings.
css = build_footer_css(item, height)
# THEN: THE css should be the same.
assert FOOTER_CSS == css, 'The footer strings should be equal.'
def test_build_footer_css_wrap(self):
"""
Test the build_footer_css() function
"""
# GIVEN: Create a theme.
item = MagicMock()
item.footer = QtCore.QRect(10, 921, 1260, 103)
item.theme_data.font_footer_name = 'Arial'
item.theme_data.font_footer_size = 12
item.theme_data.font_footer_color = '#FFFFFF'
height = 1024
# WHEN: Settings say that footer should wrap
Settings().setValue('themes/wrap footer', True)
css = build_footer_css(item, height)
# THEN: Footer should wrap
assert FOOTER_CSS_WRAP == css, 'The footer strings should be equal.'
def test_build_footer_invalid(self):
"""
Test the build_footer_css() function
"""
# GIVEN: Create a theme.
css = []
item = MagicMock()
item.theme_data = None
item.footer = 'FAIL'
height = 1024
# WHEN: Settings say that footer should wrap
css.append(build_footer_css(item, height))
item.theme_data = 'TEST'
item.footer = None
css.append(build_footer_css(item, height))
# THEN: Footer should wrap
assert FOOTER_CSS_INVALID == css[0], 'The footer strings should be blank.'
assert FOOTER_CSS_INVALID == css[1], 'The footer strings should be blank.'
def test_build_chords_css(self):
"""
Test the build_chords_css() function
"""
# GIVEN: A setting that activates chords on the mainview
Settings().setValue('songs/enable chords', True)
Settings().setValue('songs/mainview chords', True)
# WHEN: Building the chord CSS
chord_css = build_chords_css()
# THEN: The build css should look as expected
assert CHORD_CSS_ENABLED == chord_css, 'The chord CSS should look as expected'

View File

@ -30,7 +30,6 @@ from PyQt5 import QtCore, QtGui
from openlp.core.common.path import Path from openlp.core.common.path import Path
from openlp.core.lib import build_icon, check_item_selected, create_separated_list, create_thumb, \ from openlp.core.lib import build_icon, check_item_selected, create_separated_list, create_thumb, \
get_text_file_string, image_to_byte, resize_image, str_to_bool, validate_thumb get_text_file_string, image_to_byte, resize_image, str_to_bool, validate_thumb
from openlp.core.lib.formattingtags import FormattingTags
from tests.utils.constants import RESOURCE_PATH from tests.utils.constants import RESOURCE_PATH

View File

@ -27,13 +27,12 @@ from pathlib import Path
from unittest import TestCase from unittest import TestCase
from unittest.mock import MagicMock, patch from unittest.mock import MagicMock, patch
from PyQt5 import QtGui, QtCore, QtWidgets from PyQt5 import QtCore, QtWidgets
from openlp.core.state import State from openlp.core.state import State
from openlp.core.common.i18n import UiStrings from openlp.core.common.i18n import UiStrings
from openlp.core.common.registry import Registry from openlp.core.common.registry import Registry
from openlp.core.display.screens import ScreenList from openlp.core.display.screens import ScreenList
from openlp.core.lib.plugin import PluginStatus
from openlp.core.ui.mainwindow import MainWindow from openlp.core.ui.mainwindow import MainWindow
from tests.helpers.testmixin import TestMixin from tests.helpers.testmixin import TestMixin
from tests.utils.constants import TEST_RESOURCES_PATH from tests.utils.constants import TEST_RESOURCES_PATH

View File

@ -30,7 +30,7 @@ from unittest.mock import MagicMock, call, patch
from PyQt5 import QtGui from PyQt5 import QtGui
from openlp.core.common.i18n import UiStrings from openlp.core.common.i18n import UiStrings
from openlp.core.lib import ImageSource # from openlp.core.lib import ImageSource
from openlp.core.widgets.views import ListPreviewWidget, ListWidgetWithDnD, TreeWidgetWithDnD, handle_mime_data_urls from openlp.core.widgets.views import ListPreviewWidget, ListWidgetWithDnD, TreeWidgetWithDnD, handle_mime_data_urls
from openlp.core.ui.icons import UiIcons from openlp.core.ui.icons import UiIcons