forked from openlp/openlp
Head1006
This commit is contained in:
commit
6deac45c2c
@ -39,40 +39,40 @@ log = logging.getLogger(__name__)
|
|||||||
html_expands = []
|
html_expands = []
|
||||||
|
|
||||||
html_expands.append({u'desc':u'Red', u'start tag':u'{r}', \
|
html_expands.append({u'desc':u'Red', u'start tag':u'{r}', \
|
||||||
u'start html':u'<font color=red>', \
|
u'start html':u'<span style="-webkit-text-fill-color:red">', \
|
||||||
u'end tag':u'{/r}', u'end html':u'</font>', \
|
u'end tag':u'{/r}', u'end html':u'</span>', \
|
||||||
u'protected':False})
|
u'protected':False})
|
||||||
html_expands.append({u'desc':u'Black', u'start tag':u'{b}', \
|
html_expands.append({u'desc':u'Black', u'start tag':u'{b}', \
|
||||||
u'start html':u'<font color=black>', \
|
u'start html':u'<span style="-webkit-text-fill-color:black">', \
|
||||||
u'end tag':u'{/b}', u'end html':u'</font>', \
|
u'end tag':u'{/b}', u'end html':u'</span>', \
|
||||||
u'protected':False})
|
u'protected':False})
|
||||||
html_expands.append({u'desc':u'Blue', u'start tag':u'{bl}', \
|
html_expands.append({u'desc':u'Blue', u'start tag':u'{bl}', \
|
||||||
u'start html':u'<font color=blue>', \
|
u'start html':u'<span style="-webkit-text-fill-color:blue">', \
|
||||||
u'end tag':u'{/bl}', u'end html':u'</font>', \
|
u'end tag':u'{/bl}', u'end html':u'</span>', \
|
||||||
u'protected':False})
|
u'protected':False})
|
||||||
html_expands.append({u'desc':u'Yellow', u'start tag':u'{y}', \
|
html_expands.append({u'desc':u'Yellow', u'start tag':u'{y}', \
|
||||||
u'start html':u'<font color=yellow>', \
|
u'start html':u'<span style="-webkit-text-fill-color:yellow">', \
|
||||||
u'end tag':u'{/y}', u'end html':u'</font>', \
|
u'end tag':u'{/y}', u'end html':u'</span>', \
|
||||||
u'protected':False})
|
u'protected':False})
|
||||||
html_expands.append({u'desc':u'Green', u'start tag':u'{g}', \
|
html_expands.append({u'desc':u'Green', u'start tag':u'{g}', \
|
||||||
u'start html':u'<font color=green>', \
|
u'start html':u'<span style="-webkit-text-fill-color:green">', \
|
||||||
u'end tag':u'{/g}', u'end html':u'</font>', \
|
u'end tag':u'{/g}', u'end html':u'</span>', \
|
||||||
u'protected':False})
|
u'protected':False})
|
||||||
html_expands.append({u'desc':u'Pink', u'start tag':u'{pk}', \
|
html_expands.append({u'desc':u'Pink', u'start tag':u'{pk}', \
|
||||||
u'start html':u'<font color=#CC33CC>', \
|
u'start html':u'<span style="-webkit-text-fill-color:#CC33CC">', \
|
||||||
u'end tag':u'{/pk}', u'end html':u'</font>', \
|
u'end tag':u'{/pk}', u'end html':u'</span>', \
|
||||||
u'protected':False})
|
u'protected':False})
|
||||||
html_expands.append({u'desc':u'Orange', u'start tag':u'{o}', \
|
html_expands.append({u'desc':u'Orange', u'start tag':u'{o}', \
|
||||||
u'start html':u'<font color=#CC0033>', \
|
u'start html':u'<span style="-webkit-text-fill-color:#CC0033">', \
|
||||||
u'end tag':u'{/o}', u'end html':u'</font>', \
|
u'end tag':u'{/o}', u'end html':u'</span>', \
|
||||||
u'protected':False})
|
u'protected':False})
|
||||||
html_expands.append({u'desc':u'Purple', u'start tag':u'{pp}', \
|
html_expands.append({u'desc':u'Purple', u'start tag':u'{pp}', \
|
||||||
u'start html':u'<font color=#9900FF>', \
|
u'start html':u'<span style="-webkit-text-fill-color:#9900FF">', \
|
||||||
u'end tag':u'{/pp}', u'end html':u'</font>', \
|
u'end tag':u'{/pp}', u'end html':u'</span>', \
|
||||||
u'protected':False})
|
u'protected':False})
|
||||||
html_expands.append({u'desc':u'White', u'start tag':u'{w}', \
|
html_expands.append({u'desc':u'White', u'start tag':u'{w}', \
|
||||||
u'start html':u'<font color=white>', \
|
u'start html':u'<span style="-webkit-text-fill-color:white">', \
|
||||||
u'end tag':u'{/w}', u'end html':u'</font>', \
|
u'end tag':u'{/w}', u'end html':u'</span>', \
|
||||||
u'protected':False})
|
u'protected':False})
|
||||||
html_expands.append({u'desc':u'Superscript', u'start tag':u'{su}', \
|
html_expands.append({u'desc':u'Superscript', u'start tag':u'{su}', \
|
||||||
u'start html':u'<sup>', \
|
u'start html':u'<sup>', \
|
||||||
|
@ -24,6 +24,8 @@
|
|||||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
|
from PyQt4 import QtWebKit
|
||||||
|
|
||||||
from openlp.core.lib import image_to_byte
|
from openlp.core.lib import image_to_byte
|
||||||
|
|
||||||
HTMLSRC = u"""
|
HTMLSRC = u"""
|
||||||
@ -39,7 +41,7 @@ HTMLSRC = u"""
|
|||||||
body {
|
body {
|
||||||
background-color: black;
|
background-color: black;
|
||||||
}
|
}
|
||||||
.dim {
|
.size {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0px;
|
left: 0px;
|
||||||
top: 0px;
|
top: 0px;
|
||||||
@ -51,6 +53,9 @@ body {
|
|||||||
background-color: black;
|
background-color: black;
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
#image {
|
||||||
|
z-index:1;
|
||||||
|
}
|
||||||
#video {
|
#video {
|
||||||
z-index:2;
|
z-index:2;
|
||||||
}
|
}
|
||||||
@ -136,8 +141,12 @@ body {
|
|||||||
}
|
}
|
||||||
document.getElementById('black').style.display = black;
|
document.getElementById('black').style.display = black;
|
||||||
document.getElementById('lyricsmain').style.visibility = lyrics;
|
document.getElementById('lyricsmain').style.visibility = lyrics;
|
||||||
document.getElementById('lyricsoutline').style.visibility = lyrics;
|
outline = document.getElementById('lyricsoutline')
|
||||||
document.getElementById('lyricsshadow').style.visibility = lyrics;
|
if(outline!=null)
|
||||||
|
outline.style.visibility = lyrics;
|
||||||
|
shadow = document.getElementById('lyricsshadow')
|
||||||
|
if(shadow!=null)
|
||||||
|
shadow.style.visibility = lyrics;
|
||||||
document.getElementById('footer').style.visibility = lyrics;
|
document.getElementById('footer').style.visibility = lyrics;
|
||||||
var vid = document.getElementById('video');
|
var vid = document.getElementById('video');
|
||||||
if(vid.src != ''){
|
if(vid.src != ''){
|
||||||
@ -156,7 +165,7 @@ body {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if(position == ''){
|
if(position == ''){
|
||||||
position = window.getComputedStyle(text, '').verticalAlign;
|
position = getComputedStyle(text, '').verticalAlign;
|
||||||
}
|
}
|
||||||
switch(position)
|
switch(position)
|
||||||
{
|
{
|
||||||
@ -181,111 +190,62 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function show_text(newtext){
|
function show_text(newtext){
|
||||||
var text1 = document.getElementById('lyricsmain');
|
|
||||||
var texto1 = document.getElementById('lyricsoutline');
|
|
||||||
var texts1 = document.getElementById('lyricsshadow');
|
|
||||||
if(!transition){
|
|
||||||
text1.innerHTML = newtext;
|
|
||||||
texto1.innerHTML = newtext;
|
|
||||||
texts1.innerHTML = newtext;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var text2 = document.getElementById('lyricsmain2');
|
|
||||||
var texto2 = document.getElementById('lyricsoutline2');
|
|
||||||
var texts2 = document.getElementById('lyricsshadow2');
|
|
||||||
if((text2.style.opacity == '')||(parseFloat(text2.style.opacity) < 0.5))
|
|
||||||
{
|
|
||||||
text2.innerHTML = text1.innerHTML;
|
|
||||||
text2.style.opacity = text1.style.opacity;
|
|
||||||
texto2.innerHTML = text1.innerHTML;
|
|
||||||
texto2.style.opacity = text1.style.opacity;
|
|
||||||
texts2.innerHTML = text1.innerHTML;
|
|
||||||
texts2.style.opacity = text1.style.opacity;
|
|
||||||
}
|
|
||||||
text1.style.opacity = 0;
|
|
||||||
text1.innerHTML = newtext;
|
|
||||||
texto1.style.opacity = 0;
|
|
||||||
texto1.innerHTML = newtext;
|
|
||||||
texts1.style.opacity = 0;
|
|
||||||
texts1.innerHTML = newtext;
|
|
||||||
// For performance reasons, we'll not animate the shadow for now
|
|
||||||
texts2.style.opacity = 0;
|
|
||||||
if(timer != null)
|
if(timer != null)
|
||||||
clearTimeout(timer);
|
clearTimeout(timer);
|
||||||
timer = setTimeout('text_fade()', 50);
|
text_fade('lyricsmain', newtext);
|
||||||
|
text_fade('lyricsoutline', newtext);
|
||||||
|
text_fade('lyricsshadow', newtext);
|
||||||
|
if(text_opacity()==1) return;
|
||||||
|
timer = setTimeout(function(){
|
||||||
|
show_text(newtext);
|
||||||
|
}, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
function text_fade(){
|
function text_fade(id, newtext){
|
||||||
var text1 = document.getElementById('lyricsmain');
|
/*
|
||||||
var texto1 = document.getElementById('lyricsoutline');
|
Using -webkit-transition: opacity 1s linear; would have been preferred
|
||||||
var texts1 = document.getElementById('lyricsshadow');
|
but it isn't currently quick enough when animating multiple layers of
|
||||||
var text2 = document.getElementById('lyricsmain2');
|
large areas of large text. Therefore do it manually as best we can.
|
||||||
var texto2 = document.getElementById('lyricsoutline2');
|
Hopefully in the future we can revisit and do more interesting
|
||||||
var texts2 = document.getElementById('lyricsshadow2');
|
transitions using -webkit-transition and -webkit-transform.
|
||||||
if(parseFloat(text1.style.opacity) < 1){
|
However we need to ensure interrupted transitions (quickly change 2
|
||||||
text1.style.opacity = parseFloat(text1.style.opacity) + 0.1;
|
slides) still looks pretty and is zippy.
|
||||||
texto1.style.opacity = parseFloat(texto1.style.opacity) + 0.1;
|
*/
|
||||||
// Don't animate shadow (performance)
|
var text = document.getElementById(id);
|
||||||
//texts1.style.opacity = parseFloat(texts1.style.opacity) + 0.1;
|
if(text==null) return;
|
||||||
|
if(!transition){
|
||||||
|
text.innerHTML = newtext;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if(parseFloat(text2.style.opacity) > 0){
|
if(newtext==text.innerHTML){
|
||||||
text2.style.opacity = parseFloat(text2.style.opacity) - 0.1;
|
text.style.opacity = parseFloat(text.style.opacity) + 0.3;
|
||||||
texto2.style.opacity = parseFloat(texto2.style.opacity) - 0.1;
|
if(text.style.opacity>0.7)
|
||||||
// Don't animate shadow (performance)
|
text.style.opacity = 1;
|
||||||
//texts2.style.opacity = parseFloat(texts2.style.opacity) - 0.1;
|
|
||||||
}
|
|
||||||
if((parseFloat(text1.style.opacity) < 1) ||
|
|
||||||
(parseFloat(text2.style.opacity) > 0)){
|
|
||||||
t = setTimeout('text_fade()', 50);
|
|
||||||
} else {
|
} else {
|
||||||
text1.style.opacity = 1;
|
text.style.opacity = parseFloat(text.style.opacity) - 0.3;
|
||||||
texto1.style.opacity = 1;
|
if(text.style.opacity<=0.1){
|
||||||
texts1.style.opacity = 1;
|
text.innerHTML = newtext;
|
||||||
text2.style.opacity = 0;
|
}
|
||||||
texto2.style.opacity = 0;
|
|
||||||
texts2.style.opacity = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function text_opacity(){
|
||||||
|
var text = document.getElementById('lyricsmain');
|
||||||
|
return getComputedStyle(text, '').opacity;
|
||||||
|
}
|
||||||
|
|
||||||
function show_text_complete(){
|
function show_text_complete(){
|
||||||
return (document.getElementById('lyricsmain').style.opacity == 1);
|
return (text_opacity()==1);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!--
|
<img id="image" class="size" src="%s" />
|
||||||
Using tables, rather than div's to make use of the vertical-align style that
|
<video id="video" class="size"></video>
|
||||||
doesn't work on div's. This avoids the need to do positioning manually which
|
%s
|
||||||
could get messy when changing verses esp. with transitions
|
|
||||||
|
|
||||||
Would prefer to use a single table and make use of -webkit-text-fill-color
|
|
||||||
-webkit-text-stroke and text-shadow styles, but they have problems working/
|
|
||||||
co-operating in qwebkit. https://bugs.webkit.org/show_bug.cgi?id=43187
|
|
||||||
Therefore one table for text, one for outline and one for shadow.
|
|
||||||
-->
|
|
||||||
<table class="lyricstable lyricscommon">
|
|
||||||
<tr><td id="lyricsmain" class="lyrics"></td></tr>
|
|
||||||
</table>
|
|
||||||
<table class="lyricsoutlinetable lyricscommon">
|
|
||||||
<tr><td id="lyricsoutline" class="lyricsoutline lyrics"></td></tr>
|
|
||||||
</table>
|
|
||||||
<table class="lyricsshadowtable lyricscommon">
|
|
||||||
<tr><td id="lyricsshadow" class="lyricsshadow lyrics"></td></tr>
|
|
||||||
</table>
|
|
||||||
<table class="lyricstable lyricscommon">
|
|
||||||
<tr><td id="lyricsmain2" class="lyrics"></td></tr>
|
|
||||||
</table>
|
|
||||||
<table class="lyricsoutlinetable lyricscommon">
|
|
||||||
<tr><td id="lyricsoutline2" class="lyricsoutline lyrics"></td></tr>
|
|
||||||
</table>
|
|
||||||
<table class="lyricsshadowtable lyricscommon">
|
|
||||||
<tr><td id="lyricsshadow2" class="lyricsshadow lyrics"></td></tr>
|
|
||||||
</table>
|
|
||||||
<div id="alert" style="visibility:hidden;"></div>
|
|
||||||
<div id="footer" class="footer"></div>
|
<div id="footer" class="footer"></div>
|
||||||
<video class="dim" id="video"></video>
|
<div id="black" class="size"></div>
|
||||||
<div class="dim" id="black"></div>
|
<div id="alert" style="visibility:hidden;"></div>
|
||||||
<img class="dim" id="image" src="%s" />
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
"""
|
"""
|
||||||
@ -300,7 +260,13 @@ def build_html(item, screen, alert, islive):
|
|||||||
Current display information
|
Current display information
|
||||||
`alert`
|
`alert`
|
||||||
Alert display display information
|
Alert display display information
|
||||||
|
`islive`
|
||||||
|
Item is going live, rather than preview/theme building
|
||||||
"""
|
"""
|
||||||
|
try:
|
||||||
|
webkitvers = float(QtWebKit.qWebKitVersion())
|
||||||
|
except AttributeError:
|
||||||
|
webkitvers = 0
|
||||||
width = screen[u'size'].width()
|
width = screen[u'size'].width()
|
||||||
height = screen[u'size'].height()
|
height = screen[u'size'].height()
|
||||||
theme = item.themedata
|
theme = item.themedata
|
||||||
@ -309,83 +275,144 @@ def build_html(item, screen, alert, islive):
|
|||||||
else:
|
else:
|
||||||
image = u''
|
image = u''
|
||||||
html = HTMLSRC % (width, height,
|
html = HTMLSRC % (width, height,
|
||||||
build_alert(alert, width),
|
build_alert_css(alert, width),
|
||||||
build_footer(item),
|
build_footer_css(item),
|
||||||
build_lyrics(item),
|
build_lyrics_css(item, webkitvers),
|
||||||
u'true' if theme and theme.display_slideTransition and islive \
|
u'true' if theme and theme.display_slideTransition and islive \
|
||||||
else u'false',
|
else u'false',
|
||||||
image)
|
image,
|
||||||
|
build_lyrics_html(item, webkitvers))
|
||||||
return html
|
return html
|
||||||
|
|
||||||
def build_lyrics(item):
|
def build_lyrics_css(item, webkitvers):
|
||||||
"""
|
"""
|
||||||
Build the video display div
|
Build the video display css
|
||||||
|
|
||||||
`item`
|
`item`
|
||||||
Service Item containing theme and location information
|
Service Item containing theme and location information
|
||||||
|
|
||||||
|
`webkitvers`
|
||||||
|
The version of qtwebkit we're using
|
||||||
|
|
||||||
"""
|
"""
|
||||||
style = """
|
style = """
|
||||||
.lyricscommon { position: absolute; %s }
|
.lyricstable {
|
||||||
.lyricstable { z-index:4; %s }
|
z-index:4;
|
||||||
.lyricsoutlinetable { z-index:3; %s }
|
position: absolute;
|
||||||
.lyricsshadowtable { z-index:2; %s }
|
display: table;
|
||||||
.lyrics { %s }
|
%s
|
||||||
.lyricsoutline { %s }
|
}
|
||||||
.lyricsshadow { %s }
|
.lyricscell {
|
||||||
|
display:table-cell;
|
||||||
|
word-wrap: break-word;
|
||||||
|
%s
|
||||||
|
}
|
||||||
|
.lyricsmain {
|
||||||
|
%s
|
||||||
|
}
|
||||||
|
.lyricsoutline {
|
||||||
|
%s
|
||||||
|
}
|
||||||
|
.lyricsshadow {
|
||||||
|
%s
|
||||||
|
}
|
||||||
"""
|
"""
|
||||||
theme = item.themedata
|
theme = item.themedata
|
||||||
lyricscommon = u''
|
|
||||||
lyricstable = u''
|
lyricstable = u''
|
||||||
outlinetable = u''
|
|
||||||
shadowtable = u''
|
|
||||||
lyrics = u''
|
lyrics = u''
|
||||||
outline = u'display: none;'
|
lyricsmain = u''
|
||||||
shadow = u'display: none;'
|
outline = u''
|
||||||
|
shadow = u''
|
||||||
if theme:
|
if theme:
|
||||||
lyricscommon = u'width: %spx; height: %spx; word-wrap: break-word; ' \
|
|
||||||
u'font-family: %s; font-size: %spt; color: %s; line-height: %d%%;' \
|
|
||||||
% (item.main.width(), item.main.height(), theme.font_main_name,
|
|
||||||
theme.font_main_proportion, theme.font_main_color,
|
|
||||||
100 + int(theme.font_main_line_adjustment))
|
|
||||||
lyricstable = u'left: %spx; top: %spx;' % \
|
lyricstable = u'left: %spx; top: %spx;' % \
|
||||||
(item.main.x(), item.main.y())
|
(item.main.x(), item.main.y())
|
||||||
outlinetable = u'left: %spx; top: %spx;' % \
|
|
||||||
(item.main.x(), item.main.y())
|
|
||||||
shadowtable = u'left: %spx; top: %spx;' % \
|
|
||||||
(item.main.x() + float(theme.display_shadow_size),
|
|
||||||
item.main.y() + float(theme.display_shadow_size))
|
|
||||||
align = u''
|
|
||||||
if theme.display_horizontalAlign == 2:
|
if theme.display_horizontalAlign == 2:
|
||||||
align = u'text-align:center;'
|
align = u'center'
|
||||||
elif theme.display_horizontalAlign == 1:
|
elif theme.display_horizontalAlign == 1:
|
||||||
align = u'text-align:right;'
|
align = u'right'
|
||||||
else:
|
else:
|
||||||
align = u'text-align:left;'
|
align = u'left'
|
||||||
if theme.display_verticalAlign == 2:
|
if theme.display_verticalAlign == 2:
|
||||||
valign = u'vertical-align:bottom;'
|
valign = u'bottom'
|
||||||
elif theme.display_verticalAlign == 1:
|
elif theme.display_verticalAlign == 1:
|
||||||
valign = u'vertical-align:middle;'
|
valign = u'middle'
|
||||||
else:
|
else:
|
||||||
valign = u'vertical-align:top;'
|
valign = u'top'
|
||||||
lyrics = u'%s %s' % (align, valign)
|
lyrics = u'width: %spx; height: %spx; text-align: %s; ' \
|
||||||
|
'vertical-align: %s; font-family: %s; font-size: %spt; ' \
|
||||||
|
'color: %s; line-height: %d%%;' % \
|
||||||
|
(item.main.width(), item.main.height(), align, valign,
|
||||||
|
theme.font_main_name, theme.font_main_proportion,
|
||||||
|
theme.font_main_color, 100 + int(theme.font_main_line_adjustment))
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
# Before 534.4 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
|
||||||
|
#
|
||||||
|
# Before 534.4 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 theme.display_outline:
|
if theme.display_outline:
|
||||||
lyricscommon += u' letter-spacing: 1px;'
|
if webkitvers < 534.3:
|
||||||
outline = u'-webkit-text-stroke: %sem %s; ' % \
|
lyrics += u' letter-spacing: 1px;'
|
||||||
|
outline = u' -webkit-text-stroke: %sem %s; ' \
|
||||||
|
'-webkit-text-fill-color: %s; ' % \
|
||||||
(float(theme.display_outline_size) / 16,
|
(float(theme.display_outline_size) / 16,
|
||||||
theme.display_outline_color)
|
theme.display_outline_color, theme.font_main_color)
|
||||||
if theme.display_shadow:
|
if webkitvers >= 533.3:
|
||||||
|
lyricsmain += outline
|
||||||
|
if theme.display_shadow and webkitvers < 534.3:
|
||||||
shadow = u'-webkit-text-stroke: %sem %s; ' \
|
shadow = u'-webkit-text-stroke: %sem %s; ' \
|
||||||
u'-webkit-text-fill-color: %s; ' % \
|
u'-webkit-text-fill-color: %s; ' \
|
||||||
|
u' padding-left: %spx; padding-top: %spx' % \
|
||||||
(float(theme.display_outline_size) / 16,
|
(float(theme.display_outline_size) / 16,
|
||||||
theme.display_shadow_color, theme.display_shadow_color)
|
theme.display_shadow_color, theme.display_shadow_color,
|
||||||
else:
|
theme.display_shadow_size, theme.display_shadow_size)
|
||||||
if theme.display_shadow:
|
if theme.display_shadow and \
|
||||||
shadow = u'color: %s;' % (theme.display_shadow_color)
|
(not theme.display_outline or webkitvers >= 534.3):
|
||||||
lyrics_html = style % (lyricscommon, lyricstable, outlinetable,
|
lyricsmain += u' text-shadow: %s %spx %spx;' % \
|
||||||
shadowtable, lyrics, outline, shadow)
|
(theme.display_shadow_color, theme.display_shadow_size,
|
||||||
return lyrics_html
|
theme.display_shadow_size)
|
||||||
|
lyrics_css = style % (lyricstable, lyrics, lyricsmain, outline, shadow)
|
||||||
|
return lyrics_css
|
||||||
|
|
||||||
|
def build_lyrics_html(item, webkitvers):
|
||||||
|
"""
|
||||||
|
Build the HTML required to show the lyrics
|
||||||
|
|
||||||
def build_footer(item):
|
`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 = u''
|
||||||
|
theme = item.themedata
|
||||||
|
if webkitvers < 534.4 and theme and theme.display_outline:
|
||||||
|
lyrics += u'<div class="lyricstable">' \
|
||||||
|
u'<div id="lyricsshadow" style="opacity:1" ' \
|
||||||
|
u'class="lyricscell lyricsshadow"></div></div>'
|
||||||
|
if webkitvers < 533.3:
|
||||||
|
lyrics += u'<div class="lyricstable">' \
|
||||||
|
u'<div id="lyricsoutline" style="opacity:1" ' \
|
||||||
|
u'class="lyricscell lyricsoutline"></div></div>'
|
||||||
|
lyrics += u'<div class="lyricstable">' \
|
||||||
|
u'<div id="lyricsmain" style="opacity:1" ' \
|
||||||
|
u'class="lyricscell lyricsmain"></div></div>'
|
||||||
|
return lyrics
|
||||||
|
|
||||||
|
def build_footer_css(item):
|
||||||
"""
|
"""
|
||||||
Build the display of the item footer
|
Build the display of the item footer
|
||||||
|
|
||||||
@ -416,7 +443,7 @@ def build_footer(item):
|
|||||||
theme.font_footer_proportion, theme.font_footer_color, align)
|
theme.font_footer_proportion, theme.font_footer_color, align)
|
||||||
return lyrics_html
|
return lyrics_html
|
||||||
|
|
||||||
def build_alert(alertTab, width):
|
def build_alert_css(alertTab, width):
|
||||||
"""
|
"""
|
||||||
Build the display of the footer
|
Build the display of the footer
|
||||||
|
|
||||||
@ -424,7 +451,7 @@ def build_alert(alertTab, width):
|
|||||||
Details from the Alert tab for fonts etc
|
Details from the Alert tab for fonts etc
|
||||||
"""
|
"""
|
||||||
style = """
|
style = """
|
||||||
width: %s;
|
width: %spx;
|
||||||
vertical-align: %s;
|
vertical-align: %s;
|
||||||
font-family: %s;
|
font-family: %s;
|
||||||
font-size: %spt;
|
font-size: %spt;
|
||||||
|
@ -115,8 +115,11 @@ class MainDisplay(DisplayWidget):
|
|||||||
self.screen = self.screens.current
|
self.screen = self.screens.current
|
||||||
self.setVisible(False)
|
self.setVisible(False)
|
||||||
self.setGeometry(self.screen[u'size'])
|
self.setGeometry(self.screen[u'size'])
|
||||||
self.webView = QtWebKit.QWebView(self)
|
self.scene = QtGui.QGraphicsScene()
|
||||||
self.webView.setGeometry(0, 0, self.screen[u'size'].width(), \
|
self.setScene(self.scene)
|
||||||
|
self.webView = QtWebKit.QGraphicsWebView()
|
||||||
|
self.scene.addItem(self.webView)
|
||||||
|
self.webView.resize(self.screen[u'size'].width(), \
|
||||||
self.screen[u'size'].height())
|
self.screen[u'size'].height())
|
||||||
self.page = self.webView.page()
|
self.page = self.webView.page()
|
||||||
self.frame = self.page.mainFrame()
|
self.frame = self.page.mainFrame()
|
||||||
|
@ -51,9 +51,9 @@ class CSVBible(BibleDB):
|
|||||||
if u'booksfile' not in kwargs:
|
if u'booksfile' not in kwargs:
|
||||||
raise KeyError(u'You have to supply a file to import books from.')
|
raise KeyError(u'You have to supply a file to import books from.')
|
||||||
self.booksfile = kwargs[u'booksfile']
|
self.booksfile = kwargs[u'booksfile']
|
||||||
if u'versesfile' not in kwargs:
|
if u'versefile' not in kwargs:
|
||||||
raise KeyError(u'You have to supply a file to import verses from.')
|
raise KeyError(u'You have to supply a file to import verses from.')
|
||||||
self.versesfile = kwargs[u'versesfile']
|
self.versesfile = kwargs[u'versefile']
|
||||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||||
QtCore.SIGNAL(u'bibles_stop_import'), self.stop_import)
|
QtCore.SIGNAL(u'bibles_stop_import'), self.stop_import)
|
||||||
|
|
||||||
|
@ -47,7 +47,6 @@ class BibleListView(BaseListWithDnD):
|
|||||||
self.parent().onListViewResize(event.size().width(),
|
self.parent().onListViewResize(event.size().width(),
|
||||||
event.size().width())
|
event.size().width())
|
||||||
|
|
||||||
|
|
||||||
class BibleMediaItem(MediaManagerItem):
|
class BibleMediaItem(MediaManagerItem):
|
||||||
"""
|
"""
|
||||||
This is the custom media manager item for Bibles.
|
This is the custom media manager item for Bibles.
|
||||||
@ -466,19 +465,27 @@ class BibleMediaItem(MediaManagerItem):
|
|||||||
|
|
||||||
def generateSlideData(self, service_item, item=None):
|
def generateSlideData(self, service_item, item=None):
|
||||||
"""
|
"""
|
||||||
Generates and formats the slides for the service item.
|
Generates and formats the slides for the service item as well as the
|
||||||
|
service item's title.
|
||||||
"""
|
"""
|
||||||
log.debug(u'generating slide data')
|
log.debug(u'generating slide data')
|
||||||
items = self.listView.selectedIndexes()
|
items = self.listView.selectedIndexes()
|
||||||
if len(items) == 0:
|
if len(items) == 0:
|
||||||
return False
|
return False
|
||||||
|
has_dual_bible = False
|
||||||
bible_text = u''
|
bible_text = u''
|
||||||
old_chapter = u''
|
old_chapter = u''
|
||||||
raw_footer = []
|
raw_footer = []
|
||||||
raw_slides = []
|
raw_slides = []
|
||||||
service_item.add_capability(ItemCapabilities.AllowsPreview)
|
for item in items:
|
||||||
service_item.add_capability(ItemCapabilities.AllowsLoop)
|
bitem = self.listView.item(item.row())
|
||||||
service_item.add_capability(ItemCapabilities.AllowsAdditions)
|
reference = bitem.data(QtCore.Qt.UserRole)
|
||||||
|
if isinstance(reference, QtCore.QVariant):
|
||||||
|
reference = reference.toPyObject()
|
||||||
|
dual_bible = self._decodeQtObject(reference, 'dual_bible')
|
||||||
|
if dual_bible:
|
||||||
|
has_dual_bible = True
|
||||||
|
break
|
||||||
# Let's loop through the main lot, and assemble our verses.
|
# Let's loop through the main lot, and assemble our verses.
|
||||||
for item in items:
|
for item in items:
|
||||||
bitem = self.listView.item(item.row())
|
bitem = self.listView.item(item.row())
|
||||||
@ -491,7 +498,7 @@ class BibleMediaItem(MediaManagerItem):
|
|||||||
bible = self._decodeQtObject(reference, 'bible')
|
bible = self._decodeQtObject(reference, 'bible')
|
||||||
version = self._decodeQtObject(reference, 'version')
|
version = self._decodeQtObject(reference, 'version')
|
||||||
copyright = self._decodeQtObject(reference, 'copyright')
|
copyright = self._decodeQtObject(reference, 'copyright')
|
||||||
#permission = self._decodeQtObject(reference, 'permission')
|
permission = self._decodeQtObject(reference, 'permission')
|
||||||
text = self._decodeQtObject(reference, 'text')
|
text = self._decodeQtObject(reference, 'text')
|
||||||
dual_bible = self._decodeQtObject(reference, 'dual_bible')
|
dual_bible = self._decodeQtObject(reference, 'dual_bible')
|
||||||
if dual_bible:
|
if dual_bible:
|
||||||
@ -499,70 +506,57 @@ class BibleMediaItem(MediaManagerItem):
|
|||||||
'dual_version')
|
'dual_version')
|
||||||
dual_copyright = self._decodeQtObject(reference,
|
dual_copyright = self._decodeQtObject(reference,
|
||||||
'dual_copyright')
|
'dual_copyright')
|
||||||
#dual_permission = self._decodeQtObject(reference,
|
dual_permission = self._decodeQtObject(reference,
|
||||||
# 'dual_permission')
|
'dual_permission')
|
||||||
dual_text = self._decodeQtObject(reference, 'dual_text')
|
dual_text = self._decodeQtObject(reference, 'dual_text')
|
||||||
if self.parent.settings_tab.display_style == 1:
|
verse_text = self.formatVerse(old_chapter, chapter, verse)
|
||||||
verse_text = self.formatVerse(old_chapter, chapter, verse,
|
footer = u'%s (%s %s %s)' % (book, version, copyright, permission)
|
||||||
u'{su}(', u'){/su}')
|
|
||||||
elif self.parent.settings_tab.display_style == 2:
|
|
||||||
verse_text = self.formatVerse(old_chapter, chapter, verse,
|
|
||||||
u'{su}{', u'}{/su}')
|
|
||||||
elif self.parent.settings_tab.display_style == 3:
|
|
||||||
verse_text = self.formatVerse(old_chapter, chapter, verse,
|
|
||||||
u'{su}[', u']{/su}')
|
|
||||||
else:
|
|
||||||
verse_text = self.formatVerse(old_chapter, chapter, verse,
|
|
||||||
u'{su}', u'{/su}')
|
|
||||||
old_chapter = chapter
|
|
||||||
footer = u'%s (%s %s)' % (book, version, copyright)
|
|
||||||
# If not found add to footer
|
|
||||||
if footer not in raw_footer:
|
if footer not in raw_footer:
|
||||||
raw_footer.append(footer)
|
raw_footer.append(footer)
|
||||||
if dual_bible:
|
if has_dual_bible:
|
||||||
footer = u'%s (%s %s)' % (book, dual_version,
|
if dual_bible:
|
||||||
dual_copyright)
|
footer = u'%s (%s %s %s)' % (book, dual_version,
|
||||||
# If not found add second version and copyright to footer.
|
dual_copyright, dual_permission)
|
||||||
if footer not in raw_footer:
|
if footer not in raw_footer:
|
||||||
raw_footer.append(footer)
|
raw_footer.append(footer)
|
||||||
bible_text = u'%s %s \n\n %s %s' % (verse_text, text,
|
# If there is an old bible_text we have to add it.
|
||||||
verse_text, dual_text)
|
if bible_text:
|
||||||
raw_slides.append(bible_text)
|
|
||||||
bible_text = u''
|
|
||||||
else:
|
|
||||||
# If we are 'Verse Per Line' then force a new line.
|
|
||||||
if self.parent.settings_tab.layout_style == 1:
|
|
||||||
text = text + u'\n'
|
|
||||||
else:
|
|
||||||
# split the line but do not replace line breaks in renderer
|
|
||||||
service_item.add_capability(ItemCapabilities.NoLineBreaks)
|
|
||||||
text = text + u'\n'
|
|
||||||
bible_text = u'%s %s %s' % (bible_text, verse_text, text)
|
|
||||||
# If we are 'Verse Per Slide' then create a new slide.
|
|
||||||
if self.parent.settings_tab.layout_style == 0:
|
|
||||||
raw_slides.append(bible_text)
|
|
||||||
bible_text = u''
|
|
||||||
# If we are not 'Verse Per Slide' we have to make sure, that we
|
|
||||||
# add more verses.
|
|
||||||
else:
|
|
||||||
if item.row() < len(items) - 1:
|
|
||||||
bitem = items[item.row() + 1]
|
|
||||||
reference = bitem.data(QtCore.Qt.UserRole)
|
|
||||||
if isinstance(reference, QtCore.QVariant):
|
|
||||||
reference = reference.toPyObject()
|
|
||||||
bible_new = self._decodeQtObject(reference, 'bible')
|
|
||||||
dual_bible_new = self._decodeQtObject(reference,
|
|
||||||
'dual_bible')
|
|
||||||
if dual_bible_new:
|
|
||||||
raw_slides.append(bible_text)
|
|
||||||
bible_text = u''
|
|
||||||
elif bible != bible_new:
|
|
||||||
raw_slides.append(bible_text)
|
|
||||||
bible_text = u''
|
|
||||||
else:
|
|
||||||
raw_slides.append(bible_text)
|
raw_slides.append(bible_text)
|
||||||
bible_text = u''
|
bible_text = u''
|
||||||
# service item title
|
bible_text = u'%s %s\n\n%s %s' % (verse_text, text,
|
||||||
|
verse_text, dual_text)
|
||||||
|
raw_slides.append(bible_text)
|
||||||
|
bible_text = u''
|
||||||
|
elif self.parent.settings_tab.layout_style == 0:
|
||||||
|
bible_text = u'%s %s' % (verse_text, text)
|
||||||
|
raw_slides.append(bible_text)
|
||||||
|
bible_text = u''
|
||||||
|
else:
|
||||||
|
bible_text = u'%s %s %s\n' % (bible_text, verse_text, text)
|
||||||
|
# If we are 'Verse Per Slide' then create a new slide.
|
||||||
|
elif self.parent.settings_tab.layout_style == 0:
|
||||||
|
bible_text = u'%s %s' % (verse_text, text)
|
||||||
|
raw_slides.append(bible_text)
|
||||||
|
bible_text = u''
|
||||||
|
# If we are 'Verse Per Line' then force a new line.
|
||||||
|
elif self.parent.settings_tab.layout_style == 1:
|
||||||
|
bible_text = u'%s %s %s\n' % (bible_text, verse_text, text)
|
||||||
|
# We have to be 'Continuous'.
|
||||||
|
else:
|
||||||
|
bible_text = u'%s %s %s\n' % (bible_text, verse_text, text)
|
||||||
|
old_chapter = chapter
|
||||||
|
# If there are no more items we check whether we have to add bible_text.
|
||||||
|
if bible_text:
|
||||||
|
raw_slides.append(bible_text)
|
||||||
|
bible_text = u''
|
||||||
|
# Service Item: Capabilities
|
||||||
|
if self.parent.settings_tab.layout_style == 2 and not has_dual_bible:
|
||||||
|
# split the line but do not replace line breaks in renderer
|
||||||
|
service_item.add_capability(ItemCapabilities.NoLineBreaks)
|
||||||
|
service_item.add_capability(ItemCapabilities.AllowsPreview)
|
||||||
|
service_item.add_capability(ItemCapabilities.AllowsLoop)
|
||||||
|
service_item.add_capability(ItemCapabilities.AllowsAdditions)
|
||||||
|
# Service Item: Title
|
||||||
if not service_item.title:
|
if not service_item.title:
|
||||||
if dual_bible:
|
if dual_bible:
|
||||||
service_item.title = u'%s (%s, %s) %s' % (book, version,
|
service_item.title = u'%s (%s, %s) %s' % (book, version,
|
||||||
@ -573,7 +567,7 @@ class BibleMediaItem(MediaManagerItem):
|
|||||||
translate('BiblesPlugin.MediaItem', 'etc')) == -1:
|
translate('BiblesPlugin.MediaItem', 'etc')) == -1:
|
||||||
service_item.title = u'%s, %s' % (service_item.title,
|
service_item.title = u'%s, %s' % (service_item.title,
|
||||||
translate('BiblesPlugin.MediaItem', 'etc'))
|
translate('BiblesPlugin.MediaItem', 'etc'))
|
||||||
# item theme
|
# Service Item: Theme
|
||||||
if len(self.parent.settings_tab.bible_theme) == 0:
|
if len(self.parent.settings_tab.bible_theme) == 0:
|
||||||
service_item.theme = None
|
service_item.theme = None
|
||||||
else:
|
else:
|
||||||
@ -587,14 +581,20 @@ class BibleMediaItem(MediaManagerItem):
|
|||||||
service_item.raw_footer = raw_footer
|
service_item.raw_footer = raw_footer
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def formatVerse(self, old_chapter, chapter, verse, opening, closing):
|
def formatVerse(self, old_chapter, chapter, verse):
|
||||||
verse_text = opening
|
if not self.parent.settings_tab.show_new_chapters or \
|
||||||
if old_chapter != chapter:
|
old_chapter != chapter:
|
||||||
verse_text += chapter + u':'
|
verse_text = chapter + u':' + verse
|
||||||
elif not self.parent.settings_tab.show_new_chapters:
|
else:
|
||||||
verse_text += chapter + u':'
|
verse_text = verse
|
||||||
verse_text += verse
|
if self.parent.settings_tab.display_style == 1:
|
||||||
verse_text += closing
|
verse_text = u'{su}(' + verse_text + u'){/su}'
|
||||||
|
elif self.parent.settings_tab.display_style == 2:
|
||||||
|
verse_text = u'{su}{' + verse_text + u'}{/su}'
|
||||||
|
elif self.parent.settings_tab.display_style == 3:
|
||||||
|
verse_text = u'{su}[' + verse_text + u']{/su}'
|
||||||
|
else:
|
||||||
|
verse_text = u'{su}' + verse_text + u'{/su}'
|
||||||
return verse_text
|
return verse_text
|
||||||
|
|
||||||
def reloadBibles(self):
|
def reloadBibles(self):
|
||||||
@ -639,14 +639,14 @@ class BibleMediaItem(MediaManagerItem):
|
|||||||
for i in range(int(range_from), int(range_to) + 1):
|
for i in range(int(range_from), int(range_to) + 1):
|
||||||
combo.addItem(unicode(i))
|
combo.addItem(unicode(i))
|
||||||
|
|
||||||
def displayResults(self, bible, dual_bible=None):
|
def displayResults(self, bible, dual_bible=u''):
|
||||||
"""
|
"""
|
||||||
Displays the search results in the media manager. All data needed for
|
Displays the search results in the media manager. All data needed for
|
||||||
further action is saved for/in each row.
|
further action is saved for/in each row.
|
||||||
"""
|
"""
|
||||||
version = self.parent.manager.get_meta_data(bible, u'Version')
|
version = self.parent.manager.get_meta_data(bible, u'Version')
|
||||||
copyright = self.parent.manager.get_meta_data(bible, u'Copyright')
|
copyright = self.parent.manager.get_meta_data(bible, u'Copyright')
|
||||||
#permission = self.parent.manager.get_meta_data(bible, u'Permissions')
|
permission = self.parent.manager.get_meta_data(bible, u'Permissions')
|
||||||
if dual_bible:
|
if dual_bible:
|
||||||
dual_version = self.parent.manager.get_meta_data(dual_bible,
|
dual_version = self.parent.manager.get_meta_data(dual_bible,
|
||||||
u'Version')
|
u'Version')
|
||||||
@ -654,43 +654,41 @@ class BibleMediaItem(MediaManagerItem):
|
|||||||
u'Copyright')
|
u'Copyright')
|
||||||
dual_permission = self.parent.manager.get_meta_data(dual_bible,
|
dual_permission = self.parent.manager.get_meta_data(dual_bible,
|
||||||
u'Permissions')
|
u'Permissions')
|
||||||
if dual_permission:
|
if not dual_permission:
|
||||||
dual_permission = dual_permission.value
|
|
||||||
else:
|
|
||||||
dual_permission = u''
|
dual_permission = u''
|
||||||
# We count the number of rows which are maybe already present.
|
# We count the number of rows which are maybe already present.
|
||||||
start_count = self.listView.count()
|
start_count = self.listView.count()
|
||||||
for count, verse in enumerate(self.search_results):
|
for count, verse in enumerate(self.search_results):
|
||||||
if dual_bible:
|
if dual_bible:
|
||||||
vdict = {
|
vdict = {
|
||||||
'book':QtCore.QVariant(verse.book.name),
|
'book': QtCore.QVariant(verse.book.name),
|
||||||
'chapter':QtCore.QVariant(verse.chapter),
|
'chapter': QtCore.QVariant(verse.chapter),
|
||||||
'verse':QtCore.QVariant(verse.verse),
|
'verse': QtCore.QVariant(verse.verse),
|
||||||
'bible':QtCore.QVariant(bible),
|
'bible': QtCore.QVariant(bible),
|
||||||
'version':QtCore.QVariant(version.value),
|
'version': QtCore.QVariant(version.value),
|
||||||
'copyright':QtCore.QVariant(copyright.value),
|
'copyright': QtCore.QVariant(copyright.value),
|
||||||
#'permission':QtCore.QVariant(permission.value),
|
'permission': QtCore.QVariant(permission.value),
|
||||||
'text':QtCore.QVariant(verse.text),
|
'text': QtCore.QVariant(verse.text),
|
||||||
'dual_bible':QtCore.QVariant(dual_bible),
|
'dual_bible': QtCore.QVariant(dual_bible),
|
||||||
'dual_version':QtCore.QVariant(dual_version.value),
|
'dual_version': QtCore.QVariant(dual_version.value),
|
||||||
'dual_copyright':QtCore.QVariant(dual_copyright.value),
|
'dual_copyright': QtCore.QVariant(dual_copyright.value),
|
||||||
#'dual_permission':QtCore.QVariant(dual_permission),
|
'dual_permission': QtCore.QVariant(dual_permission.value),
|
||||||
'dual_text':QtCore.QVariant(
|
'dual_text': QtCore.QVariant(
|
||||||
self.dual_search_results[count].text)
|
self.dual_search_results[count].text)
|
||||||
}
|
}
|
||||||
bible_text = u' %s %d:%d (%s, %s)' % (verse.book.name,
|
bible_text = u' %s %d:%d (%s, %s)' % (verse.book.name,
|
||||||
verse.chapter, verse.verse, version.value, dual_version.value)
|
verse.chapter, verse.verse, version.value, dual_version.value)
|
||||||
else:
|
else:
|
||||||
vdict = {
|
vdict = {
|
||||||
'book':QtCore.QVariant(verse.book.name),
|
'book': QtCore.QVariant(verse.book.name),
|
||||||
'chapter':QtCore.QVariant(verse.chapter),
|
'chapter': QtCore.QVariant(verse.chapter),
|
||||||
'verse':QtCore.QVariant(verse.verse),
|
'verse': QtCore.QVariant(verse.verse),
|
||||||
'bible':QtCore.QVariant(bible),
|
'bible': QtCore.QVariant(bible),
|
||||||
'version':QtCore.QVariant(version.value),
|
'version': QtCore.QVariant(version.value),
|
||||||
'copyright':QtCore.QVariant(copyright.value),
|
'copyright': QtCore.QVariant(copyright.value),
|
||||||
#'permission':QtCore.QVariant(permission.value),
|
'permission': QtCore.QVariant(permission.value),
|
||||||
'text':QtCore.QVariant(verse.text),
|
'text': QtCore.QVariant(verse.text),
|
||||||
'dual_bible':QtCore.QVariant(dual_bible)
|
'dual_bible': QtCore.QVariant(dual_bible)
|
||||||
}
|
}
|
||||||
bible_text = u' %s %d:%d (%s)' % (verse.book.name,
|
bible_text = u' %s %d:%d (%s)' % (verse.book.name,
|
||||||
verse.chapter, verse.verse, version.value)
|
verse.chapter, verse.verse, version.value)
|
||||||
|
@ -83,6 +83,12 @@ class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard):
|
|||||||
QtCore.QObject.connect(self.wordsOfWorshipRemoveButton,
|
QtCore.QObject.connect(self.wordsOfWorshipRemoveButton,
|
||||||
QtCore.SIGNAL(u'clicked()'),
|
QtCore.SIGNAL(u'clicked()'),
|
||||||
self.onWordsOfWorshipRemoveButtonClicked)
|
self.onWordsOfWorshipRemoveButtonClicked)
|
||||||
|
QtCore.QObject.connect(self.ccliAddButton,
|
||||||
|
QtCore.SIGNAL(u'clicked()'),
|
||||||
|
self.onCCLIAddButtonClicked)
|
||||||
|
QtCore.QObject.connect(self.ccliRemoveButton,
|
||||||
|
QtCore.SIGNAL(u'clicked()'),
|
||||||
|
self.onCCLIRemoveButtonClicked)
|
||||||
QtCore.QObject.connect(self.songsOfFellowshipAddButton,
|
QtCore.QObject.connect(self.songsOfFellowshipAddButton,
|
||||||
QtCore.SIGNAL(u'clicked()'),
|
QtCore.SIGNAL(u'clicked()'),
|
||||||
self.onSongsOfFellowshipAddButtonClicked)
|
self.onSongsOfFellowshipAddButtonClicked)
|
||||||
@ -277,6 +283,16 @@ class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard):
|
|||||||
def onWordsOfWorshipRemoveButtonClicked(self):
|
def onWordsOfWorshipRemoveButtonClicked(self):
|
||||||
self.removeSelectedItems(self.wordsOfWorshipFileListWidget)
|
self.removeSelectedItems(self.wordsOfWorshipFileListWidget)
|
||||||
|
|
||||||
|
def onCCLIAddButtonClicked(self):
|
||||||
|
self.getFiles(
|
||||||
|
translate('SongsPlugin.ImportWizardForm',
|
||||||
|
'Select CCLI Files'),
|
||||||
|
self.ccliFileListWidget
|
||||||
|
)
|
||||||
|
|
||||||
|
def onCCLIRemoveButtonClicked(self):
|
||||||
|
self.removeSelectedItems(self.ccliFileListWidget)
|
||||||
|
|
||||||
def onSongsOfFellowshipAddButtonClicked(self):
|
def onSongsOfFellowshipAddButtonClicked(self):
|
||||||
self.getFiles(
|
self.getFiles(
|
||||||
translate('SongsPlugin.ImportWizardForm',
|
translate('SongsPlugin.ImportWizardForm',
|
||||||
|
310
openlp/plugins/songs/lib/cclifileimport.py
Executable file
310
openlp/plugins/songs/lib/cclifileimport.py
Executable file
@ -0,0 +1,310 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# OpenLP - Open Source Lyrics Projection #
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# Copyright (c) 2008-2010 Raoul Snyman #
|
||||||
|
# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
|
||||||
|
# Gorven, Scott Guerrieri, Meinert Jordan, Andreas Preikschat, Christian #
|
||||||
|
# Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon Tibble, #
|
||||||
|
# Carsten Tinggaard, Frode Woldsund, Derek Scotney #
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# 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 #
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import chardet
|
||||||
|
import codecs
|
||||||
|
|
||||||
|
from songimport import SongImport
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
class CCLIFileImportError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class CCLIFileImport(SongImport):
|
||||||
|
"""
|
||||||
|
The :class:`CCLIFileImport` class provides OpenLP with the
|
||||||
|
ability to import CCLI SongSelect song files in both .txt and
|
||||||
|
.usr formats. See http://www.ccli.com
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, manager, **kwargs):
|
||||||
|
"""
|
||||||
|
Initialise the import.
|
||||||
|
|
||||||
|
``manager``
|
||||||
|
The song manager for the running OpenLP installation.
|
||||||
|
``filenames``
|
||||||
|
The files to be imported.
|
||||||
|
"""
|
||||||
|
SongImport.__init__(self, manager)
|
||||||
|
if u'filenames' in kwargs:
|
||||||
|
self.filenames = kwargs[u'filenames']
|
||||||
|
log.debug(self.filenames)
|
||||||
|
else:
|
||||||
|
raise KeyError(u'Keyword argument "filenames" not supplied.')
|
||||||
|
|
||||||
|
def do_import(self):
|
||||||
|
"""
|
||||||
|
Import either a .usr or a .txt SongSelect file
|
||||||
|
"""
|
||||||
|
log.debug(u'Starting CCLI File Import')
|
||||||
|
song_total = len(self.filenames)
|
||||||
|
self.import_wizard.importProgressBar.setMaximum(song_total)
|
||||||
|
song_count = 1
|
||||||
|
for filename in self.filenames:
|
||||||
|
self.import_wizard.incrementProgressBar(
|
||||||
|
u'Importing song %s of %s' % (song_count, song_total))
|
||||||
|
filename = unicode(filename)
|
||||||
|
log.debug(u'Importing CCLI File: %s', filename)
|
||||||
|
lines = []
|
||||||
|
if os.path.isfile(filename):
|
||||||
|
detect_file = open(filename, u'r')
|
||||||
|
details = chardet.detect(detect_file.read(2048))
|
||||||
|
detect_file.close()
|
||||||
|
infile = codecs.open(filename, u'r', details['encoding'])
|
||||||
|
lines = infile.readlines()
|
||||||
|
ext = os.path.splitext(filename)[1]
|
||||||
|
if ext.lower() == ".usr":
|
||||||
|
log.info(u'SongSelect .usr format file found %s: ' , filename)
|
||||||
|
self.do_import_usr_file(lines)
|
||||||
|
elif ext.lower() == ".txt":
|
||||||
|
log.info(u'SongSelect .txt format file found %s: ', filename)
|
||||||
|
self.do_import_txt_file(lines)
|
||||||
|
else:
|
||||||
|
log.info(u'Extension %s is not valid', filename)
|
||||||
|
pass
|
||||||
|
song_count += 1
|
||||||
|
if self.stop_import_flag:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def do_import_usr_file(self, textList):
|
||||||
|
"""
|
||||||
|
The :method:`do_import_usr_file` method provides OpenLP
|
||||||
|
with the ability to import CCLI SongSelect songs in
|
||||||
|
*USR* file format
|
||||||
|
|
||||||
|
``textList``
|
||||||
|
An array of strings containing the usr file content.
|
||||||
|
|
||||||
|
**SongSelect .usr file format**
|
||||||
|
``[File]``
|
||||||
|
USR file format first line
|
||||||
|
``Type=``
|
||||||
|
Indicates the file type
|
||||||
|
e.g. *Type=SongSelect Import File*
|
||||||
|
``Version=3.0``
|
||||||
|
File format version
|
||||||
|
``[S A2672885]``
|
||||||
|
Contains the CCLI Song number e.g. *2672885*
|
||||||
|
``Title=``
|
||||||
|
Contains the song title (e.g. *Title=Above All*)
|
||||||
|
``Author=``
|
||||||
|
Contains a | delimited list of the song authors
|
||||||
|
e.g. *Author=LeBlanc, Lenny | Baloche, Paul*
|
||||||
|
``Copyright=``
|
||||||
|
Contains a | delimited list of the song copyrights
|
||||||
|
e.g. Copyright=1999 Integrity's Hosanna! Music |
|
||||||
|
LenSongs Publishing (Verwaltet von Gerth Medien
|
||||||
|
Musikverlag)
|
||||||
|
``Admin=``
|
||||||
|
Contains the song administrator
|
||||||
|
e.g. *Admin=Gerth Medien Musikverlag*
|
||||||
|
``Themes=``
|
||||||
|
Contains a /t delimited list of the song themes
|
||||||
|
e.g. *Themes=Cross/tKingship/tMajesty/tRedeemer*
|
||||||
|
``Keys=``
|
||||||
|
Contains the keys in which the music is played??
|
||||||
|
e.g. *Keys=A*
|
||||||
|
``Fields=``
|
||||||
|
Contains a list of the songs fields in order /t delimited
|
||||||
|
e.g. *Fields=Vers 1/tVers 2/tChorus 1/tAndere 1*
|
||||||
|
``Words=``
|
||||||
|
Contains the songs various lyrics in order as shown by the
|
||||||
|
*Fields* description
|
||||||
|
e.g. *Words=Above all powers....* [/n = CR, /n/t = CRLF]
|
||||||
|
"""
|
||||||
|
log.debug(u'USR file text: %s', textList)
|
||||||
|
lyrics = []
|
||||||
|
self.set_defaults()
|
||||||
|
for line in textList:
|
||||||
|
if line.startswith(u'Title='):
|
||||||
|
song_name = line[6:].strip()
|
||||||
|
elif line.startswith(u'Author='):
|
||||||
|
song_author = line[7:].strip()
|
||||||
|
elif line.startswith(u'Copyright='):
|
||||||
|
song_copyright = line[10:].strip()
|
||||||
|
elif line.startswith(u'[S A'):
|
||||||
|
song_ccli = line[4:-3].strip()
|
||||||
|
elif line.startswith(u'Fields='):
|
||||||
|
#Fields contain single line indicating verse, chorus, etc,
|
||||||
|
#/t delimited, same as with words field. store seperately
|
||||||
|
#and process at end.
|
||||||
|
song_fields = line[7:].strip()
|
||||||
|
elif line.startswith(u'Words='):
|
||||||
|
song_words = line[6:].strip()
|
||||||
|
#Unhandled usr keywords:Type,Version,Admin,Themes,Keys
|
||||||
|
#Process Fields and words sections
|
||||||
|
field_list = song_fields.split(u'/t')
|
||||||
|
words_list = song_words.split(u'/t')
|
||||||
|
for counter in range(0, len(field_list)):
|
||||||
|
if field_list[counter].startswith(u'Ver'):
|
||||||
|
verse_type = u'V'
|
||||||
|
elif field_list[counter].startswith(u'Ch'):
|
||||||
|
verse_type = u'C'
|
||||||
|
elif field_list[counter].startswith(u'Br'):
|
||||||
|
verse_type = u'B'
|
||||||
|
else: #Other
|
||||||
|
verse_type = u'O'
|
||||||
|
verse_text = unicode(words_list[counter])
|
||||||
|
verse_text = verse_text.replace("/n", "\n")
|
||||||
|
if len(verse_text) > 0:
|
||||||
|
self.add_verse(verse_text, verse_type);
|
||||||
|
#Handle multiple authors
|
||||||
|
author_list = song_author.split(u'/')
|
||||||
|
if len(author_list) < 2:
|
||||||
|
author_list = song_author.split(u'|')
|
||||||
|
for author in author_list:
|
||||||
|
seperated = author.split(u',')
|
||||||
|
self.add_author(seperated[1].strip() + " " + seperated[0].strip())
|
||||||
|
self.title = song_name
|
||||||
|
self.copyright = song_copyright
|
||||||
|
self.ccli_number = song_ccli
|
||||||
|
self.finish()
|
||||||
|
|
||||||
|
def do_import_txt_file(self, textList):
|
||||||
|
"""
|
||||||
|
The :method:`do_import_txt_file` method provides OpenLP
|
||||||
|
with the ability to import CCLI SongSelect songs in
|
||||||
|
*TXT* file format
|
||||||
|
|
||||||
|
``textList``
|
||||||
|
An array of strings containing the txt file content.
|
||||||
|
|
||||||
|
**SongSelect .txt file format**
|
||||||
|
|
||||||
|
``Song Title``
|
||||||
|
Contains the song title
|
||||||
|
|
||||||
|
<Empty line>
|
||||||
|
|
||||||
|
``Title of following verse/chorus and number``
|
||||||
|
e.g. Verse 1, Chorus 1
|
||||||
|
|
||||||
|
``Verse/Chorus lyrics``
|
||||||
|
|
||||||
|
<Empty line>
|
||||||
|
|
||||||
|
<Empty line>
|
||||||
|
|
||||||
|
``Title of next verse/chorus (repeats)``
|
||||||
|
|
||||||
|
``Verse/Chorus lyrics``
|
||||||
|
|
||||||
|
<Empty line>
|
||||||
|
|
||||||
|
<Empty line>
|
||||||
|
|
||||||
|
``Song CCLI Number``
|
||||||
|
e.g. CCLI Number (e.g.CCLI-Liednummer: 2672885)
|
||||||
|
``Song Copyright``
|
||||||
|
e.g. © 1999 Integrity's Hosanna! Music | LenSongs Publishing
|
||||||
|
``Song Authors``
|
||||||
|
e.g. Lenny LeBlanc | Paul Baloche
|
||||||
|
``Licencing info``
|
||||||
|
e.g. For use solely with the SongSelect Terms of Use.
|
||||||
|
All rights Reserved. www.ccli.com
|
||||||
|
``CCLI Licence number of user``
|
||||||
|
e.g. CCL-Liedlizenznummer: 14 / CCLI License No. 14
|
||||||
|
"""
|
||||||
|
log.debug(u'TXT file text: %s', textList)
|
||||||
|
self.set_defaults()
|
||||||
|
line_number = 0
|
||||||
|
verse_text = u''
|
||||||
|
song_comments = u''
|
||||||
|
song_copyright = u'';
|
||||||
|
verse_start = False
|
||||||
|
for line in textList:
|
||||||
|
clean_line = line.strip()
|
||||||
|
if not clean_line:
|
||||||
|
if line_number==0:
|
||||||
|
continue
|
||||||
|
elif verse_start:
|
||||||
|
if verse_text:
|
||||||
|
self.add_verse(verse_text, verse_type)
|
||||||
|
verse_text = ''
|
||||||
|
verse_start = False
|
||||||
|
else:
|
||||||
|
#line_number=0, song title
|
||||||
|
if line_number==0:
|
||||||
|
song_name = clean_line
|
||||||
|
line_number += 1
|
||||||
|
#line_number=1, verses
|
||||||
|
elif line_number==1:
|
||||||
|
#line_number=1, ccli number, first line after verses
|
||||||
|
if clean_line.startswith(u'CCLI'):
|
||||||
|
line_number += 1
|
||||||
|
ccli_parts = clean_line.split(' ')
|
||||||
|
song_ccli = ccli_parts[len(ccli_parts)-1]
|
||||||
|
elif not verse_start:
|
||||||
|
# We have the verse descriptor
|
||||||
|
verse_desc_parts = clean_line.split(' ')
|
||||||
|
if len(verse_desc_parts) == 2:
|
||||||
|
if verse_desc_parts[0].startswith(u'Ver'):
|
||||||
|
verse_type = u'V'
|
||||||
|
elif verse_desc_parts[0].startswith(u'Ch'):
|
||||||
|
verse_type = u'C'
|
||||||
|
elif verse_desc_parts[0].startswith(u'Br'):
|
||||||
|
verse_type = u'B'
|
||||||
|
else:
|
||||||
|
verse_type = u'O'
|
||||||
|
verse_number = verse_desc_parts[1]
|
||||||
|
else:
|
||||||
|
verse_type = u'O'
|
||||||
|
verse_number = 1
|
||||||
|
verse_start = True
|
||||||
|
else:
|
||||||
|
# We have verse content or the start of the
|
||||||
|
# last part. Add l so as to keep the CRLF
|
||||||
|
verse_text = verse_text + line
|
||||||
|
else:
|
||||||
|
#line_number=2, copyright
|
||||||
|
if line_number==2:
|
||||||
|
line_number += 1
|
||||||
|
song_copyright = clean_line
|
||||||
|
#n=3, authors
|
||||||
|
elif line_number==3:
|
||||||
|
line_number += 1
|
||||||
|
song_author = clean_line
|
||||||
|
#line_number=4, comments lines before last line
|
||||||
|
elif (line_number==4) and (not clean_line.startswith(u'CCL')):
|
||||||
|
song_comments = song_comments + clean_line
|
||||||
|
# split on known separators
|
||||||
|
author_list = song_author.split(u'/')
|
||||||
|
if len(author_list) < 2:
|
||||||
|
author_list = song_author.split(u'|')
|
||||||
|
#Clean spaces before and after author names
|
||||||
|
for author_name in author_list:
|
||||||
|
self.add_author(author_name.strip())
|
||||||
|
self.title = song_name
|
||||||
|
self.copyright = song_copyright
|
||||||
|
self.ccli_number = song_ccli
|
||||||
|
self.comments = song_comments
|
||||||
|
self.finish()
|
||||||
|
|
@ -29,6 +29,7 @@ from olpimport import OpenLPSongImport
|
|||||||
try:
|
try:
|
||||||
from sofimport import SofImport
|
from sofimport import SofImport
|
||||||
from oooimport import OooImport
|
from oooimport import OooImport
|
||||||
|
from cclifileimport import CCLIFileImport
|
||||||
from wowimport import WowImport
|
from wowimport import WowImport
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
pass
|
||||||
@ -68,6 +69,8 @@ class SongFormat(object):
|
|||||||
return WowImport
|
return WowImport
|
||||||
elif format == SongFormat.Generic:
|
elif format == SongFormat.Generic:
|
||||||
return OooImport
|
return OooImport
|
||||||
|
elif format == SongFormat.CCLI:
|
||||||
|
return CCLIFileImport
|
||||||
# else:
|
# else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -43,12 +43,6 @@ class SongImport(QtCore.QObject):
|
|||||||
whether the authors etc already exist and add them or refer to them
|
whether the authors etc already exist and add them or refer to them
|
||||||
as necessary
|
as necessary
|
||||||
"""
|
"""
|
||||||
|
|
||||||
COPYRIGHT_STRING = unicode(translate(
|
|
||||||
'SongsPlugin.SongImport', 'copyright'))
|
|
||||||
COPYRIGHT_SYMBOL = unicode(translate(
|
|
||||||
'SongsPlugin.SongImport', '\xa9'))
|
|
||||||
|
|
||||||
def __init__(self, manager):
|
def __init__(self, manager):
|
||||||
"""
|
"""
|
||||||
Initialise and create defaults for properties
|
Initialise and create defaults for properties
|
||||||
@ -58,11 +52,11 @@ class SongImport(QtCore.QObject):
|
|||||||
"""
|
"""
|
||||||
self.manager = manager
|
self.manager = manager
|
||||||
self.stop_import_flag = False
|
self.stop_import_flag = False
|
||||||
|
self.set_defaults()
|
||||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||||
QtCore.SIGNAL(u'songs_stop_import'), self.stop_import)
|
QtCore.SIGNAL(u'songs_stop_import'), self.stop_import)
|
||||||
self.setDefaults()
|
|
||||||
|
def set_defaults(self):
|
||||||
def setDefaults(self):
|
|
||||||
self.title = u''
|
self.title = u''
|
||||||
self.song_number = u''
|
self.song_number = u''
|
||||||
self.alternate_title = u''
|
self.alternate_title = u''
|
||||||
@ -78,6 +72,10 @@ class SongImport(QtCore.QObject):
|
|||||||
self.verses = []
|
self.verses = []
|
||||||
self.versecount = 0
|
self.versecount = 0
|
||||||
self.choruscount = 0
|
self.choruscount = 0
|
||||||
|
self.copyright_string = unicode(translate(
|
||||||
|
'SongsPlugin.SongImport', 'copyright'))
|
||||||
|
self.copyright_symbol = unicode(translate(
|
||||||
|
'SongsPlugin.SongImport', '\xa9'))
|
||||||
|
|
||||||
def stop_import(self):
|
def stop_import(self):
|
||||||
"""
|
"""
|
||||||
@ -163,8 +161,7 @@ class SongImport(QtCore.QObject):
|
|||||||
def parse_author(self, text):
|
def parse_author(self, text):
|
||||||
"""
|
"""
|
||||||
Add the author. OpenLP stores them individually so split by 'and', '&'
|
Add the author. OpenLP stores them individually so split by 'and', '&'
|
||||||
and comma.
|
and comma. However need to check for 'Mr and Mrs Smith' and turn it to
|
||||||
However need to check for 'Mr and Mrs Smith' and turn it to
|
|
||||||
'Mr Smith' and 'Mrs Smith'.
|
'Mr Smith' and 'Mrs Smith'.
|
||||||
"""
|
"""
|
||||||
for author in text.split(u','):
|
for author in text.split(u','):
|
||||||
@ -241,7 +238,7 @@ class SongImport(QtCore.QObject):
|
|||||||
"""
|
"""
|
||||||
All fields have been set to this song. Write it away
|
All fields have been set to this song. Write it away
|
||||||
"""
|
"""
|
||||||
if len(self.authors) == 0:
|
if not self.authors:
|
||||||
self.authors.append(u'Author unknown')
|
self.authors.append(u'Author unknown')
|
||||||
self.commit_song()
|
self.commit_song()
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user