openlp-core team mailing list archive
-
openlp-core team
-
Mailing list archive
-
Message #02982
[Merge] lp:~trb143/openlp/renderer into lp:openlp
Tim Bentley has proposed merging lp:~trb143/openlp/renderer into lp:openlp.
Requested reviews:
Jon Tibble (meths)
For real this time.
New Renderer and Display Code providing lots of new features and goodies.
All know code paths tested and seem to work.
--
https://code.launchpad.net/~trb143/openlp/renderer/+merge/33557
Your team OpenLP Core is subscribed to branch lp:openlp.
=== modified file 'openlp.pyw'
--- openlp.pyw 2010-07-30 22:48:09 +0000
+++ openlp.pyw 2010-08-24 17:20:53 +0000
@@ -34,7 +34,8 @@
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()
=== modified file 'openlp/core/lib/__init__.py'
--- openlp/core/lib/__init__.py 2010-07-27 09:32:52 +0000
+++ openlp/core/lib/__init__.py 2010-08-24 17:20:53 +0000
@@ -35,6 +35,67 @@
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,42 @@
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 retuns
+ 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 +272,7 @@
# 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 +293,25 @@
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 +320,7 @@
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
=== added file 'openlp/core/lib/htmlbuilder.py'
--- openlp/core/lib/htmlbuilder.py 1970-01-01 00:00:00 +0000
+++ openlp/core/lib/htmlbuilder.py 2010-08-24 17:20:53 +0000
@@ -0,0 +1,442 @@
+# -*- 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:
+ 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; ' % \
+ (float(theme.display_outline_size) / 16,
+ 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
=== modified file 'openlp/core/lib/plugin.py'
--- openlp/core/lib/plugin.py 2010-07-31 00:34:37 +0000
+++ openlp/core/lib/plugin.py 2010-08-24 17:20:53 +0000
@@ -131,7 +131,6 @@
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(),
=== modified file 'openlp/core/lib/renderer.py'
--- openlp/core/lib/renderer.py 2010-07-27 09:32:52 +0000
+++ openlp/core/lib/renderer.py 2010-08-24 17:20:53 +0000
@@ -31,7 +31,7 @@
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 @@
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 @@
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 @@
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 @@
lines = verse.split(u'\n')
for line in lines:
text.append(line)
- split_text = self.pre_render_text(text)
+ 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:
+ 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 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}
- else:
- return {u'main':self.frame, u'trans':None}
+ return formatted
def _generate_background_frame(self):
"""
@@ -270,327 +200,47 @@
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)
+ 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)
- 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')
=== modified file 'openlp/core/lib/rendermanager.py'
--- openlp/core/lib/rendermanager.py 2010-07-27 09:32:52 +0000
+++ openlp/core/lib/rendermanager.py 2010-08-24 17:20:53 +0000
@@ -28,7 +28,8 @@
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 @@
"""
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 @@
self.theme_level = u''
self.override_background = None
self.themedata = None
+ self.alertTab = None
def update_display(self):
"""
@@ -70,6 +74,8 @@
"""
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
def set_global_theme(self, global_theme, theme_level=ThemeLevel.Global):
@@ -96,17 +102,22 @@
"""
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 +125,26 @@
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 +180,8 @@
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 +191,23 @@
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']
+ # Previews do not need the transition switched on!
+ themedata.display_slideTransition = False
+ # 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 +216,7 @@
"""
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):
"""
=== modified file 'openlp/core/lib/serviceitem.py'
--- openlp/core/lib/serviceitem.py 2010-08-02 19:23:39 +0000
+++ openlp/core/lib/serviceitem.py 2010-08-24 17:20:53 +0000
@@ -35,7 +35,7 @@
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 @@
RequiresMedia = 4
AllowsLoop = 5
AllowsAdditions = 6
+ NoLineBreaks = 7
class ServiceItem(object):
"""
@@ -82,6 +83,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 = {}
=== modified file 'openlp/core/lib/theme.py'
--- openlp/core/lib/theme.py 2010-07-27 09:32:52 +0000
+++ openlp/core/lib/theme.py 2010-08-24 17:20:53 +0000
@@ -55,7 +55,6 @@
<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 @@
<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 @@
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 @@
``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 @@
#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))
=== modified file 'openlp/core/ui/__init__.py'
--- openlp/core/ui/__init__.py 2010-07-27 09:32:52 +0000
+++ openlp/core/ui/__init__.py 2010-08-24 17:20:53 +0000
@@ -19,7 +19,7 @@
# 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 #
+# You should have received a copy of the GNU General Pu__init__.pyblic License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
@@ -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 @@
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 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']
=== modified file 'openlp/core/ui/amendthemedialog.py'
--- openlp/core/ui/amendthemedialog.py 2010-07-27 10:46:39 +0000
+++ openlp/core/ui/amendthemedialog.py 2010-08-24 17:20:53 +0000
@@ -68,17 +68,6 @@
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 @@
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 @@
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 @@
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,
=== modified file 'openlp/core/ui/amendthemeform.py'
--- openlp/core/ui/amendthemeform.py 2010-07-27 10:20:20 +0000
+++ openlp/core/ui/amendthemeform.py 2010-08-24 17:20:53 +0000
@@ -50,7 +50,6 @@
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 @@
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 @@
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 @@
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 @@
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 @@
self.previewTheme()
#
- #Main Font Tab
+ # Main Font Tab
#
def onFontMainComboBoxSelected(self):
self.theme.font_main_name = self.fontMainComboBox.currentFont().family()
@@ -283,8 +272,6 @@
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 @@
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 @@
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 @@
self.previewTheme()
#
- #Other Tab
+ # Other Tab
#
def onOutlineCheckBoxChanged(self, value):
if value == 2: # checked
@@ -537,16 +509,12 @@
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 @@
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,63 +607,50 @@
self.verticalComboBox.setCurrentIndex(self.theme.display_verticalAlign)
def stateChanging(self, theme):
- if theme.background_mode == u'transparent':
+ 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(False)
- self.imageLineEdit.setVisible(False)
- self.imageFilenameWidget.setVisible(False)
+ self.imageLabel.setVisible(True)
+ self.imageLineEdit.setVisible(True)
+ self.imageFilenameWidget.setVisible(True)
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)
if not theme.font_main_override:
self.fontMainXSpinBox.setEnabled(False)
self.fontMainYSpinBox.setEnabled(False)
=== modified file 'openlp/core/ui/generaltab.py'
--- openlp/core/ui/generaltab.py 2010-08-02 16:54:21 +0000
+++ openlp/core/ui/generaltab.py 2010-08-24 17:20:53 +0000
@@ -436,10 +436,10 @@
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())
+ self.timeoutSpinBox.value())
settings.setValue(u'ccli number',
QtCore.QVariant(self.numberEdit.displayText()))
settings.setValue(u'songselect username',
@@ -486,6 +486,7 @@
else:
self.screens.reset_current_display()
Receiver.send_message(u'config_screen_changed')
+ self.overrideChanged = False
def onOverrideCheckBoxToggled(self, checked):
"""
=== modified file 'openlp/core/ui/maindisplay.py'
--- openlp/core/ui/maindisplay.py 2010-08-02 16:54:21 +0000
+++ openlp/core/ui/maindisplay.py 2010-08-24 17:20:53 +0000
@@ -26,149 +26,43 @@
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):
+ # 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 +79,251 @@
Receiver.send_message(self.hotkey_map[event.key()])
event.accept()
elif event.key() == QtCore.Qt.Key_Escape:
- self.resetDisplay()
+ self.setVisible(False)
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.
- """
log.debug(u'Setup %s for %s ' % (
self.screens, self.screens.monitor_number))
+ self.screen = self.screens.current
self.setVisible(False)
- self.screen = self.screens.current
- #Sort out screen locations and sizes
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,
- QtCore.Qt.ScrollBarAlwaysOff)
- self.videoDisplay.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)
-
- def setupImage(self):
- self.imageDisplay = QtGui.QGraphicsPixmapItem()
- self.imageDisplay.setZValue(2)
- self.scene.addItem(self.imageDisplay)
-
- 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)
-
- def setupAlert(self):
- self.alertText = QtGui.QGraphicsTextItem()
- self.alertText.setZValue(8)
- self.scene.addItem(self.alertText)
-
- def setupBlank(self):
- self.displayBlank = QtGui.QGraphicsPixmapItem()
- self.displayBlank.setZValue(10)
- self.scene.addItem(self.displayBlank)
-
-# def hideDisplayForVideo(self):
-# """
-# Hides the main display if for the video to be played
-# """
-# self.hideDisplay(HideMode.Screen)
+ 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.frame.setScrollBarPolicy(QtCore.Qt.Horizontal,
+ QtCore.Qt.ScrollBarAlwaysOff)
+ 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 text(self, slide):
+ """
+ Add the slide text from slideController
+
+ `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 alert(self, text):
+ """
+ Add the alert text
+
+ `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 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)
+
+ 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");')
+
+ 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')
+ # Wait for the fade to finish before geting the preview.
+ # Important otherwise preview will have incorrect text if at all !
+ if 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()
+ # 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):
+ log.debug(u'footer')
+ js = "show_footer('" + \
+ text.replace("\\", "\\\\").replace("\'", "\\\'") + "')"
+ self.frame.evaluateJavaScript(js)
def hideDisplay(self, mode=HideMode.Screen):
"""
@@ -343,20 +331,13 @@
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 +348,16 @@
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 +397,9 @@
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):
=== modified file 'openlp/core/ui/mainwindow.py'
--- openlp/core/ui/mainwindow.py 2010-07-31 00:34:37 +0000
+++ openlp/core/ui/mainwindow.py 2010-08-24 17:20:53 +0000
@@ -29,7 +29,7 @@
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 @@
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 @@
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 @@
#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 @@
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)
@@ -663,9 +660,10 @@
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',
@@ -746,7 +744,6 @@
their locations
"""
self.RenderManager.update_display()
- self.displayManager.setup()
self.setFocus()
self.activateWindow()
@@ -792,8 +789,8 @@
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):
"""
=== modified file 'openlp/core/ui/servicemanager.py'
--- openlp/core/ui/servicemanager.py 2010-07-31 02:06:44 +0000
+++ openlp/core/ui/servicemanager.py 2010-08-24 17:20:53 +0000
@@ -317,9 +317,8 @@
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):
"""
@@ -873,6 +872,7 @@
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'),
=== modified file 'openlp/core/ui/slidecontroller.py'
--- openlp/core/ui/slidecontroller.py 2010-08-02 19:05:40 +0000
+++ openlp/core/ui/slidecontroller.py 2010-08-24 17:20:53 +0000
@@ -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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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,39 @@
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'config_updated'), self.refreshServiceItem)
QtCore.QObject.connect(Receiver.get_receiver(),
+ QtCore.SIGNAL(u'config_screen_changed'), self.screenSizeChanged)
+ QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'%s_slide_cache' % self.typePrefix), self.slideCache)
+ 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 +470,6 @@
if item.is_media():
self.Toolbar.setVisible(False)
self.Mediabar.setVisible(True)
- #self.volumeSlider.setAudioOutput(
- # self.mainDisplay.videoDisplay.audio)
def enablePreviewToolBar(self, item):
"""
@@ -474,7 +489,7 @@
"""
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
@@ -486,10 +501,8 @@
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 +522,8 @@
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 +535,15 @@
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 +552,8 @@
[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 +567,19 @@
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 +606,14 @@
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 +625,7 @@
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 +635,7 @@
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 +669,9 @@
"""
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 +693,8 @@
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 +712,8 @@
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 +728,8 @@
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:
@@ -778,24 +786,15 @@
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 +809,7 @@
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)
@@ -822,9 +820,8 @@
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 +938,9 @@
"""
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 +950,21 @@
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 +974,7 @@
"""
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 +986,7 @@
"""
log.debug(u'SlideController onMediaStop')
if self.isLive:
- Receiver.send_message(u'videodisplay_stop')
+ self.display.videoStop()
else:
self.mediaObject.stop()
self.video.hide()
=== modified file 'openlp/core/ui/thememanager.py'
--- openlp/core/ui/thememanager.py 2010-07-31 02:06:44 +0000
+++ openlp/core/ui/thememanager.py 2010-08-24 17:20:53 +0000
@@ -660,9 +660,8 @@
"""
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 +731,8 @@
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_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 +745,7 @@
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_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 +756,8 @@
#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'
=== modified file 'openlp/plugins/alerts/alertsplugin.py'
--- openlp/plugins/alerts/alertsplugin.py 2010-07-31 22:23:48 +0000
+++ openlp/plugins/alerts/alertsplugin.py 2010-08-24 17:20:53 +0000
@@ -80,9 +80,10 @@
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 Finaliseing')
Plugin.finalise(self)
self.toolsAlertItem.setVisible(False)
=== modified file 'openlp/plugins/alerts/lib/alertsmanager.py'
--- openlp/plugins/alerts/lib/alertsmanager.py 2010-07-27 09:32:52 +0000
+++ openlp/plugins/alerts/lib/alertsmanager.py 2010-08-24 17:20:53 +0000
@@ -32,18 +32,9 @@
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 @@
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 @@
"""
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()
=== modified file 'openlp/plugins/alerts/lib/alertstab.py'
--- openlp/plugins/alerts/lib/alertstab.py 2010-07-27 09:32:52 +0000
+++ openlp/plugins/alerts/lib/alertstab.py 2010-08-24 17:20:53 +0000
@@ -261,7 +261,7 @@
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 @@
self.FontPreview.setFont(font)
self.FontPreview.setStyleSheet(u'background-color: %s; color: %s' %
(self.bg_color, self.font_color))
+
=== modified file 'openlp/plugins/bibles/lib/mediaitem.py'
--- openlp/plugins/bibles/lib/mediaitem.py 2010-08-10 16:49:52 +0000
+++ openlp/plugins/bibles/lib/mediaitem.py 2010-08-24 17:20:53 +0000
@@ -503,16 +503,16 @@
dual_text = self._decodeQtObject(reference, 'dual_text')
if self.parent.settings_tab.display_style == 1:
verse_text = self.formatVerse(old_chapter, chapter, verse,
- u'(', u')')
+ u'{su}(', u'){/su}')
elif self.parent.settings_tab.display_style == 2:
verse_text = self.formatVerse(old_chapter, chapter, verse,
- u'{', u'}')
+ u'{su}{', u'}{/su}')
elif self.parent.settings_tab.display_style == 3:
verse_text = self.formatVerse(old_chapter, chapter, verse,
- u'[', u']')
+ u'{su}[', u']{/su}')
else:
verse_text = self.formatVerse(old_chapter, chapter, verse,
- u'', u'')
+ u'{su}', u'{/su}')
old_chapter = chapter
footer = u'%s (%s %s)' % (book, version, copyright)
# If not found add to footer
@@ -531,7 +531,11 @@
else:
# If we are 'Verse Per Line' then force a new line.
if self.parent.settings_tab.layout_style == 1:
- text = text + u'\n\n'
+ text = text + u'\n'
+ else:
+ # split the line but do not replace line breaks in renderer
+ service_item.add_capability(ItemCapabilities.NoLineBreaks)
+ text = text + u'\n'
bible_text = u'%s %s %s' % (bible_text, verse_text, text)
# If we are 'Verse Per Slide' then create a new slide.
if self.parent.settings_tab.layout_style == 0:
=== modified file 'openlp/plugins/custom/forms/editcustomdialog.py'
--- openlp/plugins/custom/forms/editcustomdialog.py 2010-07-27 11:42:38 +0000
+++ openlp/plugins/custom/forms/editcustomdialog.py 2010-08-24 17:20:53 +0000
@@ -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 @@
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)
=== modified file 'openlp/plugins/images/lib/mediaitem.py'
--- openlp/plugins/images/lib/mediaitem.py 2010-07-27 09:32:52 +0000
+++ openlp/plugins/images/lib/mediaitem.py 2010-08-24 17:20:53 +0000
@@ -110,8 +110,14 @@
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 @@
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 @@
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)
=== modified file 'openlp/plugins/media/lib/mediaitem.py'
--- openlp/plugins/media/lib/mediaitem.py 2010-07-27 09:32:52 +0000
+++ openlp/plugins/media/lib/mediaitem.py 2010-08-24 17:20:53 +0000
@@ -97,8 +97,17 @@
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 @@
'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:
=== modified file 'openlp/plugins/songs/forms/editsongform.py'
--- openlp/plugins/songs/forms/editsongform.py 2010-07-31 02:06:44 +0000
+++ openlp/plugins/songs/forms/editsongform.py 2010-08-24 17:20:53 +0000
@@ -314,7 +314,7 @@
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 @@
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)
=== modified file 'openlp/plugins/songs/forms/editversedialog.py'
--- openlp/plugins/songs/forms/editversedialog.py 2010-07-27 09:32:52 +0000
+++ openlp/plugins/songs/forms/editversedialog.py 2010-08-24 17:20:53 +0000
@@ -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 @@
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()
=== modified file 'openlp/plugins/songs/forms/editverseform.py'
--- openlp/plugins/songs/forms/editverseform.py 2010-07-27 09:32:52 +0000
+++ openlp/plugins/songs/forms/editverseform.py 2010-08-24 17:20:53 +0000
@@ -45,6 +45,9 @@
"""
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 @@
)
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')
=== added directory 'resources/Fedora'
=== added directory 'resources/Fedora/191'
=== added file 'resources/Fedora/191/OpenLP.spec'
--- resources/Fedora/191/OpenLP.spec 1970-01-01 00:00:00 +0000
+++ resources/Fedora/191/OpenLP.spec 2010-08-24 17:20:53 +0000
@@ -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@xxxxxxxxxx> 1.9.1.1
+- Initial build version - Alpha 1 Release
=== added directory 'resources/Fedora/192'
Follow ups