This commit is contained in:
Andreas Preikschat 2010-08-28 19:05:45 +02:00
commit 8071a65720
55 changed files with 14408 additions and 13094 deletions

View File

@ -34,7 +34,8 @@ from PyQt4 import QtCore, QtGui
from openlp.core.lib import Receiver
from openlp.core.resources import qInitResources
from openlp.core.ui import MainWindow, SplashScreen, ScreenList
from openlp.core.ui.mainwindow import MainWindow
from openlp.core.ui import SplashScreen, ScreenList
from openlp.core.utils import AppLocation, LanguageManager, VersionThread
log = logging.getLogger()
@ -47,7 +48,6 @@ QMainWindow::separator
QDockWidget::title
{
/*background: palette(dark);*/
border: 1px solid palette(dark);
padding-left: 5px;
padding-top: 2px;

View File

@ -1 +1 @@
1.9.2
1.9.2-bzr987

View File

@ -35,6 +35,67 @@ from PyQt4 import QtCore, QtGui
log = logging.getLogger(__name__)
# TODO make external and configurable in alpha 4 via a settings dialog
html_expands = []
html_expands.append({u'desc':u'Red', u'start tag':u'{r}', \
u'start html':u'<font color=red>', \
u'end tag':u'{/r}', u'end html':u'</font>', \
u'protected':False})
html_expands.append({u'desc':u'Black', u'start tag':u'{b}', \
u'start html':u'<font color=black>', \
u'end tag':u'{/b}', u'end html':u'</font>', \
u'protected':False})
html_expands.append({u'desc':u'Blue', u'start tag':u'{bl}', \
u'start html':u'<font color=blue>', \
u'end tag':u'{/bl}', u'end html':u'</font>', \
u'protected':False})
html_expands.append({u'desc':u'Yellow', u'start tag':u'{y}', \
u'start html':u'<font color=yellow>', \
u'end tag':u'{/y}', u'end html':u'</font>', \
u'protected':False})
html_expands.append({u'desc':u'Green', u'start tag':u'{g}', \
u'start html':u'<font color=green>', \
u'end tag':u'{/g}', u'end html':u'</font>', \
u'protected':False})
html_expands.append({u'desc':u'Pink', u'start tag':u'{pk}', \
u'start html':u'<font color=#CC33CC>', \
u'end tag':u'{/pk}', u'end html':u'</font>', \
u'protected':False})
html_expands.append({u'desc':u'Orange', u'start tag':u'{o}', \
u'start html':u'<font color=#CC0033>', \
u'end tag':u'{/o}', u'end html':u'</font>', \
u'protected':False})
html_expands.append({u'desc':u'Purple', u'start tag':u'{pp}', \
u'start html':u'<font color=#9900FF>', \
u'end tag':u'{/pp}', u'end html':u'</font>', \
u'protected':False})
html_expands.append({u'desc':u'White', u'start tag':u'{w}', \
u'start html':u'<font color=white>', \
u'end tag':u'{/w}', u'end html':u'</font>', \
u'protected':False})
html_expands.append({u'desc':u'Superscript', u'start tag':u'{su}', \
u'start html':u'<sup>', \
u'end tag':u'{/su}', u'end html':u'</sup>', \
u'protected':True})
html_expands.append({u'desc':u'Subscript', u'start tag':u'{sb}', \
u'start html':u'<sub>', \
u'end tag':u'{/sb}', u'end html':u'</sub>', \
u'protected':True})
html_expands.append({u'desc':u'Paragraph', u'start tag':u'{p}', \
u'start html':u'<p>', \
u'end tag':u'{/p}', u'end html':u'</p>', \
u'protected':True})
html_expands.append({u'desc':u'Bold', u'start tag':u'{st}', \
u'start html':u'<strong>', \
u'end tag':u'{/st}', \
u'end html':u'</strong>', \
u'protected':True})
html_expands.append({u'desc':u'Italics', u'start tag':u'{it}', \
u'start html':u'<em>', \
u'end tag':u'{/it}', u'end html':u'</em>', \
u'protected':True})
def translate(context, text, comment=None):
"""
A special shortcut method to wrap around the Qt4 translation functions.
@ -166,15 +227,46 @@ def context_menu_separator(base):
action.setSeparator(True)
return action
def resize_image(image, width, height):
def image_to_byte(image):
"""
Resize an image to fit on the current screen for the web and returns
it as a byte stream.
``image``
The image to converted.
"""
byte_array = QtCore.QByteArray()
# use buffer to store pixmap into byteArray
buffie = QtCore.QBuffer(byte_array)
buffie.open(QtCore.QIODevice.WriteOnly)
if isinstance(image, QtGui.QImage):
pixmap = QtGui.QPixmap.fromImage(image)
else:
pixmap = QtGui.QPixmap(image)
pixmap.save(buffie, "PNG")
# convert to base64 encoding so does not get missed!
return byte_array.toBase64()
def resize_image(image, width, height, background=QtCore.Qt.black):
"""
Resize an image to fit on the current screen.
``image``
The image to resize.
``width``
The new image width.
``height``
The new image height.
``background``
The background colour defaults to black.
"""
preview = QtGui.QImage(image)
if not preview.isNull():
# Only resize if different size
if preview.width() == width and preview.height == height:
return preview
preview = preview.scaled(width, height, QtCore.Qt.KeepAspectRatio,
@ -184,7 +276,7 @@ def resize_image(image, width, height):
# and move it to the centre of the preview space
new_image = QtGui.QImage(width, height,
QtGui.QImage.Format_ARGB32_Premultiplied)
new_image.fill(QtCore.Qt.black)
new_image.fill(background)
painter = QtGui.QPainter(new_image)
painter.drawImage((width - realw) / 2, (height - realh) / 2, preview)
return new_image
@ -205,6 +297,25 @@ def check_item_selected(list_widget, message):
return False
return True
def clean_tags(text):
"""
Remove Tags from text for display
"""
text = text.replace(u'<br>', u'\n')
for tag in html_expands:
text = text.replace(tag[u'start tag'], u'')
text = text.replace(tag[u'end tag'], u'')
return text
def expand_tags(text):
"""
Expand tags HTML for display
"""
for tag in html_expands:
text = text.replace(tag[u'start tag'], tag[u'start html'])
text = text.replace(tag[u'end tag'], tag[u'end html'])
return text
from eventreceiver import Receiver
from settingsmanager import SettingsManager
from plugin import PluginStatus, Plugin
@ -213,6 +324,7 @@ from settingstab import SettingsTab
from serviceitem import ServiceItem
from serviceitem import ServiceItemType
from serviceitem import ItemCapabilities
from htmlbuilder import build_html
from toolbar import OpenLPToolbar
from dockwidget import OpenLPDockWidget
from theme import ThemeLevel, ThemeXML

View File

@ -0,0 +1,445 @@
# -*- 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 #
# --------------------------------------------------------------------------- #
# 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 #
###############################################################################
from openlp.core.lib import image_to_byte
HTMLSRC = u"""
<html>
<head>
<title>OpenLP Display</title>
<style>
*{
margin: 0;
padding: 0;
border: 0;
}
body {
background-color: black;
}
.dim {
position: absolute;
left: 0px;
top: 0px;
width: %spx;
height: %spx;
}
#black {
z-index:8;
background-color: black;
display: none;
}
#video {
z-index:2;
}
#alert {
position: absolute;
left: 0px;
top: 0px;
z-index:10;
%s
}
#footer {
position: absolute;
z-index:5;
%s
}
/* lyric css */
%s
</style>
<script language="javascript">
var timer = null;
var transition = %s;
function show_video(state, path, volume, loop){
var vid = document.getElementById('video');
if(path != null)
vid.src = path;
if(loop != null){
if(loop)
vid.loop = 'loop';
else
vid.loop = '';
}
if(volume != null){
vid.volume = volume;
}
switch(state){
case 'play':
vid.play();
vid.style.display = 'block';
break;
case 'pause':
vid.pause();
vid.style.display = 'block';
break;
case 'stop':
vid.pause();
vid.style.display = 'none';
break;
case 'close':
vid.pause();
vid.style.display = 'none';
vid.src = '';
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 = '';
var pause = false;
switch(state){
case 'theme':
lyrics = 'hidden';
pause = true;
break;
case 'black':
black = 'block';
pause = true;
break;
case 'desktop':
pause = true;
break;
}
document.getElementById('black').style.display = black;
document.getElementById('lyricsmain').style.visibility = lyrics;
document.getElementById('lyricsoutline').style.visibility = lyrics;
document.getElementById('lyricsshadow').style.visibility = lyrics;
document.getElementById('footer').style.visibility = lyrics;
var vid = document.getElementById('video');
if(vid.src != ''){
if(pause)
vid.pause();
else
vid.play();
}
}
function show_alert(alerttext, position){
var text = document.getElementById('alert');
text.innerHTML = alerttext;
if(alerttext == '') {
text.style.visibility = 'hidden';
return 0;
}
if(position == ''){
position = window.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 show_footer(footertext){
document.getElementById('footer').innerHTML = footertext;
}
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)
clearTimeout(timer);
timer = setTimeout('text_fade()', 50);
}
function text_fade(){
var text1 = document.getElementById('lyricsmain');
var texto1 = document.getElementById('lyricsoutline');
var texts1 = document.getElementById('lyricsshadow');
var text2 = document.getElementById('lyricsmain2');
var texto2 = document.getElementById('lyricsoutline2');
var texts2 = document.getElementById('lyricsshadow2');
if(parseFloat(text1.style.opacity) < 1){
text1.style.opacity = parseFloat(text1.style.opacity) + 0.1;
texto1.style.opacity = parseFloat(texto1.style.opacity) + 0.1;
// Don't animate shadow (performance)
//texts1.style.opacity = parseFloat(texts1.style.opacity) + 0.1;
}
if(parseFloat(text2.style.opacity) > 0){
text2.style.opacity = parseFloat(text2.style.opacity) - 0.1;
texto2.style.opacity = parseFloat(texto2.style.opacity) - 0.1;
// Don't animate shadow (performance)
//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 {
text1.style.opacity = 1;
texto1.style.opacity = 1;
texts1.style.opacity = 1;
text2.style.opacity = 0;
texto2.style.opacity = 0;
texts2.style.opacity = 0;
}
}
function show_text_complete(){
return (document.getElementById('lyricsmain').style.opacity == 1);
}
</script>
</head>
<body>
<!--
Using tables, rather than div's to make use of the vertical-align style that
doesn't work on div's. This avoids the need to do positioning manually which
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>
<video class="dim" id="video"></video>
<div class="dim" id="black"></div>
<img class="dim" id="image" src="%s" />
</body>
</html>
"""
def build_html(item, screen, alert):
"""
Build the full web paged structure for display
`item`
Service Item to be displayed
`screen`
Current display information
`alert`
Alert display display information
"""
width = screen[u'size'].width()
height = screen[u'size'].height()
theme = item.themedata
if item.bg_frame:
image = u'data:image/png;base64,%s' % image_to_byte(item.bg_frame)
else:
image = u''
html = HTMLSRC % (width, height,
build_alert(alert, width),
build_footer(item),
build_lyrics(item),
u'true' if theme and theme.display_slideTransition \
else u'false',
image)
return html
def build_lyrics(item):
"""
Build the video display div
`item`
Service Item containing theme and location information
"""
style = """
.lyricscommon { position: absolute; %s }
.lyricstable { z-index:4; %s }
.lyricsoutlinetable { z-index:3; %s }
.lyricsshadowtable { z-index:2; %s }
.lyrics { %s }
.lyricsoutline { %s }
.lyricsshadow { %s }
"""
theme = item.themedata
lyricscommon = u''
lyricstable = u''
outlinetable = u''
shadowtable = u''
lyrics = u''
outline = u'display: none;'
shadow = u'display: none;'
if theme:
lyricscommon = u'width: %spx; height: %spx; word-wrap: break-word; ' \
u'font-family: %s; font-size: %spx; 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;' % \
(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:
align = u'text-align:center;'
elif theme.display_horizontalAlign == 1:
align = u'text-align:right;'
else:
align = u'text-align:left;'
if theme.display_verticalAlign == 2:
valign = u'vertical-align:bottom;'
elif theme.display_verticalAlign == 1:
valign = u'vertical-align:middle;'
else:
valign = u'vertical-align:top;'
lyrics = u'%s %s' % (align, valign)
if theme.display_outline:
lyricscommon += u' letter-spacing: 1px;'
outline = u'-webkit-text-stroke: %sem %s; ' % \
(float(theme.display_outline_size) / 16,
theme.display_outline_color)
if theme.display_shadow:
shadow = u'-webkit-text-stroke: %sem %s; ' \
u'-webkit-text-fill-color: %s; '% \
(float(theme.display_outline_size) / 16,
theme.display_shadow_color, theme.display_shadow_color)
else:
if theme.display_shadow:
shadow = u'color: %s;' % (theme.display_shadow_color)
lyrics_html = style % (lyricscommon, lyricstable, outlinetable,
shadowtable, lyrics, outline, shadow)
return lyrics_html
def build_footer(item):
"""
Build the display of the item footer
`item`
Service Item to be processed.
"""
style = """
left: %spx;
top: %spx;
width: %spx;
height: %spx;
font-family: %s;
font-size: %spx;
color: %s;
text-align: %s;
"""
theme = item.themedata
if not theme:
return u''
if theme.display_horizontalAlign == 2:
align = u'center'
elif theme.display_horizontalAlign == 1:
align = u'right'
else:
align = u'left'
lyrics_html = style % (item.footer.x(), item.footer.y(),
item.footer.width(), item.footer.height(), theme.font_footer_name,
theme.font_footer_proportion, theme.font_footer_color, align)
return lyrics_html
def build_alert(alertTab, width):
"""
Build the display of the footer
`alertTab`
Details from the Alert tab for fonts etc
"""
style = """
width: %s;
vertical-align: %s;
font-family: %s;
font-size: %spx;
color: %s;
background-color: %s;
"""
if not alertTab:
return u''
align = u''
if alertTab.location == 2:
align = u'bottom'
elif alertTab.location == 1:
align = u'middle'
else:
align = u'top'
alert = style % (width, align, alertTab.font_face, alertTab.font_size,
alertTab.font_color, alertTab.bg_color)
return alert

View File

@ -131,7 +131,6 @@ class Plugin(QtCore.QObject):
self.serviceManager = plugin_helpers[u'service']
self.settingsForm = plugin_helpers[u'settings form']
self.mediadock = plugin_helpers[u'toolbox']
self.displayManager = plugin_helpers[u'displaymanager']
self.pluginManager = plugin_helpers[u'pluginmanager']
self.formparent = plugin_helpers[u'formparent']
QtCore.QObject.connect(Receiver.get_receiver(),

View File

@ -31,7 +31,7 @@ import logging
from PyQt4 import QtGui, QtCore
from openlp.core.lib import resize_image
from openlp.core.lib import resize_image, expand_tags
log = logging.getLogger(__name__)
@ -80,7 +80,6 @@ class Renderer(object):
self.bg_image = None
self._bg_image_filename = None
self.theme_name = theme.theme_name
self._set_theme_font()
if theme.background_type == u'image':
if theme.background_filename:
self.set_bg_image(theme.background_filename)
@ -99,6 +98,20 @@ class Renderer(object):
self.frame.width(),
self.frame.height())
def set_text_rectangle(self, rect_main, rect_footer):
"""
Sets the rectangle within which text should be rendered.
``rect_main``
The main text block.
``rect_footer``
The footer text block.
"""
log.debug(u'set_text_rectangle %s , %s' % (rect_main, rect_footer))
self._rect = rect_main
self._rect_footer = rect_footer
def set_frame_dest(self, frame_width, frame_height, preview=False):
"""
Set the size of the slide.
@ -118,26 +131,24 @@ class Renderer(object):
frame_height)
self.frame = QtGui.QImage(frame_width, frame_height,
QtGui.QImage.Format_ARGB32_Premultiplied)
self.frame_opaque = QtGui.QImage(frame_width, frame_height,
QtGui.QImage.Format_ARGB32_Premultiplied)
if self._bg_image_filename and not self.bg_image:
self.bg_image = resize_image(self._bg_image_filename,
self.frame.width(), self.frame.height())
if self.bg_frame is None:
self._generate_background_frame()
def format_slide(self, words, footer):
def format_slide(self, words, line_break):
"""
Figure out how much text can appear on a slide, using the current
theme settings.
``words``
The words to be fitted on the slide.
``footer``
The footer of the slide.
"""
log.debug(u'format_slide - Start')
line_end = u''
if line_break:
line_end = u'<br>'
words = words.replace(u'\r\n', u'\n')
verses_text = words.split(u'\n')
text = []
@ -145,124 +156,43 @@ class Renderer(object):
lines = verse.split(u'\n')
for line in lines:
text.append(line)
split_text = self.pre_render_text(text)
log.debug(u'format_slide - End')
return split_text
def pre_render_text(self, text):
metrics = QtGui.QFontMetrics(self.main_font)
#work out line width
line_width = self._rect.width()
#number of lines on a page - adjust for rounding up.
line_height = metrics.height()
if self._theme.display_shadow:
line_height += int(self._theme.display_shadow_size)
if self._theme.display_outline:
# pixels top/bottom
line_height += 2 * int(self._theme.display_outline_size)
page_length = int(self._rect.height() / line_height )
#Average number of characters in line
ave_line_width = line_width / metrics.averageCharWidth()
#Maximum size of a character
max_char_width = metrics.maxWidth()
#Max characters pre line based on min size of a character
char_per_line = line_width / metrics.width(u'i')
log.debug(u'Page Length area height %s , metrics %s , lines %s' %
(int(self._rect.height()), metrics.height(), page_length ))
split_pages = []
page = []
split_lines = []
count = 0
for line in text:
#Must be a blank line so keep it.
if len(line) == 0:
line = u' '
while line:
pos = char_per_line
split_text = line[:pos]
#line needs splitting
if metrics.width(split_text, -1) > line_width:
#We have no spaces
if split_text.find(u' ') == -1:
#Move back 1 char at a time till it fits
while metrics.width(split_text, -1) > line_width:
split_text = split_text[:-1]
pos = len(split_text)
else:
#We have spaces so split at previous one
while metrics.width(split_text, -1) > line_width:
pos = split_text.rfind(u' ')
#no more spaces and we are still too long
if pos == -1:
while \
metrics.width(split_text, -1) > line_width:
split_text = split_text[:-1]
pos = len(split_text)
else:
split_text = line[:pos]
split_lines.append(split_text)
line = line[pos:].lstrip()
#if we have more text add up to 10 spaces on the front.
if line and self._theme.font_main_indentation > 0:
line = u'%s%s' % \
(u' '[:int(self._theme.font_main_indentation)],
line)
#Text fits in a line now
for count, line in enumerate(split_lines):
page.append(line)
#last but one line and only 2 lines to go or end of page
if (len(page) == page_length - 1 and
len(split_lines) - 3 == count) or \
len(page) == page_length:
split_pages.append(page)
page = []
if page and page != u' ':
split_pages.append(page)
return split_pages
def set_text_rectangle(self, rect_main, rect_footer):
"""
Sets the rectangle within which text should be rendered.
``rect_main``
The main text block.
``rect_footer``
The footer text block.
"""
log.debug(u'set_text_rectangle %s , %s' % (rect_main, rect_footer))
self._rect = rect_main
self._rect_footer = rect_footer
def generate_frame_from_lines(self, lines, footer_lines=None):
"""
Render a set of lines according to the theme, and return the block
dimensions.
``lines``
The lines to be rendered.
``footer_lines``
Defaults to *None*. The footer to render.
"""
log.debug(u'generate_frame_from_lines - Start')
bbox = self._render_lines_unaligned(lines, False)
if footer_lines:
bbox1 = self._render_lines_unaligned(footer_lines, True)
# reset the frame. first time do not worry about what you paint on.
self.frame = QtGui.QImage(self.bg_frame)
if self._theme.display_slideTransition:
self.frame_opaque = QtGui.QImage(self.bg_frame)
x, y = self._correct_alignment(self._rect, bbox)
bbox = self._render_lines_unaligned(lines, False, (x, y), True)
if footer_lines:
bbox = self._render_lines_unaligned(footer_lines, True,
(self._rect_footer.left(), self._rect_footer.top()), True)
log.debug(u'generate_frame_from_lines - Finish')
if self._theme.display_slideTransition:
return {u'main':self.frame, u'trans':self.frame_opaque}
doc = QtGui.QTextDocument()
doc.setPageSize(QtCore.QSizeF(self._rect.width(), self._rect.height()))
df = doc.defaultFont()
df.setPixelSize(self._theme.font_main_proportion)
df.setFamily(self._theme.font_main_name)
main_weight = 50
if self._theme.font_main_weight == u'Bold':
main_weight = 75
df.setWeight(main_weight)
doc.setDefaultFont(df)
layout = doc.documentLayout()
formatted = []
if self._theme.font_main_weight == u'Bold' and \
self._theme.font_main_italics:
shell = u'{p}{st}{it}%s{/it}{/st}{/p}'
elif self._theme.font_main_weight == u'Bold' and \
not self._theme.font_main_italics:
shell = u'{p}{st}%s{/st}{/p}'
elif self._theme.font_main_italics:
shell = u'{p}{it}%s{/it}{/p}'
else:
return {u'main':self.frame, u'trans':None}
shell = u'{p}%s{/p}'
temp_text = u''
old_html_text = u''
for line in text:
# mark line ends
temp_text = temp_text + line + line_end
html_text = shell % expand_tags(temp_text)
doc.setHtml(html_text)
# Text too long so gone to next mage
if layout.pageCount() != 1:
formatted.append(shell % old_html_text)
temp_text = line
old_html_text = temp_text
formatted.append(shell % old_html_text)
log.debug(u'format_slide - End')
return formatted
def _generate_background_frame(self):
"""
@ -270,327 +200,47 @@ class Renderer(object):
Results are cached for performance reasons.
"""
assert(self._theme)
if self._theme.background_mode == u'transparent':
self.bg_frame = \
QtGui.QPixmap(self.frame.width(), self.frame.height())
self.bg_frame.fill(QtCore.Qt.transparent)
else:
self.bg_frame = QtGui.QImage(self.frame.width(),
self.frame.height(), QtGui.QImage.Format_ARGB32_Premultiplied)
self.bg_frame = QtGui.QImage(self.frame.width(),
self.frame.height(), QtGui.QImage.Format_ARGB32_Premultiplied)
log.debug(u'render background %s start', self._theme.background_type)
painter = QtGui.QPainter()
painter.begin(self.bg_frame)
if self._theme.background_mode == u'transparent':
painter.fillRect(self.frame.rect(), QtCore.Qt.transparent)
else:
if self._theme.background_type == u'solid':
painter.fillRect(self.frame.rect(),
QtGui.QColor(self._theme.background_color))
elif self._theme.background_type == u'gradient':
# gradient
gradient = None
if self._theme.background_direction == u'horizontal':
w = int(self.frame.width()) / 2
# vertical
gradient = QtGui.QLinearGradient(w, 0, w,
self.frame.height())
elif self._theme.background_direction == u'vertical':
h = int(self.frame.height()) / 2
# Horizontal
gradient = QtGui.QLinearGradient(0, h, self.frame.width(),
h)
else:
w = int(self.frame.width()) / 2
h = int(self.frame.height()) / 2
# Circular
gradient = QtGui.QRadialGradient(w, h, w)
gradient.setColorAt(0,
QtGui.QColor(self._theme.background_startColor))
gradient.setColorAt(1,
QtGui.QColor(self._theme.background_endColor))
painter.setBrush(QtGui.QBrush(gradient))
rect_path = QtGui.QPainterPath()
max_x = self.frame.width()
max_y = self.frame.height()
rect_path.moveTo(0, 0)
rect_path.lineTo(0, max_y)
rect_path.lineTo(max_x, max_y)
rect_path.lineTo(max_x, 0)
rect_path.closeSubpath()
painter.drawPath(rect_path)
elif self._theme.background_type == u'image':
# image
painter.fillRect(self.frame.rect(), QtCore.Qt.black)
if self.bg_image:
painter.drawImage(0, 0, self.bg_image)
painter.end()
log.debug(u'render background End')
def _correct_alignment(self, rect, bbox):
"""
Corrects the vertical alignment of text.
``rect``
The block dimentions.
``bbox``
Footer dimensions?
"""
x = rect.left()
if self._theme.display_verticalAlign == 0:
# top align
y = rect.top()
elif self._theme.display_verticalAlign == 2:
# bottom align
y = rect.bottom() - bbox.height()
elif self._theme.display_verticalAlign == 1:
# centre align
y = rect.top() + (rect.height() - bbox.height()) / 2
else:
log.error(u'Invalid value for theme.VerticalAlign:%s',
self._theme.display_verticalAlign)
return x, y
def _render_lines_unaligned(self, lines, footer, tlcorner=(0, 0),
live=False):
"""
Given a list of lines to render, render each one in turn (using the
``_render_single_line`` fn - which may result in going off the bottom).
They are expected to be pre-arranged to less than a screenful (eg. by
using split_set_of_lines).
Returns the bounding box of the text as QRect.
``lines``
The lines of text to render.
``footer``
The slide footer.
``tlcorner``
Defaults to *``(0, 0)``*. Co-ordinates of the top left corner.
``live``
Defaults to *False*. Whether or not this is a live screen.
"""
x, y = tlcorner
brx = x
bry = y
for line in lines:
# render after current bottom, but at original left edge
# keep track of right edge to see which is biggest
(thisx, bry) = self._render_and_wrap_single_line(line, footer,
(x, bry), live)
if (thisx > brx):
brx = thisx
retval = QtCore.QRect(x, y, brx - x, bry - y)
if self._debug:
painter = QtGui.QPainter()
painter.begin(self.frame)
painter.setPen(QtGui.QPen(QtGui.QColor(0, 0, 255)))
painter.drawRect(retval)
painter.end()
return retval
def _render_and_wrap_single_line(self, line, footer, tlcorner=(0, 0),
live=False):
"""
Render a single line of words onto the DC, top left corner specified.
If the line is too wide for the context, it wraps, but right-aligns
the surplus words in the manner of song lyrics.
Returns the bottom-right corner (of what was rendered) as a tuple(x, y).
``line``
Line of text to be rendered.
``footer``
The footer of the slide.
``tlcorner``
Defaults to *``(0, 0)``*. The top left corner.
``live``
Defaults to *False*. Whether or not this is a live screen.
"""
x, y = tlcorner
maxx = self._rect.width()
maxy = self._rect.height()
lines = []
lines.append(line)
startx = x
starty = y
rightextent = None
self.painter = QtGui.QPainter()
self.painter.begin(self.frame)
self.painter.setRenderHint(QtGui.QPainter.Antialiasing)
if self._theme.display_slideTransition:
self.painter2 = QtGui.QPainter()
self.painter2.begin(self.frame_opaque)
self.painter2.setRenderHint(QtGui.QPainter.Antialiasing)
self.painter2.setOpacity(0.7)
# dont allow alignment messing with footers
if footer:
align = 0
display_shadow_size = self._display_shadow_size_footer
display_outline_size = self._display_outline_size_footer
else:
align = self._theme.display_horizontalAlign
display_shadow_size = int(self._theme.display_shadow_size)
display_outline_size = int(self._theme.display_outline_size)
for linenum in range(len(lines)):
line = lines[linenum]
#find out how wide line is
w, h = self._get_extent_and_render(line, footer, tlcorner=(x, y),
draw=False)
if self._theme.display_shadow:
w += display_shadow_size
h += display_shadow_size
if self._theme.display_outline:
# pixels either side
w += 2 * display_outline_size
# pixels top/bottom
h += 2 * display_outline_size
if align == 0: # left align
rightextent = x + w
# shift right from last line's rh edge
if self._theme.display_wrapStyle == 1 and linenum != 0:
rightextent = self._first_line_right_extent
if rightextent > maxx:
rightextent = maxx
x = rightextent - w
# right align
elif align == 1:
rightextent = maxx
x = maxx - w
# centre
elif align == 2:
x = (maxx - w) / 2
rightextent = x + w
if live:
# now draw the text, and any outlines/shadows
if self._theme.display_shadow:
self._get_extent_and_render(line, footer,
tlcorner=(x + display_shadow_size,
y + display_shadow_size),
draw=True, color=self._theme.display_shadow_color)
self._get_extent_and_render(line, footer, tlcorner=(x, y),
draw=True, outline_size=display_outline_size)
y += h
if linenum == 0:
self._first_line_right_extent = rightextent
# draw a box around the text - debug only
if self._debug:
self.painter.setPen(QtGui.QPen(QtGui.QColor(0, 255, 0)))
self.painter.drawRect(startx, starty, rightextent-startx, y-starty)
brcorner = (rightextent, y)
self.painter.end()
if self._theme.display_slideTransition:
self.painter2.end()
return brcorner
def _set_theme_font(self):
"""
Set the fonts from the current theme settings.
"""
footer_weight = 50
if self._theme.font_footer_weight == u'Bold':
footer_weight = 75
#TODO Add myfont.setPixelSize((screen_height / 100) * font_size)
self.footer_font = QtGui.QFont(self._theme.font_footer_name,
self._theme.font_footer_proportion, # size
footer_weight, # weight
self._theme.font_footer_italics) # italic
self.footer_font.setPixelSize(self._theme.font_footer_proportion)
main_weight = 50
if self._theme.font_main_weight == u'Bold':
main_weight = 75
self.main_font = QtGui.QFont(self._theme.font_main_name,
self._theme.font_main_proportion, # size
main_weight, # weight
self._theme.font_main_italics)# italic
self.main_font.setPixelSize(self._theme.font_main_proportion)
def _get_extent_and_render(self, line, footer, tlcorner=(0, 0), draw=False,
color=None, outline_size=0):
"""
Find bounding box of text - as render_single_line. If draw is set,
actually draw the text to the current DC as well return width and
height of text as a tuple (w, h).
``line``
The line of text to render.
``footer``
The footer text.
``tlcorner``
Defaults to *``(0, 0)``*. The top left corner co-ordinates.
``draw``
Defaults to *False*. Draw the text to the current surface.
``color``
Defaults to *None*. The colour to draw with.
"""
# setup defaults
if footer:
font = self.footer_font
else:
font = self.main_font
metrics = QtGui.QFontMetrics(font)
w = metrics.width(line)
if footer:
h = metrics.height()
else:
h = metrics.height() + int(self._theme.font_main_line_adjustment)
if draw:
self.painter.setFont(font)
if color is None:
if footer:
pen = QtGui.QColor(self._theme.font_footer_color)
else:
pen = QtGui.QColor(self._theme.font_main_color)
if self._theme.background_type == u'solid':
painter.fillRect(self.frame.rect(),
QtGui.QColor(self._theme.background_color))
elif self._theme.background_type == u'gradient':
# gradient
gradient = None
if self._theme.background_direction == u'horizontal':
w = int(self.frame.width()) / 2
# vertical
gradient = QtGui.QLinearGradient(w, 0, w, self.frame.height())
elif self._theme.background_direction == u'vertical':
h = int(self.frame.height()) / 2
# Horizontal
gradient = QtGui.QLinearGradient(0, h, self.frame.width(), h)
else:
pen = QtGui.QColor(color)
x, y = tlcorner
rowpos = y + metrics.ascent()
if self._theme.display_outline and outline_size != 0 and not footer:
path = QtGui.QPainterPath()
path.addText(QtCore.QPointF(x, rowpos), font, line)
self.painter.setBrush(self.painter.pen().brush())
self.painter.setPen(QtGui.QPen(QtGui.QColor(
self._theme.display_outline_color), outline_size))
self.painter.drawPath(path)
self.painter.setPen(pen)
self.painter.drawText(x, rowpos, line)
if self._theme.display_slideTransition:
# Print 2nd image with 70% weight
if self._theme.display_outline and outline_size != 0 and \
not footer:
path = QtGui.QPainterPath()
path.addText(QtCore.QPointF(x, rowpos), font, line)
self.painter2.setBrush(self.painter2.pen().brush())
self.painter2.setPen(QtGui.QPen(
QtGui.QColor(self._theme.display_outline_color),
outline_size))
self.painter2.drawPath(path)
self.painter2.setFont(font)
self.painter2.setPen(pen)
self.painter2.drawText(x, rowpos, line)
return (w, h)
def snoop_image(self, image, image2=None):
"""
Debugging method to allow images to be viewed.
``image``
An image to save to disk.
``image2``
Defaults to *None*. Another image to save to disk.
"""
image.save(u'renderer.png', u'png')
if image2:
image2.save(u'renderer2.png', u'png')
w = int(self.frame.width()) / 2
h = int(self.frame.height()) / 2
# Circular
gradient = QtGui.QRadialGradient(w, h, w)
gradient.setColorAt(0,
QtGui.QColor(self._theme.background_startColor))
gradient.setColorAt(1,
QtGui.QColor(self._theme.background_endColor))
painter.setBrush(QtGui.QBrush(gradient))
rect_path = QtGui.QPainterPath()
max_x = self.frame.width()
max_y = self.frame.height()
rect_path.moveTo(0, 0)
rect_path.lineTo(0, max_y)
rect_path.lineTo(max_x, max_y)
rect_path.lineTo(max_x, 0)
rect_path.closeSubpath()
painter.drawPath(rect_path)
elif self._theme.background_type == u'image':
# image
painter.fillRect(self.frame.rect(), QtCore.Qt.black)
if self.bg_image:
painter.drawImage(0, 0, self.bg_image)
painter.end()

View File

@ -28,7 +28,8 @@ import logging
from PyQt4 import QtCore
from openlp.core.lib import Renderer, ThemeLevel
from openlp.core.lib import Renderer, ThemeLevel, ServiceItem
from openlp.core.ui import MainDisplay
log = logging.getLogger(__name__)
@ -55,6 +56,8 @@ class RenderManager(object):
"""
log.debug(u'Initilisation started')
self.screens = screens
self.display = MainDisplay(self, screens, False)
self.display.setup()
self.theme_manager = theme_manager
self.renderer = Renderer()
self.calculate_default(self.screens.current[u'size'])
@ -63,6 +66,7 @@ class RenderManager(object):
self.theme_level = u''
self.override_background = None
self.themedata = None
self.alertTab = None
def update_display(self):
"""
@ -70,7 +74,10 @@ class RenderManager(object):
"""
log.debug(u'Update Display')
self.calculate_default(self.screens.current[u'size'])
self.display = MainDisplay(self, self.screens, False)
self.display.setup()
self.renderer.bg_frame = None
self.themedata = None
def set_global_theme(self, global_theme, theme_level=ThemeLevel.Global):
"""
@ -96,17 +103,22 @@ class RenderManager(object):
"""
self.service_theme = service_theme
def set_override_theme(self, theme):
def set_override_theme(self, theme, overrideLevels=False):
"""
Set the appropriate theme depending on the theme level.
Called by the service item when building a display frame
``theme``
The name of the song-level theme.
The name of the song-level theme. None means the service
item wants to use the given value.
"""
log.debug(u'set override theme to %s', theme)
if self.theme_level == ThemeLevel.Global:
theme_level = self.theme_level
if overrideLevels:
theme_level = ThemeLevel.Song
if theme_level == ThemeLevel.Global:
self.theme = self.global_theme
elif self.theme_level == ThemeLevel.Service:
elif theme_level == ThemeLevel.Service:
if self.service_theme == u'':
self.theme = self.global_theme
else:
@ -114,20 +126,26 @@ class RenderManager(object):
else:
if theme:
self.theme = theme
elif self.theme_level == ThemeLevel.Song or \
self.theme_level == ThemeLevel.Service:
elif theme_level == ThemeLevel.Song or \
theme_level == ThemeLevel.Service:
if self.service_theme == u'':
self.theme = self.global_theme
else:
self.theme = self.service_theme
else:
self.theme = self.global_theme
if self.theme != self.renderer.theme_name or self.themedata is None:
if self.theme != self.renderer.theme_name or self.themedata is None \
or overrideLevels:
log.debug(u'theme is now %s', self.theme)
self.themedata = self.theme_manager.getThemeData(self.theme)
if overrideLevels:
self.themedata = theme
else:
self.themedata = self.theme_manager.getThemeData(self.theme)
self.calculate_default(self.screens.current[u'size'])
self.renderer.set_theme(self.themedata)
self.build_text_rectangle(self.themedata)
self.renderer.set_frame_dest(self.width, self.height)
return self.renderer._rect, self.renderer._rect_footer
def build_text_rectangle(self, theme):
"""
@ -163,13 +181,8 @@ class RenderManager(object):
The theme to generated a preview for.
"""
log.debug(u'generate preview')
#set the default image size for previews
# set the default image size for previews
self.calculate_default(self.screens.preview[u'size'])
self.renderer.set_theme(themedata)
self.build_text_rectangle(themedata)
self.renderer.set_frame_dest(self.width, self.height, True)
#Reset the real screen size for subsequent render requests
self.calculate_default(self.screens.current[u'size'])
verse = u'Amazing Grace!\n'\
'How sweet the sound\n'\
'To save a wretch like me;\n'\
@ -179,12 +192,21 @@ class RenderManager(object):
footer.append(u'Amazing Grace (John Newton)' )
footer.append(u'Public Domain')
footer.append(u'CCLI 123456')
formatted = self.renderer.format_slide(verse, False)
#Only Render the first slide page returned
return self.renderer.generate_frame_from_lines(formatted[0],
footer)[u'main']
# build a service item to generate preview
serviceItem = ServiceItem()
serviceItem.theme = themedata
serviceItem.add_from_text(u'', verse, footer)
serviceItem.render_manager = self
serviceItem.raw_footer = footer
serviceItem.render(True)
self.display.buildHtml(serviceItem)
frame, raw_html = serviceItem.get_rendered_frame(0)
preview = self.display.text(raw_html)
# Reset the real screen size for subsequent render requests
self.calculate_default(self.screens.current[u'size'])
return preview
def format_slide(self, words):
def format_slide(self, words, line_break):
"""
Calculate how much text can fit on a slide.
@ -193,22 +215,7 @@ class RenderManager(object):
"""
log.debug(u'format slide')
self.build_text_rectangle(self.themedata)
return self.renderer.format_slide(words, False)
def generate_slide(self, main_text, footer_text):
"""
Generate the actual slide image.
``main_text``
The text for the main area of the slide.
``footer_text``
The text for the slide footer.
"""
log.debug(u'generate slide')
self.build_text_rectangle(self.themedata)
self.renderer.set_frame_dest(self.width, self.height)
return self.renderer.generate_frame_from_lines(main_text, footer_text)
return self.renderer.format_slide(words, line_break)
def calculate_default(self, screen):
"""

View File

@ -35,7 +35,7 @@ import uuid
from PyQt4 import QtGui
from openlp.core.lib import build_icon, resize_image
from openlp.core.lib import build_icon, resize_image, clean_tags, expand_tags
log = logging.getLogger(__name__)
@ -57,6 +57,7 @@ class ItemCapabilities(object):
RequiresMedia = 4
AllowsLoop = 5
AllowsAdditions = 6
NoLineBreaks = 7
class ServiceItem(object):
"""
@ -82,6 +83,7 @@ class ServiceItem(object):
self.items = []
self.iconic_representation = None
self.raw_footer = None
self.foot_text = None
self.theme = None
self.service_item_type = None
self._raw_frames = []
@ -91,10 +93,18 @@ class ServiceItem(object):
self.from_plugin = False
self.capabilities = []
self.is_valid = True
self.cache = {}
self.icon = None
self.themedata = None
self.main = None
self.footer = None
self.bg_frame = None
def _new_item(self):
"""
Method to set the internal id of the item
This is used to compare service items to see if they are
the same
"""
self._uuid = unicode(uuid.uuid1())
def add_capability(self, capability):
@ -126,34 +136,38 @@ class ServiceItem(object):
self.icon = icon
self.iconic_representation = build_icon(icon)
def render(self):
def render(self, useOverride=False):
"""
The render method is what generates the frames for the screen.
The render method is what generates the frames for the screen and
obtains the display information from the renderemanager.
At this point all the slides are build for the given
display size.
"""
log.debug(u'Render called')
self._display_frames = []
self.clear_cache()
self.bg_frame = None
line_break = True
if self.is_capable(ItemCapabilities.NoLineBreaks):
line_break = False
if self.service_item_type == ServiceItemType.Text:
log.debug(u'Formatting slides')
if self.theme is None:
self.render_manager.set_override_theme(None)
else:
self.render_manager.set_override_theme(self.theme)
theme = None
if self.theme:
theme = self.theme
self.main, self.footer = \
self.render_manager.set_override_theme(theme, useOverride)
self.bg_frame = self.render_manager.renderer.bg_frame
self.themedata = self.render_manager.renderer._theme
for slide in self._raw_frames:
before = time.time()
formated = self.render_manager.format_slide(slide[u'raw_slide'])
for format in formated:
lines = u''
title = u''
for line in format:
if title == u'':
title = line
lines += line + u'\n'
self._display_frames.append({u'title': title,
u'text': lines.rstrip(),
formated = self.render_manager \
.format_slide(slide[u'raw_slide'], line_break)
for page in formated:
self._display_frames.append(
{u'title': clean_tags(page),
u'text': clean_tags(page.rstrip()),
u'html': expand_tags(page.rstrip()),
u'verseTag': slide[u'verseTag'] })
if len(self._display_frames) in self.cache.keys():
del self.cache[len(self._display_frames)]
log.log(15, u'Formatting took %4s' % (time.time() - before))
elif self.service_item_type == ServiceItemType.Image:
for slide in self._raw_frames:
@ -163,29 +177,14 @@ class ServiceItem(object):
pass
else:
log.error(u'Invalid value renderer :%s' % self.service_item_type)
def render_individual(self, row):
"""
Takes an array of text and generates an Image from the
theme. It assumes the text will fit on the screen as it
has generated by the render method above.
"""
log.debug(u'render individual')
if self.theme is None:
self.render_manager.set_override_theme(None)
else:
self.render_manager.set_override_theme(self.theme)
format = self._display_frames[row][u'text'].split(u'\n')
if self.cache.get(row):
frame = self.cache[row]
else:
if format[0]:
frame = self.render_manager.generate_slide(format,
self.raw_footer)
else:
frame = self.render_manager.generate_slide(format, u'')
self.cache[row] = frame
return frame
self.title = clean_tags(self.title)
self.foot_text = None
if self.raw_footer:
for foot in self.raw_footer:
if not self.foot_text:
self.foot_text = foot
else:
self.foot_text = u'%s<br>%s' % (self.foot_text, foot)
def add_from_image(self, path, title, image):
"""
@ -375,9 +374,9 @@ class ServiceItem(object):
renders it if required.
"""
if self.service_item_type == ServiceItemType.Text:
return self.render_individual(row)
return None, self._display_frames[row][u'html'].split(u'\n')[0]
else:
return {u'main':self._raw_frames[row][u'image'], u'trans':None}
return self._raw_frames[row][u'image'], u''
def get_frame_title(self, row=0):
"""
@ -390,9 +389,3 @@ class ServiceItem(object):
Returns the title of the raw frame
"""
return self._raw_frames[row][u'path']
def clear_cache(self):
"""
Clear's the service item's cache.
"""
self.cache = {}

View File

@ -55,7 +55,6 @@ BLANK_THEME_XML = \
<proportion>30</proportion>
<weight>Normal</weight>
<italics>False</italics>
<indentation>0</indentation>
<line_adjustment>0</line_adjustment>
<location override="False" x="10" y="10" width="1004" height="730"/>
</font>
@ -65,7 +64,6 @@ BLANK_THEME_XML = \
<proportion>12</proportion>
<weight>Normal</weight>
<italics>False</italics>
<indentation>0</indentation>
<line_adjustment>0</line_adjustment>
<location override="False" x="10" y="730" width="1004" height="38"/>
</font>
@ -184,7 +182,7 @@ class ThemeXML(object):
self.child_element(background, u'filename', filename)
def add_font(self, name, color, proportion, override, fonttype=u'main',
weight=u'Normal', italics=u'False', indentation=0, line_adjustment=0,
weight=u'Normal', italics=u'False', line_adjustment=0,
xpos=0, ypos=0, width=0, height=0):
"""
Add a Font.
@ -210,9 +208,6 @@ class ThemeXML(object):
``italics``
Does the font render to italics Defaults to 0 Normal
``indentation``
Number of characters the wrap line is indented
``xpos``
The X position of the text block.
@ -239,8 +234,6 @@ class ThemeXML(object):
#Create italics name element
self.child_element(background, u'italics', italics)
#Create indentation name element
self.child_element(background, u'indentation', unicode(indentation))
#Create indentation name element
self.child_element(
background, u'line_adjustment', unicode(line_adjustment))

View File

@ -204,7 +204,7 @@ class Theme(object):
val = element_text
if (element.tag.find(u'Color') > 0 or
(element.tag.find(u'BackgroundParameter') == 0 and
isinstance(int, val))):
isinstance(val, int))):
# convert to a wx.Colour
if not delphi_color_change:
val = QtGui.QColor(

View File

@ -27,6 +27,143 @@
The :mod:`ui` module provides the core user interface for OpenLP
"""
# http://john.nachtimwald.com/2009/08/22/qplaintextedit-with-in-line-spell-check/
import re
import sys
try:
import enchant
enchant_available = True
except ImportError:
enchant_available = False
from PyQt4 import QtCore, QtGui
from openlp.core.lib import html_expands, translate, context_menu_action
class SpellTextEdit(QtGui.QPlainTextEdit):
def __init__(self, *args):
QtGui.QPlainTextEdit.__init__(self, *args)
# Default dictionary based on the current locale.
if enchant_available:
self.dict = enchant.Dict()
self.highlighter = Highlighter(self.document())
self.highlighter.setDict(self.dict)
def mousePressEvent(self, event):
if event.button() == QtCore.Qt.RightButton:
# Rewrite the mouse event to a left button event so the cursor is
# moved to the location of the pointer.
event = QtGui.QMouseEvent(QtCore.QEvent.MouseButtonPress, event.pos(),
QtCore.Qt.LeftButton, QtCore.Qt.LeftButton, QtCore.Qt.NoModifier)
QtGui.QPlainTextEdit.mousePressEvent(self, event)
def contextMenuEvent(self, event):
popup_menu = self.createStandardContextMenu()
# Select the word under the cursor.
cursor = self.textCursor()
cursor.select(QtGui.QTextCursor.WordUnderCursor)
self.setTextCursor(cursor)
# Check if the selected word is misspelled and offer spelling
# suggestions if it is.
if enchant_available and self.textCursor().hasSelection():
text = unicode(self.textCursor().selectedText())
if not self.dict.check(text):
spell_menu = QtGui.QMenu(translate('OpenLP.SpellTextEdit',
'Spelling Suggestions'))
for word in self.dict.suggest(text):
action = SpellAction(word, spell_menu)
action.correct.connect(self.correctWord)
spell_menu.addAction(action)
# Only add the spelling suggests to the menu if there are
# suggestions.
if len(spell_menu.actions()) != 0:
popup_menu.insertSeparator(popup_menu.actions()[0])
popup_menu.insertMenu(popup_menu.actions()[0], spell_menu)
tag_menu = QtGui.QMenu(translate('OpenLP.SpellTextEdit',
'Formatting Tags'))
for html in html_expands:
action = SpellAction( html[u'desc'], tag_menu)
action.correct.connect(self.htmlTag)
tag_menu.addAction(action)
popup_menu.insertSeparator(popup_menu.actions()[0])
popup_menu.insertMenu(popup_menu.actions()[0], tag_menu)
popup_menu.exec_(event.globalPos())
def correctWord(self, word):
'''
Replaces the selected text with word.
'''
cursor = self.textCursor()
cursor.beginEditBlock()
cursor.removeSelectedText()
cursor.insertText(word)
cursor.endEditBlock()
def htmlTag(self, tag):
'''
Replaces the selected text with word.
'''
for html in html_expands:
if tag == html[u'desc']:
cursor = self.textCursor()
if self.textCursor().hasSelection():
text = cursor.selectedText()
cursor.beginEditBlock()
cursor.removeSelectedText()
cursor.insertText(html[u'start tag'])
cursor.insertText(text)
cursor.insertText(html[u'end tag'])
cursor.endEditBlock()
else:
cursor = self.textCursor()
cursor.insertText(html[u'start tag'])
cursor.insertText(html[u'end tag'])
class Highlighter(QtGui.QSyntaxHighlighter):
WORDS = u'(?iu)[\w\']+'
def __init__(self, *args):
QtGui.QSyntaxHighlighter.__init__(self, *args)
self.dict = None
def setDict(self, dict):
self.dict = dict
def highlightBlock(self, text):
if not self.dict:
return
text = unicode(text)
format = QtGui.QTextCharFormat()
format.setUnderlineColor(QtCore.Qt.red)
format.setUnderlineStyle(QtGui.QTextCharFormat.SpellCheckUnderline)
for word_object in re.finditer(self.WORDS, text):
if not self.dict.check(word_object.group()):
self.setFormat(word_object.start(),
word_object.end() - word_object.start(), format)
class SpellAction(QtGui.QAction):
'''
A special QAction that returns the text in a signal.
'''
correct = QtCore.pyqtSignal(unicode)
def __init__(self, *args):
QtGui.QAction.__init__(self, *args)
self.triggered.connect(lambda x: self.correct.emit(
unicode(self.text())))
class HideMode(object):
"""
This is basically an enumeration class which specifies the mode of a Bible.
@ -37,13 +174,11 @@ class HideMode(object):
Theme = 2
Screen = 3
from maindisplay import MainDisplay
from slidecontroller import HideMode
from servicenoteform import ServiceNoteForm
from serviceitemeditform import ServiceItemEditForm
from screen import ScreenList
from maindisplay import MainDisplay
from maindisplay import VideoDisplay
from maindisplay import DisplayManager
from amendthemeform import AmendThemeForm
from slidecontroller import SlideController
from splashscreen import SplashScreen
@ -56,8 +191,7 @@ from settingsform import SettingsForm
from mediadockmanager import MediaDockManager
from servicemanager import ServiceManager
from thememanager import ThemeManager
from mainwindow import MainWindow
__all__ = ['SplashScreen', 'AboutForm', 'SettingsForm', 'MainWindow',
__all__ = ['SplashScreen', 'AboutForm', 'SettingsForm',
'MainDisplay', 'SlideController', 'ServiceManager', 'ThemeManager',
'AmendThemeForm', 'MediaDockManager', 'ServiceItemEditForm']

View File

@ -68,17 +68,6 @@ class Ui_AmendThemeDialog(object):
self.backgroundLayout.setMargin(8)
self.backgroundLayout.setSpacing(8)
self.backgroundLayout.setObjectName(u'backgroundLayout')
self.backgroundLabel = QtGui.QLabel(self.backgroundTab)
self.backgroundLabel.setObjectName(u'backgroundLabel')
self.backgroundLayout.setWidget(0, QtGui.QFormLayout.LabelRole,
self.backgroundLabel)
self.backgroundComboBox = QtGui.QComboBox(self.backgroundTab)
self.backgroundComboBox.setObjectName(u'backgroundComboBox')
self.backgroundLabel.setBuddy(self.backgroundComboBox)
self.backgroundComboBox.addItem(QtCore.QString())
self.backgroundComboBox.addItem(QtCore.QString())
self.backgroundLayout.setWidget(0, QtGui.QFormLayout.FieldRole,
self.backgroundComboBox)
self.backgroundTypeLabel = QtGui.QLabel(self.backgroundTab)
self.backgroundTypeLabel.setObjectName(u'backgroundTypeLabel')
self.backgroundLayout.setWidget(1, QtGui.QFormLayout.LabelRole,
@ -216,17 +205,6 @@ class Ui_AmendThemeDialog(object):
self.fontMainLineAdjustmentSpinBox.setMinimum(-99)
self.mainFontLayout.setWidget(4, QtGui.QFormLayout.FieldRole,
self.fontMainLineAdjustmentSpinBox)
self.fontMainWrapIndentationLabel = QtGui.QLabel(self.fontMainGroupBox)
self.fontMainWrapIndentationLabel.setObjectName(
u'fontMainWrapIndentationLabel')
self.mainFontLayout.setWidget(5, QtGui.QFormLayout.LabelRole,
self.fontMainWrapIndentationLabel)
self.fontMainLineSpacingSpinBox = QtGui.QSpinBox(self.fontMainGroupBox)
self.fontMainLineSpacingSpinBox.setObjectName(
u'fontMainLineSpacingSpinBox')
self.fontMainLineSpacingSpinBox.setMaximum(10)
self.mainFontLayout.setWidget(5, QtGui.QFormLayout.FieldRole,
self.fontMainLineSpacingSpinBox)
self.fontMainLinesPageLabel = QtGui.QLabel(self.fontMainGroupBox)
self.fontMainLinesPageLabel.setObjectName(u'fontMainLinesPageLabel')
self.mainFontLayout.addRow(self.fontMainLinesPageLabel)
@ -661,12 +639,6 @@ class Ui_AmendThemeDialog(object):
translate('OpenLP.AmendThemeForm', 'Theme Maintenance'))
self.themeNameLabel.setText(
translate('OpenLP.AmendThemeForm', 'Theme &name:'))
self.backgroundLabel.setText(
translate('OpenLP.AmendThemeForm', '&Visibility:'))
self.backgroundComboBox.setItemText(0,
translate('OpenLP.AmendThemeForm', 'Opaque'))
self.backgroundComboBox.setItemText(1,
translate('OpenLP.AmendThemeForm', 'Transparent'))
self.backgroundTypeLabel.setText(
translate('OpenLP.AmendThemeForm', 'Type:'))
self.backgroundTypeComboBox.setItemText(0,
@ -700,8 +672,6 @@ class Ui_AmendThemeDialog(object):
translate('OpenLP.AmendThemeForm', 'Size:'))
self.fontMainSizeSpinBox.setSuffix(
translate('OpenLP.AmendThemeForm', 'pt'))
self.fontMainWrapIndentationLabel.setText(
translate('OpenLP.AmendThemeForm', 'Wrap indentation:'))
self.fontMainWrapLineAdjustmentLabel.setText(
translate('OpenLP.AmendThemeForm', 'Adjust line spacing:'))
self.fontMainWeightComboBox.setItemText(0,

View File

@ -50,7 +50,6 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
self.path = None
self.theme = ThemeXML()
self.setupUi(self)
# define signals
# Buttons
QtCore.QObject.connect(self.color1PushButton,
QtCore.SIGNAL(u'pressed()'), self.onColor1PushButtonClicked)
@ -68,8 +67,6 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
QtCore.QObject.connect(self.imageToolButton,
QtCore.SIGNAL(u'clicked()'), self.onImageToolButtonClicked)
# Combo boxes
QtCore.QObject.connect(self.backgroundComboBox,
QtCore.SIGNAL(u'activated(int)'), self.onBackgroundComboBoxSelected)
QtCore.QObject.connect(self.backgroundTypeComboBox,
QtCore.SIGNAL(u'activated(int)'),
self.onBackgroundTypeComboBoxSelected)
@ -109,9 +106,6 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
QtCore.QObject.connect(self.fontMainLineAdjustmentSpinBox,
QtCore.SIGNAL(u'editingFinished()'),
self.onFontMainLineAdjustmentSpinBoxChanged)
QtCore.QObject.connect(self.fontMainLineSpacingSpinBox,
QtCore.SIGNAL(u'editingFinished()'),
self.onFontMainLineSpacingSpinBoxChanged)
QtCore.QObject.connect(self.fontFooterXSpinBox,
QtCore.SIGNAL(u'editingFinished()'),
self.onFontFooterXSpinBoxChanged)
@ -151,30 +145,26 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
new_theme.new_document(theme_name)
save_from = None
save_to = None
if self.theme.background_mode == u'transparent':
new_theme.add_background_transparent()
if self.theme.background_type == u'solid':
new_theme.add_background_solid(
unicode(self.theme.background_color))
elif self.theme.background_type == u'gradient':
new_theme.add_background_gradient(
unicode(self.theme.background_startColor),
unicode(self.theme.background_endColor),
self.theme.background_direction)
else:
if self.theme.background_type == u'solid':
new_theme.add_background_solid(
unicode(self.theme.background_color))
elif self.theme.background_type == u'gradient':
new_theme.add_background_gradient(
unicode(self.theme.background_startColor),
unicode(self.theme.background_endColor),
self.theme.background_direction)
else:
filename = \
os.path.split(unicode(self.theme.background_filename))[1]
new_theme.add_background_image(filename)
save_to = os.path.join(self.path, theme_name, filename)
save_from = self.theme.background_filename
filename = \
os.path.split(unicode(self.theme.background_filename))[1]
new_theme.add_background_image(filename)
save_to = os.path.join(self.path, theme_name, filename)
save_from = self.theme.background_filename
new_theme.add_font(unicode(self.theme.font_main_name),
unicode(self.theme.font_main_color),
unicode(self.theme.font_main_proportion),
unicode(self.theme.font_main_override), u'main',
unicode(self.theme.font_main_weight),
unicode(self.theme.font_main_italics),
unicode(self.theme.font_main_indentation),
unicode(self.theme.font_main_line_adjustment),
unicode(self.theme.font_main_x),
unicode(self.theme.font_main_y),
@ -186,7 +176,6 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
unicode(self.theme.font_footer_override), u'footer',
unicode(self.theme.font_footer_weight),
unicode(self.theme.font_footer_italics),
0, # indentation
0, # line adjustment
unicode(self.theme.font_footer_x),
unicode(self.theme.font_footer_y),
@ -230,7 +219,7 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
self.previewTheme()
#
#Main Font Tab
# Main Font Tab
#
def onFontMainComboBoxSelected(self):
self.theme.font_main_name = self.fontMainComboBox.currentFont().family()
@ -283,8 +272,6 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
self.fontMainHeightSpinBox.setValue(self.theme.font_main_height)
self.fontMainLineAdjustmentSpinBox.setValue(
self.theme.font_main_line_adjustment)
self.fontMainLineSpacingSpinBox.setValue(
self.theme.font_main_indentation)
self.stateChanging(self.theme)
self.previewTheme()
@ -310,20 +297,13 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
self.fontMainLineAdjustmentSpinBox.value()
self.previewTheme()
def onFontMainLineSpacingSpinBoxChanged(self):
if self.theme.font_main_indentation != \
self.fontMainLineSpacingSpinBox.value():
self.theme.font_main_indentation = \
self.fontMainLineSpacingSpinBox.value()
self.previewTheme()
def onFontMainHeightSpinBoxChanged(self):
if self.theme.font_main_height != self.fontMainHeightSpinBox.value():
self.theme.font_main_height = self.fontMainHeightSpinBox.value()
self.previewTheme()
#
#Footer Font Tab
# Footer Font Tab
#
def onFontFooterComboBoxSelected(self):
self.theme.font_footer_name = \
@ -404,20 +384,12 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
self.previewTheme()
#
#Background Tab
# Background Tab
#
def onGradientComboBoxSelected(self, currentIndex):
self.setBackground(self.backgroundTypeComboBox.currentIndex(),
currentIndex)
def onBackgroundComboBoxSelected(self, currentIndex):
if currentIndex == 0: # Opaque
self.theme.background_mode = u'opaque'
else:
self.theme.background_mode = u'transparent'
self.stateChanging(self.theme)
self.previewTheme()
def onBackgroundTypeComboBoxSelected(self, currentIndex):
self.setBackground(currentIndex, self.gradientComboBox.currentIndex())
@ -472,7 +444,7 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
self.previewTheme()
#
#Other Tab
# Other Tab
#
def onOutlineCheckBoxChanged(self, value):
if value == 2: # checked
@ -537,16 +509,12 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
self.previewTheme()
#
#Local Methods
# Local Methods
#
def paintUi(self, theme):
self.stateChanging(theme)
self.themeNameEdit.setText(self.theme.theme_name)
# Background Tab
if self.theme.background_mode == u'opaque':
self.backgroundComboBox.setCurrentIndex(0)
else:
self.backgroundComboBox.setCurrentIndex(1)
self.imageLineEdit.setText(u'')
if theme.background_type == u'solid':
self.backgroundTypeComboBox.setCurrentIndex(0)
@ -576,8 +544,6 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
self.fontMainWeightComboBox.setCurrentIndex(2)
else:
self.fontMainWeightComboBox.setCurrentIndex(3)
self.fontMainLineSpacingSpinBox.setValue(
self.theme.font_main_indentation)
self.fontMainXSpinBox.setValue(self.theme.font_main_x)
self.fontMainYSpinBox.setValue(self.theme.font_main_y)
self.fontMainWidthSpinBox.setValue(self.theme.font_main_width)
@ -641,9 +607,15 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
self.verticalComboBox.setCurrentIndex(self.theme.display_verticalAlign)
def stateChanging(self, theme):
if theme.background_mode == u'transparent':
self.color1Label.setVisible(False)
self.color1PushButton.setVisible(False)
self.backgroundTypeComboBox.setVisible(True)
self.backgroundTypeLabel.setVisible(True)
if theme.background_type == u'solid':
self.color1PushButton.setStyleSheet(
u'background-color: %s' % unicode(theme.background_color))
self.color1Label.setText(
translate('OpenLP.AmendThemeForm', 'Color:'))
self.color1Label.setVisible(True)
self.color1PushButton.setVisible(True)
self.color2Label.setVisible(False)
self.color2PushButton.setVisible(False)
self.imageLabel.setVisible(False)
@ -651,53 +623,34 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
self.imageFilenameWidget.setVisible(False)
self.gradientLabel.setVisible(False)
self.gradientComboBox.setVisible(False)
self.backgroundTypeComboBox.setVisible(False)
self.backgroundTypeLabel.setVisible(False)
else:
self.backgroundTypeComboBox.setVisible(True)
self.backgroundTypeLabel.setVisible(True)
if theme.background_type == u'solid':
self.color1PushButton.setStyleSheet(
u'background-color: %s' % unicode(theme.background_color))
self.color1Label.setText(
translate('OpenLP.AmendThemeForm', 'Color:'))
self.color1Label.setVisible(True)
self.color1PushButton.setVisible(True)
self.color2Label.setVisible(False)
self.color2PushButton.setVisible(False)
self.imageLabel.setVisible(False)
self.imageLineEdit.setVisible(False)
self.imageFilenameWidget.setVisible(False)
self.gradientLabel.setVisible(False)
self.gradientComboBox.setVisible(False)
elif theme.background_type == u'gradient':
self.color1PushButton.setStyleSheet(u'background-color: %s' \
% unicode(theme.background_startColor))
self.color2PushButton.setStyleSheet(u'background-color: %s' \
% unicode(theme.background_endColor))
self.color1Label.setText(
translate('OpenLP.AmendThemeForm', 'First color:'))
self.color2Label.setText(
translate('OpenLP.AmendThemeForm', 'Second color:'))
self.color1Label.setVisible(True)
self.color1PushButton.setVisible(True)
self.color2Label.setVisible(True)
self.color2PushButton.setVisible(True)
self.imageLabel.setVisible(False)
self.imageLineEdit.setVisible(False)
self.imageFilenameWidget.setVisible(False)
self.gradientLabel.setVisible(True)
self.gradientComboBox.setVisible(True)
else: # must be image
self.color1Label.setVisible(False)
self.color1PushButton.setVisible(False)
self.color2Label.setVisible(False)
self.color2PushButton.setVisible(False)
self.imageLabel.setVisible(True)
self.imageLineEdit.setVisible(True)
self.imageFilenameWidget.setVisible(True)
self.gradientLabel.setVisible(False)
self.gradientComboBox.setVisible(False)
elif theme.background_type == u'gradient':
self.color1PushButton.setStyleSheet(u'background-color: %s' \
% unicode(theme.background_startColor))
self.color2PushButton.setStyleSheet(u'background-color: %s' \
% unicode(theme.background_endColor))
self.color1Label.setText(
translate('OpenLP.AmendThemeForm', 'First color:'))
self.color2Label.setText(
translate('OpenLP.AmendThemeForm', 'Second color:'))
self.color1Label.setVisible(True)
self.color1PushButton.setVisible(True)
self.color2Label.setVisible(True)
self.color2PushButton.setVisible(True)
self.imageLabel.setVisible(False)
self.imageLineEdit.setVisible(False)
self.imageFilenameWidget.setVisible(False)
self.gradientLabel.setVisible(True)
self.gradientComboBox.setVisible(True)
else: # must be image
self.color1Label.setVisible(False)
self.color1PushButton.setVisible(False)
self.color2Label.setVisible(False)
self.color2PushButton.setVisible(False)
self.imageLabel.setVisible(True)
self.imageLineEdit.setVisible(True)
self.imageFilenameWidget.setVisible(True)
self.gradientLabel.setVisible(False)
self.gradientComboBox.setVisible(False)
if not theme.font_main_override:
self.fontMainXSpinBox.setEnabled(False)
self.fontMainYSpinBox.setEnabled(False)

View File

@ -390,26 +390,16 @@ class GeneralTab(SettingsTab):
unicode(self.screens.current[u'size'].width()))
self.overrideCheckBox.setChecked(settings.value(u'override position',
QtCore.QVariant(False)).toBool())
if self.overrideCheckBox.isChecked():
self.customXValueEdit.setText(settings.value(u'x position',
QtCore.QVariant(self.screens.current[u'size'].x())).toString())
self.customYValueEdit.setText(settings.value(u'y position',
QtCore.QVariant(self.screens.current[u'size'].y())).toString())
self.customHeightValueEdit.setText(
settings.value(u'height', QtCore.QVariant(
self.screens.current[u'size'].height())).toString())
self.customWidthValueEdit.setText(
settings.value(u'width', QtCore.QVariant(
self.screens.current[u'size'].width())).toString())
else:
self.customXValueEdit.setText(
unicode(self.screens.current[u'size'].x()))
self.customYValueEdit.setText(
unicode(self.screens.current[u'size'].y()))
self.customHeightValueEdit.setText(
unicode(self.screens.current[u'size'].height()))
self.customWidthValueEdit.setText(
unicode(self.screens.current[u'size'].width()))
self.customXValueEdit.setText(settings.value(u'x position',
QtCore.QVariant(self.screens.current[u'size'].x())).toString())
self.customYValueEdit.setText(settings.value(u'y position',
QtCore.QVariant(self.screens.current[u'size'].y())).toString())
self.customHeightValueEdit.setText(
settings.value(u'height', QtCore.QVariant(
self.screens.current[u'size'].height())).toString())
self.customWidthValueEdit.setText(
settings.value(u'width', QtCore.QVariant(
self.screens.current[u'size'].width())).toString())
settings.endGroup()
self.customXValueEdit.setEnabled(self.overrideCheckBox.isChecked())
self.customYValueEdit.setEnabled(self.overrideCheckBox.isChecked())
@ -436,10 +426,8 @@ class GeneralTab(SettingsTab):
QtCore.QVariant(self.saveCheckServiceCheckBox.isChecked()))
settings.setValue(u'auto preview',
QtCore.QVariant(self.autoPreviewCheckBox.isChecked()))
settings.setValue(u'loop delay',
settings.setValue(u'loop delay',
QtCore.QVariant(self.timeoutSpinBox.value()))
Receiver.send_message(u'slidecontroller_live_spin_delay',
self.timeoutSpinBox.value())
settings.setValue(u'ccli number',
QtCore.QVariant(self.numberEdit.displayText()))
settings.setValue(u'songselect username',
@ -459,17 +447,18 @@ class GeneralTab(SettingsTab):
settings.endGroup()
self.screens.display = self.displayOnMonitorCheck.isChecked()
# Monitor Number has changed.
postUpdate = False
if self.screens.monitor_number != self.monitorNumber:
self.screens.monitor_number = self.monitorNumber
self.screens.set_current_display(self.monitorNumber)
Receiver.send_message(u'config_screen_changed')
Receiver.send_message(u'config_updated')
postUpdate = True
# On save update the screens as well
self.postSetUp()
self.postSetUp(postUpdate)
def postSetUp(self):
def postSetUp(self, postUpdate=False):
"""
Apply settings after settings tab has loaded
Apply settings after settings tab has loaded and most of the
system so must be delayed
"""
Receiver.send_message(u'slidecontroller_live_spin_delay',
self.timeoutSpinBox.value())
@ -480,12 +469,15 @@ class GeneralTab(SettingsTab):
int(self.customYValueEdit.text()),
int(self.customWidthValueEdit.text()),
int(self.customHeightValueEdit.text()))
if self.overrideCheckBox.isChecked():
self.screens.set_override_display()
Receiver.send_message(u'config_screen_changed')
else:
self.screens.reset_current_display()
Receiver.send_message(u'config_screen_changed')
if self.overrideCheckBox.isChecked():
self.screens.set_override_display()
else:
self.screens.reset_current_display()
# Order is important so be careful if you change
if self.overrideChanged or postUpdate:
Receiver.send_message(u'config_screen_changed')
Receiver.send_message(u'config_updated')
self.overrideChanged = False
def onOverrideCheckBoxToggled(self, checked):
"""

View File

@ -26,149 +26,46 @@
import logging
import os
import time
from PyQt4 import QtCore, QtGui, QtWebKit
from PyQt4.phonon import Phonon
from openlp.core.lib import Receiver, resize_image
from openlp.core.lib import Receiver, resize_image, build_html, ServiceItem, \
image_to_byte
from openlp.core.ui import HideMode
log = logging.getLogger(__name__)
#http://www.steveheffernan.com/html5-video-player/demo-video-player.html
HTMLVIDEO = u"""<html>
<head>
<style>
*{
margin: 0;
padding:0
}
</style>
<script type="text/javascript" charset="utf-8">
var video;
var bodyLoaded = function(){
video = document.getElementById("video");
video.volume = 0;
}
</script>
</head>
<body id="body" onload="bodyLoaded();">
<video id="video" src="%s" autoplay="autoplay" loop="loop"
width="%s" height="%s" autobuffer="autobuffer" preload="preload" />
</body></html>
"""
class DisplayManager(QtGui.QWidget):
"""
Wrapper class to hold the display widgets.
I will provide API's in future to access the screens allow for
extra displays to be added.
RenderManager is poked in by MainWindow
"""
def __init__(self, screens):
QtGui.QWidget.__init__(self)
self.screens = screens
self.videoDisplay = VideoDisplay(self, screens)
self.audioPlayer = AudioPlayer(self)
self.mainDisplay = MainDisplay(self, screens)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'maindisplay_hide'), self.hideDisplay)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'maindisplay_show'), self.showDisplay)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'videodisplay_start'), self.onStartVideo)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'videodisplay_stop'), self.onStopVideo)
def setup(self):
self.videoDisplay.setup()
self.mainDisplay.setup()
def hideDisplay(self, message):
"""
Hide the output displays
"""
self.videoDisplay.mediaHide(message)
self.mainDisplay.hideDisplay(message)
def showDisplay(self):
"""
Hide the output displays
"""
self.videoDisplay.mediaShow()
self.mainDisplay.showDisplay()
def addAlert(self, alertMessage, location):
"""
Handles the addition of an Alert Message to the Displays
"""
self.mainDisplay.addAlert(alertMessage, location)
def displayImageWithText(self, frame):
"""
Handles the addition of a background Image to the displays
"""
self.mainDisplay.addImageWithText(frame)
def displayImage(self, frame):
"""
Handles the addition of a background Image to the displays
"""
self.mainDisplay.displayImage(frame)
def displayVideo(self, path):
"""
Handles the addition of a background Video to the displays
"""
self.mainDisplay.displayVideo(path)
def onStartVideo(self, item):
"""
Handles the Starting of a Video and Display Management
"""
self.videoDisplay.setVisible(True)
self.mainDisplay.setVisible(False)
self.videoDisplay.onMediaQueue(item)
def onStopVideo(self):
"""
Handles the Stopping of a Video and Display Management
"""
self.mainDisplay.setVisible(True)
self.videoDisplay.setVisible(False)
self.videoDisplay.onMediaStop()
def close(self):
"""
Handles the closure of the displays
"""
self.videoDisplay.close()
self.audioPlayer.close()
self.mainDisplay.close()
class DisplayWidget(QtGui.QGraphicsView):
"""
Customised version of QTableWidget which can respond to keyboard
events.
"""
log.info(u'MainDisplay loaded')
log.info(u'Display Widget loaded')
def __init__(self, parent=None, name=None, primary=False):
QtGui.QWidget.__init__(self, None)
def __init__(self, live, parent=None):
QtGui.QGraphicsView.__init__(self)
self.parent = parent
self.primary = primary
self.live = live
self.hotkey_map = {
QtCore.Qt.Key_Return: 'servicemanager_next_item',
QtCore.Qt.Key_Space: 'slidecontroller_live_next_noloop',
QtCore.Qt.Key_Enter: 'slidecontroller_live_next_noloop',
QtCore.Qt.Key_0: 'servicemanager_next_item',
QtCore.Qt.Key_Backspace: 'slidecontroller_live_previous_noloop'}
self.setStyleSheet(u'border: none;')
def keyPressEvent(self, event):
"""
Handle key events from display screen
"""
# Key events only needed for live
if not self.live:
return
if isinstance(event, QtGui.QKeyEvent):
#here accept the event and do something
# Here accept the event and do something
if event.key() == QtCore.Qt.Key_Up:
Receiver.send_message(u'slidecontroller_live_previous')
event.accept()
@ -185,157 +82,269 @@ class DisplayWidget(QtGui.QGraphicsView):
Receiver.send_message(self.hotkey_map[event.key()])
event.accept()
elif event.key() == QtCore.Qt.Key_Escape:
self.resetDisplay()
self.setVisible(False)
self.videoStop()
event.accept()
event.ignore()
else:
event.ignore()
def resetDisplay(self):
log.debug(u'resetDisplay')
Receiver.send_message(u'slidecontroller_live_stop_loop')
if self.primary:
self.setVisible(False)
else:
self.setVisible(True)
class MainDisplay(DisplayWidget):
"""
This is the form that is used to display things on the projector.
"""
log.info(u'MainDisplay Loaded')
def __init__(self, parent, screens):
"""
The constructor for the display form.
``parent``
The parent widget.
``screens``
The list of screens.
"""
log.debug(u'Initialisation started')
DisplayWidget.__init__(self, parent, primary=True)
self.setWindowFlags(QtCore.Qt.Window | QtCore.Qt.FramelessWindowHint)
self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
# WA_TranslucentBackground is not available in QT4.4
try:
self.setAttribute(QtCore.Qt.WA_TranslucentBackground)
except AttributeError:
pass
def __init__(self, parent, screens, live):
DisplayWidget.__init__(self, live, parent=None)
self.parent = parent
self.screens = screens
self.setupScene()
self.setupVideo()
self.setupImage()
self.setupText()
self.setupAlert()
self.setupBlank()
self.blankFrame = None
self.frame = None
#Hide desktop for now until we know where to put it
#and what size it should be.
self.setVisible(False)
self.isLive = live
self.alertTab = None
self.setWindowTitle(u'OpenLP Display')
self.setWindowFlags(QtCore.Qt.FramelessWindowHint |
QtCore.Qt.WindowStaysOnTopHint)
if self.isLive:
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'maindisplay_hide'), self.hideDisplay)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'maindisplay_show'), self.showDisplay)
def setup(self):
"""
Sets up the screen on a particular screen.
Set up and build the output screen
"""
log.debug(u'Setup %s for %s ' % (
self.screens, self.screens.monitor_number))
self.setVisible(False)
log.debug(u'Setup live = %s for %s ' % (self.isLive,
self.screens.monitor_number))
self.screen = self.screens.current
#Sort out screen locations and sizes
self.setVisible(False)
self.setGeometry(self.screen[u'size'])
self.scene.setSceneRect(0, 0, self.size().width(),
self.size().height())
self.webView.setGeometry(0, 0, self.size().width(),
self.size().height())
self.alertText.setTextWidth(self.size().width())
#Build a custom splash screen
self.initialFrame = QtGui.QImage(
self.screen[u'size'].width(),
self.screen[u'size'].height(),
QtGui.QImage.Format_ARGB32_Premultiplied)
splash_image = QtGui.QImage(u':/graphics/openlp-splash-screen.png')
painter_image = QtGui.QPainter()
painter_image.begin(self.initialFrame)
painter_image.fillRect(self.initialFrame.rect(), QtCore.Qt.white)
painter_image.drawImage(
(self.screen[u'size'].width() - splash_image.width()) / 2,
(self.screen[u'size'].height() - splash_image.height()) / 2,
splash_image)
#build a blank transparent image
self.transparent = QtGui.QPixmap(
self.screen[u'size'].width(), self.screen[u'size'].height())
self.transparent.fill(QtCore.Qt.transparent)
self.displayImage(self.initialFrame)
self.repaint()
#Build a Black screen
painter = QtGui.QPainter()
self.blankFrame = QtGui.QImage(
self.screen[u'size'].width(),
self.screen[u'size'].height(),
QtGui.QImage.Format_ARGB32_Premultiplied)
painter.begin(self.blankFrame)
painter.fillRect(self.blankFrame.rect(), QtCore.Qt.black)
# To display or not to display?
if not self.screen[u'primary']:
self.setVisible(True)
self.primary = False
else:
self.setVisible(False)
self.primary = True
def setupScene(self):
self.scene = QtGui.QGraphicsScene(self)
self.scene.setSceneRect(0, 0, self.size().width(), self.size().height())
self.setScene(self.scene)
def setupVideo(self):
self.webView = QtWebKit.QWebView()
self.webView = QtWebKit.QWebView(self)
self.webView.setGeometry(0, 0, self.screen[u'size'].width(), \
self.screen[u'size'].height())
self.page = self.webView.page()
self.videoDisplay = self.page.mainFrame()
self.videoDisplay.setScrollBarPolicy(QtCore.Qt.Vertical,
self.frame = self.page.mainFrame()
QtCore.QObject.connect(self.webView,
QtCore.SIGNAL(u'loadFinished(bool)'), self.isLoaded)
self.frame.setScrollBarPolicy(QtCore.Qt.Vertical,
QtCore.Qt.ScrollBarAlwaysOff)
self.videoDisplay.setScrollBarPolicy(QtCore.Qt.Horizontal,
self.frame.setScrollBarPolicy(QtCore.Qt.Horizontal,
QtCore.Qt.ScrollBarAlwaysOff)
self.proxy = QtGui.QGraphicsProxyWidget()
self.proxy.setWidget(self.webView)
self.proxy.setWindowFlags(QtCore.Qt.Window |
QtCore.Qt.FramelessWindowHint)
self.proxy.setZValue(1)
self.scene.addItem(self.proxy)
if self.isLive:
# Build the initial frame.
self.black = QtGui.QImage(
self.screens.current[u'size'].width(),
self.screens.current[u'size'].height(),
QtGui.QImage.Format_ARGB32_Premultiplied)
painter_image = QtGui.QPainter()
painter_image.begin(self.black)
painter_image.fillRect(self.black.rect(), QtCore.Qt.black)
#Build the initial frame.
initialFrame = QtGui.QImage(
self.screens.current[u'size'].width(),
self.screens.current[u'size'].height(),
QtGui.QImage.Format_ARGB32_Premultiplied)
splash_image = QtGui.QImage(u':/graphics/openlp-splash-screen.png')
painter_image = QtGui.QPainter()
painter_image.begin(initialFrame)
painter_image.fillRect(initialFrame.rect(), QtCore.Qt.white)
painter_image.drawImage(
(self.screens.current[u'size'].width() \
- splash_image.width()) / 2,
(self.screens.current[u'size'].height() \
- splash_image.height()) / 2,
splash_image)
serviceItem = ServiceItem()
serviceItem.bg_frame = initialFrame
self.webView.setHtml(build_html(serviceItem, self.screen, \
self.parent.alertTab))
self.initialFrame = True
self.show()
# To display or not to display?
if not self.screen[u'primary']:
self.primary = False
else:
self.primary = True
def setupImage(self):
self.imageDisplay = QtGui.QGraphicsPixmapItem()
self.imageDisplay.setZValue(2)
self.scene.addItem(self.imageDisplay)
def text(self, slide):
"""
Add the slide text from slideController
def setupText(self):
#self.displayText = QtGui.QGraphicsTextItem()
self.displayText = QtGui.QGraphicsPixmapItem()
#self.displayText.setPos(0,0)
#self.displayText.setTextWidth(self.size().width())
self.displayText.setZValue(4)
self.scene.addItem(self.displayText)
`slide`
The slide text to be displayed
"""
log.debug(u'text')
self.frame.evaluateJavaScript(u'show_text("%s")' % \
slide.replace(u'\\', u'\\\\').replace(u'\"', u'\\\"'))
return self.preview()
def setupAlert(self):
self.alertText = QtGui.QGraphicsTextItem()
self.alertText.setZValue(8)
self.scene.addItem(self.alertText)
def alert(self, text):
"""
Add the alert text
def setupBlank(self):
self.displayBlank = QtGui.QGraphicsPixmapItem()
self.displayBlank.setZValue(10)
self.scene.addItem(self.displayBlank)
`slide`
The slide text to be displayed
"""
log.debug(u'alert')
if self.height() != self.screen[u'size'].height() \
or not self.isVisible():
shrink = True
else:
shrink = False
js = u'show_alert("%s", "%s")' % (
text.replace(u'\\', u'\\\\').replace(u'\"', u'\\\"'),
u'top' if shrink else u'')
height = self.frame.evaluateJavaScript(js)
if shrink:
if text:
self.resize(self.width(), int(height.toString()))
self.setVisible(True)
else:
self.setGeometry(self.screen[u'size'])
self.setVisible(False)
# def hideDisplayForVideo(self):
# """
# Hides the main display if for the video to be played
# """
# self.hideDisplay(HideMode.Screen)
def image(self, image):
"""
Add an image as the background. The image is converted to a
bytestream on route.
`Image`
The Image to be displayed can be QImage or QPixmap
"""
log.debug(u'image')
image = resize_image(image, self.screen[u'size'].width(),
self.screen[u'size'].height())
self.resetVideo()
self.displayImage(image)
# show screen
if self.isLive:
self.setVisible(True)
def displayImage(self, image):
"""
Display an image, as is.
"""
if image:
js = u'show_image("data:image/png;base64,%s");' % \
image_to_byte(image)
else:
js = u'show_image("");'
self.frame.evaluateJavaScript(js)
def resetImage(self):
"""
Reset the backgound image to the service item image.
Used after Image plugin has changed the background
"""
log.debug(u'resetImage')
self.displayImage(self.serviceItem.bg_frame)
def resetVideo(self):
"""
Used after Video plugin has changed the background
"""
log.debug(u'resetVideo')
self.frame.evaluateJavaScript(u'show_video("close");')
def videoPlay(self):
"""
Responds to the request to play a loaded video
"""
log.debug(u'videoPlay')
self.frame.evaluateJavaScript(u'show_video("play");')
# show screen
if self.isLive:
self.setVisible(True)
def videoPause(self):
"""
Responds to the request to pause a loaded video
"""
log.debug(u'videoPause')
self.frame.evaluateJavaScript(u'show_video("pause");')
def videoStop(self):
"""
Responds to the request to stop a loaded video
"""
log.debug(u'videoStop')
self.frame.evaluateJavaScript(u'show_video("stop");')
def videoVolume(self, volume):
"""
Changes the volume of a running video
"""
log.debug(u'videoVolume %d' % volume)
self.frame.evaluateJavaScript(u'show_video(null, null, %s);' %
str(float(volume)/float(10)))
def video(self, videoPath, volume):
"""
Loads and starts a video to run with the option of sound
"""
log.debug(u'video')
self.loaded = True
js = u'show_video("play", "%s", %s, true);' % \
(videoPath.replace(u'\\', u'\\\\'), str(float(volume)/float(10)))
self.frame.evaluateJavaScript(js)
return self.preview()
def isLoaded(self):
"""
Called by webView event to show display is fully loaded
"""
log.debug(u'loaded')
self.loaded = True
def preview(self):
"""
Generates a preview of the image displayed.
"""
log.debug(u'preview for %s', self.isLive)
# Wait for the fade to finish before geting the preview.
# Important otherwise preview will have incorrect text if at all !
if self.serviceItem.themedata and \
self.serviceItem.themedata.display_slideTransition:
while self.frame.evaluateJavaScript(u'show_text_complete()') \
.toString() == u'false':
Receiver.send_message(u'openlp_process_events')
# Wait for the webview to update before geting the preview.
# Important otherwise first preview will miss the background !
while not self.loaded:
Receiver.send_message(u'openlp_process_events')
preview = QtGui.QImage(self.screen[u'size'].width(),
self.screen[u'size'].height(),
QtGui.QImage.Format_ARGB32_Premultiplied)
painter = QtGui.QPainter(preview)
painter.setRenderHint(QtGui.QPainter.Antialiasing)
self.frame.render(painter)
painter.end()
# Make display show up if in single screen mode
if self.isLive:
self.setVisible(True)
# save preview for debugging
if log.isEnabledFor(logging.DEBUG):
preview.save(u'temp.png', u'png')
return preview
def buildHtml(self, serviceItem):
"""
Store the serviceItem and build the new HTML from it. Add the
HTML to the display
"""
log.debug(u'buildHtml')
self.loaded = False
self.initialFrame = False
self.serviceItem = serviceItem
html = build_html(self.serviceItem, self.screen, self.parent.alertTab)
self.webView.setHtml(html)
if serviceItem.foot_text and serviceItem.foot_text:
self.footer(serviceItem.foot_text)
def footer(self, text):
"""
Display the Footer
"""
log.debug(u'footer')
js = "show_footer('" + \
text.replace("\\", "\\\\").replace("\'", "\\\'") + "')"
self.frame.evaluateJavaScript(js)
def hideDisplay(self, mode=HideMode.Screen):
"""
@ -343,20 +352,13 @@ class MainDisplay(DisplayWidget):
Store the images so they can be replaced when required
"""
log.debug(u'hideDisplay mode = %d', mode)
#self.displayText.setPixmap(self.transparent)
if mode == HideMode.Screen:
#self.display_image.setPixmap(self.transparent)
self.frame.evaluateJavaScript(u'show_blank("desktop");')
self.setVisible(False)
elif mode == HideMode.Blank:
self.displayBlank.setPixmap(
QtGui.QPixmap.fromImage(self.blankFrame))
elif mode == HideMode.Blank or self.initialFrame:
self.frame.evaluateJavaScript(u'show_blank("black");')
else:
if self.parent.renderManager.renderer.bg_frame:
self.displayBlank.setPixmap(QtGui.QPixmap.fromImage(
self.parent.renderManager.renderer.bg_frame))
else:
self.displayBlank.setPixmap(
QtGui.QPixmap.fromImage(self.blankFrame))
self.frame.evaluateJavaScript(u'show_blank("theme");')
if mode != HideMode.Screen and self.isHidden():
self.setVisible(True)
@ -367,275 +369,16 @@ class MainDisplay(DisplayWidget):
Make the stored images None to release memory.
"""
log.debug(u'showDisplay')
self.displayBlank.setPixmap(self.transparent)
self.frame.evaluateJavaScript('show_blank("show");')
if self.isHidden():
self.setVisible(True)
#Trigger actions when display is active again
# Trigger actions when display is active again
Receiver.send_message(u'maindisplay_active')
def addImageWithText(self, frame):
log.debug(u'addImageWithText')
frame = resize_image(
frame, self.screen[u'size'].width(), self.screen[u'size'].height())
self.imageDisplay.setPixmap(QtGui.QPixmap.fromImage(frame))
self.videoDisplay.setHtml(u'<html></html>')
def addAlert(self, message, location):
"""
Places the Alert text on the display at the correct location
``message``
Text to be displayed
``location``
Where on the screen the text should be. From the AlertTab
Combo box.
"""
log.debug(u'addAlertImage')
if location == 0:
self.alertText.setPos(0, 0)
elif location == 1:
self.alertText.setPos(0, self.size().height() / 2)
else:
self.alertText.setPos(0, self.size().height() - 76)
self.alertText.setHtml(message)
def displayImage(self, frame):
"""
Places the Image passed on the display screen
``frame``
The image to be displayed
"""
log.debug(u'adddisplayImage')
if isinstance(frame, QtGui.QImage):
self.imageDisplay.setPixmap(QtGui.QPixmap.fromImage(frame))
else:
self.imageDisplay.setPixmap(frame)
self.frameView(self.transparent)
self.videoDisplay.setHtml(u'<html></html>')
def displayVideo(self, path):
"""
Places the Video passed on the display screen
``path``
The path to the image to be displayed
"""
log.debug(u'adddisplayVideo')
self.displayImage(self.transparent)
self.videoDisplay.setHtml(HTMLVIDEO %
(path, self.screen[u'size'].width(),
self.screen[u'size'].height()))
def frameView(self, frame, transition=False):
"""
Called from a slide controller to display a frame
if the alert is in progress the alert is added on top
``frame``
Image frame to be rendered
``transition``
Are transitions required.
"""
log.debug(u'frameView')
if transition:
if self.frame is not None:
self.displayText.setPixmap(
QtGui.QPixmap.fromImage(self.frame))
self.repaint()
Receiver.send_message(u'openlp_process_events')
time.sleep(0.1)
self.frame = None
if frame[u'trans'] is not None:
self.displayText.setPixmap(
QtGui.QPixmap.fromImage(frame[u'trans']))
self.repaint()
Receiver.send_message(u'openlp_process_events')
time.sleep(0.1)
self.frame = frame[u'trans']
self.displayText.setPixmap(
QtGui.QPixmap.fromImage(frame[u'main']))
else:
if isinstance(frame, QtGui.QPixmap):
self.displayText.setPixmap(frame)
else:
self.displayText.setPixmap(QtGui.QPixmap.fromImage(frame))
if not self.isVisible() and self.screens.current['primary']:
self.setVisible(True)
class VideoDisplay(Phonon.VideoWidget):
"""
This is the form that is used to display videos on the projector.
"""
log.info(u'VideoDisplay Loaded')
def __init__(self, parent, screens,
aspect=Phonon.VideoWidget.AspectRatioWidget):
"""
The constructor for the display form.
``parent``
The parent widget.
``screens``
The list of screens.
"""
log.debug(u'VideoDisplay Initialisation started')
Phonon.VideoWidget.__init__(self)
self.setWindowTitle(u'OpenLP Video Display')
self.parent = parent
self.screens = screens
self.hidden = False
self.message = None
self.mediaActive = False
self.mediaObject = Phonon.MediaObject()
self.setAspectRatio(aspect)
self.audioObject = Phonon.AudioOutput(Phonon.VideoCategory)
Phonon.createPath(self.mediaObject, self)
Phonon.createPath(self.mediaObject, self.audioObject)
flags = QtCore.Qt.FramelessWindowHint | QtCore.Qt.Dialog
## # WindowsStaysOnBottomHint is not available in QT4.4
# try:
# flags = flags | QtCore.Qt.WindowStaysOnBottomHint
# except AttributeError:
# pass
self.setWindowFlags(flags)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'videodisplay_play'), self.onMediaPlay)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'videodisplay_pause'), self.onMediaPause)
# QtCore.QObject.connect(Receiver.get_receiver(),
# QtCore.SIGNAL(u'videodisplay_background'), self.onMediaBackground)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'config_updated'), self.setup)
QtCore.QObject.connect(self.mediaObject,
QtCore.SIGNAL(u'finished()'), self.onMediaStop)
self.setVisible(False)
def keyPressEvent(self, event):
if isinstance(event, QtGui.QKeyEvent):
#here accept the event and do something
if event.key() == QtCore.Qt.Key_Escape:
self.onMediaStop()
event.accept()
event.ignore()
else:
event.ignore()
def setup(self):
"""
Sets up the screen on a particular screen.
"""
log.debug(u'VideoDisplay Setup %s for %s ' % (self.screens,
self.screens.monitor_number))
self.screen = self.screens.current
#Sort out screen locations and sizes
self.setGeometry(self.screen[u'size'])
# To display or not to display?
if not self.screen[u'primary']: # and self.isVisible():
#self.showFullScreen()
self.setVisible(False)
self.primary = False
else:
self.setVisible(False)
self.primary = True
def closeEvent(self, event):
"""
Shutting down so clean up connections
"""
self.onMediaStop()
for path in self.outputPaths():
path.disconnect()
# def onMediaBackground(self, message=None):
# """
# Play a video triggered from the video plugin with the
# file name passed in on the event.
# Also triggered from the Finish event so the video will loop
# if it is triggered from the plugin
# """
# log.debug(u'VideoDisplay Queue new media message %s' % message)
# #If not file take the stored one
# if not message:
# message = self.message
# # still no file name then stop as it was a normal video stopping
# if message:
# self.mediaObject.setCurrentSource(Phonon.MediaSource(message))
# self.message = message
# self._play()
def onMediaQueue(self, message):
"""
Set up a video to play from the serviceitem.
"""
log.debug(u'VideoDisplay Queue new media message %s' % message)
file = os.path.join(message.get_frame_path(),
message.get_frame_title())
self.mediaObject.setCurrentSource(Phonon.MediaSource(file))
self.mediaActive = True
self._play()
def onMediaPlay(self):
"""
Respond to the Play button on the slide controller unless the display
has been hidden by the slidecontroller
"""
if not self.hidden:
log.debug(u'VideoDisplay Play the new media, Live ')
self._play()
def _play(self):
"""
We want to play the video so start it and display the screen
"""
log.debug(u'VideoDisplay _play called')
self.mediaObject.play()
self.setVisible(True)
def onMediaPause(self):
"""
Pause the video and refresh the screen
"""
log.debug(u'VideoDisplay Media paused by user')
self.mediaObject.pause()
self.show()
def onMediaStop(self):
"""
Stop the video and clean up
"""
log.debug(u'VideoDisplay Media stopped by user')
self.message = None
self.mediaActive = False
self.mediaObject.stop()
self.onMediaFinish()
def onMediaFinish(self):
"""
Clean up the Object queue
"""
log.debug(u'VideoDisplay Reached end of media playlist')
self.mediaObject.clearQueue()
self.setVisible(False)
def mediaHide(self, message=u''):
"""
Hide the video display
"""
self.mediaObject.pause()
self.hidden = True
self.setVisible(False)
def mediaShow(self):
"""
Show the video display if it was already hidden
"""
if self.hidden:
self.hidden = False
if self.mediaActive:
self._play()
class AudioPlayer(QtCore.QObject):
"""
This Class will play audio only allowing components to work with a
soundtrack which does not take over the user interface.
soundtrack independent of the user interface.
"""
log.info(u'AudioPlayer Loaded')
@ -675,9 +418,9 @@ class AudioPlayer(QtCore.QObject):
Set up a video to play from the serviceitem.
"""
log.debug(u'AudioPlayer Queue new media message %s' % message)
file = os.path.join(message[0].get_frame_path(),
mfile = os.path.join(message[0].get_frame_path(),
message[0].get_frame_title())
self.mediaObject.setCurrentSource(Phonon.MediaSource(file))
self.mediaObject.setCurrentSource(Phonon.MediaSource(mfile))
self.onMediaPlay()
def onMediaPlay(self):

View File

@ -29,7 +29,7 @@ import logging
from PyQt4 import QtCore, QtGui
from openlp.core.ui import AboutForm, SettingsForm, ServiceManager, \
ThemeManager, SlideController, PluginForm, MediaDockManager, DisplayManager
ThemeManager, SlideController, PluginForm, MediaDockManager
from openlp.core.lib import RenderManager, build_icon, OpenLPDockWidget, \
SettingsManager, PluginManager, Receiver, translate
from openlp.core.utils import AppLocation, add_actions, LanguageManager
@ -94,8 +94,8 @@ class Ui_MainWindow(object):
self.ControlSplitter.setObjectName(u'ControlSplitter')
self.MainContentLayout.addWidget(self.ControlSplitter)
# Create slide controllers
self.PreviewController = SlideController(self, self.settingsmanager)
self.LiveController = SlideController(self, self.settingsmanager, True)
self.PreviewController = SlideController(self, self.settingsmanager, self.screens)
self.LiveController = SlideController(self, self.settingsmanager, self.screens, True)
# Create menu
self.MenuBar = QtGui.QMenuBar(MainWindow)
self.MenuBar.setGeometry(QtCore.QRect(0, 0, 1087, 27))
@ -509,7 +509,6 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.songsSettingsSection = u'songs'
self.serviceNotSaved = False
self.settingsmanager = SettingsManager(screens)
self.displayManager = DisplayManager(screens)
self.aboutForm = AboutForm(self, applicationVersion)
self.settingsForm = SettingsForm(self.screens, self, self)
self.recentFiles = QtCore.QStringList()
@ -594,7 +593,6 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
#ThemeManager needs to call RenderManager
self.RenderManager = RenderManager(
self.ThemeManagerContents, self.screens)
self.displayManager.renderManager = self.RenderManager
#Define the media Dock Manager
self.mediaDockManager = MediaDockManager(self.MediaToolBox)
log.info(u'Load Plugins')
@ -605,7 +603,6 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.plugin_helpers[u'service'] = self.ServiceManagerContents
self.plugin_helpers[u'settings form'] = self.settingsForm
self.plugin_helpers[u'toolbox'] = self.mediaDockManager
self.plugin_helpers[u'displaymanager'] = self.displayManager
self.plugin_helpers[u'pluginmanager'] = self.plugin_manager
self.plugin_helpers[u'formparent'] = self
self.plugin_manager.find_plugins(pluginpath, self.plugin_helpers)
@ -652,8 +649,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
version_text = unicode(translate('OpenLP.MainWindow',
'Version %s of OpenLP is now available for download (you are '
'currently running version %s). \n\nYou can download the latest '
'version from '
'<a href="http://openlp.org/">http://openlp.org/</a>.'))
'version from http://openlp.org/.'))
QtGui.QMessageBox.question(self,
translate('OpenLP.MainWindow', 'OpenLP Version Updated'),
version_text % (version, self.applicationVersion[u'full']))
@ -663,9 +659,10 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
Show the main form, as well as the display form
"""
QtGui.QWidget.show(self)
self.displayManager.setup()
if self.displayManager.mainDisplay.isVisible():
self.displayManager.mainDisplay.setFocus()
self.LiveController.display.setup()
self.PreviewController.display.setup()
if self.LiveController.display.isVisible():
self.LiveController.display.setFocus()
self.activateWindow()
if QtCore.QSettings().value(
self.generalSettingsSection + u'/auto open',
@ -745,8 +742,8 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
The screen has changed to so tell the displays to update_display
their locations
"""
log.debug(u'screenChanged')
self.RenderManager.update_display()
self.displayManager.setup()
self.setFocus()
self.activateWindow()
@ -792,8 +789,8 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.plugin_manager.finalise_plugins()
# Save settings
self.saveSettings()
#Close down the displays
self.displayManager.close()
#Close down the display
self.LiveController.display.close()
def serviceChanged(self, reset=False, serviceName=None):
"""

View File

@ -44,9 +44,9 @@ class ScreenList(object):
self.override = None
self.screen_list = []
self.display_count = 0
#actual display number
# actual display number
self.current_display = 0
#save config display number
# save config display number
self.monitor_number = 0
def add_screen(self, screen):

View File

@ -317,9 +317,8 @@ class ServiceManager(QtGui.QWidget):
self.serviceItemEditForm.setServiceItem(
self.serviceItems[item][u'service_item'])
if self.serviceItemEditForm.exec_():
self.serviceItems[item][u'service_item'] = \
self.serviceItemEditForm.getServiceItem()
self.repaintServiceList(item, 0)
self.addServiceItem(self.serviceItemEditForm.getServiceItem(),
replace=True)
def nextItem(self):
"""
@ -780,7 +779,7 @@ class ServiceManager(QtGui.QWidget):
Rebuild the service list as things have changed and a
repaint is the easiest way to do this.
"""
#force reset of renderer as theme data has changed
# force reset of renderer as theme data has changed
self.parent.RenderManager.themedata = None
if self.serviceItems:
tempServiceItems = self.serviceItems
@ -790,8 +789,8 @@ class ServiceManager(QtGui.QWidget):
for item in tempServiceItems:
self.addServiceItem(
item[u'service_item'], False, item[u'expanded'])
#Set to False as items may have changed rendering
#does not impact the saved song so True may also be valid
# Set to False as items may have changed rendering
# does not impact the saved song so True may also be valid
self.parent.serviceChanged(False, self.serviceName)
def addServiceItem(self, item, rebuild=False, expand=True, replace=False):
@ -873,6 +872,7 @@ class ServiceManager(QtGui.QWidget):
ItemCapabilities.AllowsPreview):
self.parent.PreviewController.addServiceManagerItem(
self.serviceItems[item][u'service_item'], 0)
self.parent.LiveController.PreviewListWidget.setFocus()
else:
QtGui.QMessageBox.critical(self,
translate('OpenLP.ServiceManager', 'Missing Display Handler'),

View File

@ -25,36 +25,17 @@
###############################################################################
import logging
import time
import os
from PyQt4 import QtCore, QtGui
from PyQt4.phonon import Phonon
from openlp.core.ui import HideMode
from openlp.core.ui import HideMode, MainDisplay
from openlp.core.lib import OpenLPToolbar, Receiver, resize_image, \
ItemCapabilities, translate
log = logging.getLogger(__name__)
class SlideThread(QtCore.QThread):
"""
A special Qt thread class to speed up the display of text based frames.
This is threaded so it loads the frames in background
"""
def __init__(self, parent, prefix, count):
QtCore.QThread.__init__(self, parent)
self.prefix = prefix
self.count = count
def run(self):
"""
Run the thread.
"""
time.sleep(1)
for i in range(0, self.count):
Receiver.send_message(u'%s_slide_cache' % self.prefix, i)
class SlideList(QtGui.QTableWidget):
"""
Customised version of QTableWidget which can respond to keyboard
@ -97,7 +78,7 @@ class SlideController(QtGui.QWidget):
SlideController is the slide controller widget. This widget is what the
user uses to control the displaying of verses/slides/etc on the screen.
"""
def __init__(self, parent, settingsmanager, isLive=False):
def __init__(self, parent, settingsmanager, screens, isLive=False):
"""
Set up the Slide Controller.
"""
@ -105,8 +86,10 @@ class SlideController(QtGui.QWidget):
self.settingsmanager = settingsmanager
self.isLive = isLive
self.parent = parent
self.mainDisplay = self.parent.displayManager.mainDisplay
self.displayManager = self.parent.displayManager
self.screens = screens
self.ratio = float(self.screens.current[u'size'].width()) / \
float(self.screens.current[u'size'].height())
self.display = MainDisplay(self, screens, isLive)
self.loopList = [
u'Start Loop',
u'Loop Separator',
@ -115,13 +98,14 @@ class SlideController(QtGui.QWidget):
self.songEditList = [
u'Edit Song',
]
self.volume = 10
self.timer_id = 0
self.songEdit = False
self.selectedRow = 0
self.serviceItem = None
self.alertTab = None
self.Panel = QtGui.QWidget(parent.ControlSplitter)
self.slideList = {}
self.canDisplay = True
# Layout for holding panel
self.PanelLayout = QtGui.QVBoxLayout(self.Panel)
self.PanelLayout.setSpacing(0)
@ -177,11 +161,11 @@ class SlideController(QtGui.QWidget):
sizeToolbarPolicy.setHeightForWidth(
self.Toolbar.sizePolicy().hasHeightForWidth())
self.Toolbar.setSizePolicy(sizeToolbarPolicy)
if self.isLive:
self.Toolbar.addToolbarButton(
u'First Slide', u':/slides/slide_first.png',
translate('OpenLP.SlideController', 'Move to first'),
self.onSlideSelectedFirst)
# if self.isLive:
# self.Toolbar.addToolbarButton(
# u'First Slide', u':/slides/slide_first.png',
# translate('OpenLP.SlideController', 'Move to first'),
# self.onSlideSelectedFirst)
self.Toolbar.addToolbarButton(
u'Previous Slide', u':/slides/slide_previous.png',
translate('OpenLP.SlideController', 'Move to previous'),
@ -190,11 +174,11 @@ class SlideController(QtGui.QWidget):
u'Next Slide', u':/slides/slide_next.png',
translate('OpenLP.SlideController', 'Move to next'),
self.onSlideSelectedNext)
if self.isLive:
self.Toolbar.addToolbarButton(
u'Last Slide', u':/slides/slide_last.png',
translate('OpenLP.SlideController', 'Move to last'),
self.onSlideSelectedLast)
# if self.isLive:
# self.Toolbar.addToolbarButton(
# u'Last Slide', u':/slides/slide_last.png',
# translate('OpenLP.SlideController', 'Move to last'),
# self.onSlideSelectedLast)
if self.isLive:
self.Toolbar.addToolbarSeparator(u'Close Separator')
self.HideMenu = QtGui.QToolButton(self.Toolbar)
@ -213,15 +197,17 @@ class SlideController(QtGui.QWidget):
self.ThemeScreen.setCheckable(True)
QtCore.QObject.connect(self.ThemeScreen,
QtCore.SIGNAL("triggered(bool)"), self.onThemeDisplay)
self.DesktopScreen = QtGui.QAction(QtGui.QIcon(
u':/slides/slide_desktop.png'), u'Show Desktop', self.HideMenu)
self.DesktopScreen.setCheckable(True)
QtCore.QObject.connect(self.DesktopScreen,
QtCore.SIGNAL("triggered(bool)"), self.onHideDisplay)
if self.screens.display_count > 1:
self.DesktopScreen = QtGui.QAction(QtGui.QIcon(
u':/slides/slide_desktop.png'), u'Show Desktop', self.HideMenu)
self.DesktopScreen.setCheckable(True)
QtCore.QObject.connect(self.DesktopScreen,
QtCore.SIGNAL("triggered(bool)"), self.onHideDisplay)
self.HideMenu.setDefaultAction(self.BlankScreen)
self.HideMenu.menu().addAction(self.BlankScreen)
self.HideMenu.menu().addAction(self.ThemeScreen)
self.HideMenu.menu().addAction(self.DesktopScreen)
if self.screens.display_count > 1:
self.HideMenu.menu().addAction(self.DesktopScreen)
if not self.isLive:
self.Toolbar.addToolbarSeparator(u'Close Separator')
self.Toolbar.addToolbarButton(
@ -251,7 +237,7 @@ class SlideController(QtGui.QWidget):
self.DelaySpinBox.setToolTip(translate('OpenLP.SlideController',
'Delay between slides in seconds'))
self.ControllerLayout.addWidget(self.Toolbar)
#Build a Media ToolBar
# Build a Media ToolBar
self.Mediabar = OpenLPToolbar(self)
self.Mediabar.addToolbarButton(
u'Media Start', u':/slides/media_playback_start.png',
@ -271,10 +257,19 @@ class SlideController(QtGui.QWidget):
self.seekSlider.setObjectName(u'seekSlider')
self.Mediabar.addToolbarWidget(
u'Seek Slider', self.seekSlider)
self.volumeSlider = Phonon.VolumeSlider()
self.volumeSlider.setGeometry(QtCore.QRect(90, 260, 221, 24))
self.volumeSlider.setObjectName(u'volumeSlider')
self.Mediabar.addToolbarWidget(u'Audio Volume', self.volumeSlider)
self.volumeSlider = Phonon.VolumeSlider()
self.volumeSlider.setGeometry(QtCore.QRect(90, 260, 221, 24))
self.volumeSlider.setObjectName(u'volumeSlider')
self.Mediabar.addToolbarWidget(u'Audio Volume', self.volumeSlider)
else:
self.volumeSlider = QtGui.QSlider(QtCore.Qt.Horizontal)
self.volumeSlider.setTickInterval(1)
self.volumeSlider.setTickPosition(QtGui.QSlider.TicksAbove)
self.volumeSlider.setMinimum(0)
self.volumeSlider.setMaximum(10)
self.volumeSlider.setGeometry(QtCore.QRect(90, 260, 221, 24))
self.volumeSlider.setObjectName(u'volumeSlider')
self.Mediabar.addToolbarWidget(u'Audio Volume', self.volumeSlider)
self.ControllerLayout.addWidget(self.Mediabar)
# Build the Song Toolbar
if isLive:
@ -322,7 +317,7 @@ class SlideController(QtGui.QWidget):
self.SlidePreview.setSizePolicy(sizePolicy)
self.SlidePreview.setFixedSize(
QtCore.QSize(self.settingsmanager.slidecontroller_image,
self.settingsmanager.slidecontroller_image / 1.3 ))
self.settingsmanager.slidecontroller_image / self.ratio))
self.SlidePreview.setFrameShape(QtGui.QFrame.Box)
self.SlidePreview.setFrameShadow(QtGui.QFrame.Plain)
self.SlidePreview.setLineWidth(1)
@ -390,17 +385,37 @@ class SlideController(QtGui.QWidget):
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'config_updated'), self.refreshServiceItem)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'%s_slide_cache' % self.typePrefix), self.slideCache)
QtCore.SIGNAL(u'config_screen_changed'), self.screenSizeChanged)
if self.isLive:
QtCore.QObject.connect(self.volumeSlider,
QtCore.SIGNAL(u'sliderReleased()'), self.mediaVolume)
def screenSizeChanged(self):
"""
Settings dialog has changed the screen size of adjust output and
screen previews
"""
log.debug(u'screenSizeChanged live = %s' % self.isLive)
# rebuild display as screen size changed
self.display = MainDisplay(self, self.screens, self.isLive)
self.display.alertTab = self.alertTab
self.ratio = float(self.screens.current[u'size'].width()) / \
float(self.screens.current[u'size'].height())
self.display.setup()
self.SlidePreview.setFixedSize(
QtCore.QSize(self.settingsmanager.slidecontroller_image,
self.settingsmanager.slidecontroller_image / self.ratio))
def widthChanged(self):
"""
Handle changes of width from the splitter between the live and preview
controller. Event only issues when changes have finished
"""
log.debug(u'widthChanged live = %s' % self.isLive)
width = self.parent.ControlSplitter.sizes()[self.split]
height = width * self.parent.RenderManager.screen_ratio
self.PreviewListWidget.setColumnWidth(0, width)
#Sort out image heights (Songs, bibles excluded)
# Sort out image heights (Songs, bibles excluded)
if self.serviceItem and not self.serviceItem.is_text():
for framenumber in range(len(self.serviceItem.get_frames())):
self.PreviewListWidget.setRowHeight(framenumber, height)
@ -453,8 +468,6 @@ class SlideController(QtGui.QWidget):
if item.is_media():
self.Toolbar.setVisible(False)
self.Mediabar.setVisible(True)
#self.volumeSlider.setAudioOutput(
# self.mainDisplay.videoDisplay.audio)
def enablePreviewToolBar(self, item):
"""
@ -474,22 +487,20 @@ class SlideController(QtGui.QWidget):
"""
Method to update the service item if the screen has changed
"""
log.debug(u'refreshServiceItem')
log.debug(u'refreshServiceItem live = %s' % self.isLive)
if self.serviceItem:
if self.serviceItem.is_text() or self.serviceItem.is_image():
item = self.serviceItem
item.render()
self.addServiceManagerItem(item, self.selectedRow)
self._processItem(item, self.selectedRow)
def addServiceItem(self, item):
"""
Method to install the service item into the controller
Called by plugins
"""
log.debug(u'addServiceItem')
before = time.time()
log.debug(u'addServiceItem live = %s' % self.isLive)
item.render()
log.log(15, u'Rendering took %4s' % (time.time() - before))
slideno = 0
if self.songEdit:
slideno = self.selectedRow
@ -509,8 +520,8 @@ class SlideController(QtGui.QWidget):
request the correct toolbar for the plugin.
Called by ServiceManager
"""
log.debug(u'addServiceManagerItem')
#If service item is the same as the current on only change slide
log.debug(u'addServiceManagerItem live = %s' % self.isLive)
# If service item is the same as the current on only change slide
if item.__eq__(self.serviceItem):
self.PreviewListWidget.selectRow(slideno)
self.onSlideSelected()
@ -522,17 +533,15 @@ class SlideController(QtGui.QWidget):
Loads a ServiceItem into the system from ServiceManager
Display the slide number passed
"""
log.debug(u'processManagerItem')
log.debug(u'processManagerItem live = %s' % self.isLive)
self.onStopLoop()
#If old item was a command tell it to stop
# If old item was a command tell it to stop
if self.serviceItem:
if self.serviceItem.is_command():
Receiver.send_message(u'%s_stop' %
self.serviceItem.name.lower(), [serviceItem, self.isLive])
if self.serviceItem.is_media():
self.onMediaStop()
if serviceItem.is_media():
self.onMediaStart(serviceItem)
if self.isLive:
blanked = self.BlankScreen.isChecked()
else:
@ -541,12 +550,8 @@ class SlideController(QtGui.QWidget):
[serviceItem, self.isLive, blanked, slideno])
self.slideList = {}
width = self.parent.ControlSplitter.sizes()[self.split]
#Set pointing cursor when we have somthing to point at
# Set pointing cursor when we have somthing to point at
self.PreviewListWidget.setCursor(QtCore.Qt.PointingHandCursor)
before = time.time()
#Clear the old serviceItem cache to release memory
if self.serviceItem and self.serviceItem is not serviceItem:
self.serviceItem.clear_cache()
self.serviceItem = serviceItem
self.PreviewListWidget.clear()
self.PreviewListWidget.setRowCount(0)
@ -560,20 +565,19 @@ class SlideController(QtGui.QWidget):
self.PreviewListWidget.rowCount() + 1)
item = QtGui.QTableWidgetItem()
slideHeight = 0
#It is a based Text Render
if self.serviceItem.is_text():
if frame[u'verseTag']:
bits = frame[u'verseTag'].split(u':')
tag = u'%s\n%s' % (bits[0][0], bits[1][0:] )
tag1 = u'%s%s' % (bits[0][0], bits[1][0:] )
row = tag
if self.isLive:
if tag1 not in self.slideList:
self.slideList[tag1] = framenumber
self.SongMenu.menu().addAction(tag1,
self.onSongBarHandler)
else:
row += 1
if self.isLive and frame[u'verseTag'] is not None:
if tag1 not in self.slideList:
self.slideList[tag1] = framenumber
self.SongMenu.menu().addAction(tag1,
self.onSongBarHandler)
item.setText(frame[u'text'])
else:
label = QtGui.QLabel()
@ -600,15 +604,14 @@ class SlideController(QtGui.QWidget):
else:
self.PreviewListWidget.selectRow(slideno)
self.enableToolBar(serviceItem)
# Pass to display for viewing
self.display.buildHtml(self.serviceItem)
if serviceItem.is_media():
self.onMediaStart(serviceItem)
self.onSlideSelected()
self.PreviewListWidget.setFocus()
Receiver.send_message(u'slidecontroller_%s_started' % self.typePrefix,
[serviceItem])
if self.serviceItem.is_text():
st = SlideThread(
self, self.typePrefix, len(self.serviceItem.get_frames()))
st.start()
log.log(15, u'Display Rendering took %4s' % (time.time() - before))
def onTextRequest(self):
"""
@ -620,7 +623,7 @@ class SlideController(QtGui.QWidget):
dataItem = {}
if self.serviceItem.is_text():
dataItem[u'tag'] = unicode(frame[u'verseTag'])
dataItem[u'text'] = unicode(frame[u'text'])
dataItem[u'text'] = unicode(frame[u'html'])
else:
dataItem[u'tag'] = unicode(framenumber)
dataItem[u'text'] = u''
@ -630,7 +633,7 @@ class SlideController(QtGui.QWidget):
Receiver.send_message(u'slidecontroller_%s_text_response'
% self.typePrefix, data)
#Screen event methods
# Screen event methods
def onSlideSelectedFirst(self):
"""
Go to the first slide.
@ -664,9 +667,9 @@ class SlideController(QtGui.QWidget):
"""
Allow the main display to blank the main display at startup time
"""
log.debug(u'mainDisplaySetBackground')
if not self.mainDisplay.primary:
self.onBlankDisplay(True)
log.debug(u'mainDisplaySetBackground live = %s' % self.isLive)
if not self.display.primary:
self.onHideDisplay(True)
def onSlideBlank(self):
"""
@ -688,7 +691,8 @@ class SlideController(QtGui.QWidget):
self.HideMenu.setDefaultAction(self.BlankScreen)
self.BlankScreen.setChecked(checked)
self.ThemeScreen.setChecked(False)
self.DesktopScreen.setChecked(False)
if self.screens.display_count > 1:
self.DesktopScreen.setChecked(False)
QtCore.QSettings().setValue(
self.parent.generalSettingsSection + u'/screen blank',
QtCore.QVariant(checked))
@ -706,7 +710,8 @@ class SlideController(QtGui.QWidget):
self.HideMenu.setDefaultAction(self.ThemeScreen)
self.BlankScreen.setChecked(False)
self.ThemeScreen.setChecked(checked)
self.DesktopScreen.setChecked(False)
if self.screens.display_count > 1:
self.DesktopScreen.setChecked(False)
if checked:
Receiver.send_message(u'maindisplay_hide', HideMode.Theme)
else:
@ -721,7 +726,8 @@ class SlideController(QtGui.QWidget):
self.HideMenu.setDefaultAction(self.DesktopScreen)
self.BlankScreen.setChecked(False)
self.ThemeScreen.setChecked(False)
self.DesktopScreen.setChecked(checked)
if self.screens.display_count > 1:
self.DesktopScreen.setChecked(checked)
if checked:
Receiver.send_message(u'maindisplay_hide', HideMode.Screen)
else:
@ -758,13 +764,6 @@ class SlideController(QtGui.QWidget):
% self.serviceItem.name.lower(),
[self.serviceItem, self.isLive])
def slideCache(self, slide):
"""
Generate a slide cache item rendered and ready for use
in the background.
"""
self.serviceItem.get_rendered_frame(int(slide))
def onSlideSelected(self):
"""
Generate the preview when you click on a slide.
@ -778,24 +777,15 @@ class SlideController(QtGui.QWidget):
if self.serviceItem.is_command() and self.isLive:
self.updatePreview()
else:
before = time.time()
frame = self.serviceItem.get_rendered_frame(row)
frame, raw_html = self.serviceItem.get_rendered_frame(row)
if self.serviceItem.is_text():
frame = self.display.text(raw_html)
else:
self.display.image(frame)
if isinstance(frame, QtGui.QImage):
self.SlidePreview.setPixmap(QtGui.QPixmap.fromImage(frame))
else:
if isinstance(frame[u'main'], basestring):
self.SlidePreview.setPixmap(
QtGui.QPixmap(frame[u'main']))
else:
self.SlidePreview.setPixmap(
QtGui.QPixmap.fromImage(frame[u'main']))
log.log(
15, u'Slide Rendering took %4s' % (time.time() - before))
if self.isLive:
if self.serviceItem.is_text():
self.mainDisplay.frameView(frame, True)
else:
self.displayManager.displayImage(frame[u'main'])
self.SlidePreview.setPixmap(QtGui.QPixmap(frame))
self.selectedRow = row
Receiver.send_message(u'slidecontroller_%s_changed' % self.typePrefix,
row)
@ -810,8 +800,7 @@ class SlideController(QtGui.QWidget):
row)
def updatePreview(self):
rm = self.parent.RenderManager
if not rm.screens.current[u'primary']:
if not self.screens.current[u'primary']:
# Grab now, but try again in a couple of seconds if slide change
# is slow
QtCore.QTimer.singleShot(0.5, self.grabMainDisplay)
@ -819,12 +808,12 @@ class SlideController(QtGui.QWidget):
else:
label = self.PreviewListWidget.cellWidget(
self.PreviewListWidget.currentRow(), 1)
self.SlidePreview.setPixmap(label.pixmap())
if label:
self.SlidePreview.setPixmap(label.pixmap())
def grabMainDisplay(self):
rm = self.parent.RenderManager
winid = QtGui.QApplication.desktop().winId()
rect = rm.screens.current[u'size']
rect = self.screens.current[u'size']
winimg = QtGui.QPixmap.grabWindow(winid, rect.x(),
rect.y(), rect.width(), rect.height())
self.SlidePreview.setPixmap(winimg)
@ -941,7 +930,9 @@ class SlideController(QtGui.QWidget):
"""
log.debug(u'SlideController onMediaStart')
if self.isLive:
Receiver.send_message(u'videodisplay_start', item)
file = os.path.join(item.get_frame_path(), item.get_frame_title())
self.display.video(file, self.volume)
self.volumeSlider.setValue(self.volume)
else:
self.mediaObject.stop()
self.mediaObject.clearQueue()
@ -951,13 +942,21 @@ class SlideController(QtGui.QWidget):
self.seekSlider.show()
self.onMediaPlay()
def mediaVolume(self):
"""
Respond to the release of Volume Slider
"""
log.debug(u'SlideController mediaVolume')
self.volume = self.volumeSlider.value()
self.display.videoVolume(self.volume)
def onMediaPause(self):
"""
Respond to the Pause from the media Toolbar
"""
log.debug(u'SlideController onMediaPause')
if self.isLive:
Receiver.send_message(u'videodisplay_pause')
self.display.videoPause()
else:
self.mediaObject.pause()
@ -967,7 +966,7 @@ class SlideController(QtGui.QWidget):
"""
log.debug(u'SlideController onMediaPlay')
if self.isLive:
Receiver.send_message(u'videodisplay_play')
self.display.videoPlay()
else:
self.SlidePreview.hide()
self.video.show()
@ -979,7 +978,7 @@ class SlideController(QtGui.QWidget):
"""
log.debug(u'SlideController onMediaStop')
if self.isLive:
Receiver.send_message(u'videodisplay_stop')
self.display.videoStop()
else:
self.mediaObject.stop()
self.video.hide()

View File

@ -139,13 +139,13 @@ class ThemeManager(QtGui.QWidget):
"""
log.debug(u'changeGlobalFromTab %s', themeName)
for count in range (0, self.themeListWidget.count()):
#reset the old name
# reset the old name
item = self.themeListWidget.item(count)
oldName = item.text()
newName = unicode(item.data(QtCore.Qt.UserRole).toString())
if oldName != newName:
self.themeListWidget.item(count).setText(newName)
#Set the new name
# Set the new name
if themeName == newName:
name = unicode(translate('OpenLP.ThemeManager',
'%s (default)')) % newName
@ -161,11 +161,11 @@ class ThemeManager(QtGui.QWidget):
for count in range (0, self.themeListWidget.count()):
item = self.themeListWidget.item(count)
oldName = item.text()
#reset the old name
# reset the old name
if oldName != unicode(item.data(QtCore.Qt.UserRole).toString()):
self.themeListWidget.item(count).setText(
unicode(item.data(QtCore.Qt.UserRole).toString()))
#Set the new name
# Set the new name
if count == selected_row:
self.global_theme = unicode(
self.themeListWidget.item(count).text())
@ -295,7 +295,7 @@ class ThemeManager(QtGui.QWidget):
path = unicode(path)
if path:
SettingsManager.set_last_dir(self.settingsSection, path, 1)
themePath = os.path.join(path, theme + u'.theme')
themePath = os.path.join(path, theme + u'.thz')
zip = None
try:
zip = zipfile.ZipFile(themePath, u'w')
@ -346,11 +346,10 @@ class ThemeManager(QtGui.QWidget):
log.debug(u'Load themes from dir')
self.themelist = []
self.themeListWidget.clear()
#root, dirs, files = os.walk(self.path)
dirList = os.listdir(self.path)
for name in dirList:
if name.endswith(u'.png'):
#check to see file is in theme root directory
# check to see file is in theme root directory
theme = os.path.join(self.path, name)
if os.path.exists(theme):
textName = os.path.splitext(name)[0]
@ -660,9 +659,8 @@ class ThemeManager(QtGui.QWidget):
"""
Call the RenderManager to build a Sample Image
"""
log.debug(u'generateImage %s ', themedata)
frame = self.parent.RenderManager.generate_preview(themedata)
return frame
log.debug(u'generateImage \n%s ', themedata)
return self.parent.RenderManager.generate_preview(themedata)
def getPreviewImage(self, theme):
"""
@ -732,8 +730,6 @@ class ThemeManager(QtGui.QWidget):
theme.display_slideTransition = theme.display_slideTransition
theme.font_footer_color = theme.font_footer_color.strip()
theme.font_footer_height = int(theme.font_footer_height.strip())
theme.font_footer_indentation = \
int(theme.font_footer_indentation.strip())
theme.font_footer_italics = str_to_bool(theme.font_footer_italics)
theme.font_footer_name = theme.font_footer_name.strip()
#theme.font_footer_override
@ -746,7 +742,6 @@ class ThemeManager(QtGui.QWidget):
theme.font_main_color = theme.font_main_color.strip()
theme.font_main_height = int(theme.font_main_height.strip())
theme.font_main_italics = str_to_bool(theme.font_main_italics)
theme.font_main_indentation = int(theme.font_main_indentation)
theme.font_main_name = theme.font_main_name.strip()
#theme.font_main_override
theme.font_main_proportion = int(theme.font_main_proportion.strip())
@ -757,3 +752,8 @@ class ThemeManager(QtGui.QWidget):
#theme.theme_mode
theme.theme_name = theme.theme_name.strip()
#theme.theme_version
# Remove the Transparent settings as they are not relevent
if theme.background_mode == u'transparent':
theme.background_mode = u'opaque'
theme.background_type = u'solid'
theme.background_startColor = u'#000000'

View File

@ -70,6 +70,8 @@ class VersionThread(QtCore.QThread):
remote_version[u'release'] = int(match.group(3))
if len(match.groups()) > 3 and match.group(4):
remote_version[u'revision'] = int(match.group(4))
else:
return
match = self.version_splitter.match(self.app_version[u'full'])
if match:
local_version[u'major'] = int(match.group(1))
@ -77,6 +79,8 @@ class VersionThread(QtCore.QThread):
local_version[u'release'] = int(match.group(3))
if len(match.groups()) > 3 and match.group(4):
local_version[u'revision'] = int(match.group(4))
else:
return
if remote_version[u'major'] > local_version[u'major'] or \
remote_version[u'minor'] > local_version[u'minor'] or \
remote_version[u'release'] > local_version[u'release']:
@ -147,10 +151,10 @@ class AppLocation(object):
return plugin_path
elif dir_type == AppLocation.VersionDir:
if hasattr(sys, u'frozen') and sys.frozen == 1:
plugin_path = os.path.abspath(os.path.split(sys.argv[0])[0])
version_path = os.path.abspath(os.path.split(sys.argv[0])[0])
else:
plugin_path = os.path.split(openlp.__file__)[0]
return plugin_path
version_path = os.path.split(openlp.__file__)[0]
return version_path
elif dir_type == AppLocation.CacheDir:
if sys.platform == u'win32':
path = os.path.join(os.getenv(u'APPDATA'), u'openlp')
@ -206,11 +210,14 @@ def check_latest_version(current_version):
else:
req = urllib2.Request(u'http://www.openlp.org/files/version.txt')
req.add_header(u'User-Agent', u'OpenLP/%s' % current_version[u'full'])
remote_version = None
try:
version_string = unicode(urllib2.urlopen(req, None).read()).strip()
remote_version = unicode(urllib2.urlopen(req, None).read()).strip()
except IOError, e:
if hasattr(e, u'reason'):
log.exception(u'Reason for failure: %s', e.reason)
if remote_version:
version_string = remote_version
return version_string
def add_actions(target, actions):

View File

@ -80,9 +80,10 @@ class AlertsPlugin(Plugin):
log.info(u'Alerts Initialising')
Plugin.initialise(self)
self.toolsAlertItem.setVisible(True)
self.liveController.alertTab = self.alertsTab
def finalise(self):
log.info(u'Plugin Finalise')
log.info(u'Alerts Finalising')
Plugin.finalise(self)
self.toolsAlertItem.setVisible(False)

View File

@ -32,18 +32,9 @@ from openlp.core.lib import Receiver, translate
log = logging.getLogger(__name__)
HTMLCODE = u"""
<p style=\"color:%s;
background-color:%s;
font-family:%s;
font-size: %spt; \">
%s
</p>
"""
class AlertsManager(QtCore.QObject):
"""
AlertsTab is the Alerts settings tab in the settings dialog.
AlertsManager manages the settings of Alerts.
"""
log.info(u'Alert Manager loaded')
@ -94,10 +85,7 @@ class AlertsManager(QtCore.QObject):
return
text = self.alertList.pop(0)
alertTab = self.parent.alertsTab
text = HTMLCODE % (alertTab.font_color, alertTab.bg_color,
alertTab.font_face, alertTab.font_size, text)
self.parent.previewController.parent.displayManager.addAlert(text,
alertTab.location)
self.parent.liveController.display.alert(text)
# check to see if we have a timer running
if self.timer_id == 0:
self.timer_id = self.startTimer(int(alertTab.timeout) * 1000)
@ -111,10 +99,8 @@ class AlertsManager(QtCore.QObject):
"""
log.debug(u'timer event')
alertTab = self.parent.alertsTab
if event.timerId() == self.timer_id:
self.parent.previewController.parent.displayManager.addAlert(u'',
alertTab.location)
self.parent.liveController.display.alert(u'')
self.killTimer(self.timer_id)
self.timer_id = 0
self.generateAlert()

View File

@ -261,7 +261,7 @@ class AlertsTab(SettingsTab):
self.font_face = unicode(settings.value(
u'font face', QtCore.QVariant(QtGui.QFont().family())).toString())
self.location = settings.value(
u'location', QtCore.QVariant(0)).toInt()[0]
u'location', QtCore.QVariant(1)).toInt()[0]
settings.endGroup()
self.FontSizeSpinBox.setValue(self.font_size)
self.TimeoutSpinBox.setValue(self.timeout)
@ -296,3 +296,4 @@ class AlertsTab(SettingsTab):
self.FontPreview.setFont(font)
self.FontPreview.setStyleSheet(u'background-color: %s; color: %s' %
(self.bg_color, self.font_color))

View File

@ -401,9 +401,10 @@ class BibleMediaItem(MediaManagerItem):
self.AdvancedBookComboBox.itemData(item).toInt()[0])
def onImportClick(self):
self.bibleimportform = ImportWizardForm(self,
self.parent.manager, self.parent)
self.bibleimportform.exec_()
if not hasattr(self, u'import_wizard'):
self.import_wizard = ImportWizardForm(self, self.parent.manager,
self.parent)
self.import_wizard.exec_()
self.reloadBibles()
def onAdvancedFromVerse(self):
@ -464,10 +465,10 @@ class BibleMediaItem(MediaManagerItem):
self.displayResults(bible, dual_bible)
def generateSlideData(self, service_item, item=None):
'''
"""
Generates and formats the slides for the service item as well as the
service item's title.
'''
"""
log.debug(u'generating slide data')
items = self.listView.selectedIndexes()
if len(items) == 0:
@ -505,20 +506,20 @@ class BibleMediaItem(MediaManagerItem):
dual_text = self._decodeQtObject(reference, 'dual_text')
verse_text = self.formatVerse(old_chapter, chapter, verse)
# footer
old_chapter = chapter
footer = u'%s (%s %s)' % (book, version, copyright)
if footer not in raw_footer:
raw_footer.append(footer)
if dual_bible:
service_item.add_capability(ItemCapabilities.NoLineBreaks)
footer = u'%s (%s %s)' % (book, dual_version, dual_copyright)
if footer not in raw_footer:
raw_footer.append(footer)
# If we were previously 'Verse Per Line' we have to add the old
# bible_text, because it was not added until now.
if bible_text:
raw_slides.append(bible_text)
bible_text = u''
bible_text = u'%s %s\n\n%s %s' % (verse_text, text,
verse_text, dual_text)
bible_text = u'%s %s \n %s %s' % (verse_text, text,
verse_text, dual_text)
raw_slides.append(bible_text)
bible_text = u''
# If we are 'Verse Per Slide' then create a new slide.
@ -528,7 +529,8 @@ class BibleMediaItem(MediaManagerItem):
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\n' % (bible_text, verse_text, text)
service_item.add_capability(ItemCapabilities.NoLineBreaks)
bible_text = u'%s %s %s\n' % (bible_text, verse_text, text)
# We have to be 'Continuous'.
else:
# We add a line break if the previously verse has a different
@ -536,7 +538,8 @@ class BibleMediaItem(MediaManagerItem):
if first:
bible_text = u'%s %s %s' % (bible_text, verse_text, text)
elif bible != old_bible or book != old_book:
bible_text = u'%s\n\n%s %s' % (bible_text, verse_text,
service_item.add_capability(ItemCapabilities.NoLineBreaks)
bible_text = u'%s\n%s %s' % (bible_text, verse_text,
text)
else:
bible_text = u'%s %s %s' % (bible_text, verse_text, text)
@ -580,11 +583,13 @@ class BibleMediaItem(MediaManagerItem):
verse_text = chapter + u':'
verse_text += verse
if self.parent.settings_tab.display_style == 1:
verse_text = u'(' + verse_text + u')'
verse_text = u'{su}(' + verse_text + u'){/su}'
elif self.parent.settings_tab.display_style == 2:
verse_text = u'{' + verse_text + u'}'
verse_text = u'{su}{' + verse_text + u'}{/su}'
elif self.parent.settings_tab.display_style == 3:
verse_text = u'[' + verse_text + u']'
verse_text = u'{su}[' + verse_text + u']{/su}'
else:
verse_text = u'{su}' + verse_text + u'{/su}'
return verse_text
def reloadBibles(self):
@ -630,24 +635,24 @@ class BibleMediaItem(MediaManagerItem):
combo.addItem(unicode(i))
def displayResults(self, bible, dual_bible=u''):
'''
"""
Displays the search results in the media manager. All data needed for
further action is saved for/in each row.
'''
"""
version = self.parent.manager.get_meta_data(bible, u'Version')
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:
dual_version = self.parent.manager.get_meta_data(dual_bible,
u'Version')
dual_copyright = self.parent.manager.get_meta_data(dual_bible,
u'Copyright')
dual_permission = self.parent.manager.get_meta_data(dual_bible,
u'Permissions')
if dual_permission:
dual_permission = dual_permission.value
else:
dual_permission = u''
#dual_permission = self.parent.manager.get_meta_data(dual_bible,
# u'Permissions')
#if dual_permission:
# dual_permission = dual_permission.value
#else:
# dual_permission = u''
# We count the number of rows which are maybe already present.
start_count = self.listView.count()
for count, verse in enumerate(self.search_results):

View File

@ -27,6 +27,7 @@
from PyQt4 import QtCore, QtGui
from openlp.core.lib import build_icon, translate
from openlp.core.ui import SpellTextEdit
class Ui_CustomEditDialog(object):
def setupUi(self, customEditDialog):
@ -73,7 +74,7 @@ class Ui_CustomEditDialog(object):
self.editLayout3.setSpacing(8)
self.editLayout3.setMargin(0)
self.editLayout3.setObjectName(u'editLayout3')
self.verseTextEdit = QtGui.QTextEdit(self.editWidget)
self.verseTextEdit = SpellTextEdit(self)
self.verseTextEdit.setObjectName(u'verseTextEdit')
self.editLayout3.addWidget(self.verseTextEdit)
self.buttonWidget = QtGui.QWidget(self.editWidget)
@ -142,7 +143,7 @@ class Ui_CustomEditDialog(object):
customEditDialog.setWindowTitle(
translate('CustomPlugin.EditCustomForm', 'Edit Custom Slides'))
self.upButton.setToolTip(
translate('CustomPlugin.EditCustomForm', 'Move slide up once '
translate('CustomPlugin.EditCustomForm', 'Move slide up one '
'position.'))
self.downButton.setToolTip(
translate('CustomPlugin.EditCustomForm', 'Move slide down one '

View File

@ -110,8 +110,14 @@ class ImageMediaItem(MediaManagerItem):
u':/slides/slide_blank.png',
translate('ImagePlugin.MediaItem', 'Replace Live Background'),
self.onReplaceClick, False)
self.resetButton = self.toolbar.addToolbarButton(
translate('ImagePlugin.MediaItem', u'Reset Background'),
u':/system/system_close.png',
translate('ImagePlugin.MediaItem', 'Reset Live Background'),
self.onResetClick, False)
# Add the song widget to the page layout
self.pageLayout.addWidget(self.ImageWidget)
self.resetButton.setVisible(False)
def onDeleteClick(self):
"""
@ -169,6 +175,10 @@ class ImageMediaItem(MediaManagerItem):
else:
return False
def onResetClick(self):
self.resetButton.setVisible(False)
self.parent.liveController.display.resetImage()
def onReplaceClick(self):
if check_item_selected(self.listView,
translate('ImagePlugin.MediaItem',
@ -178,7 +188,8 @@ class ImageMediaItem(MediaManagerItem):
bitem = self.listView.item(item.row())
filename = unicode(bitem.data(QtCore.Qt.UserRole).toString())
frame = QtGui.QImage(unicode(filename))
self.parent.displayManager.displayImageWithText(frame)
self.parent.liveController.display.image(frame)
self.resetButton.setVisible(True)
def onPreviewClick(self):
MediaManagerItem.onPreviewClick(self)

View File

@ -97,8 +97,17 @@ class MediaMediaItem(MediaManagerItem):
u':/slides/slide_blank.png',
translate('MediaPlugin.MediaItem', 'Replace Live Background'),
self.onReplaceClick, False)
self.resetButton = self.toolbar.addToolbarButton(
u'Reset Background', u':/system/system_close.png',
translate('ImagePlugin.MediaItem', 'Reset Live Background'),
self.onResetClick, False)
# Add the song widget to the page layout
self.pageLayout.addWidget(self.ImageWidget)
self.resetButton.setVisible(False)
def onResetClick(self):
self.resetButton.setVisible(False)
self.parent.liveController.display.resetVideo()
def onReplaceClick(self):
if check_item_selected(self.listView,
@ -106,7 +115,8 @@ class MediaMediaItem(MediaManagerItem):
'You must select a media file to replace the background with.')):
item = self.listView.currentItem()
filename = unicode(item.data(QtCore.Qt.UserRole).toString())
self.parent.displayManager.displayVideo(filename)
self.parent.liveController.display.video(filename, 0)
self.resetButton.setVisible(True)
def generateSlideData(self, service_item, item=None):
if item is None:

View File

@ -314,7 +314,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
author = self.songmanager.get_object(Author, item_id)
if author in self.song.authors:
QtGui.QMessageBox.warning(self,
translate('SongsPlugin.EditSongForm', 'Error'),
translate('SongsPlugin.EditSongForm', 'Error'),
translate('SongsPlugin.EditSongForm', 'This author is '
'already in the list.'))
else:
@ -422,7 +422,9 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
self.VerseDeleteButton.setEnabled(True)
def onVerseAddButtonClicked(self):
self.verse_form.setVerse(u'', True)
# Allow insert button as you do not know if multiple verses will
# be entered.
self.verse_form.setVerse(u'')
if self.verse_form.exec_():
afterText, verse, subVerse = self.verse_form.getVerse()
data = u'%s:%s' % (verse, subVerse)

View File

@ -27,6 +27,7 @@
from PyQt4 import QtCore, QtGui
from openlp.core.lib import build_icon, translate
from openlp.core.ui import SpellTextEdit
from openlp.plugins.songs.lib import VerseType
class Ui_EditVerseDialog(object):
@ -38,7 +39,7 @@ class Ui_EditVerseDialog(object):
self.EditVerseLayout.setSpacing(8)
self.EditVerseLayout.setMargin(8)
self.EditVerseLayout.setObjectName(u'EditVerseLayout')
self.VerseTextEdit = QtGui.QPlainTextEdit(EditVerseDialog)
self.VerseTextEdit = SpellTextEdit(EditVerseDialog)
self.VerseTextEdit.setObjectName(u'VerseTextEdit')
self.EditVerseLayout.addWidget(self.VerseTextEdit)
self.VerseTypeLayout = QtGui.QHBoxLayout()

View File

@ -45,6 +45,9 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog):
"""
QtGui.QDialog.__init__(self, parent)
self.setupUi(self)
QtCore.QObject.connect(self.VerseTextEdit,
QtCore.SIGNAL('customContextMenuRequested(QPoint)'),
self.contextMenu)
QtCore.QObject.connect(
self.InsertButton,
QtCore.SIGNAL(u'clicked()'),
@ -57,6 +60,10 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog):
)
self.verse_regex = re.compile(r'---\[([-\w]+):([\d]+)\]---')
def contextMenu(self, point):
item = self.serviceManagerList.itemAt(point)
print item
def insertVerse(self, title, num=1):
if self.VerseTextEdit.textCursor().columnNumber() != 0:
self.VerseTextEdit.insertPlainText(u'\n')

View File

@ -25,59 +25,76 @@
###############################################################################
import logging
import os
from PyQt4 import QtCore, QtGui
from songimportwizard import Ui_SongImportWizard
from openlp.core.lib import Receiver, SettingsManager, translate
#from openlp.core.utils import AppLocation
from openlp.plugins.songs.lib import SongFormat
from openlp.plugins.songs.lib.importer import SongFormat
log = logging.getLogger(__name__)
class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard):
"""
This is the Bible Import Wizard, which allows easy importing of Bibles
into OpenLP from other formats like OSIS, CSV and OpenSong.
This is the Song Import Wizard, which allows easy importing of Songs
into OpenLP from other formats like OpenLyrics, OpenSong and CCLI.
"""
log.info(u'BibleImportForm loaded')
log.info(u'SongImportForm loaded')
def __init__(self, parent, manager, songsplugin):
def __init__(self, parent, plugin):
"""
Instantiate the wizard, and run any extra setup we need to.
``parent``
The QWidget-derived parent of the wizard.
``config``
The configuration object for storing and retrieving settings.
``manager``
The Bible manager.
``bibleplugin``
The Bible plugin.
``plugin``
The songs plugin.
"""
QtGui.QWizard.__init__(self, parent)
self.setupUi(self)
self.registerFields()
self.finishButton = self.button(QtGui.QWizard.FinishButton)
self.cancelButton = self.button(QtGui.QWizard.CancelButton)
self.manager = manager
self.songsplugin = songsplugin
#self.manager.set_process_dialog(self)
# QtCore.QObject.connect(self.OsisFileButton,
# QtCore.SIGNAL(u'clicked()'),
# self.onOsisFileButtonClicked)
# QtCore.QObject.connect(self.BooksFileButton,
# QtCore.SIGNAL(u'clicked()'),
# self.onBooksFileButtonClicked)
# QtCore.QObject.connect(self.CsvVersesFileButton,
# QtCore.SIGNAL(u'clicked()'),
# self.onCsvVersesFileButtonClicked)
# QtCore.QObject.connect(self.OpenSongBrowseButton,
# QtCore.SIGNAL(u'clicked()'),
# self.onOpenSongBrowseButtonClicked)
self.plugin = plugin
QtCore.QObject.connect(self.openLP2BrowseButton,
QtCore.SIGNAL(u'clicked()'),
self.onOpenLP2BrowseButtonClicked)
QtCore.QObject.connect(self.openLP1BrowseButton,
QtCore.SIGNAL(u'clicked()'),
self.onOpenLP1BrowseButtonClicked)
QtCore.QObject.connect(self.openLyricsAddButton,
QtCore.SIGNAL(u'clicked()'),
self.onOpenLyricsAddButtonClicked)
QtCore.QObject.connect(self.openLyricsRemoveButton,
QtCore.SIGNAL(u'clicked()'),
self.onOpenLyricsRemoveButtonClicked)
QtCore.QObject.connect(self.openSongAddButton,
QtCore.SIGNAL(u'clicked()'),
self.onOpenSongAddButtonClicked)
QtCore.QObject.connect(self.openSongRemoveButton,
QtCore.SIGNAL(u'clicked()'),
self.onOpenSongRemoveButtonClicked)
QtCore.QObject.connect(self.wordsOfWorshipAddButton,
QtCore.SIGNAL(u'clicked()'),
self.onWordsOfWorshipAddButtonClicked)
QtCore.QObject.connect(self.wordsOfWorshipRemoveButton,
QtCore.SIGNAL(u'clicked()'),
self.onWordsOfWorshipRemoveButtonClicked)
QtCore.QObject.connect(self.songsOfFellowshipAddButton,
QtCore.SIGNAL(u'clicked()'),
self.onSongsOfFellowshipAddButtonClicked)
QtCore.QObject.connect(self.songsOfFellowshipRemoveButton,
QtCore.SIGNAL(u'clicked()'),
self.onSongsOfFellowshipRemoveButtonClicked)
QtCore.QObject.connect(self.genericAddButton,
QtCore.SIGNAL(u'clicked()'),
self.onGenericAddButtonClicked)
QtCore.QObject.connect(self.genericRemoveButton,
QtCore.SIGNAL(u'clicked()'),
self.onGenericRemoveButtonClicked)
QtCore.QObject.connect(self.cancelButton,
QtCore.SIGNAL(u'clicked(bool)'),
self.onCancelButtonClicked)
@ -101,154 +118,294 @@ class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard):
return True
elif self.currentId() == 1:
# Select page
source_format = self.field(u'source_format').toInt()[0]
if source_format == SongFormat.OpenLyrics:
if self.OpenLyricsFileListWidget.count() == 0:
source_format = self.formatComboBox.currentIndex()
if source_format == SongFormat.OpenLP2:
if self.openLP2FilenameEdit.text().isEmpty():
QtGui.QMessageBox.critical(self,
translate('SongsPlugin.ImportWizardForm',
'No OpenLP 2.0 Song Database Selected'),
translate('SongsPlugin.ImportWizardForm',
'You need to select an OpenLP 2.0 song database '
'file to import from.'))
self.openLP2BrowseButton.setFocus()
return False
elif source_format == SongFormat.OpenLP1:
if self.openSongFilenameEdit.text().isEmpty():
QtGui.QMessageBox.critical(self,
translate('SongsPlugin.ImportWizardForm',
'No openlp.org 1.x Song Database Selected'),
translate('SongsPlugin.ImportWizardForm',
'You need to select an openlp.org 1.x song '
'database file to import from.'))
self.openLP1BrowseButton.setFocus()
return False
elif source_format == SongFormat.OpenLyrics:
if self.openLyricsFileListWidget.count() == 0:
QtGui.QMessageBox.critical(self,
translate('SongsPlugin.ImportWizardForm',
'No OpenLyrics Files Selected'),
translate('SongsPlugin.ImportWizardForm',
'You need to add at least one OpenLyrics '
'song file to import from.'))
self.OpenLyricsAddButton.setFocus()
self.openLyricsAddButton.setFocus()
return False
elif source_format == SongFormat.OpenSong:
if self.OpenSongFileListWidget.count() == 0:
if self.openSongFileListWidget.count() == 0:
QtGui.QMessageBox.critical(self,
translate('SongsPlugin.ImportWizardForm',
'No OpenSong Files Selected'),
translate('SongsPlugin.ImportWizardForm',
'You need to add at least one OpenSong '
'song file to import from.'))
self.OpenSongAddButton.setFocus()
self.openSongAddButton.setFocus()
return False
elif source_format == SongFormat.WordsOfWorship:
if self.wordsOfWorshipListWidget.count() == 0:
QtGui.QMessageBox.critical(self,
translate('SongsPlugin.ImportWizardForm',
'No Words of Worship Files Selected'),
translate('SongsPlugin.ImportWizardForm',
'You need to add at least one Words of Worship '
'file to import from.'))
self.wordsOfWorshipAddButton.setFocus()
return False
elif source_format == SongFormat.CCLI:
if self.CCLIFileListWidget.count() == 0:
if self.ccliFileListWidget.count() == 0:
QtGui.QMessageBox.critical(self,
translate('SongsPlugin.ImportWizardForm',
'No CCLI Files Selected'),
translate('SongsPlugin.ImportWizardForm',
'You need to add at least one CCLI file '
'to import from.'))
self.CCLIAddButton.setFocus()
self.ccliAddButton.setFocus()
return False
elif source_format == SongFormat.CSV:
if self.CSVFilenameEdit.text().isEmpty():
elif source_format == SongFormat.SongsOfFellowship:
if self.songsOfFellowshipFileListWidget.count() == 0:
QtGui.QMessageBox.critical(self,
translate('SongsPlugin.ImportWizardForm',
'No CSV File Selected'),
'No Songs of Fellowship File Selected'),
translate('SongsPlugin.ImportWizardForm',
'You need to specify a CSV file to import from.'))
self.CSVFilenameEdit.setFocus()
'You need to add at least one Songs of Fellowship '
'file to import from.'))
self.songsOfFellowshipAddButton.setFocus()
return False
elif source_format == SongFormat.Generic:
if self.genericFileListWidget.count() == 0:
QtGui.QMessageBox.critical(self,
translate('SongsPlugin.ImportWizardForm',
'No Document/Presentation Selected'),
translate('SongsPlugin.ImportWizardForm',
'You need to add at least one document or '
'presentation file to import from.'))
self.genericAddButton.setFocus()
return False
return True
elif self.currentId() == 2:
# Progress page
return True
def getFileName(self, title, editbox):
filename = QtGui.QFileDialog.getOpenFileName(self, title,
SettingsManager.get_last_dir(self.plugin.settingsSection, 1))
if filename:
editbox.setText(filename)
SettingsManager.set_last_dir(
self.plugin.settingsSection,
os.path.split(unicode(filename))[0], 1)
def getFiles(self, title, listbox):
filenames = QtGui.QFileDialog.getOpenFileNames(self, title,
SettingsManager.get_last_dir(self.plugin.settingsSection, 1))
if filenames:
listbox.addItems(filenames)
SettingsManager.set_last_dir(
self.plugin.settingsSection,
os.path.split(unicode(filenames[0]))[0], 1)
def getListOfFiles(self, listbox):
files = []
for row in range(0, listbox.count()):
files.append(unicode(listbox.item(row).text()))
return files
def removeSelectedItems(self, listbox):
for item in listbox.selectedItems():
item = listbox.takeItem(listbox.row(item))
del item
def onOpenLP2BrowseButtonClicked(self):
self.getFileName(
translate('SongsPlugin.ImportWizardForm',
'Select OpenLP 2.0 Database File'),
self.openLP2FilenameEdit
)
def onOpenLP1BrowseButtonClicked(self):
self.getFileName(
translate('SongsPlugin.ImportWizardForm',
'Select openlp.org 1.x Database File'),
self.openLP1FilenameEdit
)
def onOpenLyricsAddButtonClicked(self):
self.getFiles(
translate('SongsPlugin.ImportWizardForm',
'Select OpenLyrics Files'),
self.openLyricsFileListWidget
)
def onOpenLyricsRemoveButtonClicked(self):
self.removeSelectedItems(self.openLyricsFileListWidget)
def onOpenSongAddButtonClicked(self):
self.getFiles(
translate('SongsPlugin.ImportWizardForm',
'Select Open Song Files'),
self.openSongFileListWidget
)
def onOpenSongRemoveButtonClicked(self):
self.removeSelectedItems(self.openSongFileListWidget)
def onWordsOfWorshipAddButtonClicked(self):
self.getFiles(
translate('SongsPlugin.ImportWizardForm',
'Select Words of Worship Files'),
self.wordsOfWorshipFileListWidget
)
def onWordsOfWorshipRemoveButtonClicked(self):
self.removeSelectedItems(self.wordsOfWorshipFileListWidget)
def onSongsOfFellowshipAddButtonClicked(self):
self.getFiles(
translate('SongsPlugin.ImportWizardForm',
'Select Songs of Fellowship Files'),
self.songsOfFellowshipFileListWidget
)
def onSongsOfFellowshipRemoveButtonClicked(self):
self.removeSelectedItems(self.songsOfFellowshipFileListWidget)
def onGenericAddButtonClicked(self):
self.getFiles(
translate('SongsPlugin.ImportWizardForm',
'Select Document/Presentation Files'),
self.genericFileListWidget
)
def onGenericRemoveButtonClicked(self):
self.removeSelectedItems(self.genericFileListWidget)
def onCancelButtonClicked(self, checked):
"""
Stop the import on pressing the cancel button.
"""
log.debug('Cancel button pressed!')
if self.currentId() == 3:
Receiver.send_message(u'openlp_stop_song_import')
if self.currentId() == 2:
Receiver.send_message(u'songs_stop_import')
def onCurrentIdChanged(self, id):
if id == 3:
if id == 2:
self.preImport()
self.performImport()
self.postImport()
def registerFields(self):
self.SourcePage.registerField(u'source_format', self.FormatComboBox)
pass
def setDefaults(self):
self.setField(u'source_format', QtCore.QVariant(0))
self.OpenLyricsFileListWidget.clear()
self.OpenSongFileListWidget.clear()
self.CCLIFileListWidget.clear()
self.CSVFilenameEdit.setText(u'')
self.formatComboBox.setCurrentIndex(0)
self.openLP2FilenameEdit.setText(u'')
self.openLP1FilenameEdit.setText(u'')
self.openLyricsFileListWidget.clear()
self.openSongFileListWidget.clear()
self.wordsOfWorshipFileListWidget.clear()
self.ccliFileListWidget.clear()
self.songsOfFellowshipFileListWidget.clear()
self.genericFileListWidget.clear()
#self.csvFilenameEdit.setText(u'')
def getFileName(self, title, editbox):
filename = QtGui.QFileDialog.getOpenFileName(self, title,
SettingsManager.get_last_dir(self.songsplugin.settingsSection, 1))
if filename:
editbox.setText(filename)
SettingsManager.set_last_dir(self.songsplugin.settingsSection,
filename, 1)
def incrementProgressBar(self, status_text):
def incrementProgressBar(self, status_text, increment=1):
log.debug(u'IncrementBar %s', status_text)
self.ImportProgressLabel.setText(status_text)
self.ImportProgressBar.setValue(self.ImportProgressBar.value() + 1)
Receiver.send_message(u'process_events')
if status_text:
self.importProgressLabel.setText(status_text)
if increment > 0:
self.importProgressBar.setValue(self.importProgressBar.value() +
increment)
Receiver.send_message(u'openlp_process_events')
def preImport(self):
self.finishButton.setVisible(False)
self.ImportProgressBar.setMinimum(0)
self.ImportProgressBar.setMaximum(1188)
self.ImportProgressBar.setValue(0)
self.ImportProgressLabel.setText(
self.importProgressBar.setMinimum(0)
self.importProgressBar.setMaximum(1188)
self.importProgressBar.setValue(0)
self.importProgressLabel.setText(
translate('SongsPlugin.ImportWizardForm', 'Starting import...'))
Receiver.send_message(u'process_events')
Receiver.send_message(u'openlp_process_events')
def performImport(self):
pass
# source_format = self.field(u'source_format').toInt()[0]
# importer = None
# if bible_type == BibleFormat.OSIS:
# # Import an OSIS bible
# importer = self.manager.import_bible(BibleFormat.OSIS,
# name=license_version,
# filename=unicode(self.field(u'osis_location').toString())
# )
# elif bible_type == BibleFormat.CSV:
# # Import a CSV bible
# importer = self.manager.import_bible(BibleFormat.CSV,
# name=license_version,
# booksfile=unicode(self.field(u'csv_booksfile').toString()),
# versefile=unicode(self.field(u'csv_versefile').toString())
# )
# elif bible_type == BibleFormat.OpenSong:
# # Import an OpenSong bible
# importer = self.manager.import_bible(BibleFormat.OpenSong,
# name=license_version,
# filename=unicode(self.field(u'opensong_file').toString())
# )
# elif bible_type == BibleFormat.WebDownload:
# # Import a bible from the web
# self.ImportProgressBar.setMaximum(1)
# download_location = self.field(u'web_location').toInt()[0]
# bible_version = self.BibleComboBox.currentText()
# if not isinstance(bible_version, unicode):
# bible_version = unicode(bible_version, u'utf8')
# if download_location == WebDownload.Crosswalk:
# bible = self.web_bible_list[WebDownload.Crosswalk][bible_version]
# elif download_location == WebDownload.BibleGateway:
# bible = self.web_bible_list[WebDownload.BibleGateway][bible_version]
# importer = self.manager.import_bible(
# BibleFormat.WebDownload,
# name=license_version,
# download_source=WebDownload.get_name(download_location),
# download_name=bible,
# proxy_server=unicode(self.field(u'proxy_server').toString()),
# proxy_username=unicode(self.field(u'proxy_username').toString()),
# proxy_password=unicode(self.field(u'proxy_password').toString())
# )
# success = importer.do_import()
# if success:
# self.manager.save_meta_data(license_version, license_version,
# license_copyright, license_permission)
# self.manager.reload_bibles()
# self.ImportProgressLabel.setText(translate('SongsPlugin.SongImportForm', 'Finished import.'))
# else:
# self.ImportProgressLabel.setText(
# translate('SongsPlugin.SongImportForm', 'Your Bible import failed.'))
# importer.delete()
"""
Perform the actual import. This method pulls in the correct importer
class, and then runs the ``do_import`` method of the importer to do
the actual importing.
"""
source_format = self.formatComboBox.currentIndex()
importer = None
if source_format == SongFormat.OpenLP2:
# Import an OpenLP 2.0 database
importer = self.plugin.importSongs(SongFormat.OpenLP2,
filename=unicode(self.openLP2FilenameEdit.text())
)
#elif source_format == SongFormat.OpenLP1:
# # Import an openlp.org database
# importer = self.plugin.importSongs(SongFormat.OpenLP1,
# filename=unicode(self.field(u'openlp1_filename').toString())
# )
elif source_format == SongFormat.OpenLyrics:
# Import OpenLyrics songs
importer = self.plugin.importSongs(SongFormat.OpenLyrics,
filenames=self.getListOfFiles(self.openLyricsFileListWidget)
)
elif source_format == SongFormat.OpenSong:
# Import OpenSong songs
importer = self.plugin.importSongs(SongFormat.OpenSong,
filenames=self.getListOfFiles(self.openSongFileListWidget)
)
elif source_format == SongFormat.WordsOfWorship:
# Import Words Of Worship songs
importer = self.plugin.importSongs(SongFormat.WordsOfWorship,
filenames=self.getListOfFiles(
self.wordsOfWorshipFileListWidget)
)
elif source_format == SongFormat.CCLI:
# Import Words Of Worship songs
importer = self.plugin.importSongs(SongFormat.CCLI,
filenames=self.getListOfFiles(self.ccliFileListWidget)
)
elif source_format == SongFormat.SongsOfFellowship:
# Import a Songs of Fellowship RTF file
importer = self.plugin.importSongs(SongFormat.SongsOfFellowship,
filenames=self.getListOfFiles(
self.songsOfFellowshipFileListWidget)
)
elif source_format == SongFormat.Generic:
# Import a generic document or presentatoin
importer = self.plugin.importSongs(SongFormat.Generic,
filenames=self.getListOfFiles(self.genericFileListWidget)
)
success = importer.do_import()
if success:
# reload songs
self.importProgressLabel.setText(
translate('SongsPlugin.SongImportForm', 'Finished import.'))
else:
self.importProgressLabel.setText(
translate('SongsPlugin.SongImportForm',
'Your song import failed.'))
def postImport(self):
self.ImportProgressBar.setValue(self.ImportProgressBar.maximum())
self.importProgressBar.setValue(self.importProgressBar.maximum())
self.finishButton.setVisible(True)
self.cancelButton.setVisible(False)
Receiver.send_message(u'process_events')
Receiver.send_message(u'openlp_process_events')

View File

@ -29,247 +29,425 @@ from PyQt4 import QtCore, QtGui
from openlp.core.lib import build_icon, translate
class Ui_SongImportWizard(object):
def setupUi(self, SongImportWizard):
SongImportWizard.setObjectName(u'SongImportWizard')
SongImportWizard.resize(550, 386)
SongImportWizard.setModal(True)
SongImportWizard.setWizardStyle(QtGui.QWizard.ModernStyle)
SongImportWizard.setOptions(
def setupUi(self, songImportWizard):
openIcon = build_icon(u':/general/general_open.png')
deleteIcon = build_icon(u':/general/general_delete.png')
songImportWizard.setObjectName(u'songImportWizard')
songImportWizard.resize(550, 386)
songImportWizard.setModal(True)
songImportWizard.setWizardStyle(QtGui.QWizard.ModernStyle)
songImportWizard.setOptions(
QtGui.QWizard.IndependentPages |
QtGui.QWizard.NoBackButtonOnStartPage |
QtGui.QWizard.NoBackButtonOnLastPage)
self.WelcomePage = QtGui.QWizardPage()
self.WelcomePage.setObjectName(u'WelcomePage')
self.WelcomePage.setPixmap(QtGui.QWizard.WatermarkPixmap,
self.welcomePage = QtGui.QWizardPage()
self.welcomePage.setObjectName(u'welcomePage')
self.welcomePage.setPixmap(QtGui.QWizard.WatermarkPixmap,
QtGui.QPixmap(u':/wizards/wizard_importsong.bmp'))
self.WelcomeLayout = QtGui.QHBoxLayout(self.WelcomePage)
self.WelcomeLayout.setSpacing(8)
self.WelcomeLayout.setMargin(0)
self.WelcomeLayout.setObjectName(u'WelcomeLayout')
self.WelcomeTextLayout = QtGui.QVBoxLayout()
self.WelcomeTextLayout.setSpacing(8)
self.WelcomeTextLayout.setObjectName(u'WelcomeTextLayout')
self.TitleLabel = QtGui.QLabel(self.WelcomePage)
self.TitleLabel.setObjectName(u'TitleLabel')
self.WelcomeTextLayout.addWidget(self.TitleLabel)
self.WelcomeTopSpacer = QtGui.QSpacerItem(20, 40,
self.welcomeLayout = QtGui.QHBoxLayout(self.welcomePage)
self.welcomeLayout.setSpacing(8)
self.welcomeLayout.setMargin(0)
self.welcomeLayout.setObjectName(u'welcomeLayout')
self.welcomeTextLayout = QtGui.QVBoxLayout()
self.welcomeTextLayout.setSpacing(8)
self.welcomeTextLayout.setObjectName(u'welcomeTextLayout')
self.titleLabel = QtGui.QLabel(self.welcomePage)
self.titleLabel.setObjectName(u'TitleLabel')
self.welcomeTextLayout.addWidget(self.titleLabel)
self.welcomeTopSpacer = QtGui.QSpacerItem(20, 40,
QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Fixed)
self.WelcomeTextLayout.addItem(self.WelcomeTopSpacer)
self.InformationLabel = QtGui.QLabel(self.WelcomePage)
self.InformationLabel.setWordWrap(True)
self.InformationLabel.setMargin(10)
self.InformationLabel.setObjectName(u'InformationLabel')
self.WelcomeTextLayout.addWidget(self.InformationLabel)
self.WelcomeBottomSpacer = QtGui.QSpacerItem(20, 40,
self.welcomeTextLayout.addItem(self.welcomeTopSpacer)
self.informationLabel = QtGui.QLabel(self.welcomePage)
self.informationLabel.setWordWrap(True)
self.informationLabel.setMargin(10)
self.informationLabel.setObjectName(u'InformationLabel')
self.welcomeTextLayout.addWidget(self.informationLabel)
self.welcomeBottomSpacer = QtGui.QSpacerItem(20, 40,
QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
self.WelcomeTextLayout.addItem(self.WelcomeBottomSpacer)
self.WelcomeLayout.addLayout(self.WelcomeTextLayout)
SongImportWizard.addPage(self.WelcomePage)
self.SourcePage = QtGui.QWizardPage()
self.SourcePage.setObjectName(u'SourcePage')
self.SourceLayout = QtGui.QVBoxLayout(self.SourcePage)
self.SourceLayout.setSpacing(8)
self.SourceLayout.setMargin(20)
self.SourceLayout.setObjectName(u'SourceLayout')
self.FormatLayout = QtGui.QHBoxLayout()
self.FormatLayout.setSpacing(8)
self.FormatLayout.setObjectName(u'FormatLayout')
self.FormatLabel = QtGui.QLabel(self.SourcePage)
self.FormatLabel.setObjectName(u'FormatLabel')
self.FormatLayout.addWidget(self.FormatLabel)
self.FormatComboBox = QtGui.QComboBox(self.SourcePage)
self.welcomeTextLayout.addItem(self.welcomeBottomSpacer)
self.welcomeLayout.addLayout(self.welcomeTextLayout)
songImportWizard.addPage(self.welcomePage)
self.sourcePage = QtGui.QWizardPage()
self.sourcePage.setObjectName(u'SourcePage')
self.sourceLayout = QtGui.QVBoxLayout(self.sourcePage)
self.sourceLayout.setSpacing(8)
self.sourceLayout.setMargin(20)
self.sourceLayout.setObjectName(u'SourceLayout')
self.formatLayout = QtGui.QHBoxLayout()
self.formatLayout.setSpacing(8)
self.formatLayout.setObjectName(u'FormatLayout')
self.formatLabel = QtGui.QLabel(self.sourcePage)
self.formatLabel.setObjectName(u'FormatLabel')
self.formatLayout.addWidget(self.formatLabel)
self.formatComboBox = QtGui.QComboBox(self.sourcePage)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding,
QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(
self.FormatComboBox.sizePolicy().hasHeightForWidth())
self.FormatComboBox.setSizePolicy(sizePolicy)
self.FormatComboBox.setObjectName(u'FormatComboBox')
self.FormatComboBox.addItem(u'')
self.FormatComboBox.addItem(u'')
self.FormatComboBox.addItem(u'')
self.FormatComboBox.addItem(u'')
self.FormatLayout.addWidget(self.FormatComboBox)
self.FormatSpacer = QtGui.QSpacerItem(40, 20,
self.formatComboBox.sizePolicy().hasHeightForWidth())
self.formatComboBox.setSizePolicy(sizePolicy)
self.formatComboBox.setObjectName(u'formatComboBox')
self.formatComboBox.addItem(u'')
self.formatComboBox.addItem(u'')
self.formatComboBox.addItem(u'')
self.formatComboBox.addItem(u'')
self.formatComboBox.addItem(u'')
self.formatComboBox.addItem(u'')
self.formatComboBox.addItem(u'')
self.formatComboBox.addItem(u'')
# self.formatComboBox.addItem(u'')
self.formatLayout.addWidget(self.formatComboBox)
self.formatSpacer = QtGui.QSpacerItem(40, 20,
QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.FormatLayout.addItem(self.FormatSpacer)
self.SourceLayout.addLayout(self.FormatLayout)
self.FormatStackedWidget = QtGui.QStackedWidget(self.SourcePage)
self.FormatStackedWidget.setObjectName(u'FormatStackedWidget')
self.OpenLyricsPage = QtGui.QWidget()
self.OpenLyricsPage.setObjectName(u'OpenLyricsPage')
self.OpenLyricsLayout = QtGui.QVBoxLayout(self.OpenLyricsPage)
self.OpenLyricsLayout.setSpacing(8)
self.OpenLyricsLayout.setMargin(0)
self.OpenLyricsLayout.setObjectName(u'OpenLyricsLayout')
self.OpenLyricsFileListWidget = QtGui.QListWidget(self.OpenLyricsPage)
self.OpenLyricsFileListWidget.setObjectName(u'OpenLyricsFileListWidget')
self.OpenLyricsLayout.addWidget(self.OpenLyricsFileListWidget)
self.OpenLyricsButtonLayout = QtGui.QHBoxLayout()
self.OpenLyricsButtonLayout.setSpacing(8)
self.OpenLyricsButtonLayout.setObjectName(u'OpenLyricsButtonLayout')
self.OpenLyricsAddButton = QtGui.QPushButton(self.OpenLyricsPage)
openIcon = build_icon(u':/general/general_open.png')
self.OpenLyricsAddButton.setIcon(openIcon)
self.OpenLyricsAddButton.setObjectName(u'OpenLyricsAddButton')
self.OpenLyricsButtonLayout.addWidget(self.OpenLyricsAddButton)
self.OpenLyricsButtonSpacer = QtGui.QSpacerItem(40, 20,
self.formatLayout.addItem(self.formatSpacer)
self.sourceLayout.addLayout(self.formatLayout)
self.formatStackedWidget = QtGui.QStackedWidget(self.sourcePage)
self.formatStackedWidget.setObjectName(u'FormatStackedWidget')
# OpenLP 2.0
self.openLP2Page = QtGui.QWidget()
self.openLP2Page.setObjectName(u'openLP2Page')
self.openLP2Layout = QtGui.QFormLayout(self.openLP2Page)
self.openLP2Layout.setMargin(0)
self.openLP2Layout.setSpacing(8)
self.openLP2Layout.setObjectName(u'openLP2Layout')
self.openLP2FilenameLabel = QtGui.QLabel(self.openLP2Page)
self.openLP2FilenameLabel.setObjectName(u'openLP2FilenameLabel')
self.openLP2Layout.setWidget(0, QtGui.QFormLayout.LabelRole,
self.openLP2FilenameLabel)
self.openLP2FileLayout = QtGui.QHBoxLayout()
self.openLP2FileLayout.setSpacing(8)
self.openLP2FileLayout.setObjectName(u'openLP2FileLayout')
self.openLP2FilenameEdit = QtGui.QLineEdit(self.openLP2Page)
self.openLP2FilenameEdit.setObjectName(u'openLP2FilenameEdit')
self.openLP2FileLayout.addWidget(self.openLP2FilenameEdit)
self.openLP2BrowseButton = QtGui.QToolButton(self.openLP2Page)
self.openLP2BrowseButton.setIcon(openIcon)
self.openLP2BrowseButton.setObjectName(u'openLP2BrowseButton')
self.openLP2FileLayout.addWidget(self.openLP2BrowseButton)
self.openLP2Layout.setLayout(0, QtGui.QFormLayout.FieldRole,
self.openLP2FileLayout)
self.formatStackedWidget.addWidget(self.openLP2Page)
# openlp.org 1.x
self.openLP1Page = QtGui.QWidget()
self.openLP1Page.setObjectName(u'openLP1Page')
self.openLP1Layout = QtGui.QFormLayout(self.openLP1Page)
self.openLP1Layout.setMargin(0)
self.openLP1Layout.setSpacing(8)
self.openLP1Layout.setObjectName(u'openLP1Layout')
self.openLP1FilenameLabel = QtGui.QLabel(self.openLP1Page)
self.openLP1FilenameLabel.setObjectName(u'openLP1FilenameLabel')
self.openLP1Layout.setWidget(0, QtGui.QFormLayout.LabelRole,
self.openLP1FilenameLabel)
self.openLP1FileLayout = QtGui.QHBoxLayout()
self.openLP1FileLayout.setSpacing(8)
self.openLP1FileLayout.setObjectName(u'openLP1FileLayout')
self.openLP1FilenameEdit = QtGui.QLineEdit(self.openLP1Page)
self.openLP1FilenameEdit.setObjectName(u'openLP1FilenameEdit')
self.openLP1FileLayout.addWidget(self.openLP1FilenameEdit)
self.openLP1BrowseButton = QtGui.QToolButton(self.openLP1Page)
self.openLP1BrowseButton.setIcon(openIcon)
self.openLP1BrowseButton.setObjectName(u'openLP1BrowseButton')
self.openLP1FileLayout.addWidget(self.openLP1BrowseButton)
self.openLP1Layout.setLayout(0, QtGui.QFormLayout.FieldRole,
self.openLP1FileLayout)
self.formatStackedWidget.addWidget(self.openLP1Page)
# OpenLyrics
self.openLyricsPage = QtGui.QWidget()
self.openLyricsPage.setObjectName(u'OpenLyricsPage')
self.openLyricsLayout = QtGui.QVBoxLayout(self.openLyricsPage)
self.openLyricsLayout.setSpacing(8)
self.openLyricsLayout.setMargin(0)
self.openLyricsLayout.setObjectName(u'OpenLyricsLayout')
self.openLyricsFileListWidget = QtGui.QListWidget(self.openLyricsPage)
self.openLyricsFileListWidget.setSelectionMode(
QtGui.QAbstractItemView.ExtendedSelection)
self.openLyricsFileListWidget.setObjectName(u'OpenLyricsFileListWidget')
self.openLyricsLayout.addWidget(self.openLyricsFileListWidget)
self.openLyricsButtonLayout = QtGui.QHBoxLayout()
self.openLyricsButtonLayout.setSpacing(8)
self.openLyricsButtonLayout.setObjectName(u'OpenLyricsButtonLayout')
self.openLyricsAddButton = QtGui.QPushButton(self.openLyricsPage)
self.openLyricsAddButton.setIcon(openIcon)
self.openLyricsAddButton.setObjectName(u'OpenLyricsAddButton')
self.openLyricsButtonLayout.addWidget(self.openLyricsAddButton)
self.openLyricsButtonSpacer = QtGui.QSpacerItem(40, 20,
QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.OpenLyricsButtonLayout.addItem(self.OpenLyricsButtonSpacer)
self.OpenLyricsRemoveButton = QtGui.QPushButton(self.OpenLyricsPage)
deleteIcon = build_icon(u':/general/general_delete.png')
self.OpenLyricsRemoveButton.setIcon(deleteIcon)
self.OpenLyricsRemoveButton.setObjectName(u'OpenLyricsRemoveButton')
self.OpenLyricsButtonLayout.addWidget(self.OpenLyricsRemoveButton)
self.OpenLyricsLayout.addLayout(self.OpenLyricsButtonLayout)
self.FormatStackedWidget.addWidget(self.OpenLyricsPage)
self.OpenSongPage = QtGui.QWidget()
self.OpenSongPage.setObjectName(u'OpenSongPage')
self.OpenSongLayout = QtGui.QVBoxLayout(self.OpenSongPage)
self.OpenSongLayout.setSpacing(8)
self.OpenSongLayout.setMargin(0)
self.OpenSongLayout.setObjectName(u'OpenSongLayout')
self.OpenSongFileListWidget = QtGui.QListWidget(self.OpenSongPage)
self.OpenSongFileListWidget.setObjectName(u'OpenSongFileListWidget')
self.OpenSongLayout.addWidget(self.OpenSongFileListWidget)
self.OpenSongButtonLayout = QtGui.QHBoxLayout()
self.OpenSongButtonLayout.setSpacing(8)
self.OpenSongButtonLayout.setObjectName(u'OpenSongButtonLayout')
self.OpenSongAddButton = QtGui.QPushButton(self.OpenSongPage)
self.OpenSongAddButton.setIcon(openIcon)
self.OpenSongAddButton.setObjectName(u'OpenSongAddButton')
self.OpenSongButtonLayout.addWidget(self.OpenSongAddButton)
self.OpenSongButtonSpacer = QtGui.QSpacerItem(40, 20,
self.openLyricsButtonLayout.addItem(self.openLyricsButtonSpacer)
self.openLyricsRemoveButton = QtGui.QPushButton(self.openLyricsPage)
self.openLyricsRemoveButton.setIcon(deleteIcon)
self.openLyricsRemoveButton.setObjectName(u'OpenLyricsRemoveButton')
self.openLyricsButtonLayout.addWidget(self.openLyricsRemoveButton)
self.openLyricsLayout.addLayout(self.openLyricsButtonLayout)
self.formatStackedWidget.addWidget(self.openLyricsPage)
# Open Song
self.openSongPage = QtGui.QWidget()
self.openSongPage.setObjectName(u'OpenSongPage')
self.openSongLayout = QtGui.QVBoxLayout(self.openSongPage)
self.openSongLayout.setSpacing(8)
self.openSongLayout.setMargin(0)
self.openSongLayout.setObjectName(u'OpenSongLayout')
self.openSongFileListWidget = QtGui.QListWidget(self.openSongPage)
self.openSongFileListWidget.setSelectionMode(
QtGui.QAbstractItemView.ExtendedSelection)
self.openSongFileListWidget.setObjectName(u'OpenSongFileListWidget')
self.openSongLayout.addWidget(self.openSongFileListWidget)
self.openSongButtonLayout = QtGui.QHBoxLayout()
self.openSongButtonLayout.setSpacing(8)
self.openSongButtonLayout.setObjectName(u'OpenSongButtonLayout')
self.openSongAddButton = QtGui.QPushButton(self.openSongPage)
self.openSongAddButton.setIcon(openIcon)
self.openSongAddButton.setObjectName(u'OpenSongAddButton')
self.openSongButtonLayout.addWidget(self.openSongAddButton)
self.openSongButtonSpacer = QtGui.QSpacerItem(40, 20,
QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.OpenSongButtonLayout.addItem(self.OpenSongButtonSpacer)
self.OpenSongRemoveButton = QtGui.QPushButton(self.OpenSongPage)
self.OpenSongRemoveButton.setIcon(deleteIcon)
self.OpenSongRemoveButton.setObjectName(u'OpenSongRemoveButton')
self.OpenSongButtonLayout.addWidget(self.OpenSongRemoveButton)
self.OpenSongLayout.addLayout(self.OpenSongButtonLayout)
self.FormatStackedWidget.addWidget(self.OpenSongPage)
self.CCLIPage = QtGui.QWidget()
self.CCLIPage.setObjectName(u'CCLIPage')
self.CCLILayout = QtGui.QVBoxLayout(self.CCLIPage)
self.CCLILayout.setSpacing(8)
self.CCLILayout.setMargin(0)
self.CCLILayout.setObjectName(u'CCLILayout')
self.CCLIFileListWidget = QtGui.QListWidget(self.CCLIPage)
self.CCLIFileListWidget.setObjectName(u'CCLIFileListWidget')
self.CCLILayout.addWidget(self.CCLIFileListWidget)
self.CCLIButtonLayout = QtGui.QHBoxLayout()
self.CCLIButtonLayout.setSpacing(8)
self.CCLIButtonLayout.setObjectName(u'CCLIButtonLayout')
self.CCLIAddButton = QtGui.QPushButton(self.CCLIPage)
self.CCLIAddButton.setIcon(openIcon)
self.CCLIAddButton.setObjectName(u'CCLIAddButton')
self.CCLIButtonLayout.addWidget(self.CCLIAddButton)
self.CCLIButtonSpacer = QtGui.QSpacerItem(40, 20,
self.openSongButtonLayout.addItem(self.openSongButtonSpacer)
self.openSongRemoveButton = QtGui.QPushButton(self.openSongPage)
self.openSongRemoveButton.setIcon(deleteIcon)
self.openSongRemoveButton.setObjectName(u'OpenSongRemoveButton')
self.openSongButtonLayout.addWidget(self.openSongRemoveButton)
self.openSongLayout.addLayout(self.openSongButtonLayout)
self.formatStackedWidget.addWidget(self.openSongPage)
# Words of Worship
self.wordsOfWorshipPage = QtGui.QWidget()
self.wordsOfWorshipPage.setObjectName(u'wordsOfWorshipPage')
self.wordsOfWorshipLayout = QtGui.QVBoxLayout(self.wordsOfWorshipPage)
self.wordsOfWorshipLayout.setSpacing(8)
self.wordsOfWorshipLayout.setMargin(0)
self.wordsOfWorshipLayout.setObjectName(u'wordsOfWorshipLayout')
self.wordsOfWorshipFileListWidget = QtGui.QListWidget(self.wordsOfWorshipPage)
self.wordsOfWorshipFileListWidget.setSelectionMode(
QtGui.QAbstractItemView.ExtendedSelection)
self.wordsOfWorshipFileListWidget.setObjectName(u'wordsOfWorshipFileListWidget')
self.wordsOfWorshipLayout.addWidget(self.wordsOfWorshipFileListWidget)
self.wordsOfWorshipButtonLayout = QtGui.QHBoxLayout()
self.wordsOfWorshipButtonLayout.setSpacing(8)
self.wordsOfWorshipButtonLayout.setObjectName(u'wordsOfWorshipButtonLayout')
self.wordsOfWorshipAddButton = QtGui.QPushButton(self.wordsOfWorshipPage)
self.wordsOfWorshipAddButton.setIcon(openIcon)
self.wordsOfWorshipAddButton.setObjectName(u'wordsOfWorshipAddButton')
self.wordsOfWorshipButtonLayout.addWidget(self.wordsOfWorshipAddButton)
self.wordsOfWorshipButtonSpacer = QtGui.QSpacerItem(40, 20,
QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.CCLIButtonLayout.addItem(self.CCLIButtonSpacer)
self.CCLIRemoveButton = QtGui.QPushButton(self.CCLIPage)
self.CCLIRemoveButton.setIcon(deleteIcon)
self.CCLIRemoveButton.setObjectName(u'CCLIRemoveButton')
self.CCLIButtonLayout.addWidget(self.CCLIRemoveButton)
self.CCLILayout.addLayout(self.CCLIButtonLayout)
self.FormatStackedWidget.addWidget(self.CCLIPage)
self.CSVPage = QtGui.QWidget()
self.CSVPage.setObjectName(u'CSVPage')
self.CSVLayout = QtGui.QFormLayout(self.CSVPage)
self.CSVLayout.setMargin(0)
self.CSVLayout.setSpacing(8)
self.CSVLayout.setObjectName(u'CSVLayout')
self.CSVFilenameLabel = QtGui.QLabel(self.CSVPage)
self.CSVFilenameLabel.setObjectName(u'CSVFilenameLabel')
self.CSVLayout.setWidget(0, QtGui.QFormLayout.LabelRole,
self.CSVFilenameLabel)
self.CSVFileLayout = QtGui.QHBoxLayout()
self.CSVFileLayout.setSpacing(8)
self.CSVFileLayout.setObjectName(u'CSVFileLayout')
self.CSVFilenameEdit = QtGui.QLineEdit(self.CSVPage)
self.CSVFilenameEdit.setObjectName(u'CSVFilenameEdit')
self.CSVFileLayout.addWidget(self.CSVFilenameEdit)
self.CSVBrowseButton = QtGui.QToolButton(self.CSVPage)
self.CSVBrowseButton.setIcon(openIcon)
self.CSVBrowseButton.setObjectName(u'CSVBrowseButton')
self.CSVFileLayout.addWidget(self.CSVBrowseButton)
self.CSVLayout.setLayout(0, QtGui.QFormLayout.FieldRole,
self.CSVFileLayout)
self.FormatStackedWidget.addWidget(self.CSVPage)
self.SourceLayout.addWidget(self.FormatStackedWidget)
SongImportWizard.addPage(self.SourcePage)
self.ImportPage = QtGui.QWizardPage()
self.ImportPage.setObjectName(u'ImportPage')
self.ImportLayout = QtGui.QVBoxLayout(self.ImportPage)
self.ImportLayout.setSpacing(8)
self.ImportLayout.setMargin(50)
self.ImportLayout.setObjectName(u'ImportLayout')
self.ImportProgressLabel = QtGui.QLabel(self.ImportPage)
self.ImportProgressLabel.setObjectName(u'ImportProgressLabel')
self.ImportLayout.addWidget(self.ImportProgressLabel)
self.ImportProgressBar = QtGui.QProgressBar(self.ImportPage)
self.ImportProgressBar.setProperty(u'value', 0)
self.ImportProgressBar.setInvertedAppearance(False)
self.ImportProgressBar.setObjectName(u'ImportProgressBar')
self.ImportLayout.addWidget(self.ImportProgressBar)
SongImportWizard.addPage(self.ImportPage)
self.retranslateUi(SongImportWizard)
self.FormatStackedWidget.setCurrentIndex(0)
QtCore.QObject.connect(self.FormatComboBox,
self.wordsOfWorshipButtonLayout.addItem(self.wordsOfWorshipButtonSpacer)
self.wordsOfWorshipRemoveButton = QtGui.QPushButton(self.wordsOfWorshipPage)
self.wordsOfWorshipRemoveButton.setIcon(deleteIcon)
self.wordsOfWorshipRemoveButton.setObjectName(u'wordsOfWorshipRemoveButton')
self.wordsOfWorshipButtonLayout.addWidget(self.wordsOfWorshipRemoveButton)
self.wordsOfWorshipLayout.addLayout(self.wordsOfWorshipButtonLayout)
self.formatStackedWidget.addWidget(self.wordsOfWorshipPage)
# CCLI File import
self.ccliPage = QtGui.QWidget()
self.ccliPage.setObjectName(u'ccliPage')
self.ccliLayout = QtGui.QVBoxLayout(self.ccliPage)
self.ccliLayout.setSpacing(8)
self.ccliLayout.setMargin(0)
self.ccliLayout.setObjectName(u'ccliLayout')
self.ccliFileListWidget = QtGui.QListWidget(self.ccliPage)
self.ccliFileListWidget.setSelectionMode(
QtGui.QAbstractItemView.ExtendedSelection)
self.ccliFileListWidget.setObjectName(u'ccliFileListWidget')
self.ccliLayout.addWidget(self.ccliFileListWidget)
self.ccliButtonLayout = QtGui.QHBoxLayout()
self.ccliButtonLayout.setSpacing(8)
self.ccliButtonLayout.setObjectName(u'ccliButtonLayout')
self.ccliAddButton = QtGui.QPushButton(self.ccliPage)
self.ccliAddButton.setIcon(openIcon)
self.ccliAddButton.setObjectName(u'ccliAddButton')
self.ccliButtonLayout.addWidget(self.ccliAddButton)
self.ccliButtonSpacer = QtGui.QSpacerItem(40, 20,
QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.ccliButtonLayout.addItem(self.ccliButtonSpacer)
self.ccliRemoveButton = QtGui.QPushButton(self.ccliPage)
self.ccliRemoveButton.setIcon(deleteIcon)
self.ccliRemoveButton.setObjectName(u'ccliRemoveButton')
self.ccliButtonLayout.addWidget(self.ccliRemoveButton)
self.ccliLayout.addLayout(self.ccliButtonLayout)
self.formatStackedWidget.addWidget(self.ccliPage)
# Songs of Fellowship
self.songsOfFellowshipPage = QtGui.QWidget()
self.songsOfFellowshipPage.setObjectName(u'songsOfFellowshipPage')
self.songsOfFellowshipLayout = QtGui.QVBoxLayout(self.songsOfFellowshipPage)
self.songsOfFellowshipLayout.setMargin(0)
self.songsOfFellowshipLayout.setSpacing(8)
self.songsOfFellowshipLayout.setObjectName(u'songsOfFellowshipLayout')
self.songsOfFellowshipFileListWidget = QtGui.QListWidget(self.songsOfFellowshipPage)
self.songsOfFellowshipFileListWidget.setSelectionMode(
QtGui.QAbstractItemView.ExtendedSelection)
self.songsOfFellowshipFileListWidget.setObjectName(u'songsOfFellowshipFileListWidget')
self.songsOfFellowshipLayout.addWidget(self.songsOfFellowshipFileListWidget)
self.songsOfFellowshipButtonLayout = QtGui.QHBoxLayout()
self.songsOfFellowshipButtonLayout.setSpacing(8)
self.songsOfFellowshipButtonLayout.setObjectName(u'songsOfFellowshipButtonLayout')
self.songsOfFellowshipAddButton = QtGui.QPushButton(self.songsOfFellowshipPage)
self.songsOfFellowshipAddButton.setIcon(openIcon)
self.songsOfFellowshipAddButton.setObjectName(u'songsOfFellowshipAddButton')
self.songsOfFellowshipButtonLayout.addWidget(self.songsOfFellowshipAddButton)
self.songsOfFellowshipButtonSpacer = QtGui.QSpacerItem(40, 20,
QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.songsOfFellowshipButtonLayout.addItem(self.songsOfFellowshipButtonSpacer)
self.songsOfFellowshipRemoveButton = QtGui.QPushButton(self.songsOfFellowshipPage)
self.songsOfFellowshipRemoveButton.setIcon(deleteIcon)
self.songsOfFellowshipRemoveButton.setObjectName(u'songsOfFellowshipRemoveButton')
self.songsOfFellowshipButtonLayout.addWidget(self.songsOfFellowshipRemoveButton)
self.songsOfFellowshipLayout.addLayout(self.songsOfFellowshipButtonLayout)
self.formatStackedWidget.addWidget(self.songsOfFellowshipPage)
# Generic Document/Presentation import
self.genericPage = QtGui.QWidget()
self.genericPage.setObjectName(u'genericPage')
self.genericLayout = QtGui.QVBoxLayout(self.genericPage)
self.genericLayout.setMargin(0)
self.genericLayout.setSpacing(8)
self.genericLayout.setObjectName(u'genericLayout')
self.genericFileListWidget = QtGui.QListWidget(self.genericPage)
self.genericFileListWidget.setSelectionMode(
QtGui.QAbstractItemView.ExtendedSelection)
self.genericFileListWidget.setObjectName(u'genericFileListWidget')
self.genericLayout.addWidget(self.genericFileListWidget)
self.genericButtonLayout = QtGui.QHBoxLayout()
self.genericButtonLayout.setSpacing(8)
self.genericButtonLayout.setObjectName(u'genericButtonLayout')
self.genericAddButton = QtGui.QPushButton(self.genericPage)
self.genericAddButton.setIcon(openIcon)
self.genericAddButton.setObjectName(u'genericAddButton')
self.genericButtonLayout.addWidget(self.genericAddButton)
self.genericButtonSpacer = QtGui.QSpacerItem(40, 20,
QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.genericButtonLayout.addItem(self.genericButtonSpacer)
self.genericRemoveButton = QtGui.QPushButton(self.genericPage)
self.genericRemoveButton.setIcon(deleteIcon)
self.genericRemoveButton.setObjectName(u'genericRemoveButton')
self.genericButtonLayout.addWidget(self.genericRemoveButton)
self.genericLayout.addLayout(self.genericButtonLayout)
self.formatStackedWidget.addWidget(self.genericPage)
# Commented out for future use.
# self.csvPage = QtGui.QWidget()
# self.csvPage.setObjectName(u'CSVPage')
# self.csvLayout = QtGui.QFormLayout(self.csvPage)
# self.csvLayout.setMargin(0)
# self.csvLayout.setSpacing(8)
# self.csvLayout.setObjectName(u'CSVLayout')
# self.csvFilenameLabel = QtGui.QLabel(self.csvPage)
# self.csvFilenameLabel.setObjectName(u'CSVFilenameLabel')
# self.csvLayout.setWidget(0, QtGui.QFormLayout.LabelRole,
# self.csvFilenameLabel)
# self.csvFileLayout = QtGui.QHBoxLayout()
# self.csvFileLayout.setSpacing(8)
# self.csvFileLayout.setObjectName(u'CSVFileLayout')
# self.csvFilenameEdit = QtGui.QLineEdit(self.csvPage)
# self.csvFilenameEdit.setObjectName(u'CSVFilenameEdit')
# self.csvFileLayout.addWidget(self.csvFilenameEdit)
# self.csvBrowseButton = QtGui.QToolButton(self.csvPage)
# self.csvBrowseButton.setIcon(openIcon)
# self.csvBrowseButton.setObjectName(u'CSVBrowseButton')
# self.csvFileLayout.addWidget(self.csvBrowseButton)
# self.csvLayout.setLayout(0, QtGui.QFormLayout.FieldRole,
# self.csvFileLayout)
# self.formatStackedWidget.addWidget(self.csvPage)
self.sourceLayout.addWidget(self.formatStackedWidget)
songImportWizard.addPage(self.sourcePage)
self.importPage = QtGui.QWizardPage()
self.importPage.setObjectName(u'importPage')
self.importLayout = QtGui.QVBoxLayout(self.importPage)
self.importLayout.setSpacing(8)
self.importLayout.setMargin(50)
self.importLayout.setObjectName(u'importLayout')
self.importProgressLabel = QtGui.QLabel(self.importPage)
self.importProgressLabel.setObjectName(u'importProgressLabel')
self.importLayout.addWidget(self.importProgressLabel)
self.importProgressBar = QtGui.QProgressBar(self.importPage)
self.importProgressBar.setProperty(u'value', 0)
self.importProgressBar.setInvertedAppearance(False)
self.importProgressBar.setObjectName(u'importProgressBar')
self.importLayout.addWidget(self.importProgressBar)
songImportWizard.addPage(self.importPage)
self.retranslateUi(songImportWizard)
self.formatStackedWidget.setCurrentIndex(0)
QtCore.QObject.connect(self.formatComboBox,
QtCore.SIGNAL(u'currentIndexChanged(int)'),
self.FormatStackedWidget.setCurrentIndex)
QtCore.QMetaObject.connectSlotsByName(SongImportWizard)
self.formatStackedWidget.setCurrentIndex)
QtCore.QMetaObject.connectSlotsByName(songImportWizard)
def retranslateUi(self, SongImportWizard):
SongImportWizard.setWindowTitle(
def retranslateUi(self, songImportWizard):
songImportWizard.setWindowTitle(
translate('SongsPlugin.ImportWizardForm', 'Song Import Wizard'))
self.TitleLabel.setText(
self.titleLabel.setText(
u'<span style="font-size:14pt; font-weight:600;">%s</span>' % \
translate('SongsPlugin.ImportWizardForm',
'Welcome to the Song Import Wizard'))
self.InformationLabel.setText(
self.informationLabel.setText(
translate('SongsPlugin.ImportWizardForm',
'This wizard will help you to import songs from a variety of '
'formats. Click the next button below to start the process by '
'selecting a format to import from.'))
self.SourcePage.setTitle(
self.sourcePage.setTitle(
translate('SongsPlugin.ImportWizardForm', 'Select Import Source'))
self.SourcePage.setSubTitle(
self.sourcePage.setSubTitle(
translate('SongsPlugin.ImportWizardForm',
'Select the import format, and where to import from.'))
self.FormatLabel.setText(
self.formatLabel.setText(
translate('SongsPlugin.ImportWizardForm', 'Format:'))
self.FormatComboBox.setItemText(0,
self.formatComboBox.setItemText(0,
translate('SongsPlugin.ImportWizardForm', 'OpenLP 2.0'))
self.formatComboBox.setItemText(1,
translate('SongsPlugin.ImportWizardForm', 'openlp.org 1.x'))
self.formatComboBox.setItemText(2,
translate('SongsPlugin.ImportWizardForm', 'OpenLyrics'))
self.FormatComboBox.setItemText(1,
self.formatComboBox.setItemText(3,
translate('SongsPlugin.ImportWizardForm', 'OpenSong'))
self.FormatComboBox.setItemText(2,
translate('SongsPlugin.ImportWizardForm', 'CCLI'))
self.FormatComboBox.setItemText(3,
translate('SongsPlugin.ImportWizardForm', 'CSV'))
self.OpenLyricsAddButton.setText(
translate('SongsPlugin.ImportWizardForm', 'Add Files...'))
self.OpenLyricsRemoveButton.setText(
translate('SongsPlugin.ImportWizardForm', 'Remove File(s)'))
self.OpenSongAddButton.setText(
translate('SongsPlugin.ImportWizardForm', 'Add Files...'))
self.OpenSongRemoveButton.setText(
translate('SongsPlugin.ImportWizardForm', 'Remove File(s)'))
self.CCLIAddButton.setText(
translate('SongsPlugin.ImportWizardForm', 'Add Files...'))
self.CCLIRemoveButton.setText(
translate('SongsPlugin.ImportWizardForm', 'Remove File(s)'))
self.CSVFilenameLabel.setText(
self.formatComboBox.setItemText(4,
translate('SongsPlugin.ImportWizardForm', 'Words of Worship'))
self.formatComboBox.setItemText(5,
translate('SongsPlugin.ImportWizardForm', 'CCLI/SongSelect'))
self.formatComboBox.setItemText(6,
translate('SongsPlugin.ImportWizardForm', 'Songs of Fellowship'))
self.formatComboBox.setItemText(7,
translate('SongsPlugin.ImportWizardForm',
'Generic Document/Presentation'))
# self.formatComboBox.setItemText(8,
# translate('SongsPlugin.ImportWizardForm', 'CSV'))
self.openLP2FilenameLabel.setText(
translate('SongsPlugin.ImportWizardForm', 'Filename:'))
self.CSVBrowseButton.setText(
self.openLP2BrowseButton.setText(
translate('SongsPlugin.ImportWizardForm', 'Browse...'))
self.ImportPage.setTitle(
self.openLP1FilenameLabel.setText(
translate('SongsPlugin.ImportWizardForm', 'Filename:'))
self.openLP1BrowseButton.setText(
translate('SongsPlugin.ImportWizardForm', 'Browse...'))
self.openLyricsAddButton.setText(
translate('SongsPlugin.ImportWizardForm', 'Add Files...'))
self.openLyricsRemoveButton.setText(
translate('SongsPlugin.ImportWizardForm', 'Remove File(s)'))
self.openSongAddButton.setText(
translate('SongsPlugin.ImportWizardForm', 'Add Files...'))
self.openSongRemoveButton.setText(
translate('SongsPlugin.ImportWizardForm', 'Remove File(s)'))
self.wordsOfWorshipAddButton.setText(
translate('SongsPlugin.ImportWizardForm', 'Add Files...'))
self.wordsOfWorshipRemoveButton.setText(
translate('SongsPlugin.ImportWizardForm', 'Remove File(s)'))
self.ccliAddButton.setText(
translate('SongsPlugin.ImportWizardForm', 'Add Files...'))
self.ccliRemoveButton.setText(
translate('SongsPlugin.ImportWizardForm', 'Remove File(s)'))
self.songsOfFellowshipAddButton.setText(
translate('SongsPlugin.ImportWizardForm', 'Add Files...'))
self.songsOfFellowshipRemoveButton.setText(
translate('SongsPlugin.ImportWizardForm', 'Remove File(s)'))
self.genericAddButton.setText(
translate('SongsPlugin.ImportWizardForm', 'Add Files...'))
self.genericRemoveButton.setText(
translate('SongsPlugin.ImportWizardForm', 'Remove File(s)'))
# self.csvFilenameLabel.setText(
# translate('SongsPlugin.ImportWizardForm', 'Filename:'))
# self.csvBrowseButton.setText(
# translate('SongsPlugin.ImportWizardForm', 'Browse...'))
self.importPage.setTitle(
translate('SongsPlugin.ImportWizardForm', 'Importing'))
self.ImportPage.setSubTitle(
self.importPage.setSubTitle(
translate('SongsPlugin.ImportWizardForm',
'Please wait while your songs are imported.'))
self.ImportProgressLabel.setText(
self.importProgressLabel.setText(
translate('SongsPlugin.ImportWizardForm', 'Ready.'))
self.ImportProgressBar.setFormat(
self.importProgressBar.setFormat(
translate('SongsPlugin.ImportWizardForm', '%p%'))

View File

@ -88,9 +88,8 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
item = self.songmanager.get_object(item_class, item_id)
if item and len(item.songs) == 0:
if QtGui.QMessageBox.warning(self, dlg_title, del_text,
QtGui.QMessageBox.StandardButtons(
QtGui.QMessageBox.No | QtGui.QMessageBox.Yes)
) == QtGui.QMessageBox.Yes:
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.No |
QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.Yes:
self.songmanager.delete_object(item_class, item.id)
reset_func()
else:

View File

@ -26,52 +26,6 @@
from openlp.core.lib import translate
#from openlp.plugins.songs.lib import OpenLyricsSong, OpenSongSong, CCLISong, \
# CSVSong
class SongFormat(object):
"""
This is a special enumeration class that holds the various types of songs,
plus a few helper functions to facilitate generic handling of song types
for importing.
"""
Unknown = -1
OpenLyrics = 0
OpenSong = 1
CCLI = 2
CSV = 3
@staticmethod
def get_class(format):
"""
Return the appropriate imeplementation class.
``format``
The song format.
"""
# if format == SongFormat.OpenLyrics:
# return OpenLyricsSong
# elif format == SongFormat.OpenSong:
# return OpenSongSong
# elif format == SongFormat.CCLI:
# return CCLISong
# elif format == SongFormat.CSV:
# return CSVSong
# else:
return None
@staticmethod
def list():
"""
Return a list of the supported song formats.
"""
return [
SongFormat.OpenLyrics,
SongFormat.OpenSong,
SongFormat.CCLI,
SongFormat.CSV
]
class VerseType(object):
"""
VerseType provides an enumeration for the tags that may be associated
@ -138,14 +92,7 @@ class VerseType(object):
unicode(VerseType.to_string(VerseType.Other)).lower():
return VerseType.Other
from xml import LyricsXML, SongXMLBuilder, SongXMLParser
from songstab import SongsTab
from mediaitem import SongMediaItem
from songimport import SongImport
from opensongimport import OpenSongImport
from olpimport import OpenLPSongImport
try:
from sofimport import SofImport
from oooimport import OooImport
except ImportError:
pass

View File

@ -0,0 +1,87 @@
# -*- 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 #
# --------------------------------------------------------------------------- #
# 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 #
###############################################################################
from opensongimport import OpenSongImport
from olpimport import OpenLPSongImport
try:
from sofimport import SofImport
from oooimport import OooImport
except ImportError:
pass
class SongFormat(object):
"""
This is a special enumeration class that holds the various types of songs,
plus a few helper functions to facilitate generic handling of song types
for importing.
"""
Unknown = -1
OpenLP2 = 0
OpenLP1 = 1
OpenLyrics = 2
OpenSong = 3
WordsOfWorship = 4
CCLI = 5
SongsOfFellowship = 6
Generic = 7
CSV = 8
@staticmethod
def get_class(format):
"""
Return the appropriate imeplementation class.
``format``
The song format.
"""
if format == SongFormat.OpenLP2:
return OpenLPSongImport
elif format == SongFormat.OpenSong:
return OpenSongImport
elif format == SongFormat.SongsOfFellowship:
return SofImport
elif format == SongFormat.Generic:
return OooImport
# else:
return None
@staticmethod
def list():
"""
Return a list of the supported song formats.
"""
return [
SongFormat.OpenLP2,
SongFormat.OpenLP1,
SongFormat.OpenLyrics,
SongFormat.OpenSong,
SongFormat.WordsOfWorship,
SongFormat.CCLI,
SongFormat.SongsOfFellowship,
SongFormat.Generic
]
__all__ = [u'SongFormat']

View File

@ -236,9 +236,10 @@ class SongMediaItem(MediaManagerItem):
self.onSearchTextButtonClick()
def onImportClick(self):
songimportform = ImportWizardForm(self, self.parent.manager,
self.parent)
songimportform.exec_()
if not hasattr(self, u'import_wizard'):
self.import_wizard = ImportWizardForm(self, self.parent)
self.import_wizard.exec_()
Receiver.send_message(u'songs_load_list')
def onNewClick(self):
self.edit_song_form.newSong()

View File

@ -36,6 +36,7 @@ from sqlalchemy.orm.exc import UnmappedClassError
from openlp.core.lib.db import BaseModel
from openlp.plugins.songs.lib.db import Author, Book, Song, Topic #, MediaFile
from songimport import SongImport
log = logging.getLogger(__name__)
@ -69,26 +70,27 @@ class OldTopic(BaseModel):
"""
pass
class OpenLPSongImport(object):
class OpenLPSongImport(SongImport):
"""
The :class:`OpenLPSongImport` class provides OpenLP with the ability to
import song databases from other installations of OpenLP.
"""
def __init__(self, master_manager, source_db):
def __init__(self, manager, **kwargs):
"""
Initialise the import.
``master_manager``
``manager``
The song manager for the running OpenLP installation.
``source_db``
The database providing the data to import.
"""
self.master_manager = master_manager
self.import_source = source_db
SongImport.__init__(self, manager)
self.import_source = u'sqlite:///%s' % kwargs[u'filename']
log.debug(self.import_source)
self.source_session = None
def import_source_v2_db(self):
def do_import(self):
"""
Run the import for an OpenLP version 2 song database.
"""
@ -142,7 +144,12 @@ class OpenLPSongImport(object):
mapper(OldTopic, source_topics_table)
source_songs = self.source_session.query(OldSong).all()
song_total = len(source_songs)
self.import_wizard.importProgressBar.setMaximum(song_total)
song_count = 1
for song in source_songs:
self.import_wizard.incrementProgressBar(
u'Importing song %s of %s' % (song_count, song_total))
new_song = Song()
new_song.title = song.title
if has_media_files:
@ -164,7 +171,7 @@ class OpenLPSongImport(object):
new_song.ccli_number = song.ccli_number
if song.authors:
for author in song.authors:
existing_author = self.master_manager.get_object_filtered(
existing_author = self.manager.get_object_filtered(
Author, Author.display_name == author.display_name)
if existing_author:
new_song.authors.append(existing_author)
@ -174,7 +181,7 @@ class OpenLPSongImport(object):
last_name=author.last_name,
display_name=author.display_name))
else:
au = self.master_manager.get_object_filtered(Author,
au = self.manager.get_object_filtered(Author,
Author.display_name == u'Author Unknown')
if au:
new_song.authors.append(au)
@ -182,7 +189,7 @@ class OpenLPSongImport(object):
new_song.authors.append(Author.populate(
display_name=u'Author Unknown'))
if song.book:
existing_song_book = self.master_manager.get_object_filtered(
existing_song_book = self.manager.get_object_filtered(
Book, Book.name == song.book.name)
if existing_song_book:
new_song.book = existing_song_book
@ -191,7 +198,7 @@ class OpenLPSongImport(object):
publisher=song.book.publisher)
if song.topics:
for topic in song.topics:
existing_topic = self.master_manager.get_object_filtered(
existing_topic = self.manager.get_object_filtered(
Topic, Topic.name == topic.name)
if existing_topic:
new_song.topics.append(existing_topic)
@ -201,12 +208,16 @@ class OpenLPSongImport(object):
# if song.media_files:
# for media_file in song.media_files:
# existing_media_file = \
# self.master_manager.get_object_filtered(MediaFile,
# self.manager.get_object_filtered(MediaFile,
# MediaFile.file_name == media_file.file_name)
# if existing_media_file:
# new_song.media_files.append(existing_media_file)
# else:
# new_song.media_files.append(MediaFile.populate(
# file_name=media_file.file_name))
self.master_manager.save_object(new_song)
self.manager.save_object(new_song)
song_count += 1
if self.stop_import_flag:
return False
engine.dispose()
return True

View File

@ -24,13 +24,18 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
import logging
import re
from PyQt4 import QtCore
from openlp.core.lib import translate
from openlp.plugins.songs.lib import SongXMLBuilder, VerseType
from openlp.core.lib import Receiver, translate
from openlp.plugins.songs.lib import VerseType
from openlp.plugins.songs.lib.db import Song, Author, Topic, Book
from openlp.plugins.songs.lib.xml import SongXMLBuilder
class SongImport(object):
log = logging.getLogger(__name__)
class SongImport(QtCore.QObject):
"""
Helper class for import a song from a third party source into OpenLP
@ -38,15 +43,15 @@ class SongImport(object):
whether the authors etc already exist and add them or refer to them
as necessary
"""
def __init__(self, song_manager):
def __init__(self, manager):
"""
Initialise and create defaults for properties
song_manager is an instance of a SongManager, through which all
database access is performed
"""
self.manager = song_manager
self.manager = manager
self.stop_import_flag = False
self.title = u''
self.song_number = u''
self.alternate_title = u''
@ -66,6 +71,18 @@ class SongImport(object):
'SongsPlugin.SongImport', 'copyright'))
self.copyright_symbol = unicode(translate(
'SongsPlugin.SongImport', '\xa9'))
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'songs_stop_import'), self.stop_import)
def stop_import(self):
"""
Sets the flag for importers to stop their import
"""
log.debug(u'Stopping songs import')
self.stop_import_flag = True
def register(self, import_wizard):
self.import_wizard = import_wizard
@staticmethod
def process_songs_text(manager, text):

View File

@ -28,18 +28,11 @@ import logging
from PyQt4 import QtCore, QtGui
from openlp.core.lib import Plugin, build_icon, Receiver, translate
from openlp.core.lib import Plugin, build_icon, translate
from openlp.core.lib.db import Manager
from openlp.plugins.songs.lib import OpenLPSongImport, SongMediaItem, SongsTab
from openlp.plugins.songs.lib import SongMediaItem, SongsTab
from openlp.plugins.songs.lib.db import init_schema, Song
try:
from openlp.plugins.songs.lib import SofImport, OooImport
OOo_available = True
except ImportError:
OOo_available = False
from openlp.plugins.songs.lib import OpenSongImport
from openlp.plugins.songs.lib.importer import SongFormat
log = logging.getLogger(__name__)
@ -99,76 +92,6 @@ class SongsPlugin(Plugin):
# Signals and slots
QtCore.QObject.connect(self.SongImportItem,
QtCore.SIGNAL(u'triggered()'), self.onSongImportItemClicked)
if OOo_available:
# Songs of Fellowship import menu item - will be removed and the
# functionality will be contained within the import wizard
self.ImportSofItem = QtGui.QAction(import_menu)
self.ImportSofItem.setObjectName(u'ImportSofItem')
self.ImportSofItem.setText(
translate('SongsPlugin',
'Songs of Fellowship (temp menu item)'))
self.ImportSofItem.setToolTip(
translate('SongsPlugin',
'Import songs from the VOLS1_2.RTF, sof3words' \
+ '.rtf and sof4words.rtf supplied with the music books'))
self.ImportSofItem.setStatusTip(
translate('SongsPlugin',
'Import songs from the VOLS1_2.RTF, sof3words' \
+ '.rtf and sof4words.rtf supplied with the music books'))
import_menu.addAction(self.ImportSofItem)
# OpenOffice.org import menu item - will be removed and the
# functionality will be contained within the import wizard
self.ImportOooItem = QtGui.QAction(import_menu)
self.ImportOooItem.setObjectName(u'ImportOooItem')
self.ImportOooItem.setText(
translate('SongsPlugin',
'Generic Document/Presentation Import '
'(temp menu item)'))
self.ImportOooItem.setToolTip(
translate('SongsPlugin',
'Import songs from '
'Word/Writer/Powerpoint/Impress'))
self.ImportOooItem.setStatusTip(
translate('SongsPlugin',
'Import songs from '
'Word/Writer/Powerpoint/Impress'))
import_menu.addAction(self.ImportOooItem)
# Signals and slots
QtCore.QObject.connect(self.ImportSofItem,
QtCore.SIGNAL(u'triggered()'), self.onImportSofItemClick)
QtCore.QObject.connect(self.ImportOooItem,
QtCore.SIGNAL(u'triggered()'), self.onImportOooItemClick)
# OpenSong import menu item - will be removed and the
# functionality will be contained within the import wizard
self.ImportOpenSongItem = QtGui.QAction(import_menu)
self.ImportOpenSongItem.setObjectName(u'ImportOpenSongItem')
self.ImportOpenSongItem.setText(
translate('SongsPlugin',
'OpenSong (temp menu item)'))
self.ImportOpenSongItem.setToolTip(
translate('SongsPlugin',
'Import songs from OpenSong files' +
'(either raw text or ZIPfiles)'))
self.ImportOpenSongItem.setStatusTip(
translate('SongsPlugin',
'Import songs from OpenSong files' +
'(either raw text or ZIPfiles)'))
import_menu.addAction(self.ImportOpenSongItem)
QtCore.QObject.connect(self.ImportOpenSongItem,
QtCore.SIGNAL(u'triggered()'), self.onImportOpenSongItemClick)
# OpenLP v2 import menu item - ditto above regarding refactoring into
# an import wizard
self.ImportOpenLPSongItem = QtGui.QAction(import_menu)
self.ImportOpenLPSongItem.setObjectName(u'ImportOpenLPSongItem')
self.ImportOpenLPSongItem.setText(translate('SongsPlugin',
'OpenLP v2 Songs (temporary)'))
self.ImportOpenLPSongItem.setToolTip(translate('SongsPlugin',
'Import an OpenLP v2 song database'))
self.ImportOpenLPSongItem.setStatusTip(translate('SongsPlugin',
'Import an OpenLP v2 song database'))
import_menu.addAction(self.ImportOpenLPSongItem)
QtCore.QObject.connect(self.ImportOpenLPSongItem,
QtCore.SIGNAL(u'triggered()'), self.onImportOpenLPSongItemClick)
def addExportMenuItem(self, export_menu):
"""
@ -186,68 +109,6 @@ class SongsPlugin(Plugin):
if self.mediaItem:
self.mediaItem.onImportClick()
def onImportSofItemClick(self):
filenames = QtGui.QFileDialog.getOpenFileNames(
None, translate('SongsPlugin',
'Open Songs of Fellowship file'),
u'', u'Songs of Fellowship file (*.rtf *.RTF)')
try:
for filename in filenames:
sofimport = SofImport(self.manager)
sofimport.import_sof(unicode(filename))
except:
log.exception('Could not import SoF file')
QtGui.QMessageBox.critical(None,
translate('SongsPlugin', 'Import Error'),
translate('SongsPlugin', 'Error importing Songs of '
'Fellowship file.\nOpenOffice.org must be installed'
' and you must be using an unedited copy of the RTF'
' included with the Songs of Fellowship Music Editions'))
Receiver.send_message(u'songs_load_list')
def onImportOpenSongItemClick(self):
filenames = QtGui.QFileDialog.getOpenFileNames(
None, translate('SongsPlugin',
'Open OpenSong file'),
u'', u'All files (*.*)')
try:
for filename in filenames:
importer = OpenSongImport(self.manager)
importer.do_import(unicode(filename))
except:
log.exception('Could not import OpenSong file')
QtGui.QMessageBox.critical(None,
translate('SongsPlugin', 'Import Error'),
translate('SongsPlugin', 'Error importing OpenSong file'))
Receiver.send_message(u'songs_load_list')
def onImportOpenLPSongItemClick(self):
filenames = QtGui.QFileDialog.getOpenFileNames(None,
translate('SongsPlugin', 'Select OpenLP database(s) to import...'),
u'', u'OpenLP databases (*.sqlite);;All Files (*)')
try:
for filename in filenames:
db_url = u'sqlite:///%s' % filename
importer = OpenLPSongImport(self.manager, db_url)
importer.import_source_v2_db()
QtGui.QMessageBox.information(None, translate('SongsPlugin',
'Database(s) imported'), translate('SongsPlugin', 'Your '
'OpenLP v2 song databases have been successfully imported'))
except:
log.exception(u'Failed to import OpenLP v2 database(s)')
QtGui.QMessageBox.critical(None, translate('SongsPlugin',
'Import Error'), translate('SongsPlugin',
'Error importing OpenLP v2 database(s)'))
Receiver.send_message(u'songs_load_list')
def onImportOooItemClick(self):
filenames = QtGui.QFileDialog.getOpenFileNames(
None, translate('SongsPlugin', 'Open documents or presentations'),
'', u'All Files(*.*)')
oooimport = OooImport(self.manager)
oooimport.import_docs(filenames)
Receiver.send_message(u'songs_load_list')
def about(self):
about_text = translate('SongsPlugin', '<strong>Songs Plugin</strong>'
'<br />The songs plugin provides the ability to display and '
@ -280,3 +141,9 @@ class SongsPlugin(Plugin):
for song in songsUsingTheme:
song.theme_name = newTheme
self.custommanager.save_object(song)
def importSongs(self, format, **kwargs):
class_ = SongFormat.get_class(format)
importer = class_(self.manager, **kwargs)
importer.register(self.mediaItem.import_wizard)
return importer

View File

@ -0,0 +1,91 @@
%{!?python_sitelib:%global python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")}
Summary: Open source Church presentation and lyrics projection application
Name: OpenLP
Version: 1.9.1.1
Release: 1%{?dist}
Source0: http://downloads.sourceforge.net/openlp/openlp/%{version}/%{name}-%{version}.tar.gz
License: GPLv2
Group: Applications/Multimedia
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
BuildArch: noarch
URL: http://openlp.org/
BuildRequires: desktop-file-utils
BuildRequires: python2-devel
BuildRequires: python-setuptools
Requires: PyQt4
Requires: phonon
Requires: python-BeautifulSoup
Requires: python-chardet
Requires: python-lxml
Requires: python-sqlalchemy
Requires: hicolor-icon-theme
%description
OpenLP is a church presentation software, for lyrics projection software,
used to display slides of Songs, Bible verses, videos, images, and
presentations (if OpenOffice.org is installed) using a computer and projector.
%prep
%setup -q
%build
python setup.py build
%install
rm -rf %{buildroot}
python setup.py install --skip-build -O1 --root %{buildroot}
install -m644 -p -D resources/images/openlp-logo-16x16.png \
%{buildroot}%{_datadir}/icons/hicolor/16x16/apps/openlp.png
install -m644 -p -D resources/images/openlp-logo-32x32.png \
%{buildroot}%{_datadir}/icons/hicolor/32x32/apps/openlp.png
install -m644 -p -D resources/images/openlp-logo-48x48.png \
%{buildroot}%{_datadir}/icons/hicolor/48x48/apps/openlp.png
install -m644 -p -D resources/images/openlp-logo.svg \
%{buildroot}%{_datadir}/icons/hicolor/scalable/apps/openlp.svg
desktop-file-install \
--dir %{buildroot}/%{_datadir}/applications \
resources/openlp.desktop
mv %{buildroot}%{_bindir}/bible-1to2-converter.py \
%{buildroot}%{_bindir}/bible-1to2-converter
mv %{buildroot}%{_bindir}/openlp-1to2-converter.py \
%{buildroot}%{_bindir}/openlp-1to2-converter
mv %{buildroot}%{_bindir}/openlp-remoteclient.py \
%{buildroot}%{_bindir}/openlp-remoteclient
mv %{buildroot}%{_bindir}/openlp.pyw %{buildroot}%{_bindir}/openlp
%post
touch --no-create %{_datadir}/icons/hicolor ||:
gtk-update-icon-cache -q %{_datadir}/icons/hicolor 2> /dev/null ||:
%postun
touch --no-create %{_datadir}/icons/hicolor ||:
gtk-update-icon-cache -q %{_datadir}/icons/hicolor 2> /dev/null ||:
%clean
rm -rf %{buildroot}
%files
%defattr(-,root,root)
%doc copyright.txt LICENSE
%{_bindir}/bible-1to2-converter
%{_bindir}/openlp-1to2-converter
%{_bindir}/openlp-remoteclient
%{_bindir}/openlp
%{_datadir}/applications/openlp.desktop
%{_datadir}/icons/hicolor/*/apps/openlp.*
%{python_sitelib}/openlp/
%{python_sitelib}/OpenLP-%{version}*.egg-info
%doc documentation/*.txt
%changelog
* Sun Mar 28 2010 Tim Bentley <timbentley@openlp.org> 1.9.1.1
- Initial build version - Alpha 1 Release

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
@ -9,11 +10,11 @@
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="1052.3622"
height="744.09448"
width="467.39178"
height="467.39178"
id="svg5740"
sodipodi:version="0.32"
inkscape:version="0.46"
inkscape:version="0.47 r22583"
version="1.0"
sodipodi:docname="openlp-logo.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
@ -65,7 +66,8 @@
id="perspective5748" />
<filter
inkscape:collect="always"
id="filter6926">
id="filter6926"
color-interpolation-filters="sRGB">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="3.5771872"
@ -164,14 +166,6 @@
y1="276.68851"
x2="469.44925"
y2="104.30029" />
<filter
inkscape:collect="always"
id="filter4005">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="4.333215"
id="feGaussianBlur4007" />
</filter>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3208"
@ -261,15 +255,16 @@
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.0119683"
inkscape:cx="513.59551"
inkscape:cy="369.01895"
inkscape:cx="501.72348"
inkscape:cy="187.6618"
inkscape:document-units="px"
inkscape:current-layer="layer6"
showgrid="false"
inkscape:window-width="1280"
inkscape:window-height="958"
inkscape:window-x="-4"
inkscape:window-y="-4" />
inkscape:window-width="1600"
inkscape:window-height="839"
inkscape:window-x="1022"
inkscape:window-y="-3"
inkscape:window-maximized="1" />
<metadata
id="metadata5745">
<rdf:RDF>
@ -285,27 +280,32 @@
inkscape:label="Shadow"
inkscape:groupmode="layer"
id="layer1"
style="display:inline" />
style="display:inline"
transform="translate(-11.872025,-13.171852)" />
<g
inkscape:groupmode="layer"
id="layer5"
inkscape:label="Border"
style="display:inline" />
style="display:inline"
transform="translate(-11.872025,-13.171852)" />
<g
inkscape:groupmode="layer"
id="layer3"
inkscape:label="Rays Background"
style="display:inline" />
style="display:inline"
transform="translate(-11.872025,-13.171852)" />
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="Rays Foreground"
style="display:inline" />
style="display:inline"
transform="translate(-11.872025,-13.171852)" />
<g
inkscape:groupmode="layer"
id="layer6"
inkscape:label="Reflection"
style="display:inline">
style="display:inline"
transform="translate(-11.872025,-13.171852)">
<g
id="g4018"
transform="translate(9.8817328,9.8817328)">
@ -314,179 +314,51 @@
inkscape:export-xdpi="90"
inkscape:export-filename="/home/raoul/openlp-logo-0.2.png"
transform="matrix(0.6379835,0,0,0.6379835,-67.554612,-15.189295)"
d="M 833.03006,395.26932 A 357.71872,357.71872 0 1 1 117.59262,395.26932 A 357.71872,357.71872 0 1 1 833.03006,395.26932 z"
d="m 833.03006,395.26932 c 0,197.56259 -160.15613,357.71872 -357.71872,357.71872 -197.56259,0 -357.71872,-160.15613 -357.71872,-357.71872 0,-197.5626 160.15613,-357.718722 357.71872,-357.718722 197.56259,0 357.71872,160.156122 357.71872,357.718722 z"
sodipodi:ry="357.71872"
sodipodi:rx="357.71872"
sodipodi:cy="395.26932"
sodipodi:cx="475.31134"
id="path6903"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5.00028753;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline;filter:url(#filter6926)"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;display:inline;filter:url(#filter6926)"
sodipodi:type="arc" />
<path
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
inkscape:export-filename="/home/raoul/openlp-logo-0.2.png"
sodipodi:type="arc"
style="fill:#051e52;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5.00028753;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline"
style="fill:#051e52;fill-opacity:1;fill-rule:nonzero;stroke:none;display:inline"
id="path6900"
sodipodi:cx="475.31134"
sodipodi:cy="395.26932"
sodipodi:rx="357.71872"
sodipodi:ry="357.71872"
d="M 833.03006,395.26932 A 357.71872,357.71872 0 1 1 117.59262,395.26932 A 357.71872,357.71872 0 1 1 833.03006,395.26932 z"
d="m 833.03006,395.26932 c 0,197.56259 -160.15613,357.71872 -357.71872,357.71872 -197.56259,0 -357.71872,-160.15613 -357.71872,-357.71872 0,-197.5626 160.15613,-357.718722 357.71872,-357.718722 197.56259,0 357.71872,160.156122 357.71872,357.718722 z"
transform="matrix(0.6379835,0,0,0.6379835,-67.554612,-15.189295)" />
<path
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
inkscape:export-filename="/home/raoul/openlp-logo-0.2.png"
transform="matrix(0.6317287,0,0,0.6317287,-64.581662,-12.716988)"
d="M 833.03006,395.26932 A 357.71872,357.71872 0 1 1 117.59262,395.26932 A 357.71872,357.71872 0 1 1 833.03006,395.26932 z"
d="m 833.03006,395.26932 c 0,197.56259 -160.15613,357.71872 -357.71872,357.71872 -197.56259,0 -357.71872,-160.15613 -357.71872,-357.71872 0,-197.5626 160.15613,-357.718722 357.71872,-357.718722 197.56259,0 357.71872,160.156122 357.71872,357.718722 z"
sodipodi:ry="357.71872"
sodipodi:rx="357.71872"
sodipodi:cy="395.26932"
sodipodi:cx="475.31134"
id="path6317"
style="fill:url(#linearGradient4053);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5.00028753;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline"
style="fill:url(#linearGradient4053);fill-opacity:1;fill-rule:nonzero;stroke:none;display:inline"
sodipodi:type="arc" />
<path
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
inkscape:export-filename="/home/raoul/openlp-logo-0.2.png"
id="path6327"
d="M 235.67972,13.233984 C 199.75196,13.233984 165.79894,21.722639 135.704,36.792417 L 296.72396,165.96674 L 452.81639,291.19091 C 457.1409,273.83274 459.43393,255.67894 459.43393,236.98819 C 459.43393,113.48164 359.18627,13.233985 235.67972,13.233984 z M 79.118968,77.210299 C 71.146114,85.023824 63.764822,93.431949 57.026574,102.35694 L 274.63156,209.66285 L 434.20584,288.36064 L 275.3035,193.86221 L 79.118968,77.210299 z M 24.488653,162.95322 C 20.860793,173.29149 17.984378,183.97391 15.896035,194.94138 L 260.17479,255.29332 L 422.98657,295.52794 L 260.21551,241.36595 L 24.488653,162.95322 z M 13.513722,263.49906 C 14.818764,274.53653 16.911081,285.32646 19.764749,295.81301 L 248.30394,302.32874 L 421.76487,307.29698 L 253.55725,289.23619 L 13.513722,263.49906 z M 428.50457,317.76287 L 249.79034,336.84174 L 47.782384,358.40473 C 53.741585,367.60372 60.347088,376.34577 67.553549,384.54909 L 244.45559,351.80755 L 428.50457,317.76287 z M 442.28941,322.97545 L 253.92376,385.15994 L 120.92144,429.05966 C 154.48464,449.16902 193.73296,460.72203 235.67972,460.72204 C 328.7226,460.72204 408.56552,403.84299 442.28941,322.97545 z"
style="fill:url(#linearGradient4055);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline" />
d="m 235.67972,13.233984 c -35.92776,0 -69.88078,8.488655 -99.97572,23.558433 L 296.72396,165.96674 452.81639,291.19091 c 4.32451,-17.35817 6.61754,-35.51197 6.61754,-54.20272 0,-123.50655 -100.24766,-223.754205 -223.75421,-223.754206 z M 79.118968,77.210299 C 71.146114,85.023824 63.764822,93.431949 57.026574,102.35694 L 274.63156,209.66285 434.20584,288.36064 275.3035,193.86221 79.118968,77.210299 z M 24.488653,162.95322 c -3.62786,10.33827 -6.504275,21.02069 -8.592618,31.98816 L 260.17479,255.29332 422.98657,295.52794 260.21551,241.36595 24.488653,162.95322 z M 13.513722,263.49906 c 1.305042,11.03747 3.397359,21.8274 6.251027,32.31395 l 228.539191,6.51573 173.46093,4.96824 L 253.55725,289.23619 13.513722,263.49906 z M 428.50457,317.76287 249.79034,336.84174 47.782384,358.40473 c 5.959201,9.19899 12.564704,17.94104 19.771165,26.14436 L 244.45559,351.80755 428.50457,317.76287 z m 13.78484,5.21258 -188.36565,62.18449 -133.00232,43.89972 c 33.5632,20.10936 72.81152,31.66237 114.75828,31.66238 93.04288,0 172.8858,-56.87905 206.60969,-137.74659 z"
style="fill:url(#linearGradient4055);fill-opacity:1;fill-rule:nonzero;stroke:none;display:inline" />
<path
id="path3203"
d="M 235.67972,13.233984 C 199.75196,13.233984 165.79894,21.722639 135.704,36.792417 L 296.72396,165.96674 L 349.27738,208.13573 C 388.42508,203.26072 423.85383,195.91016 453.73266,186.69491 C 430.89209,87.375898 341.89666,13.233985 235.67972,13.233984 z M 79.118968,77.210299 C 71.146114,85.023824 63.764822,93.431949 57.026574,102.35694 L 274.63156,209.66285 L 282.95948,213.77591 C 290.87301,213.39575 298.68426,212.91815 306.39574,212.35059 L 275.3035,193.86221 L 79.118968,77.210299 z M 24.488653,162.95322 C 21.826867,170.53849 19.56686,178.3145 17.728584,186.24695 C 60.352717,199.56405 114.44154,209.03001 174.67621,212.92072 L 24.488653,162.95322 z"
style="fill:url(#linearGradient4057);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4.80000019;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline" />
</g>
<g
id="g4025"
transform="translate(-0.9881736,-11.858079)">
<g
id="g3202"
transform="matrix(0.6515729,0,0,0.6515729,482.27854,11.483464)">
<path
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
inkscape:export-filename="/home/raoul/openlp-logo-0.2.png"
transform="matrix(0.9791437,0,0,0.9791437,6.955563,-15.153813)"
d="M 833.03006,395.26932 A 357.71872,357.71872 0 1 1 117.59262,395.26932 A 357.71872,357.71872 0 1 1 833.03006,395.26932 z"
sodipodi:ry="357.71872"
sodipodi:rx="357.71872"
sodipodi:cy="395.26932"
sodipodi:cx="475.31134"
id="path3204"
style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5.00028753;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline;filter:url(#filter6926)"
sodipodi:type="arc" />
<path
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
inkscape:export-filename="/home/raoul/openlp-logo-0.2.png"
sodipodi:type="arc"
style="opacity:1;fill:#051e52;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5.00028753;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline"
id="path3206"
sodipodi:cx="475.31134"
sodipodi:cy="395.26932"
sodipodi:rx="357.71872"
sodipodi:ry="357.71872"
d="M 833.03006,395.26932 A 357.71872,357.71872 0 1 1 117.59262,395.26932 A 357.71872,357.71872 0 1 1 833.03006,395.26932 z"
transform="matrix(0.9791437,0,0,0.9791437,6.955563,-15.153813)" />
<path
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
inkscape:export-filename="/home/raoul/openlp-logo-0.2.png"
transform="matrix(0.9695442,0,0,0.9695442,11.51829,-11.359445)"
d="M 833.03006,395.26932 A 357.71872,357.71872 0 1 1 117.59262,395.26932 A 357.71872,357.71872 0 1 1 833.03006,395.26932 z"
sodipodi:ry="357.71872"
sodipodi:rx="357.71872"
sodipodi:cy="395.26932"
sodipodi:cx="475.31134"
id="path3208"
style="opacity:1;fill:url(#linearGradient4047);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5.00028753;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline"
sodipodi:type="arc" />
<path
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
inkscape:export-filename="/home/raoul/openlp-logo-0.2.png"
id="path3210"
d="M 472.34375,28.46875 C 417.2037,28.46875 365.09439,41.496693 318.90625,64.625 L 566.03125,262.875 L 805.59375,455.0625 C 812.23078,428.42209 815.75,400.56059 815.75,371.875 C 815.75,182.3236 661.89515,28.468751 472.34375,28.46875 z M 232.0625,126.65625 C 219.82618,138.64804 208.49776,151.55239 198.15625,165.25 L 532.125,329.9375 L 777.03125,450.71875 L 533.15625,305.6875 L 232.0625,126.65625 z M 148.21875,258.25 C 142.6509,274.11664 138.23633,290.51145 135.03125,307.34375 L 509.9375,399.96875 L 759.8125,461.71875 L 510,378.59375 L 148.21875,258.25 z M 131.375,412.5625 C 133.37791,429.50222 136.58909,446.06205 140.96875,462.15625 L 491.71875,472.15625 L 757.9375,479.78125 L 499.78125,452.0625 L 131.375,412.5625 z M 768.28125,495.84375 L 494,525.125 L 183.96875,558.21875 C 193.11462,572.33688 203.2524,585.75373 214.3125,598.34375 L 485.8125,548.09375 L 768.28125,495.84375 z M 789.4375,503.84375 L 500.34375,599.28125 L 296.21875,666.65625 C 347.72979,697.51903 407.96606,715.24999 472.34375,715.25 C 615.1411,715.25 737.67984,627.95502 789.4375,503.84375 z"
style="opacity:1;fill:url(#linearGradient4049);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline" />
<path
id="path3212"
d="M 472.34375,28.46875 C 417.2037,28.46875 365.09439,41.496693 318.90625,64.625 L 566.03125,262.875 L 646.6875,327.59375 C 706.76934,320.11184 761.14353,308.83058 807,294.6875 C 771.94549,142.25788 635.35996,28.468751 472.34375,28.46875 z M 232.0625,126.65625 C 219.82618,138.64804 208.49776,151.55239 198.15625,165.25 L 532.125,329.9375 L 544.90625,336.25 C 557.05152,335.66655 569.03982,334.93356 580.875,334.0625 L 533.15625,305.6875 L 232.0625,126.65625 z M 148.21875,258.25 C 144.13358,269.89147 140.66504,281.82569 137.84375,294 C 203.26104,314.43839 286.27373,328.96625 378.71875,334.9375 L 148.21875,258.25 z"
style="opacity:1;fill:url(#linearGradient4051);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4.80000019;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline" />
</g>
<g
style="fill:#ffffff;fill-opacity:1;filter:url(#filter4005)"
id="g2762"
transform="matrix(0.8481394,0,0,0.8481394,20.507371,-653.75135)">
<path
style="fill:#ffffff;fill-opacity:1"
id="path2764"
d="M 801.444,1038.553 L 817.061,1038.553 C 835.923,1038.553 845.557,1048.997 845.557,1064.514 C 845.557,1079.726 835.923,1090.373 817.061,1090.373 L 808.745,1090.373 L 808.745,1107.512 L 801.444,1107.512 L 801.444,1038.553 L 801.444,1038.553 z M 816.655,1083.984 C 832.172,1083.984 837.952,1075.872 837.952,1064.513 C 837.952,1053.154 832.172,1045.042 816.655,1045.042 L 808.745,1045.042 L 808.745,1083.983 L 816.655,1083.983 L 816.655,1083.984 z" />
<path
style="fill:#ffffff;fill-opacity:1"
id="path2766"
d="M 852.858,1038.553 L 894.842,1038.553 L 894.842,1045.043 L 860.158,1045.043 L 860.158,1077.393 L 891.089,1077.393 L 891.089,1083.782 L 860.158,1083.782 L 860.158,1101.022 L 896.261,1101.022 L 896.261,1107.512 L 852.858,1107.512 L 852.858,1038.553 z" />
<path
style="fill:#ffffff;fill-opacity:1"
id="path2768"
d="M 913.197,1059.545 C 911.27,1057.212 908.43,1053.155 908.43,1053.155 C 908.43,1053.155 909.038,1058.023 909.038,1060.965 L 909.038,1107.512 L 902.142,1107.512 L 902.142,1037.843 L 903.359,1037.843 L 944.532,1086.52 C 946.459,1088.853 948.791,1091.683 948.791,1091.683 C 948.791,1091.683 948.791,1088.041 948.791,1085.101 L 948.791,1038.553 L 955.586,1038.553 L 955.586,1108.222 L 954.369,1108.222 L 913.197,1059.545 z" />
<path
style="fill:#ffffff;fill-opacity:1"
id="path2770"
d="M 677.015,1070.032 C 677.015,1035.196 703.268,1011.468 735.579,1011.468 C 767.89,1011.468 794.143,1035.197 794.143,1070.032 C 794.143,1104.867 767.89,1128.596 735.579,1128.596 C 703.268,1128.596 677.015,1104.868 677.015,1070.032 z M 787.075,1070.032 C 787.075,1040.077 765.03,1017.694 735.579,1017.694 C 706.128,1017.694 684.083,1040.077 684.083,1070.032 C 684.083,1099.988 706.128,1122.37 735.579,1122.37 C 765.03,1122.37 787.075,1099.988 787.075,1070.032 z" />
<path
style="fill:#ffffff;fill-opacity:1"
id="path2772"
d="M 967.521,1012.814 L 991.082,1012.814 L 991.082,1106.551 L 1042.915,1106.551 L 1042.915,1127.25 L 967.521,1127.25 L 967.521,1012.814 z" />
<path
style="fill:#ffffff;fill-opacity:1"
id="path2774"
d="M 1054.85,1012.814 L 1086.489,1012.814 C 1118.464,1012.814 1137.649,1029.475 1137.649,1057.074 C 1137.649,1084.674 1118.295,1101.166 1086.489,1101.166 L 1078.411,1101.166 L 1078.411,1127.251 L 1054.85,1127.251 L 1054.85,1012.814 z M 1085.815,1080.467 C 1105,1080.467 1113.414,1072.726 1113.414,1057.074 C 1113.414,1041.255 1104.663,1033.513 1085.815,1033.513 L 1078.41,1033.513 L 1078.41,1080.466 L 1085.815,1080.466 L 1085.815,1080.467 z" />
</g>
<g
style="fill:#000d26;fill-opacity:1"
transform="matrix(0.8481394,0,0,0.8481394,20.507371,-653.75135)"
id="g3221">
<path
style="fill:#000d26;fill-opacity:1"
d="M 801.444,1038.553 L 817.061,1038.553 C 835.923,1038.553 845.557,1048.997 845.557,1064.514 C 845.557,1079.726 835.923,1090.373 817.061,1090.373 L 808.745,1090.373 L 808.745,1107.512 L 801.444,1107.512 L 801.444,1038.553 L 801.444,1038.553 z M 816.655,1083.984 C 832.172,1083.984 837.952,1075.872 837.952,1064.513 C 837.952,1053.154 832.172,1045.042 816.655,1045.042 L 808.745,1045.042 L 808.745,1083.983 L 816.655,1083.983 L 816.655,1083.984 z"
id="path3223" />
<path
style="fill:#000d26;fill-opacity:1"
d="M 852.858,1038.553 L 894.842,1038.553 L 894.842,1045.043 L 860.158,1045.043 L 860.158,1077.393 L 891.089,1077.393 L 891.089,1083.782 L 860.158,1083.782 L 860.158,1101.022 L 896.261,1101.022 L 896.261,1107.512 L 852.858,1107.512 L 852.858,1038.553 z"
id="path3225" />
<path
style="fill:#000d26;fill-opacity:1"
d="M 913.197,1059.545 C 911.27,1057.212 908.43,1053.155 908.43,1053.155 C 908.43,1053.155 909.038,1058.023 909.038,1060.965 L 909.038,1107.512 L 902.142,1107.512 L 902.142,1037.843 L 903.359,1037.843 L 944.532,1086.52 C 946.459,1088.853 948.791,1091.683 948.791,1091.683 C 948.791,1091.683 948.791,1088.041 948.791,1085.101 L 948.791,1038.553 L 955.586,1038.553 L 955.586,1108.222 L 954.369,1108.222 L 913.197,1059.545 z"
id="path3227" />
<path
style="fill:#000d26;fill-opacity:1"
d="M 677.015,1070.032 C 677.015,1035.196 703.268,1011.468 735.579,1011.468 C 767.89,1011.468 794.143,1035.197 794.143,1070.032 C 794.143,1104.867 767.89,1128.596 735.579,1128.596 C 703.268,1128.596 677.015,1104.868 677.015,1070.032 z M 787.075,1070.032 C 787.075,1040.077 765.03,1017.694 735.579,1017.694 C 706.128,1017.694 684.083,1040.077 684.083,1070.032 C 684.083,1099.988 706.128,1122.37 735.579,1122.37 C 765.03,1122.37 787.075,1099.988 787.075,1070.032 z"
id="path3229" />
<path
style="fill:#000d26;fill-opacity:1"
d="M 967.521,1012.814 L 991.082,1012.814 L 991.082,1106.551 L 1042.915,1106.551 L 1042.915,1127.25 L 967.521,1127.25 L 967.521,1012.814 z"
id="path3231" />
<path
style="fill:#000d26;fill-opacity:1"
d="M 1054.85,1012.814 L 1086.489,1012.814 C 1118.464,1012.814 1137.649,1029.475 1137.649,1057.074 C 1137.649,1084.674 1118.295,1101.166 1086.489,1101.166 L 1078.411,1101.166 L 1078.411,1127.251 L 1054.85,1127.251 L 1054.85,1012.814 z M 1085.815,1080.467 C 1105,1080.467 1113.414,1072.726 1113.414,1057.074 C 1113.414,1041.255 1104.663,1033.513 1085.815,1033.513 L 1078.41,1033.513 L 1078.41,1080.466 L 1085.815,1080.466 L 1085.815,1080.467 z"
id="path3233" />
</g>
d="m 235.67972,13.233984 c -35.92776,0 -69.88078,8.488655 -99.97572,23.558433 l 161.01996,129.174323 52.55342,42.16899 c 39.1477,-4.87501 74.57645,-12.22557 104.45528,-21.44082 C 430.89209,87.375898 341.89666,13.233985 235.67972,13.233984 z M 79.118968,77.210299 c -7.972854,7.813525 -15.354146,16.22165 -22.092394,25.146641 l 217.604986,107.30591 8.32792,4.11306 c 7.91353,-0.38016 15.72478,-0.85776 23.43626,-1.42532 L 275.3035,193.86221 79.118968,77.210299 z M 24.488653,162.95322 c -2.661786,7.58527 -4.921793,15.36128 -6.760069,23.29373 42.624133,13.3171 96.712956,22.78306 156.947626,26.67377 L 24.488653,162.95322 z"
style="fill:url(#linearGradient4057);fill-opacity:1;fill-rule:nonzero;stroke:none;display:inline" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 14 KiB

492
resources/images/openlp.svg Normal file
View File

@ -0,0 +1,492 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="1052.3622"
height="744.09448"
id="svg5740"
sodipodi:version="0.32"
inkscape:version="0.46"
version="1.0"
sodipodi:docname="openlp-logo.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
inkscape:export-filename="/home/raoul/openlp-logo-0.2.png"
inkscape:export-xdpi="91.860847"
inkscape:export-ydpi="91.860847"
style="display:inline">
<defs
id="defs5742">
<linearGradient
id="linearGradient3208">
<stop
style="stop-color:#ffffff;stop-opacity:0.25098041;"
offset="0"
id="stop3210" />
<stop
style="stop-color:#ffffff;stop-opacity:0;"
offset="1"
id="stop3212" />
</linearGradient>
<linearGradient
id="linearGradient3195">
<stop
style="stop-color:#cdcdff;stop-opacity:1;"
offset="0"
id="stop3197" />
<stop
style="stop-color:#ebebff;stop-opacity:1;"
offset="1"
id="stop3199" />
</linearGradient>
<linearGradient
id="linearGradient6359">
<stop
style="stop-color:#000d26;stop-opacity:1;"
offset="0"
id="stop6361" />
<stop
style="stop-color:#507fda;stop-opacity:1;"
offset="1"
id="stop6363" />
</linearGradient>
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 526.18109 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
id="perspective5748" />
<filter
inkscape:collect="always"
id="filter6926">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="3.5771872"
id="feGaussianBlur6928" />
</filter>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3208"
id="linearGradient3214"
x1="470.25891"
y1="276.68851"
x2="463.2301"
y2="14.822601"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3208"
id="linearGradient3229"
gradientUnits="userSpaceOnUse"
x1="470.25891"
y1="276.68851"
x2="463.2301"
y2="14.822601" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3208"
id="linearGradient3279"
gradientUnits="userSpaceOnUse"
x1="470.25891"
y1="276.68851"
x2="463.2301"
y2="14.822601" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3208"
id="linearGradient3287"
gradientUnits="userSpaceOnUse"
x1="470.25891"
y1="276.68851"
x2="463.2301"
y2="14.822601"
gradientTransform="matrix(1.1122448,0,0,1.2037738,-57.29825,4.8849318)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3195"
id="linearGradient3196"
gradientUnits="userSpaceOnUse"
x1="117.59262"
y1="384.05795"
x2="418.20981"
y2="436.03787" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient6359"
id="linearGradient3198"
gradientUnits="userSpaceOnUse"
x1="815.75"
y1="480.55844"
x2="201.10622"
y2="371.85938" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3208"
id="linearGradient3200"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.1122448,0,0,1.2037738,-57.29825,4.8849318)"
x1="470.25891"
y1="276.68851"
x2="469.44925"
y2="104.30029" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3195"
id="linearGradient3215"
gradientUnits="userSpaceOnUse"
x1="117.59262"
y1="384.05795"
x2="418.20981"
y2="436.03787" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient6359"
id="linearGradient3217"
gradientUnits="userSpaceOnUse"
x1="815.75"
y1="480.55844"
x2="201.10622"
y2="371.85938" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3208"
id="linearGradient3219"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.1122448,0,0,1.2037738,-57.29825,4.8849318)"
x1="470.25891"
y1="276.68851"
x2="469.44925"
y2="104.30029" />
<filter
inkscape:collect="always"
id="filter4005">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="4.333215"
id="feGaussianBlur4007" />
</filter>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3208"
id="linearGradient4010"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.7247086,0,0,0.7843464,-109.42065,-2.1325924)"
x1="470.25891"
y1="276.68851"
x2="469.44925"
y2="104.30029" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient6359"
id="linearGradient4013"
gradientUnits="userSpaceOnUse"
x1="815.75"
y1="480.55844"
x2="201.10622"
y2="371.85938"
gradientTransform="matrix(0.6515729,0,0,0.6515729,-72.086668,-5.3154816)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3195"
id="linearGradient4047"
gradientUnits="userSpaceOnUse"
x1="117.59262"
y1="384.05795"
x2="418.20981"
y2="436.03787" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient6359"
id="linearGradient4049"
gradientUnits="userSpaceOnUse"
x1="815.75"
y1="480.55844"
x2="201.10622"
y2="371.85938" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3208"
id="linearGradient4051"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.1122448,0,0,1.2037738,-57.29825,4.8849318)"
x1="470.25891"
y1="276.68851"
x2="469.44925"
y2="104.30029" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3195"
id="linearGradient4053"
gradientUnits="userSpaceOnUse"
x1="117.59262"
y1="384.05795"
x2="418.20981"
y2="436.03787" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient6359"
id="linearGradient4055"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.6515729,0,0,0.6515729,-72.086668,-5.3154816)"
x1="815.75"
y1="480.55844"
x2="201.10622"
y2="371.85938" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3208"
id="linearGradient4057"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.7247086,0,0,0.7843464,-109.42065,-2.1325924)"
x1="470.25891"
y1="276.68851"
x2="469.44925"
y2="104.30029" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
gridtolerance="10000"
guidetolerance="10"
objecttolerance="10"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.0119683"
inkscape:cx="513.59551"
inkscape:cy="369.01895"
inkscape:document-units="px"
inkscape:current-layer="layer6"
showgrid="false"
inkscape:window-width="1280"
inkscape:window-height="958"
inkscape:window-x="-4"
inkscape:window-y="-4" />
<metadata
id="metadata5745">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Shadow"
inkscape:groupmode="layer"
id="layer1"
style="display:inline" />
<g
inkscape:groupmode="layer"
id="layer5"
inkscape:label="Border"
style="display:inline" />
<g
inkscape:groupmode="layer"
id="layer3"
inkscape:label="Rays Background"
style="display:inline" />
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="Rays Foreground"
style="display:inline" />
<g
inkscape:groupmode="layer"
id="layer6"
inkscape:label="Reflection"
style="display:inline">
<g
id="g4018"
transform="translate(9.8817328,9.8817328)">
<path
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
inkscape:export-filename="/home/raoul/openlp-logo-0.2.png"
transform="matrix(0.6379835,0,0,0.6379835,-67.554612,-15.189295)"
d="M 833.03006,395.26932 A 357.71872,357.71872 0 1 1 117.59262,395.26932 A 357.71872,357.71872 0 1 1 833.03006,395.26932 z"
sodipodi:ry="357.71872"
sodipodi:rx="357.71872"
sodipodi:cy="395.26932"
sodipodi:cx="475.31134"
id="path6903"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5.00028753;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline;filter:url(#filter6926)"
sodipodi:type="arc" />
<path
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
inkscape:export-filename="/home/raoul/openlp-logo-0.2.png"
sodipodi:type="arc"
style="fill:#051e52;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5.00028753;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline"
id="path6900"
sodipodi:cx="475.31134"
sodipodi:cy="395.26932"
sodipodi:rx="357.71872"
sodipodi:ry="357.71872"
d="M 833.03006,395.26932 A 357.71872,357.71872 0 1 1 117.59262,395.26932 A 357.71872,357.71872 0 1 1 833.03006,395.26932 z"
transform="matrix(0.6379835,0,0,0.6379835,-67.554612,-15.189295)" />
<path
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
inkscape:export-filename="/home/raoul/openlp-logo-0.2.png"
transform="matrix(0.6317287,0,0,0.6317287,-64.581662,-12.716988)"
d="M 833.03006,395.26932 A 357.71872,357.71872 0 1 1 117.59262,395.26932 A 357.71872,357.71872 0 1 1 833.03006,395.26932 z"
sodipodi:ry="357.71872"
sodipodi:rx="357.71872"
sodipodi:cy="395.26932"
sodipodi:cx="475.31134"
id="path6317"
style="fill:url(#linearGradient4053);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5.00028753;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline"
sodipodi:type="arc" />
<path
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
inkscape:export-filename="/home/raoul/openlp-logo-0.2.png"
id="path6327"
d="M 235.67972,13.233984 C 199.75196,13.233984 165.79894,21.722639 135.704,36.792417 L 296.72396,165.96674 L 452.81639,291.19091 C 457.1409,273.83274 459.43393,255.67894 459.43393,236.98819 C 459.43393,113.48164 359.18627,13.233985 235.67972,13.233984 z M 79.118968,77.210299 C 71.146114,85.023824 63.764822,93.431949 57.026574,102.35694 L 274.63156,209.66285 L 434.20584,288.36064 L 275.3035,193.86221 L 79.118968,77.210299 z M 24.488653,162.95322 C 20.860793,173.29149 17.984378,183.97391 15.896035,194.94138 L 260.17479,255.29332 L 422.98657,295.52794 L 260.21551,241.36595 L 24.488653,162.95322 z M 13.513722,263.49906 C 14.818764,274.53653 16.911081,285.32646 19.764749,295.81301 L 248.30394,302.32874 L 421.76487,307.29698 L 253.55725,289.23619 L 13.513722,263.49906 z M 428.50457,317.76287 L 249.79034,336.84174 L 47.782384,358.40473 C 53.741585,367.60372 60.347088,376.34577 67.553549,384.54909 L 244.45559,351.80755 L 428.50457,317.76287 z M 442.28941,322.97545 L 253.92376,385.15994 L 120.92144,429.05966 C 154.48464,449.16902 193.73296,460.72203 235.67972,460.72204 C 328.7226,460.72204 408.56552,403.84299 442.28941,322.97545 z"
style="fill:url(#linearGradient4055);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline" />
<path
id="path3203"
d="M 235.67972,13.233984 C 199.75196,13.233984 165.79894,21.722639 135.704,36.792417 L 296.72396,165.96674 L 349.27738,208.13573 C 388.42508,203.26072 423.85383,195.91016 453.73266,186.69491 C 430.89209,87.375898 341.89666,13.233985 235.67972,13.233984 z M 79.118968,77.210299 C 71.146114,85.023824 63.764822,93.431949 57.026574,102.35694 L 274.63156,209.66285 L 282.95948,213.77591 C 290.87301,213.39575 298.68426,212.91815 306.39574,212.35059 L 275.3035,193.86221 L 79.118968,77.210299 z M 24.488653,162.95322 C 21.826867,170.53849 19.56686,178.3145 17.728584,186.24695 C 60.352717,199.56405 114.44154,209.03001 174.67621,212.92072 L 24.488653,162.95322 z"
style="fill:url(#linearGradient4057);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4.80000019;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline" />
</g>
<g
id="g4025"
transform="translate(-0.9881736,-11.858079)">
<g
id="g3202"
transform="matrix(0.6515729,0,0,0.6515729,482.27854,11.483464)">
<path
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
inkscape:export-filename="/home/raoul/openlp-logo-0.2.png"
transform="matrix(0.9791437,0,0,0.9791437,6.955563,-15.153813)"
d="M 833.03006,395.26932 A 357.71872,357.71872 0 1 1 117.59262,395.26932 A 357.71872,357.71872 0 1 1 833.03006,395.26932 z"
sodipodi:ry="357.71872"
sodipodi:rx="357.71872"
sodipodi:cy="395.26932"
sodipodi:cx="475.31134"
id="path3204"
style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5.00028753;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline;filter:url(#filter6926)"
sodipodi:type="arc" />
<path
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
inkscape:export-filename="/home/raoul/openlp-logo-0.2.png"
sodipodi:type="arc"
style="opacity:1;fill:#051e52;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5.00028753;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline"
id="path3206"
sodipodi:cx="475.31134"
sodipodi:cy="395.26932"
sodipodi:rx="357.71872"
sodipodi:ry="357.71872"
d="M 833.03006,395.26932 A 357.71872,357.71872 0 1 1 117.59262,395.26932 A 357.71872,357.71872 0 1 1 833.03006,395.26932 z"
transform="matrix(0.9791437,0,0,0.9791437,6.955563,-15.153813)" />
<path
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
inkscape:export-filename="/home/raoul/openlp-logo-0.2.png"
transform="matrix(0.9695442,0,0,0.9695442,11.51829,-11.359445)"
d="M 833.03006,395.26932 A 357.71872,357.71872 0 1 1 117.59262,395.26932 A 357.71872,357.71872 0 1 1 833.03006,395.26932 z"
sodipodi:ry="357.71872"
sodipodi:rx="357.71872"
sodipodi:cy="395.26932"
sodipodi:cx="475.31134"
id="path3208"
style="opacity:1;fill:url(#linearGradient4047);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5.00028753;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline"
sodipodi:type="arc" />
<path
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
inkscape:export-filename="/home/raoul/openlp-logo-0.2.png"
id="path3210"
d="M 472.34375,28.46875 C 417.2037,28.46875 365.09439,41.496693 318.90625,64.625 L 566.03125,262.875 L 805.59375,455.0625 C 812.23078,428.42209 815.75,400.56059 815.75,371.875 C 815.75,182.3236 661.89515,28.468751 472.34375,28.46875 z M 232.0625,126.65625 C 219.82618,138.64804 208.49776,151.55239 198.15625,165.25 L 532.125,329.9375 L 777.03125,450.71875 L 533.15625,305.6875 L 232.0625,126.65625 z M 148.21875,258.25 C 142.6509,274.11664 138.23633,290.51145 135.03125,307.34375 L 509.9375,399.96875 L 759.8125,461.71875 L 510,378.59375 L 148.21875,258.25 z M 131.375,412.5625 C 133.37791,429.50222 136.58909,446.06205 140.96875,462.15625 L 491.71875,472.15625 L 757.9375,479.78125 L 499.78125,452.0625 L 131.375,412.5625 z M 768.28125,495.84375 L 494,525.125 L 183.96875,558.21875 C 193.11462,572.33688 203.2524,585.75373 214.3125,598.34375 L 485.8125,548.09375 L 768.28125,495.84375 z M 789.4375,503.84375 L 500.34375,599.28125 L 296.21875,666.65625 C 347.72979,697.51903 407.96606,715.24999 472.34375,715.25 C 615.1411,715.25 737.67984,627.95502 789.4375,503.84375 z"
style="opacity:1;fill:url(#linearGradient4049);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline" />
<path
id="path3212"
d="M 472.34375,28.46875 C 417.2037,28.46875 365.09439,41.496693 318.90625,64.625 L 566.03125,262.875 L 646.6875,327.59375 C 706.76934,320.11184 761.14353,308.83058 807,294.6875 C 771.94549,142.25788 635.35996,28.468751 472.34375,28.46875 z M 232.0625,126.65625 C 219.82618,138.64804 208.49776,151.55239 198.15625,165.25 L 532.125,329.9375 L 544.90625,336.25 C 557.05152,335.66655 569.03982,334.93356 580.875,334.0625 L 533.15625,305.6875 L 232.0625,126.65625 z M 148.21875,258.25 C 144.13358,269.89147 140.66504,281.82569 137.84375,294 C 203.26104,314.43839 286.27373,328.96625 378.71875,334.9375 L 148.21875,258.25 z"
style="opacity:1;fill:url(#linearGradient4051);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4.80000019;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline" />
</g>
<g
style="fill:#ffffff;fill-opacity:1;filter:url(#filter4005)"
id="g2762"
transform="matrix(0.8481394,0,0,0.8481394,20.507371,-653.75135)">
<path
style="fill:#ffffff;fill-opacity:1"
id="path2764"
d="M 801.444,1038.553 L 817.061,1038.553 C 835.923,1038.553 845.557,1048.997 845.557,1064.514 C 845.557,1079.726 835.923,1090.373 817.061,1090.373 L 808.745,1090.373 L 808.745,1107.512 L 801.444,1107.512 L 801.444,1038.553 L 801.444,1038.553 z M 816.655,1083.984 C 832.172,1083.984 837.952,1075.872 837.952,1064.513 C 837.952,1053.154 832.172,1045.042 816.655,1045.042 L 808.745,1045.042 L 808.745,1083.983 L 816.655,1083.983 L 816.655,1083.984 z" />
<path
style="fill:#ffffff;fill-opacity:1"
id="path2766"
d="M 852.858,1038.553 L 894.842,1038.553 L 894.842,1045.043 L 860.158,1045.043 L 860.158,1077.393 L 891.089,1077.393 L 891.089,1083.782 L 860.158,1083.782 L 860.158,1101.022 L 896.261,1101.022 L 896.261,1107.512 L 852.858,1107.512 L 852.858,1038.553 z" />
<path
style="fill:#ffffff;fill-opacity:1"
id="path2768"
d="M 913.197,1059.545 C 911.27,1057.212 908.43,1053.155 908.43,1053.155 C 908.43,1053.155 909.038,1058.023 909.038,1060.965 L 909.038,1107.512 L 902.142,1107.512 L 902.142,1037.843 L 903.359,1037.843 L 944.532,1086.52 C 946.459,1088.853 948.791,1091.683 948.791,1091.683 C 948.791,1091.683 948.791,1088.041 948.791,1085.101 L 948.791,1038.553 L 955.586,1038.553 L 955.586,1108.222 L 954.369,1108.222 L 913.197,1059.545 z" />
<path
style="fill:#ffffff;fill-opacity:1"
id="path2770"
d="M 677.015,1070.032 C 677.015,1035.196 703.268,1011.468 735.579,1011.468 C 767.89,1011.468 794.143,1035.197 794.143,1070.032 C 794.143,1104.867 767.89,1128.596 735.579,1128.596 C 703.268,1128.596 677.015,1104.868 677.015,1070.032 z M 787.075,1070.032 C 787.075,1040.077 765.03,1017.694 735.579,1017.694 C 706.128,1017.694 684.083,1040.077 684.083,1070.032 C 684.083,1099.988 706.128,1122.37 735.579,1122.37 C 765.03,1122.37 787.075,1099.988 787.075,1070.032 z" />
<path
style="fill:#ffffff;fill-opacity:1"
id="path2772"
d="M 967.521,1012.814 L 991.082,1012.814 L 991.082,1106.551 L 1042.915,1106.551 L 1042.915,1127.25 L 967.521,1127.25 L 967.521,1012.814 z" />
<path
style="fill:#ffffff;fill-opacity:1"
id="path2774"
d="M 1054.85,1012.814 L 1086.489,1012.814 C 1118.464,1012.814 1137.649,1029.475 1137.649,1057.074 C 1137.649,1084.674 1118.295,1101.166 1086.489,1101.166 L 1078.411,1101.166 L 1078.411,1127.251 L 1054.85,1127.251 L 1054.85,1012.814 z M 1085.815,1080.467 C 1105,1080.467 1113.414,1072.726 1113.414,1057.074 C 1113.414,1041.255 1104.663,1033.513 1085.815,1033.513 L 1078.41,1033.513 L 1078.41,1080.466 L 1085.815,1080.466 L 1085.815,1080.467 z" />
</g>
<g
style="fill:#000d26;fill-opacity:1"
transform="matrix(0.8481394,0,0,0.8481394,20.507371,-653.75135)"
id="g3221">
<path
style="fill:#000d26;fill-opacity:1"
d="M 801.444,1038.553 L 817.061,1038.553 C 835.923,1038.553 845.557,1048.997 845.557,1064.514 C 845.557,1079.726 835.923,1090.373 817.061,1090.373 L 808.745,1090.373 L 808.745,1107.512 L 801.444,1107.512 L 801.444,1038.553 L 801.444,1038.553 z M 816.655,1083.984 C 832.172,1083.984 837.952,1075.872 837.952,1064.513 C 837.952,1053.154 832.172,1045.042 816.655,1045.042 L 808.745,1045.042 L 808.745,1083.983 L 816.655,1083.983 L 816.655,1083.984 z"
id="path3223" />
<path
style="fill:#000d26;fill-opacity:1"
d="M 852.858,1038.553 L 894.842,1038.553 L 894.842,1045.043 L 860.158,1045.043 L 860.158,1077.393 L 891.089,1077.393 L 891.089,1083.782 L 860.158,1083.782 L 860.158,1101.022 L 896.261,1101.022 L 896.261,1107.512 L 852.858,1107.512 L 852.858,1038.553 z"
id="path3225" />
<path
style="fill:#000d26;fill-opacity:1"
d="M 913.197,1059.545 C 911.27,1057.212 908.43,1053.155 908.43,1053.155 C 908.43,1053.155 909.038,1058.023 909.038,1060.965 L 909.038,1107.512 L 902.142,1107.512 L 902.142,1037.843 L 903.359,1037.843 L 944.532,1086.52 C 946.459,1088.853 948.791,1091.683 948.791,1091.683 C 948.791,1091.683 948.791,1088.041 948.791,1085.101 L 948.791,1038.553 L 955.586,1038.553 L 955.586,1108.222 L 954.369,1108.222 L 913.197,1059.545 z"
id="path3227" />
<path
style="fill:#000d26;fill-opacity:1"
d="M 677.015,1070.032 C 677.015,1035.196 703.268,1011.468 735.579,1011.468 C 767.89,1011.468 794.143,1035.197 794.143,1070.032 C 794.143,1104.867 767.89,1128.596 735.579,1128.596 C 703.268,1128.596 677.015,1104.868 677.015,1070.032 z M 787.075,1070.032 C 787.075,1040.077 765.03,1017.694 735.579,1017.694 C 706.128,1017.694 684.083,1040.077 684.083,1070.032 C 684.083,1099.988 706.128,1122.37 735.579,1122.37 C 765.03,1122.37 787.075,1099.988 787.075,1070.032 z"
id="path3229" />
<path
style="fill:#000d26;fill-opacity:1"
d="M 967.521,1012.814 L 991.082,1012.814 L 991.082,1106.551 L 1042.915,1106.551 L 1042.915,1127.25 L 967.521,1127.25 L 967.521,1012.814 z"
id="path3231" />
<path
style="fill:#000d26;fill-opacity:1"
d="M 1054.85,1012.814 L 1086.489,1012.814 C 1118.464,1012.814 1137.649,1029.475 1137.649,1057.074 C 1137.649,1084.674 1118.295,1101.166 1086.489,1101.166 L 1078.411,1101.166 L 1078.411,1127.251 L 1054.85,1127.251 L 1054.85,1012.814 z M 1085.815,1080.467 C 1105,1080.467 1113.414,1072.726 1113.414,1057.074 C 1113.414,1041.255 1104.663,1033.513 1085.815,1033.513 L 1078.41,1033.513 L 1078.41,1080.466 L 1085.815,1080.466 L 1085.815,1080.467 z"
id="path3233" />
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 24 KiB