diff --git a/openlp.pyw b/openlp.pyw
index 074cd489f..c4f062b87 100755
--- a/openlp.pyw
+++ b/openlp.pyw
@@ -34,7 +34,8 @@ from PyQt4 import QtCore, QtGui
from openlp.core.lib import Receiver
from openlp.core.resources import qInitResources
-from openlp.core.ui import MainWindow, SplashScreen, ScreenList
+from openlp.core.ui.mainwindow import MainWindow
+from openlp.core.ui import SplashScreen, ScreenList
from openlp.core.utils import AppLocation, LanguageManager, VersionThread
log = logging.getLogger()
diff --git a/openlp/core/lib/__init__.py b/openlp/core/lib/__init__.py
index ae5d0602c..b76179c2c 100644
--- a/openlp/core/lib/__init__.py
+++ b/openlp/core/lib/__init__.py
@@ -35,6 +35,67 @@ from PyQt4 import QtCore, QtGui
log = logging.getLogger(__name__)
+# TODO make external and configurable in alpha 4 via a settings dialog
+html_expands = []
+
+html_expands.append({u'desc':u'Red', u'start tag':u'{r}', \
+ u'start html':u'', \
+ u'end tag':u'{/r}', u'end html':u'', \
+ u'protected':False})
+html_expands.append({u'desc':u'Black', u'start tag':u'{b}', \
+ u'start html':u'', \
+ u'end tag':u'{/b}', u'end html':u'', \
+ u'protected':False})
+html_expands.append({u'desc':u'Blue', u'start tag':u'{bl}', \
+ u'start html':u'', \
+ u'end tag':u'{/bl}', u'end html':u'', \
+ u'protected':False})
+html_expands.append({u'desc':u'Yellow', u'start tag':u'{y}', \
+ u'start html':u'', \
+ u'end tag':u'{/y}', u'end html':u'', \
+ u'protected':False})
+html_expands.append({u'desc':u'Green', u'start tag':u'{g}', \
+ u'start html':u'', \
+ u'end tag':u'{/g}', u'end html':u'', \
+ u'protected':False})
+html_expands.append({u'desc':u'Pink', u'start tag':u'{pk}', \
+ u'start html':u'', \
+ u'end tag':u'{/pk}', u'end html':u'', \
+ u'protected':False})
+html_expands.append({u'desc':u'Orange', u'start tag':u'{o}', \
+ u'start html':u'', \
+ u'end tag':u'{/o}', u'end html':u'', \
+ u'protected':False})
+html_expands.append({u'desc':u'Purple', u'start tag':u'{pp}', \
+ u'start html':u'', \
+ u'end tag':u'{/pp}', u'end html':u'', \
+ u'protected':False})
+html_expands.append({u'desc':u'White', u'start tag':u'{w}', \
+ u'start html':u'', \
+ u'end tag':u'{/w}', u'end html':u'', \
+ u'protected':False})
+html_expands.append({u'desc':u'Superscript', u'start tag':u'{su}', \
+ u'start html':u'', \
+ u'end tag':u'{/su}', u'end html':u'', \
+ u'protected':True})
+html_expands.append({u'desc':u'Subscript', u'start tag':u'{sb}', \
+ u'start html':u'', \
+ u'end tag':u'{/sb}', u'end html':u'', \
+ u'protected':True})
+html_expands.append({u'desc':u'Paragraph', u'start tag':u'{p}', \
+ u'start html':u'
', \
+ u'end tag':u'{/p}', u'end html':u'
', \
+ u'protected':True})
+html_expands.append({u'desc':u'Bold', u'start tag':u'{st}', \
+ u'start html':u'', \
+ u'end tag':u'{/st}', \
+ u'end html':u'', \
+ u'protected':True})
+html_expands.append({u'desc':u'Italics', u'start tag':u'{it}', \
+ u'start html':u'', \
+ u'end tag':u'{/it}', u'end html':u'', \
+ u'protected':True})
+
def translate(context, text, comment=None):
"""
A special shortcut method to wrap around the Qt4 translation functions.
@@ -166,15 +227,46 @@ def context_menu_separator(base):
action.setSeparator(True)
return action
-def resize_image(image, width, height):
+def image_to_byte(image):
+ """
+ Resize an image to fit on the current screen for the web and returns
+ it as a byte stream.
+
+ ``image``
+ The image to converted.
+ """
+ byte_array = QtCore.QByteArray()
+ # use buffer to store pixmap into byteArray
+ buffie = QtCore.QBuffer(byte_array)
+ buffie.open(QtCore.QIODevice.WriteOnly)
+ if isinstance(image, QtGui.QImage):
+ pixmap = QtGui.QPixmap.fromImage(image)
+ else:
+ pixmap = QtGui.QPixmap(image)
+ pixmap.save(buffie, "PNG")
+ # convert to base64 encoding so does not get missed!
+ return byte_array.toBase64()
+
+def resize_image(image, width, height, background=QtCore.Qt.black):
"""
Resize an image to fit on the current screen.
``image``
The image to resize.
+
+ ``width``
+ The new image width.
+
+ ``height``
+ The new image height.
+
+ ``background``
+ The background colour defaults to black.
+
"""
preview = QtGui.QImage(image)
if not preview.isNull():
+ # Only resize if different size
if preview.width() == width and preview.height == height:
return preview
preview = preview.scaled(width, height, QtCore.Qt.KeepAspectRatio,
@@ -184,7 +276,7 @@ def resize_image(image, width, height):
# and move it to the centre of the preview space
new_image = QtGui.QImage(width, height,
QtGui.QImage.Format_ARGB32_Premultiplied)
- new_image.fill(QtCore.Qt.black)
+ new_image.fill(background)
painter = QtGui.QPainter(new_image)
painter.drawImage((width - realw) / 2, (height - realh) / 2, preview)
return new_image
@@ -205,6 +297,25 @@ def check_item_selected(list_widget, message):
return False
return True
+def clean_tags(text):
+ """
+ Remove Tags from text for display
+ """
+ text = text.replace(u'
', u'\n')
+ for tag in html_expands:
+ text = text.replace(tag[u'start tag'], u'')
+ text = text.replace(tag[u'end tag'], u'')
+ return text
+
+def expand_tags(text):
+ """
+ Expand tags HTML for display
+ """
+ for tag in html_expands:
+ text = text.replace(tag[u'start tag'], tag[u'start html'])
+ text = text.replace(tag[u'end tag'], tag[u'end html'])
+ return text
+
from eventreceiver import Receiver
from settingsmanager import SettingsManager
from plugin import PluginStatus, Plugin
@@ -213,6 +324,7 @@ from settingstab import SettingsTab
from serviceitem import ServiceItem
from serviceitem import ServiceItemType
from serviceitem import ItemCapabilities
+from htmlbuilder import build_html
from toolbar import OpenLPToolbar
from dockwidget import OpenLPDockWidget
from theme import ThemeLevel, ThemeXML
diff --git a/openlp/core/lib/htmlbuilder.py b/openlp/core/lib/htmlbuilder.py
new file mode 100644
index 000000000..2fa7b0df0
--- /dev/null
+++ b/openlp/core/lib/htmlbuilder.py
@@ -0,0 +1,445 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2010 Raoul Snyman #
+# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
+# Gorven, Scott Guerrieri, Meinert Jordan, Andreas Preikschat, Christian #
+# Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon Tibble, #
+# Carsten Tinggaard, Frode Woldsund #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it #
+# under the terms of the GNU General Public License as published by the Free #
+# Software Foundation; version 2 of the License. #
+# #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
+# more details. #
+# #
+# You should have received a copy of the GNU General Public License along #
+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
+###############################################################################
+
+from openlp.core.lib import image_to_byte
+
+HTMLSRC = u"""
+
+
+OpenLP Display
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ """
+
+def build_html(item, screen, alert):
+ """
+ Build the full web paged structure for display
+
+ `item`
+ Service Item to be displayed
+ `screen`
+ Current display information
+ `alert`
+ Alert display display information
+ """
+ width = screen[u'size'].width()
+ height = screen[u'size'].height()
+ theme = item.themedata
+ if item.bg_frame:
+ image = u'data:image/png;base64,%s' % image_to_byte(item.bg_frame)
+ else:
+ image = u''
+ html = HTMLSRC % (width, height,
+ build_alert(alert, width),
+ build_footer(item),
+ build_lyrics(item),
+ u'true' if theme and theme.display_slideTransition \
+ else u'false',
+ image)
+ return html
+
+def build_lyrics(item):
+ """
+ Build the video display div
+
+ `item`
+ Service Item containing theme and location information
+ """
+ style = """
+ .lyricscommon { position: absolute; %s }
+ .lyricstable { z-index:4; %s }
+ .lyricsoutlinetable { z-index:3; %s }
+ .lyricsshadowtable { z-index:2; %s }
+ .lyrics { %s }
+ .lyricsoutline { %s }
+ .lyricsshadow { %s }
+ """
+ theme = item.themedata
+ lyricscommon = u''
+ lyricstable = u''
+ outlinetable = u''
+ shadowtable = u''
+ lyrics = u''
+ outline = u'display: none;'
+ shadow = u'display: none;'
+ if theme:
+ lyricscommon = u'width: %spx; height: %spx; word-wrap: break-word; ' \
+ u'font-family: %s; font-size: %spx; color: %s; line-height: %d%%;' % \
+ (item.main.width(), item.main.height(),
+ theme.font_main_name, theme.font_main_proportion,
+ theme.font_main_color, 100 + int(theme.font_main_line_adjustment))
+ lyricstable = u'left: %spx; top: %spx;' % \
+ (item.main.x(), item.main.y())
+ outlinetable = u'left: %spx; top: %spx;' % \
+ (item.main.x(), item.main.y())
+ shadowtable = u'left: %spx; top: %spx;' % \
+ (item.main.x() + float(theme.display_shadow_size),
+ item.main.y() + float(theme.display_shadow_size))
+ align = u''
+ if theme.display_horizontalAlign == 2:
+ align = u'text-align:center;'
+ elif theme.display_horizontalAlign == 1:
+ align = u'text-align:right;'
+ else:
+ align = u'text-align:left;'
+ if theme.display_verticalAlign == 2:
+ valign = u'vertical-align:bottom;'
+ elif theme.display_verticalAlign == 1:
+ valign = u'vertical-align:middle;'
+ else:
+ valign = u'vertical-align:top;'
+ lyrics = u'%s %s' % (align, valign)
+ if theme.display_outline:
+ lyricscommon += u' letter-spacing: 1px;'
+ outline = u'-webkit-text-stroke: %sem %s; ' % \
+ (float(theme.display_outline_size) / 16,
+ theme.display_outline_color)
+ if theme.display_shadow:
+ shadow = u'-webkit-text-stroke: %sem %s; ' \
+ u'-webkit-text-fill-color: %s; '% \
+ (float(theme.display_outline_size) / 16,
+ theme.display_shadow_color, theme.display_shadow_color)
+ else:
+ if theme.display_shadow:
+ shadow = u'color: %s;' % (theme.display_shadow_color)
+ lyrics_html = style % (lyricscommon, lyricstable, outlinetable,
+ shadowtable, lyrics, outline, shadow)
+ return lyrics_html
+
+def build_footer(item):
+ """
+ Build the display of the item footer
+
+ `item`
+ Service Item to be processed.
+ """
+ style = """
+ left: %spx;
+ top: %spx;
+ width: %spx;
+ height: %spx;
+ font-family: %s;
+ font-size: %spx;
+ color: %s;
+ text-align: %s;
+ """
+ theme = item.themedata
+ if not theme:
+ return u''
+ if theme.display_horizontalAlign == 2:
+ align = u'center'
+ elif theme.display_horizontalAlign == 1:
+ align = u'right'
+ else:
+ align = u'left'
+ lyrics_html = style % (item.footer.x(), item.footer.y(),
+ item.footer.width(), item.footer.height(), theme.font_footer_name,
+ theme.font_footer_proportion, theme.font_footer_color, align)
+ return lyrics_html
+
+def build_alert(alertTab, width):
+ """
+ Build the display of the footer
+
+ `alertTab`
+ Details from the Alert tab for fonts etc
+ """
+ style = """
+ width: %s;
+ vertical-align: %s;
+ font-family: %s;
+ font-size: %spx;
+ color: %s;
+ background-color: %s;
+ """
+ if not alertTab:
+ return u''
+ align = u''
+ if alertTab.location == 2:
+ align = u'bottom'
+ elif alertTab.location == 1:
+ align = u'middle'
+ else:
+ align = u'top'
+ alert = style % (width, align, alertTab.font_face, alertTab.font_size,
+ alertTab.font_color, alertTab.bg_color)
+ return alert
diff --git a/openlp/core/lib/plugin.py b/openlp/core/lib/plugin.py
index 45fb12ec4..45fbcb6b0 100644
--- a/openlp/core/lib/plugin.py
+++ b/openlp/core/lib/plugin.py
@@ -131,7 +131,6 @@ class Plugin(QtCore.QObject):
self.serviceManager = plugin_helpers[u'service']
self.settingsForm = plugin_helpers[u'settings form']
self.mediadock = plugin_helpers[u'toolbox']
- self.displayManager = plugin_helpers[u'displaymanager']
self.pluginManager = plugin_helpers[u'pluginmanager']
self.formparent = plugin_helpers[u'formparent']
QtCore.QObject.connect(Receiver.get_receiver(),
diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py
index f764f069f..433018c23 100644
--- a/openlp/core/lib/renderer.py
+++ b/openlp/core/lib/renderer.py
@@ -31,7 +31,7 @@ import logging
from PyQt4 import QtGui, QtCore
-from openlp.core.lib import resize_image
+from openlp.core.lib import resize_image, expand_tags
log = logging.getLogger(__name__)
@@ -80,7 +80,6 @@ class Renderer(object):
self.bg_image = None
self._bg_image_filename = None
self.theme_name = theme.theme_name
- self._set_theme_font()
if theme.background_type == u'image':
if theme.background_filename:
self.set_bg_image(theme.background_filename)
@@ -99,6 +98,20 @@ class Renderer(object):
self.frame.width(),
self.frame.height())
+ def set_text_rectangle(self, rect_main, rect_footer):
+ """
+ Sets the rectangle within which text should be rendered.
+
+ ``rect_main``
+ The main text block.
+
+ ``rect_footer``
+ The footer text block.
+ """
+ log.debug(u'set_text_rectangle %s , %s' % (rect_main, rect_footer))
+ self._rect = rect_main
+ self._rect_footer = rect_footer
+
def set_frame_dest(self, frame_width, frame_height, preview=False):
"""
Set the size of the slide.
@@ -118,26 +131,24 @@ class Renderer(object):
frame_height)
self.frame = QtGui.QImage(frame_width, frame_height,
QtGui.QImage.Format_ARGB32_Premultiplied)
- self.frame_opaque = QtGui.QImage(frame_width, frame_height,
- QtGui.QImage.Format_ARGB32_Premultiplied)
if self._bg_image_filename and not self.bg_image:
self.bg_image = resize_image(self._bg_image_filename,
self.frame.width(), self.frame.height())
if self.bg_frame is None:
self._generate_background_frame()
- def format_slide(self, words, footer):
+ def format_slide(self, words, line_break):
"""
Figure out how much text can appear on a slide, using the current
theme settings.
``words``
The words to be fitted on the slide.
-
- ``footer``
- The footer of the slide.
"""
log.debug(u'format_slide - Start')
+ line_end = u''
+ if line_break:
+ line_end = u'
'
words = words.replace(u'\r\n', u'\n')
verses_text = words.split(u'\n')
text = []
@@ -145,124 +156,43 @@ class Renderer(object):
lines = verse.split(u'\n')
for line in lines:
text.append(line)
- split_text = self.pre_render_text(text)
- log.debug(u'format_slide - End')
- return split_text
-
- def pre_render_text(self, text):
- metrics = QtGui.QFontMetrics(self.main_font)
- #work out line width
- line_width = self._rect.width()
- #number of lines on a page - adjust for rounding up.
- line_height = metrics.height()
- if self._theme.display_shadow:
- line_height += int(self._theme.display_shadow_size)
- if self._theme.display_outline:
- # pixels top/bottom
- line_height += 2 * int(self._theme.display_outline_size)
- page_length = int(self._rect.height() / line_height )
- #Average number of characters in line
- ave_line_width = line_width / metrics.averageCharWidth()
- #Maximum size of a character
- max_char_width = metrics.maxWidth()
- #Max characters pre line based on min size of a character
- char_per_line = line_width / metrics.width(u'i')
- log.debug(u'Page Length area height %s , metrics %s , lines %s' %
- (int(self._rect.height()), metrics.height(), page_length ))
- split_pages = []
- page = []
- split_lines = []
- count = 0
- for line in text:
- #Must be a blank line so keep it.
- if len(line) == 0:
- line = u' '
- while line:
- pos = char_per_line
- split_text = line[:pos]
- #line needs splitting
- if metrics.width(split_text, -1) > line_width:
- #We have no spaces
- if split_text.find(u' ') == -1:
- #Move back 1 char at a time till it fits
- while metrics.width(split_text, -1) > line_width:
- split_text = split_text[:-1]
- pos = len(split_text)
- else:
- #We have spaces so split at previous one
- while metrics.width(split_text, -1) > line_width:
- pos = split_text.rfind(u' ')
- #no more spaces and we are still too long
- if pos == -1:
- while \
- metrics.width(split_text, -1) > line_width:
- split_text = split_text[:-1]
- pos = len(split_text)
- else:
- split_text = line[:pos]
- split_lines.append(split_text)
- line = line[pos:].lstrip()
- #if we have more text add up to 10 spaces on the front.
- if line and self._theme.font_main_indentation > 0:
- line = u'%s%s' % \
- (u' '[:int(self._theme.font_main_indentation)],
- line)
- #Text fits in a line now
- for count, line in enumerate(split_lines):
- page.append(line)
- #last but one line and only 2 lines to go or end of page
- if (len(page) == page_length - 1 and
- len(split_lines) - 3 == count) or \
- len(page) == page_length:
- split_pages.append(page)
- page = []
- if page and page != u' ':
- split_pages.append(page)
- return split_pages
-
- def set_text_rectangle(self, rect_main, rect_footer):
- """
- Sets the rectangle within which text should be rendered.
-
- ``rect_main``
- The main text block.
-
- ``rect_footer``
- The footer text block.
- """
- log.debug(u'set_text_rectangle %s , %s' % (rect_main, rect_footer))
- self._rect = rect_main
- self._rect_footer = rect_footer
-
- def generate_frame_from_lines(self, lines, footer_lines=None):
- """
- Render a set of lines according to the theme, and return the block
- dimensions.
-
- ``lines``
- The lines to be rendered.
-
- ``footer_lines``
- Defaults to *None*. The footer to render.
- """
- log.debug(u'generate_frame_from_lines - Start')
- bbox = self._render_lines_unaligned(lines, False)
- if footer_lines:
- bbox1 = self._render_lines_unaligned(footer_lines, True)
- # reset the frame. first time do not worry about what you paint on.
- self.frame = QtGui.QImage(self.bg_frame)
- if self._theme.display_slideTransition:
- self.frame_opaque = QtGui.QImage(self.bg_frame)
- x, y = self._correct_alignment(self._rect, bbox)
- bbox = self._render_lines_unaligned(lines, False, (x, y), True)
- if footer_lines:
- bbox = self._render_lines_unaligned(footer_lines, True,
- (self._rect_footer.left(), self._rect_footer.top()), True)
- log.debug(u'generate_frame_from_lines - Finish')
- if self._theme.display_slideTransition:
- return {u'main':self.frame, u'trans':self.frame_opaque}
+ doc = QtGui.QTextDocument()
+ doc.setPageSize(QtCore.QSizeF(self._rect.width(), self._rect.height()))
+ df = doc.defaultFont()
+ df.setPixelSize(self._theme.font_main_proportion)
+ df.setFamily(self._theme.font_main_name)
+ main_weight = 50
+ if self._theme.font_main_weight == u'Bold':
+ main_weight = 75
+ df.setWeight(main_weight)
+ doc.setDefaultFont(df)
+ layout = doc.documentLayout()
+ formatted = []
+ if self._theme.font_main_weight == u'Bold' and \
+ self._theme.font_main_italics:
+ shell = u'{p}{st}{it}%s{/it}{/st}{/p}'
+ elif self._theme.font_main_weight == u'Bold' and \
+ not self._theme.font_main_italics:
+ shell = u'{p}{st}%s{/st}{/p}'
+ elif self._theme.font_main_italics:
+ shell = u'{p}{it}%s{/it}{/p}'
else:
- return {u'main':self.frame, u'trans':None}
+ shell = u'{p}%s{/p}'
+ temp_text = u''
+ old_html_text = u''
+ for line in text:
+ # mark line ends
+ temp_text = temp_text + line + line_end
+ html_text = shell % expand_tags(temp_text)
+ doc.setHtml(html_text)
+ # Text too long so gone to next mage
+ if layout.pageCount() != 1:
+ formatted.append(shell % old_html_text)
+ temp_text = line
+ old_html_text = temp_text
+ formatted.append(shell % old_html_text)
+ log.debug(u'format_slide - End')
+ return formatted
def _generate_background_frame(self):
"""
@@ -270,327 +200,47 @@ class Renderer(object):
Results are cached for performance reasons.
"""
assert(self._theme)
- if self._theme.background_mode == u'transparent':
- self.bg_frame = \
- QtGui.QPixmap(self.frame.width(), self.frame.height())
- self.bg_frame.fill(QtCore.Qt.transparent)
- else:
- self.bg_frame = QtGui.QImage(self.frame.width(),
- self.frame.height(), QtGui.QImage.Format_ARGB32_Premultiplied)
+ self.bg_frame = QtGui.QImage(self.frame.width(),
+ self.frame.height(), QtGui.QImage.Format_ARGB32_Premultiplied)
log.debug(u'render background %s start', self._theme.background_type)
painter = QtGui.QPainter()
painter.begin(self.bg_frame)
- if self._theme.background_mode == u'transparent':
- painter.fillRect(self.frame.rect(), QtCore.Qt.transparent)
- else:
- if self._theme.background_type == u'solid':
- painter.fillRect(self.frame.rect(),
- QtGui.QColor(self._theme.background_color))
- elif self._theme.background_type == u'gradient':
- # gradient
- gradient = None
- if self._theme.background_direction == u'horizontal':
- w = int(self.frame.width()) / 2
- # vertical
- gradient = QtGui.QLinearGradient(w, 0, w,
- self.frame.height())
- elif self._theme.background_direction == u'vertical':
- h = int(self.frame.height()) / 2
- # Horizontal
- gradient = QtGui.QLinearGradient(0, h, self.frame.width(),
- h)
- else:
- w = int(self.frame.width()) / 2
- h = int(self.frame.height()) / 2
- # Circular
- gradient = QtGui.QRadialGradient(w, h, w)
- gradient.setColorAt(0,
- QtGui.QColor(self._theme.background_startColor))
- gradient.setColorAt(1,
- QtGui.QColor(self._theme.background_endColor))
- painter.setBrush(QtGui.QBrush(gradient))
- rect_path = QtGui.QPainterPath()
- max_x = self.frame.width()
- max_y = self.frame.height()
- rect_path.moveTo(0, 0)
- rect_path.lineTo(0, max_y)
- rect_path.lineTo(max_x, max_y)
- rect_path.lineTo(max_x, 0)
- rect_path.closeSubpath()
- painter.drawPath(rect_path)
- elif self._theme.background_type == u'image':
- # image
- painter.fillRect(self.frame.rect(), QtCore.Qt.black)
- if self.bg_image:
- painter.drawImage(0, 0, self.bg_image)
- painter.end()
- log.debug(u'render background End')
-
- def _correct_alignment(self, rect, bbox):
- """
- Corrects the vertical alignment of text.
-
- ``rect``
- The block dimentions.
-
- ``bbox``
- Footer dimensions?
- """
- x = rect.left()
- if self._theme.display_verticalAlign == 0:
- # top align
- y = rect.top()
- elif self._theme.display_verticalAlign == 2:
- # bottom align
- y = rect.bottom() - bbox.height()
- elif self._theme.display_verticalAlign == 1:
- # centre align
- y = rect.top() + (rect.height() - bbox.height()) / 2
- else:
- log.error(u'Invalid value for theme.VerticalAlign:%s',
- self._theme.display_verticalAlign)
- return x, y
-
- def _render_lines_unaligned(self, lines, footer, tlcorner=(0, 0),
- live=False):
- """
- Given a list of lines to render, render each one in turn (using the
- ``_render_single_line`` fn - which may result in going off the bottom).
- They are expected to be pre-arranged to less than a screenful (eg. by
- using split_set_of_lines).
-
- Returns the bounding box of the text as QRect.
-
- ``lines``
- The lines of text to render.
-
- ``footer``
- The slide footer.
-
- ``tlcorner``
- Defaults to *``(0, 0)``*. Co-ordinates of the top left corner.
-
- ``live``
- Defaults to *False*. Whether or not this is a live screen.
- """
- x, y = tlcorner
- brx = x
- bry = y
- for line in lines:
- # render after current bottom, but at original left edge
- # keep track of right edge to see which is biggest
- (thisx, bry) = self._render_and_wrap_single_line(line, footer,
- (x, bry), live)
- if (thisx > brx):
- brx = thisx
- retval = QtCore.QRect(x, y, brx - x, bry - y)
- if self._debug:
- painter = QtGui.QPainter()
- painter.begin(self.frame)
- painter.setPen(QtGui.QPen(QtGui.QColor(0, 0, 255)))
- painter.drawRect(retval)
- painter.end()
- return retval
-
- def _render_and_wrap_single_line(self, line, footer, tlcorner=(0, 0),
- live=False):
- """
- Render a single line of words onto the DC, top left corner specified.
- If the line is too wide for the context, it wraps, but right-aligns
- the surplus words in the manner of song lyrics.
-
- Returns the bottom-right corner (of what was rendered) as a tuple(x, y).
-
- ``line``
- Line of text to be rendered.
-
- ``footer``
- The footer of the slide.
-
- ``tlcorner``
- Defaults to *``(0, 0)``*. The top left corner.
-
- ``live``
- Defaults to *False*. Whether or not this is a live screen.
- """
- x, y = tlcorner
- maxx = self._rect.width()
- maxy = self._rect.height()
- lines = []
- lines.append(line)
- startx = x
- starty = y
- rightextent = None
- self.painter = QtGui.QPainter()
- self.painter.begin(self.frame)
- self.painter.setRenderHint(QtGui.QPainter.Antialiasing)
- if self._theme.display_slideTransition:
- self.painter2 = QtGui.QPainter()
- self.painter2.begin(self.frame_opaque)
- self.painter2.setRenderHint(QtGui.QPainter.Antialiasing)
- self.painter2.setOpacity(0.7)
- # dont allow alignment messing with footers
- if footer:
- align = 0
- display_shadow_size = self._display_shadow_size_footer
- display_outline_size = self._display_outline_size_footer
- else:
- align = self._theme.display_horizontalAlign
- display_shadow_size = int(self._theme.display_shadow_size)
- display_outline_size = int(self._theme.display_outline_size)
- for linenum in range(len(lines)):
- line = lines[linenum]
- #find out how wide line is
- w, h = self._get_extent_and_render(line, footer, tlcorner=(x, y),
- draw=False)
- if self._theme.display_shadow:
- w += display_shadow_size
- h += display_shadow_size
- if self._theme.display_outline:
- # pixels either side
- w += 2 * display_outline_size
- # pixels top/bottom
- h += 2 * display_outline_size
- if align == 0: # left align
- rightextent = x + w
- # shift right from last line's rh edge
- if self._theme.display_wrapStyle == 1 and linenum != 0:
- rightextent = self._first_line_right_extent
- if rightextent > maxx:
- rightextent = maxx
- x = rightextent - w
- # right align
- elif align == 1:
- rightextent = maxx
- x = maxx - w
- # centre
- elif align == 2:
- x = (maxx - w) / 2
- rightextent = x + w
- if live:
- # now draw the text, and any outlines/shadows
- if self._theme.display_shadow:
- self._get_extent_and_render(line, footer,
- tlcorner=(x + display_shadow_size,
- y + display_shadow_size),
- draw=True, color=self._theme.display_shadow_color)
- self._get_extent_and_render(line, footer, tlcorner=(x, y),
- draw=True, outline_size=display_outline_size)
- y += h
- if linenum == 0:
- self._first_line_right_extent = rightextent
- # draw a box around the text - debug only
-
- if self._debug:
- self.painter.setPen(QtGui.QPen(QtGui.QColor(0, 255, 0)))
- self.painter.drawRect(startx, starty, rightextent-startx, y-starty)
- brcorner = (rightextent, y)
- self.painter.end()
- if self._theme.display_slideTransition:
- self.painter2.end()
- return brcorner
-
- def _set_theme_font(self):
- """
- Set the fonts from the current theme settings.
- """
- footer_weight = 50
- if self._theme.font_footer_weight == u'Bold':
- footer_weight = 75
- #TODO Add myfont.setPixelSize((screen_height / 100) * font_size)
- self.footer_font = QtGui.QFont(self._theme.font_footer_name,
- self._theme.font_footer_proportion, # size
- footer_weight, # weight
- self._theme.font_footer_italics) # italic
- self.footer_font.setPixelSize(self._theme.font_footer_proportion)
- main_weight = 50
- if self._theme.font_main_weight == u'Bold':
- main_weight = 75
- self.main_font = QtGui.QFont(self._theme.font_main_name,
- self._theme.font_main_proportion, # size
- main_weight, # weight
- self._theme.font_main_italics)# italic
- self.main_font.setPixelSize(self._theme.font_main_proportion)
-
- def _get_extent_and_render(self, line, footer, tlcorner=(0, 0), draw=False,
- color=None, outline_size=0):
- """
- Find bounding box of text - as render_single_line. If draw is set,
- actually draw the text to the current DC as well return width and
- height of text as a tuple (w, h).
-
- ``line``
- The line of text to render.
-
- ``footer``
- The footer text.
-
- ``tlcorner``
- Defaults to *``(0, 0)``*. The top left corner co-ordinates.
-
- ``draw``
- Defaults to *False*. Draw the text to the current surface.
-
- ``color``
- Defaults to *None*. The colour to draw with.
- """
- # setup defaults
- if footer:
- font = self.footer_font
- else:
- font = self.main_font
- metrics = QtGui.QFontMetrics(font)
- w = metrics.width(line)
- if footer:
- h = metrics.height()
- else:
- h = metrics.height() + int(self._theme.font_main_line_adjustment)
- if draw:
- self.painter.setFont(font)
- if color is None:
- if footer:
- pen = QtGui.QColor(self._theme.font_footer_color)
- else:
- pen = QtGui.QColor(self._theme.font_main_color)
+ if self._theme.background_type == u'solid':
+ painter.fillRect(self.frame.rect(),
+ QtGui.QColor(self._theme.background_color))
+ elif self._theme.background_type == u'gradient':
+ # gradient
+ gradient = None
+ if self._theme.background_direction == u'horizontal':
+ w = int(self.frame.width()) / 2
+ # vertical
+ gradient = QtGui.QLinearGradient(w, 0, w, self.frame.height())
+ elif self._theme.background_direction == u'vertical':
+ h = int(self.frame.height()) / 2
+ # Horizontal
+ gradient = QtGui.QLinearGradient(0, h, self.frame.width(), h)
else:
- pen = QtGui.QColor(color)
- x, y = tlcorner
- rowpos = y + metrics.ascent()
- if self._theme.display_outline and outline_size != 0 and not footer:
- path = QtGui.QPainterPath()
- path.addText(QtCore.QPointF(x, rowpos), font, line)
- self.painter.setBrush(self.painter.pen().brush())
- self.painter.setPen(QtGui.QPen(QtGui.QColor(
- self._theme.display_outline_color), outline_size))
- self.painter.drawPath(path)
- self.painter.setPen(pen)
- self.painter.drawText(x, rowpos, line)
- if self._theme.display_slideTransition:
- # Print 2nd image with 70% weight
- if self._theme.display_outline and outline_size != 0 and \
- not footer:
- path = QtGui.QPainterPath()
- path.addText(QtCore.QPointF(x, rowpos), font, line)
- self.painter2.setBrush(self.painter2.pen().brush())
- self.painter2.setPen(QtGui.QPen(
- QtGui.QColor(self._theme.display_outline_color),
- outline_size))
- self.painter2.drawPath(path)
- self.painter2.setFont(font)
- self.painter2.setPen(pen)
- self.painter2.drawText(x, rowpos, line)
- return (w, h)
-
- def snoop_image(self, image, image2=None):
- """
- Debugging method to allow images to be viewed.
-
- ``image``
- An image to save to disk.
-
- ``image2``
- Defaults to *None*. Another image to save to disk.
- """
- image.save(u'renderer.png', u'png')
- if image2:
- image2.save(u'renderer2.png', u'png')
+ w = int(self.frame.width()) / 2
+ h = int(self.frame.height()) / 2
+ # Circular
+ gradient = QtGui.QRadialGradient(w, h, w)
+ gradient.setColorAt(0,
+ QtGui.QColor(self._theme.background_startColor))
+ gradient.setColorAt(1,
+ QtGui.QColor(self._theme.background_endColor))
+ painter.setBrush(QtGui.QBrush(gradient))
+ rect_path = QtGui.QPainterPath()
+ max_x = self.frame.width()
+ max_y = self.frame.height()
+ rect_path.moveTo(0, 0)
+ rect_path.lineTo(0, max_y)
+ rect_path.lineTo(max_x, max_y)
+ rect_path.lineTo(max_x, 0)
+ rect_path.closeSubpath()
+ painter.drawPath(rect_path)
+ elif self._theme.background_type == u'image':
+ # image
+ painter.fillRect(self.frame.rect(), QtCore.Qt.black)
+ if self.bg_image:
+ painter.drawImage(0, 0, self.bg_image)
+ painter.end()
diff --git a/openlp/core/lib/rendermanager.py b/openlp/core/lib/rendermanager.py
index 7b6124fa8..13a8cfc6b 100644
--- a/openlp/core/lib/rendermanager.py
+++ b/openlp/core/lib/rendermanager.py
@@ -28,7 +28,8 @@ import logging
from PyQt4 import QtCore
-from openlp.core.lib import Renderer, ThemeLevel
+from openlp.core.lib import Renderer, ThemeLevel, ServiceItem
+from openlp.core.ui import MainDisplay
log = logging.getLogger(__name__)
@@ -55,6 +56,8 @@ class RenderManager(object):
"""
log.debug(u'Initilisation started')
self.screens = screens
+ self.display = MainDisplay(self, screens, False)
+ self.display.setup()
self.theme_manager = theme_manager
self.renderer = Renderer()
self.calculate_default(self.screens.current[u'size'])
@@ -63,6 +66,7 @@ class RenderManager(object):
self.theme_level = u''
self.override_background = None
self.themedata = None
+ self.alertTab = None
def update_display(self):
"""
@@ -70,7 +74,10 @@ class RenderManager(object):
"""
log.debug(u'Update Display')
self.calculate_default(self.screens.current[u'size'])
+ self.display = MainDisplay(self, self.screens, False)
+ self.display.setup()
self.renderer.bg_frame = None
+ self.themedata = None
def set_global_theme(self, global_theme, theme_level=ThemeLevel.Global):
"""
@@ -96,17 +103,22 @@ class RenderManager(object):
"""
self.service_theme = service_theme
- def set_override_theme(self, theme):
+ def set_override_theme(self, theme, overrideLevels=False):
"""
Set the appropriate theme depending on the theme level.
+ Called by the service item when building a display frame
``theme``
- The name of the song-level theme.
+ The name of the song-level theme. None means the service
+ item wants to use the given value.
"""
log.debug(u'set override theme to %s', theme)
- if self.theme_level == ThemeLevel.Global:
+ theme_level = self.theme_level
+ if overrideLevels:
+ theme_level = ThemeLevel.Song
+ if theme_level == ThemeLevel.Global:
self.theme = self.global_theme
- elif self.theme_level == ThemeLevel.Service:
+ elif theme_level == ThemeLevel.Service:
if self.service_theme == u'':
self.theme = self.global_theme
else:
@@ -114,20 +126,26 @@ class RenderManager(object):
else:
if theme:
self.theme = theme
- elif self.theme_level == ThemeLevel.Song or \
- self.theme_level == ThemeLevel.Service:
+ elif theme_level == ThemeLevel.Song or \
+ theme_level == ThemeLevel.Service:
if self.service_theme == u'':
self.theme = self.global_theme
else:
self.theme = self.service_theme
else:
self.theme = self.global_theme
- if self.theme != self.renderer.theme_name or self.themedata is None:
+ if self.theme != self.renderer.theme_name or self.themedata is None \
+ or overrideLevels:
log.debug(u'theme is now %s', self.theme)
- self.themedata = self.theme_manager.getThemeData(self.theme)
+ if overrideLevels:
+ self.themedata = theme
+ else:
+ self.themedata = self.theme_manager.getThemeData(self.theme)
self.calculate_default(self.screens.current[u'size'])
self.renderer.set_theme(self.themedata)
self.build_text_rectangle(self.themedata)
+ self.renderer.set_frame_dest(self.width, self.height)
+ return self.renderer._rect, self.renderer._rect_footer
def build_text_rectangle(self, theme):
"""
@@ -163,13 +181,8 @@ class RenderManager(object):
The theme to generated a preview for.
"""
log.debug(u'generate preview')
- #set the default image size for previews
+ # set the default image size for previews
self.calculate_default(self.screens.preview[u'size'])
- self.renderer.set_theme(themedata)
- self.build_text_rectangle(themedata)
- self.renderer.set_frame_dest(self.width, self.height, True)
- #Reset the real screen size for subsequent render requests
- self.calculate_default(self.screens.current[u'size'])
verse = u'Amazing Grace!\n'\
'How sweet the sound\n'\
'To save a wretch like me;\n'\
@@ -179,12 +192,21 @@ class RenderManager(object):
footer.append(u'Amazing Grace (John Newton)' )
footer.append(u'Public Domain')
footer.append(u'CCLI 123456')
- formatted = self.renderer.format_slide(verse, False)
- #Only Render the first slide page returned
- return self.renderer.generate_frame_from_lines(formatted[0],
- footer)[u'main']
+ # build a service item to generate preview
+ serviceItem = ServiceItem()
+ serviceItem.theme = themedata
+ serviceItem.add_from_text(u'', verse, footer)
+ serviceItem.render_manager = self
+ serviceItem.raw_footer = footer
+ serviceItem.render(True)
+ self.display.buildHtml(serviceItem)
+ frame, raw_html = serviceItem.get_rendered_frame(0)
+ preview = self.display.text(raw_html)
+ # Reset the real screen size for subsequent render requests
+ self.calculate_default(self.screens.current[u'size'])
+ return preview
- def format_slide(self, words):
+ def format_slide(self, words, line_break):
"""
Calculate how much text can fit on a slide.
@@ -193,22 +215,7 @@ class RenderManager(object):
"""
log.debug(u'format slide')
self.build_text_rectangle(self.themedata)
- return self.renderer.format_slide(words, False)
-
- def generate_slide(self, main_text, footer_text):
- """
- Generate the actual slide image.
-
- ``main_text``
- The text for the main area of the slide.
-
- ``footer_text``
- The text for the slide footer.
- """
- log.debug(u'generate slide')
- self.build_text_rectangle(self.themedata)
- self.renderer.set_frame_dest(self.width, self.height)
- return self.renderer.generate_frame_from_lines(main_text, footer_text)
+ return self.renderer.format_slide(words, line_break)
def calculate_default(self, screen):
"""
diff --git a/openlp/core/lib/serviceitem.py b/openlp/core/lib/serviceitem.py
index 2bb28ada5..134df0c42 100644
--- a/openlp/core/lib/serviceitem.py
+++ b/openlp/core/lib/serviceitem.py
@@ -35,7 +35,7 @@ import uuid
from PyQt4 import QtGui
-from openlp.core.lib import build_icon, resize_image
+from openlp.core.lib import build_icon, resize_image, clean_tags, expand_tags
log = logging.getLogger(__name__)
@@ -57,6 +57,7 @@ class ItemCapabilities(object):
RequiresMedia = 4
AllowsLoop = 5
AllowsAdditions = 6
+ NoLineBreaks = 7
class ServiceItem(object):
"""
@@ -82,6 +83,7 @@ class ServiceItem(object):
self.items = []
self.iconic_representation = None
self.raw_footer = None
+ self.foot_text = None
self.theme = None
self.service_item_type = None
self._raw_frames = []
@@ -91,10 +93,18 @@ class ServiceItem(object):
self.from_plugin = False
self.capabilities = []
self.is_valid = True
- self.cache = {}
self.icon = None
+ self.themedata = None
+ self.main = None
+ self.footer = None
+ self.bg_frame = None
def _new_item(self):
+ """
+ Method to set the internal id of the item
+ This is used to compare service items to see if they are
+ the same
+ """
self._uuid = unicode(uuid.uuid1())
def add_capability(self, capability):
@@ -126,34 +136,38 @@ class ServiceItem(object):
self.icon = icon
self.iconic_representation = build_icon(icon)
- def render(self):
+ def render(self, useOverride=False):
"""
- The render method is what generates the frames for the screen.
+ The render method is what generates the frames for the screen and
+ obtains the display information from the renderemanager.
+ At this point all the slides are build for the given
+ display size.
"""
log.debug(u'Render called')
self._display_frames = []
- self.clear_cache()
+ self.bg_frame = None
+ line_break = True
+ if self.is_capable(ItemCapabilities.NoLineBreaks):
+ line_break = False
if self.service_item_type == ServiceItemType.Text:
log.debug(u'Formatting slides')
- if self.theme is None:
- self.render_manager.set_override_theme(None)
- else:
- self.render_manager.set_override_theme(self.theme)
+ theme = None
+ if self.theme:
+ theme = self.theme
+ self.main, self.footer = \
+ self.render_manager.set_override_theme(theme, useOverride)
+ self.bg_frame = self.render_manager.renderer.bg_frame
+ self.themedata = self.render_manager.renderer._theme
for slide in self._raw_frames:
before = time.time()
- formated = self.render_manager.format_slide(slide[u'raw_slide'])
- for format in formated:
- lines = u''
- title = u''
- for line in format:
- if title == u'':
- title = line
- lines += line + u'\n'
- self._display_frames.append({u'title': title,
- u'text': lines.rstrip(),
+ formated = self.render_manager \
+ .format_slide(slide[u'raw_slide'], line_break)
+ for page in formated:
+ self._display_frames.append(
+ {u'title': clean_tags(page),
+ u'text': clean_tags(page.rstrip()),
+ u'html': expand_tags(page.rstrip()),
u'verseTag': slide[u'verseTag'] })
- if len(self._display_frames) in self.cache.keys():
- del self.cache[len(self._display_frames)]
log.log(15, u'Formatting took %4s' % (time.time() - before))
elif self.service_item_type == ServiceItemType.Image:
for slide in self._raw_frames:
@@ -163,29 +177,14 @@ class ServiceItem(object):
pass
else:
log.error(u'Invalid value renderer :%s' % self.service_item_type)
-
- def render_individual(self, row):
- """
- Takes an array of text and generates an Image from the
- theme. It assumes the text will fit on the screen as it
- has generated by the render method above.
- """
- log.debug(u'render individual')
- if self.theme is None:
- self.render_manager.set_override_theme(None)
- else:
- self.render_manager.set_override_theme(self.theme)
- format = self._display_frames[row][u'text'].split(u'\n')
- if self.cache.get(row):
- frame = self.cache[row]
- else:
- if format[0]:
- frame = self.render_manager.generate_slide(format,
- self.raw_footer)
- else:
- frame = self.render_manager.generate_slide(format, u'')
- self.cache[row] = frame
- return frame
+ self.title = clean_tags(self.title)
+ self.foot_text = None
+ if self.raw_footer:
+ for foot in self.raw_footer:
+ if not self.foot_text:
+ self.foot_text = foot
+ else:
+ self.foot_text = u'%s
%s' % (self.foot_text, foot)
def add_from_image(self, path, title, image):
"""
@@ -375,9 +374,9 @@ class ServiceItem(object):
renders it if required.
"""
if self.service_item_type == ServiceItemType.Text:
- return self.render_individual(row)
+ return None, self._display_frames[row][u'html'].split(u'\n')[0]
else:
- return {u'main':self._raw_frames[row][u'image'], u'trans':None}
+ return self._raw_frames[row][u'image'], u''
def get_frame_title(self, row=0):
"""
@@ -390,9 +389,3 @@ class ServiceItem(object):
Returns the title of the raw frame
"""
return self._raw_frames[row][u'path']
-
- def clear_cache(self):
- """
- Clear's the service item's cache.
- """
- self.cache = {}
diff --git a/openlp/core/lib/theme.py b/openlp/core/lib/theme.py
index 9f084e40c..50894cc47 100644
--- a/openlp/core/lib/theme.py
+++ b/openlp/core/lib/theme.py
@@ -55,7 +55,6 @@ BLANK_THEME_XML = \
30
Normal
False
- 0
0
@@ -65,7 +64,6 @@ BLANK_THEME_XML = \
12
Normal
False
- 0
0
@@ -184,7 +182,7 @@ class ThemeXML(object):
self.child_element(background, u'filename', filename)
def add_font(self, name, color, proportion, override, fonttype=u'main',
- weight=u'Normal', italics=u'False', indentation=0, line_adjustment=0,
+ weight=u'Normal', italics=u'False', line_adjustment=0,
xpos=0, ypos=0, width=0, height=0):
"""
Add a Font.
@@ -210,9 +208,6 @@ class ThemeXML(object):
``italics``
Does the font render to italics Defaults to 0 Normal
- ``indentation``
- Number of characters the wrap line is indented
-
``xpos``
The X position of the text block.
@@ -239,8 +234,6 @@ class ThemeXML(object):
#Create italics name element
self.child_element(background, u'italics', italics)
#Create indentation name element
- self.child_element(background, u'indentation', unicode(indentation))
- #Create indentation name element
self.child_element(
background, u'line_adjustment', unicode(line_adjustment))
diff --git a/openlp/core/theme/theme.py b/openlp/core/theme/theme.py
index e5f3b4c4c..52dda1631 100644
--- a/openlp/core/theme/theme.py
+++ b/openlp/core/theme/theme.py
@@ -204,7 +204,7 @@ class Theme(object):
val = element_text
if (element.tag.find(u'Color') > 0 or
(element.tag.find(u'BackgroundParameter') == 0 and
- isinstance(int, val))):
+ isinstance(val, int))):
# convert to a wx.Colour
if not delphi_color_change:
val = QtGui.QColor(
diff --git a/openlp/core/ui/__init__.py b/openlp/core/ui/__init__.py
index 60d6ea941..e6da7f975 100644
--- a/openlp/core/ui/__init__.py
+++ b/openlp/core/ui/__init__.py
@@ -27,6 +27,143 @@
The :mod:`ui` module provides the core user interface for OpenLP
"""
+# http://john.nachtimwald.com/2009/08/22/qplaintextedit-with-in-line-spell-check/
+
+import re
+import sys
+try:
+ import enchant
+ enchant_available = True
+except ImportError:
+ enchant_available = False
+
+from PyQt4 import QtCore, QtGui
+from openlp.core.lib import html_expands, translate, context_menu_action
+
+class SpellTextEdit(QtGui.QPlainTextEdit):
+
+ def __init__(self, *args):
+ QtGui.QPlainTextEdit.__init__(self, *args)
+ # Default dictionary based on the current locale.
+ if enchant_available:
+ self.dict = enchant.Dict()
+ self.highlighter = Highlighter(self.document())
+ self.highlighter.setDict(self.dict)
+
+ def mousePressEvent(self, event):
+ if event.button() == QtCore.Qt.RightButton:
+ # Rewrite the mouse event to a left button event so the cursor is
+ # moved to the location of the pointer.
+ event = QtGui.QMouseEvent(QtCore.QEvent.MouseButtonPress, event.pos(),
+ QtCore.Qt.LeftButton, QtCore.Qt.LeftButton, QtCore.Qt.NoModifier)
+ QtGui.QPlainTextEdit.mousePressEvent(self, event)
+
+ def contextMenuEvent(self, event):
+ popup_menu = self.createStandardContextMenu()
+
+ # Select the word under the cursor.
+ cursor = self.textCursor()
+ cursor.select(QtGui.QTextCursor.WordUnderCursor)
+ self.setTextCursor(cursor)
+
+ # Check if the selected word is misspelled and offer spelling
+ # suggestions if it is.
+ if enchant_available and self.textCursor().hasSelection():
+ text = unicode(self.textCursor().selectedText())
+ if not self.dict.check(text):
+ spell_menu = QtGui.QMenu(translate('OpenLP.SpellTextEdit',
+ 'Spelling Suggestions'))
+ for word in self.dict.suggest(text):
+ action = SpellAction(word, spell_menu)
+ action.correct.connect(self.correctWord)
+ spell_menu.addAction(action)
+ # Only add the spelling suggests to the menu if there are
+ # suggestions.
+ if len(spell_menu.actions()) != 0:
+ popup_menu.insertSeparator(popup_menu.actions()[0])
+ popup_menu.insertMenu(popup_menu.actions()[0], spell_menu)
+ tag_menu = QtGui.QMenu(translate('OpenLP.SpellTextEdit',
+ 'Formatting Tags'))
+ for html in html_expands:
+ action = SpellAction( html[u'desc'], tag_menu)
+ action.correct.connect(self.htmlTag)
+ tag_menu.addAction(action)
+ popup_menu.insertSeparator(popup_menu.actions()[0])
+ popup_menu.insertMenu(popup_menu.actions()[0], tag_menu)
+
+ popup_menu.exec_(event.globalPos())
+
+ def correctWord(self, word):
+ '''
+ Replaces the selected text with word.
+ '''
+ cursor = self.textCursor()
+ cursor.beginEditBlock()
+
+ cursor.removeSelectedText()
+ cursor.insertText(word)
+
+ cursor.endEditBlock()
+
+ def htmlTag(self, tag):
+ '''
+ Replaces the selected text with word.
+ '''
+ for html in html_expands:
+ if tag == html[u'desc']:
+ cursor = self.textCursor()
+ if self.textCursor().hasSelection():
+ text = cursor.selectedText()
+ cursor.beginEditBlock()
+ cursor.removeSelectedText()
+ cursor.insertText(html[u'start tag'])
+ cursor.insertText(text)
+ cursor.insertText(html[u'end tag'])
+ cursor.endEditBlock()
+ else:
+ cursor = self.textCursor()
+ cursor.insertText(html[u'start tag'])
+ cursor.insertText(html[u'end tag'])
+
+class Highlighter(QtGui.QSyntaxHighlighter):
+
+ WORDS = u'(?iu)[\w\']+'
+
+ def __init__(self, *args):
+ QtGui.QSyntaxHighlighter.__init__(self, *args)
+
+ self.dict = None
+
+ def setDict(self, dict):
+ self.dict = dict
+
+ def highlightBlock(self, text):
+ if not self.dict:
+ return
+
+ text = unicode(text)
+
+ format = QtGui.QTextCharFormat()
+ format.setUnderlineColor(QtCore.Qt.red)
+ format.setUnderlineStyle(QtGui.QTextCharFormat.SpellCheckUnderline)
+
+ for word_object in re.finditer(self.WORDS, text):
+ if not self.dict.check(word_object.group()):
+ self.setFormat(word_object.start(),
+ word_object.end() - word_object.start(), format)
+
+class SpellAction(QtGui.QAction):
+ '''
+ A special QAction that returns the text in a signal.
+ '''
+ correct = QtCore.pyqtSignal(unicode)
+
+ def __init__(self, *args):
+ QtGui.QAction.__init__(self, *args)
+
+ self.triggered.connect(lambda x: self.correct.emit(
+ unicode(self.text())))
+
class HideMode(object):
"""
This is basically an enumeration class which specifies the mode of a Bible.
@@ -37,13 +174,11 @@ class HideMode(object):
Theme = 2
Screen = 3
+from maindisplay import MainDisplay
from slidecontroller import HideMode
from servicenoteform import ServiceNoteForm
from serviceitemeditform import ServiceItemEditForm
from screen import ScreenList
-from maindisplay import MainDisplay
-from maindisplay import VideoDisplay
-from maindisplay import DisplayManager
from amendthemeform import AmendThemeForm
from slidecontroller import SlideController
from splashscreen import SplashScreen
@@ -56,8 +191,7 @@ from settingsform import SettingsForm
from mediadockmanager import MediaDockManager
from servicemanager import ServiceManager
from thememanager import ThemeManager
-from mainwindow import MainWindow
-__all__ = ['SplashScreen', 'AboutForm', 'SettingsForm', 'MainWindow',
+__all__ = ['SplashScreen', 'AboutForm', 'SettingsForm',
'MainDisplay', 'SlideController', 'ServiceManager', 'ThemeManager',
'AmendThemeForm', 'MediaDockManager', 'ServiceItemEditForm']
diff --git a/openlp/core/ui/amendthemedialog.py b/openlp/core/ui/amendthemedialog.py
index 893b5e32d..b77c9cfff 100644
--- a/openlp/core/ui/amendthemedialog.py
+++ b/openlp/core/ui/amendthemedialog.py
@@ -68,17 +68,6 @@ class Ui_AmendThemeDialog(object):
self.backgroundLayout.setMargin(8)
self.backgroundLayout.setSpacing(8)
self.backgroundLayout.setObjectName(u'backgroundLayout')
- self.backgroundLabel = QtGui.QLabel(self.backgroundTab)
- self.backgroundLabel.setObjectName(u'backgroundLabel')
- self.backgroundLayout.setWidget(0, QtGui.QFormLayout.LabelRole,
- self.backgroundLabel)
- self.backgroundComboBox = QtGui.QComboBox(self.backgroundTab)
- self.backgroundComboBox.setObjectName(u'backgroundComboBox')
- self.backgroundLabel.setBuddy(self.backgroundComboBox)
- self.backgroundComboBox.addItem(QtCore.QString())
- self.backgroundComboBox.addItem(QtCore.QString())
- self.backgroundLayout.setWidget(0, QtGui.QFormLayout.FieldRole,
- self.backgroundComboBox)
self.backgroundTypeLabel = QtGui.QLabel(self.backgroundTab)
self.backgroundTypeLabel.setObjectName(u'backgroundTypeLabel')
self.backgroundLayout.setWidget(1, QtGui.QFormLayout.LabelRole,
@@ -216,17 +205,6 @@ class Ui_AmendThemeDialog(object):
self.fontMainLineAdjustmentSpinBox.setMinimum(-99)
self.mainFontLayout.setWidget(4, QtGui.QFormLayout.FieldRole,
self.fontMainLineAdjustmentSpinBox)
- self.fontMainWrapIndentationLabel = QtGui.QLabel(self.fontMainGroupBox)
- self.fontMainWrapIndentationLabel.setObjectName(
- u'fontMainWrapIndentationLabel')
- self.mainFontLayout.setWidget(5, QtGui.QFormLayout.LabelRole,
- self.fontMainWrapIndentationLabel)
- self.fontMainLineSpacingSpinBox = QtGui.QSpinBox(self.fontMainGroupBox)
- self.fontMainLineSpacingSpinBox.setObjectName(
- u'fontMainLineSpacingSpinBox')
- self.fontMainLineSpacingSpinBox.setMaximum(10)
- self.mainFontLayout.setWidget(5, QtGui.QFormLayout.FieldRole,
- self.fontMainLineSpacingSpinBox)
self.fontMainLinesPageLabel = QtGui.QLabel(self.fontMainGroupBox)
self.fontMainLinesPageLabel.setObjectName(u'fontMainLinesPageLabel')
self.mainFontLayout.addRow(self.fontMainLinesPageLabel)
@@ -661,12 +639,6 @@ class Ui_AmendThemeDialog(object):
translate('OpenLP.AmendThemeForm', 'Theme Maintenance'))
self.themeNameLabel.setText(
translate('OpenLP.AmendThemeForm', 'Theme &name:'))
- self.backgroundLabel.setText(
- translate('OpenLP.AmendThemeForm', '&Visibility:'))
- self.backgroundComboBox.setItemText(0,
- translate('OpenLP.AmendThemeForm', 'Opaque'))
- self.backgroundComboBox.setItemText(1,
- translate('OpenLP.AmendThemeForm', 'Transparent'))
self.backgroundTypeLabel.setText(
translate('OpenLP.AmendThemeForm', 'Type:'))
self.backgroundTypeComboBox.setItemText(0,
@@ -700,8 +672,6 @@ class Ui_AmendThemeDialog(object):
translate('OpenLP.AmendThemeForm', 'Size:'))
self.fontMainSizeSpinBox.setSuffix(
translate('OpenLP.AmendThemeForm', 'pt'))
- self.fontMainWrapIndentationLabel.setText(
- translate('OpenLP.AmendThemeForm', 'Wrap indentation:'))
self.fontMainWrapLineAdjustmentLabel.setText(
translate('OpenLP.AmendThemeForm', 'Adjust line spacing:'))
self.fontMainWeightComboBox.setItemText(0,
diff --git a/openlp/core/ui/amendthemeform.py b/openlp/core/ui/amendthemeform.py
index cefd79df2..e23044a2b 100644
--- a/openlp/core/ui/amendthemeform.py
+++ b/openlp/core/ui/amendthemeform.py
@@ -50,7 +50,6 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
self.path = None
self.theme = ThemeXML()
self.setupUi(self)
- # define signals
# Buttons
QtCore.QObject.connect(self.color1PushButton,
QtCore.SIGNAL(u'pressed()'), self.onColor1PushButtonClicked)
@@ -68,8 +67,6 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
QtCore.QObject.connect(self.imageToolButton,
QtCore.SIGNAL(u'clicked()'), self.onImageToolButtonClicked)
# Combo boxes
- QtCore.QObject.connect(self.backgroundComboBox,
- QtCore.SIGNAL(u'activated(int)'), self.onBackgroundComboBoxSelected)
QtCore.QObject.connect(self.backgroundTypeComboBox,
QtCore.SIGNAL(u'activated(int)'),
self.onBackgroundTypeComboBoxSelected)
@@ -109,9 +106,6 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
QtCore.QObject.connect(self.fontMainLineAdjustmentSpinBox,
QtCore.SIGNAL(u'editingFinished()'),
self.onFontMainLineAdjustmentSpinBoxChanged)
- QtCore.QObject.connect(self.fontMainLineSpacingSpinBox,
- QtCore.SIGNAL(u'editingFinished()'),
- self.onFontMainLineSpacingSpinBoxChanged)
QtCore.QObject.connect(self.fontFooterXSpinBox,
QtCore.SIGNAL(u'editingFinished()'),
self.onFontFooterXSpinBoxChanged)
@@ -151,30 +145,26 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
new_theme.new_document(theme_name)
save_from = None
save_to = None
- if self.theme.background_mode == u'transparent':
- new_theme.add_background_transparent()
+ if self.theme.background_type == u'solid':
+ new_theme.add_background_solid(
+ unicode(self.theme.background_color))
+ elif self.theme.background_type == u'gradient':
+ new_theme.add_background_gradient(
+ unicode(self.theme.background_startColor),
+ unicode(self.theme.background_endColor),
+ self.theme.background_direction)
else:
- if self.theme.background_type == u'solid':
- new_theme.add_background_solid(
- unicode(self.theme.background_color))
- elif self.theme.background_type == u'gradient':
- new_theme.add_background_gradient(
- unicode(self.theme.background_startColor),
- unicode(self.theme.background_endColor),
- self.theme.background_direction)
- else:
- filename = \
- os.path.split(unicode(self.theme.background_filename))[1]
- new_theme.add_background_image(filename)
- save_to = os.path.join(self.path, theme_name, filename)
- save_from = self.theme.background_filename
+ filename = \
+ os.path.split(unicode(self.theme.background_filename))[1]
+ new_theme.add_background_image(filename)
+ save_to = os.path.join(self.path, theme_name, filename)
+ save_from = self.theme.background_filename
new_theme.add_font(unicode(self.theme.font_main_name),
unicode(self.theme.font_main_color),
unicode(self.theme.font_main_proportion),
unicode(self.theme.font_main_override), u'main',
unicode(self.theme.font_main_weight),
unicode(self.theme.font_main_italics),
- unicode(self.theme.font_main_indentation),
unicode(self.theme.font_main_line_adjustment),
unicode(self.theme.font_main_x),
unicode(self.theme.font_main_y),
@@ -186,7 +176,6 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
unicode(self.theme.font_footer_override), u'footer',
unicode(self.theme.font_footer_weight),
unicode(self.theme.font_footer_italics),
- 0, # indentation
0, # line adjustment
unicode(self.theme.font_footer_x),
unicode(self.theme.font_footer_y),
@@ -230,7 +219,7 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
self.previewTheme()
#
- #Main Font Tab
+ # Main Font Tab
#
def onFontMainComboBoxSelected(self):
self.theme.font_main_name = self.fontMainComboBox.currentFont().family()
@@ -283,8 +272,6 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
self.fontMainHeightSpinBox.setValue(self.theme.font_main_height)
self.fontMainLineAdjustmentSpinBox.setValue(
self.theme.font_main_line_adjustment)
- self.fontMainLineSpacingSpinBox.setValue(
- self.theme.font_main_indentation)
self.stateChanging(self.theme)
self.previewTheme()
@@ -310,20 +297,13 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
self.fontMainLineAdjustmentSpinBox.value()
self.previewTheme()
- def onFontMainLineSpacingSpinBoxChanged(self):
- if self.theme.font_main_indentation != \
- self.fontMainLineSpacingSpinBox.value():
- self.theme.font_main_indentation = \
- self.fontMainLineSpacingSpinBox.value()
- self.previewTheme()
-
def onFontMainHeightSpinBoxChanged(self):
if self.theme.font_main_height != self.fontMainHeightSpinBox.value():
self.theme.font_main_height = self.fontMainHeightSpinBox.value()
self.previewTheme()
#
- #Footer Font Tab
+ # Footer Font Tab
#
def onFontFooterComboBoxSelected(self):
self.theme.font_footer_name = \
@@ -404,20 +384,12 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
self.previewTheme()
#
- #Background Tab
+ # Background Tab
#
def onGradientComboBoxSelected(self, currentIndex):
self.setBackground(self.backgroundTypeComboBox.currentIndex(),
currentIndex)
- def onBackgroundComboBoxSelected(self, currentIndex):
- if currentIndex == 0: # Opaque
- self.theme.background_mode = u'opaque'
- else:
- self.theme.background_mode = u'transparent'
- self.stateChanging(self.theme)
- self.previewTheme()
-
def onBackgroundTypeComboBoxSelected(self, currentIndex):
self.setBackground(currentIndex, self.gradientComboBox.currentIndex())
@@ -472,7 +444,7 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
self.previewTheme()
#
- #Other Tab
+ # Other Tab
#
def onOutlineCheckBoxChanged(self, value):
if value == 2: # checked
@@ -537,16 +509,12 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
self.previewTheme()
#
- #Local Methods
+ # Local Methods
#
def paintUi(self, theme):
self.stateChanging(theme)
self.themeNameEdit.setText(self.theme.theme_name)
# Background Tab
- if self.theme.background_mode == u'opaque':
- self.backgroundComboBox.setCurrentIndex(0)
- else:
- self.backgroundComboBox.setCurrentIndex(1)
self.imageLineEdit.setText(u'')
if theme.background_type == u'solid':
self.backgroundTypeComboBox.setCurrentIndex(0)
@@ -576,8 +544,6 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
self.fontMainWeightComboBox.setCurrentIndex(2)
else:
self.fontMainWeightComboBox.setCurrentIndex(3)
- self.fontMainLineSpacingSpinBox.setValue(
- self.theme.font_main_indentation)
self.fontMainXSpinBox.setValue(self.theme.font_main_x)
self.fontMainYSpinBox.setValue(self.theme.font_main_y)
self.fontMainWidthSpinBox.setValue(self.theme.font_main_width)
@@ -641,9 +607,15 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
self.verticalComboBox.setCurrentIndex(self.theme.display_verticalAlign)
def stateChanging(self, theme):
- if theme.background_mode == u'transparent':
- self.color1Label.setVisible(False)
- self.color1PushButton.setVisible(False)
+ self.backgroundTypeComboBox.setVisible(True)
+ self.backgroundTypeLabel.setVisible(True)
+ if theme.background_type == u'solid':
+ self.color1PushButton.setStyleSheet(
+ u'background-color: %s' % unicode(theme.background_color))
+ self.color1Label.setText(
+ translate('OpenLP.AmendThemeForm', 'Color:'))
+ self.color1Label.setVisible(True)
+ self.color1PushButton.setVisible(True)
self.color2Label.setVisible(False)
self.color2PushButton.setVisible(False)
self.imageLabel.setVisible(False)
@@ -651,53 +623,34 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
self.imageFilenameWidget.setVisible(False)
self.gradientLabel.setVisible(False)
self.gradientComboBox.setVisible(False)
- self.backgroundTypeComboBox.setVisible(False)
- self.backgroundTypeLabel.setVisible(False)
- else:
- self.backgroundTypeComboBox.setVisible(True)
- self.backgroundTypeLabel.setVisible(True)
- if theme.background_type == u'solid':
- self.color1PushButton.setStyleSheet(
- u'background-color: %s' % unicode(theme.background_color))
- self.color1Label.setText(
- translate('OpenLP.AmendThemeForm', 'Color:'))
- self.color1Label.setVisible(True)
- self.color1PushButton.setVisible(True)
- self.color2Label.setVisible(False)
- self.color2PushButton.setVisible(False)
- self.imageLabel.setVisible(False)
- self.imageLineEdit.setVisible(False)
- self.imageFilenameWidget.setVisible(False)
- self.gradientLabel.setVisible(False)
- self.gradientComboBox.setVisible(False)
- elif theme.background_type == u'gradient':
- self.color1PushButton.setStyleSheet(u'background-color: %s' \
- % unicode(theme.background_startColor))
- self.color2PushButton.setStyleSheet(u'background-color: %s' \
- % unicode(theme.background_endColor))
- self.color1Label.setText(
- translate('OpenLP.AmendThemeForm', 'First color:'))
- self.color2Label.setText(
- translate('OpenLP.AmendThemeForm', 'Second color:'))
- self.color1Label.setVisible(True)
- self.color1PushButton.setVisible(True)
- self.color2Label.setVisible(True)
- self.color2PushButton.setVisible(True)
- self.imageLabel.setVisible(False)
- self.imageLineEdit.setVisible(False)
- self.imageFilenameWidget.setVisible(False)
- self.gradientLabel.setVisible(True)
- self.gradientComboBox.setVisible(True)
- else: # must be image
- self.color1Label.setVisible(False)
- self.color1PushButton.setVisible(False)
- self.color2Label.setVisible(False)
- self.color2PushButton.setVisible(False)
- self.imageLabel.setVisible(True)
- self.imageLineEdit.setVisible(True)
- self.imageFilenameWidget.setVisible(True)
- self.gradientLabel.setVisible(False)
- self.gradientComboBox.setVisible(False)
+ elif theme.background_type == u'gradient':
+ self.color1PushButton.setStyleSheet(u'background-color: %s' \
+ % unicode(theme.background_startColor))
+ self.color2PushButton.setStyleSheet(u'background-color: %s' \
+ % unicode(theme.background_endColor))
+ self.color1Label.setText(
+ translate('OpenLP.AmendThemeForm', 'First color:'))
+ self.color2Label.setText(
+ translate('OpenLP.AmendThemeForm', 'Second color:'))
+ self.color1Label.setVisible(True)
+ self.color1PushButton.setVisible(True)
+ self.color2Label.setVisible(True)
+ self.color2PushButton.setVisible(True)
+ self.imageLabel.setVisible(False)
+ self.imageLineEdit.setVisible(False)
+ self.imageFilenameWidget.setVisible(False)
+ self.gradientLabel.setVisible(True)
+ self.gradientComboBox.setVisible(True)
+ else: # must be image
+ self.color1Label.setVisible(False)
+ self.color1PushButton.setVisible(False)
+ self.color2Label.setVisible(False)
+ self.color2PushButton.setVisible(False)
+ self.imageLabel.setVisible(True)
+ self.imageLineEdit.setVisible(True)
+ self.imageFilenameWidget.setVisible(True)
+ self.gradientLabel.setVisible(False)
+ self.gradientComboBox.setVisible(False)
if not theme.font_main_override:
self.fontMainXSpinBox.setEnabled(False)
self.fontMainYSpinBox.setEnabled(False)
diff --git a/openlp/core/ui/generaltab.py b/openlp/core/ui/generaltab.py
index faafb5223..bc050b6f9 100644
--- a/openlp/core/ui/generaltab.py
+++ b/openlp/core/ui/generaltab.py
@@ -390,26 +390,16 @@ class GeneralTab(SettingsTab):
unicode(self.screens.current[u'size'].width()))
self.overrideCheckBox.setChecked(settings.value(u'override position',
QtCore.QVariant(False)).toBool())
- if self.overrideCheckBox.isChecked():
- self.customXValueEdit.setText(settings.value(u'x position',
- QtCore.QVariant(self.screens.current[u'size'].x())).toString())
- self.customYValueEdit.setText(settings.value(u'y position',
- QtCore.QVariant(self.screens.current[u'size'].y())).toString())
- self.customHeightValueEdit.setText(
- settings.value(u'height', QtCore.QVariant(
- self.screens.current[u'size'].height())).toString())
- self.customWidthValueEdit.setText(
- settings.value(u'width', QtCore.QVariant(
- self.screens.current[u'size'].width())).toString())
- else:
- self.customXValueEdit.setText(
- unicode(self.screens.current[u'size'].x()))
- self.customYValueEdit.setText(
- unicode(self.screens.current[u'size'].y()))
- self.customHeightValueEdit.setText(
- unicode(self.screens.current[u'size'].height()))
- self.customWidthValueEdit.setText(
- unicode(self.screens.current[u'size'].width()))
+ self.customXValueEdit.setText(settings.value(u'x position',
+ QtCore.QVariant(self.screens.current[u'size'].x())).toString())
+ self.customYValueEdit.setText(settings.value(u'y position',
+ QtCore.QVariant(self.screens.current[u'size'].y())).toString())
+ self.customHeightValueEdit.setText(
+ settings.value(u'height', QtCore.QVariant(
+ self.screens.current[u'size'].height())).toString())
+ self.customWidthValueEdit.setText(
+ settings.value(u'width', QtCore.QVariant(
+ self.screens.current[u'size'].width())).toString())
settings.endGroup()
self.customXValueEdit.setEnabled(self.overrideCheckBox.isChecked())
self.customYValueEdit.setEnabled(self.overrideCheckBox.isChecked())
@@ -436,10 +426,8 @@ class GeneralTab(SettingsTab):
QtCore.QVariant(self.saveCheckServiceCheckBox.isChecked()))
settings.setValue(u'auto preview',
QtCore.QVariant(self.autoPreviewCheckBox.isChecked()))
- settings.setValue(u'loop delay',
+ settings.setValue(u'loop delay',
QtCore.QVariant(self.timeoutSpinBox.value()))
- Receiver.send_message(u'slidecontroller_live_spin_delay',
- self.timeoutSpinBox.value())
settings.setValue(u'ccli number',
QtCore.QVariant(self.numberEdit.displayText()))
settings.setValue(u'songselect username',
@@ -459,17 +447,18 @@ class GeneralTab(SettingsTab):
settings.endGroup()
self.screens.display = self.displayOnMonitorCheck.isChecked()
# Monitor Number has changed.
+ postUpdate = False
if self.screens.monitor_number != self.monitorNumber:
self.screens.monitor_number = self.monitorNumber
self.screens.set_current_display(self.monitorNumber)
- Receiver.send_message(u'config_screen_changed')
- Receiver.send_message(u'config_updated')
+ postUpdate = True
# On save update the screens as well
- self.postSetUp()
+ self.postSetUp(postUpdate)
- def postSetUp(self):
+ def postSetUp(self, postUpdate=False):
"""
- Apply settings after settings tab has loaded
+ Apply settings after settings tab has loaded and most of the
+ system so must be delayed
"""
Receiver.send_message(u'slidecontroller_live_spin_delay',
self.timeoutSpinBox.value())
@@ -480,12 +469,15 @@ class GeneralTab(SettingsTab):
int(self.customYValueEdit.text()),
int(self.customWidthValueEdit.text()),
int(self.customHeightValueEdit.text()))
- if self.overrideCheckBox.isChecked():
- self.screens.set_override_display()
- Receiver.send_message(u'config_screen_changed')
- else:
- self.screens.reset_current_display()
- Receiver.send_message(u'config_screen_changed')
+ if self.overrideCheckBox.isChecked():
+ self.screens.set_override_display()
+ else:
+ self.screens.reset_current_display()
+ # Order is important so be careful if you change
+ if self.overrideChanged or postUpdate:
+ Receiver.send_message(u'config_screen_changed')
+ Receiver.send_message(u'config_updated')
+ self.overrideChanged = False
def onOverrideCheckBoxToggled(self, checked):
"""
diff --git a/openlp/core/ui/maindisplay.py b/openlp/core/ui/maindisplay.py
index 169faa5a0..98b7a84ec 100644
--- a/openlp/core/ui/maindisplay.py
+++ b/openlp/core/ui/maindisplay.py
@@ -26,149 +26,46 @@
import logging
import os
-import time
from PyQt4 import QtCore, QtGui, QtWebKit
from PyQt4.phonon import Phonon
-from openlp.core.lib import Receiver, resize_image
+from openlp.core.lib import Receiver, resize_image, build_html, ServiceItem, \
+ image_to_byte
from openlp.core.ui import HideMode
log = logging.getLogger(__name__)
#http://www.steveheffernan.com/html5-video-player/demo-video-player.html
-HTMLVIDEO = u"""
-
-
-
-
-
-
-
- """
-
-class DisplayManager(QtGui.QWidget):
- """
- Wrapper class to hold the display widgets.
- I will provide API's in future to access the screens allow for
- extra displays to be added.
- RenderManager is poked in by MainWindow
- """
- def __init__(self, screens):
- QtGui.QWidget.__init__(self)
- self.screens = screens
- self.videoDisplay = VideoDisplay(self, screens)
- self.audioPlayer = AudioPlayer(self)
- self.mainDisplay = MainDisplay(self, screens)
- QtCore.QObject.connect(Receiver.get_receiver(),
- QtCore.SIGNAL(u'maindisplay_hide'), self.hideDisplay)
- QtCore.QObject.connect(Receiver.get_receiver(),
- QtCore.SIGNAL(u'maindisplay_show'), self.showDisplay)
- QtCore.QObject.connect(Receiver.get_receiver(),
- QtCore.SIGNAL(u'videodisplay_start'), self.onStartVideo)
- QtCore.QObject.connect(Receiver.get_receiver(),
- QtCore.SIGNAL(u'videodisplay_stop'), self.onStopVideo)
-
- def setup(self):
- self.videoDisplay.setup()
- self.mainDisplay.setup()
-
- def hideDisplay(self, message):
- """
- Hide the output displays
- """
- self.videoDisplay.mediaHide(message)
- self.mainDisplay.hideDisplay(message)
-
- def showDisplay(self):
- """
- Hide the output displays
- """
- self.videoDisplay.mediaShow()
- self.mainDisplay.showDisplay()
-
- def addAlert(self, alertMessage, location):
- """
- Handles the addition of an Alert Message to the Displays
- """
- self.mainDisplay.addAlert(alertMessage, location)
-
- def displayImageWithText(self, frame):
- """
- Handles the addition of a background Image to the displays
- """
- self.mainDisplay.addImageWithText(frame)
-
- def displayImage(self, frame):
- """
- Handles the addition of a background Image to the displays
- """
- self.mainDisplay.displayImage(frame)
-
- def displayVideo(self, path):
- """
- Handles the addition of a background Video to the displays
- """
- self.mainDisplay.displayVideo(path)
-
- def onStartVideo(self, item):
- """
- Handles the Starting of a Video and Display Management
- """
- self.videoDisplay.setVisible(True)
- self.mainDisplay.setVisible(False)
- self.videoDisplay.onMediaQueue(item)
-
- def onStopVideo(self):
- """
- Handles the Stopping of a Video and Display Management
- """
- self.mainDisplay.setVisible(True)
- self.videoDisplay.setVisible(False)
- self.videoDisplay.onMediaStop()
-
- def close(self):
- """
- Handles the closure of the displays
- """
- self.videoDisplay.close()
- self.audioPlayer.close()
- self.mainDisplay.close()
-
class DisplayWidget(QtGui.QGraphicsView):
"""
Customised version of QTableWidget which can respond to keyboard
events.
"""
- log.info(u'MainDisplay loaded')
+ log.info(u'Display Widget loaded')
- def __init__(self, parent=None, name=None, primary=False):
- QtGui.QWidget.__init__(self, None)
+ def __init__(self, live, parent=None):
+ QtGui.QGraphicsView.__init__(self)
self.parent = parent
- self.primary = primary
+ self.live = live
self.hotkey_map = {
QtCore.Qt.Key_Return: 'servicemanager_next_item',
QtCore.Qt.Key_Space: 'slidecontroller_live_next_noloop',
QtCore.Qt.Key_Enter: 'slidecontroller_live_next_noloop',
QtCore.Qt.Key_0: 'servicemanager_next_item',
QtCore.Qt.Key_Backspace: 'slidecontroller_live_previous_noloop'}
+ self.setStyleSheet(u'border: none;')
def keyPressEvent(self, event):
+ """
+ Handle key events from display screen
+ """
+ # Key events only needed for live
+ if not self.live:
+ return
if isinstance(event, QtGui.QKeyEvent):
- #here accept the event and do something
+ # Here accept the event and do something
if event.key() == QtCore.Qt.Key_Up:
Receiver.send_message(u'slidecontroller_live_previous')
event.accept()
@@ -185,157 +82,269 @@ class DisplayWidget(QtGui.QGraphicsView):
Receiver.send_message(self.hotkey_map[event.key()])
event.accept()
elif event.key() == QtCore.Qt.Key_Escape:
- self.resetDisplay()
+ self.setVisible(False)
+ self.videoStop()
event.accept()
event.ignore()
else:
event.ignore()
- def resetDisplay(self):
- log.debug(u'resetDisplay')
- Receiver.send_message(u'slidecontroller_live_stop_loop')
- if self.primary:
- self.setVisible(False)
- else:
- self.setVisible(True)
-
class MainDisplay(DisplayWidget):
- """
- This is the form that is used to display things on the projector.
- """
- log.info(u'MainDisplay Loaded')
- def __init__(self, parent, screens):
- """
- The constructor for the display form.
-
- ``parent``
- The parent widget.
-
- ``screens``
- The list of screens.
- """
- log.debug(u'Initialisation started')
- DisplayWidget.__init__(self, parent, primary=True)
- self.setWindowFlags(QtCore.Qt.Window | QtCore.Qt.FramelessWindowHint)
- self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
- self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
- # WA_TranslucentBackground is not available in QT4.4
- try:
- self.setAttribute(QtCore.Qt.WA_TranslucentBackground)
- except AttributeError:
- pass
+ def __init__(self, parent, screens, live):
+ DisplayWidget.__init__(self, live, parent=None)
+ self.parent = parent
self.screens = screens
- self.setupScene()
- self.setupVideo()
- self.setupImage()
- self.setupText()
- self.setupAlert()
- self.setupBlank()
- self.blankFrame = None
- self.frame = None
- #Hide desktop for now until we know where to put it
- #and what size it should be.
- self.setVisible(False)
+ self.isLive = live
+ self.alertTab = None
+ self.setWindowTitle(u'OpenLP Display')
+ self.setWindowFlags(QtCore.Qt.FramelessWindowHint |
+ QtCore.Qt.WindowStaysOnTopHint)
+ if self.isLive:
+ QtCore.QObject.connect(Receiver.get_receiver(),
+ QtCore.SIGNAL(u'maindisplay_hide'), self.hideDisplay)
+ QtCore.QObject.connect(Receiver.get_receiver(),
+ QtCore.SIGNAL(u'maindisplay_show'), self.showDisplay)
def setup(self):
"""
- Sets up the screen on a particular screen.
+ Set up and build the output screen
"""
- log.debug(u'Setup %s for %s ' % (
- self.screens, self.screens.monitor_number))
- self.setVisible(False)
+ log.debug(u'Setup live = %s for %s ' % (self.isLive,
+ self.screens.monitor_number))
self.screen = self.screens.current
- #Sort out screen locations and sizes
+ self.setVisible(False)
self.setGeometry(self.screen[u'size'])
- self.scene.setSceneRect(0, 0, self.size().width(),
- self.size().height())
- self.webView.setGeometry(0, 0, self.size().width(),
- self.size().height())
- self.alertText.setTextWidth(self.size().width())
- #Build a custom splash screen
- self.initialFrame = QtGui.QImage(
- self.screen[u'size'].width(),
- self.screen[u'size'].height(),
- QtGui.QImage.Format_ARGB32_Premultiplied)
- splash_image = QtGui.QImage(u':/graphics/openlp-splash-screen.png')
- painter_image = QtGui.QPainter()
- painter_image.begin(self.initialFrame)
- painter_image.fillRect(self.initialFrame.rect(), QtCore.Qt.white)
- painter_image.drawImage(
- (self.screen[u'size'].width() - splash_image.width()) / 2,
- (self.screen[u'size'].height() - splash_image.height()) / 2,
- splash_image)
- #build a blank transparent image
- self.transparent = QtGui.QPixmap(
- self.screen[u'size'].width(), self.screen[u'size'].height())
- self.transparent.fill(QtCore.Qt.transparent)
- self.displayImage(self.initialFrame)
- self.repaint()
- #Build a Black screen
- painter = QtGui.QPainter()
- self.blankFrame = QtGui.QImage(
- self.screen[u'size'].width(),
- self.screen[u'size'].height(),
- QtGui.QImage.Format_ARGB32_Premultiplied)
- painter.begin(self.blankFrame)
- painter.fillRect(self.blankFrame.rect(), QtCore.Qt.black)
- # To display or not to display?
- if not self.screen[u'primary']:
- self.setVisible(True)
- self.primary = False
- else:
- self.setVisible(False)
- self.primary = True
-
- def setupScene(self):
- self.scene = QtGui.QGraphicsScene(self)
- self.scene.setSceneRect(0, 0, self.size().width(), self.size().height())
- self.setScene(self.scene)
-
- def setupVideo(self):
- self.webView = QtWebKit.QWebView()
+ self.webView = QtWebKit.QWebView(self)
+ self.webView.setGeometry(0, 0, self.screen[u'size'].width(), \
+ self.screen[u'size'].height())
self.page = self.webView.page()
- self.videoDisplay = self.page.mainFrame()
- self.videoDisplay.setScrollBarPolicy(QtCore.Qt.Vertical,
+ self.frame = self.page.mainFrame()
+ QtCore.QObject.connect(self.webView,
+ QtCore.SIGNAL(u'loadFinished(bool)'), self.isLoaded)
+ self.frame.setScrollBarPolicy(QtCore.Qt.Vertical,
QtCore.Qt.ScrollBarAlwaysOff)
- self.videoDisplay.setScrollBarPolicy(QtCore.Qt.Horizontal,
+ self.frame.setScrollBarPolicy(QtCore.Qt.Horizontal,
QtCore.Qt.ScrollBarAlwaysOff)
- self.proxy = QtGui.QGraphicsProxyWidget()
- self.proxy.setWidget(self.webView)
- self.proxy.setWindowFlags(QtCore.Qt.Window |
- QtCore.Qt.FramelessWindowHint)
- self.proxy.setZValue(1)
- self.scene.addItem(self.proxy)
+ if self.isLive:
+ # Build the initial frame.
+ self.black = QtGui.QImage(
+ self.screens.current[u'size'].width(),
+ self.screens.current[u'size'].height(),
+ QtGui.QImage.Format_ARGB32_Premultiplied)
+ painter_image = QtGui.QPainter()
+ painter_image.begin(self.black)
+ painter_image.fillRect(self.black.rect(), QtCore.Qt.black)
+ #Build the initial frame.
+ initialFrame = QtGui.QImage(
+ self.screens.current[u'size'].width(),
+ self.screens.current[u'size'].height(),
+ QtGui.QImage.Format_ARGB32_Premultiplied)
+ splash_image = QtGui.QImage(u':/graphics/openlp-splash-screen.png')
+ painter_image = QtGui.QPainter()
+ painter_image.begin(initialFrame)
+ painter_image.fillRect(initialFrame.rect(), QtCore.Qt.white)
+ painter_image.drawImage(
+ (self.screens.current[u'size'].width() \
+ - splash_image.width()) / 2,
+ (self.screens.current[u'size'].height() \
+ - splash_image.height()) / 2,
+ splash_image)
+ serviceItem = ServiceItem()
+ serviceItem.bg_frame = initialFrame
+ self.webView.setHtml(build_html(serviceItem, self.screen, \
+ self.parent.alertTab))
+ self.initialFrame = True
+ self.show()
+ # To display or not to display?
+ if not self.screen[u'primary']:
+ self.primary = False
+ else:
+ self.primary = True
- def setupImage(self):
- self.imageDisplay = QtGui.QGraphicsPixmapItem()
- self.imageDisplay.setZValue(2)
- self.scene.addItem(self.imageDisplay)
+ def text(self, slide):
+ """
+ Add the slide text from slideController
- def setupText(self):
- #self.displayText = QtGui.QGraphicsTextItem()
- self.displayText = QtGui.QGraphicsPixmapItem()
- #self.displayText.setPos(0,0)
- #self.displayText.setTextWidth(self.size().width())
- self.displayText.setZValue(4)
- self.scene.addItem(self.displayText)
+ `slide`
+ The slide text to be displayed
+ """
+ log.debug(u'text')
+ self.frame.evaluateJavaScript(u'show_text("%s")' % \
+ slide.replace(u'\\', u'\\\\').replace(u'\"', u'\\\"'))
+ return self.preview()
- def setupAlert(self):
- self.alertText = QtGui.QGraphicsTextItem()
- self.alertText.setZValue(8)
- self.scene.addItem(self.alertText)
+ def alert(self, text):
+ """
+ Add the alert text
- def setupBlank(self):
- self.displayBlank = QtGui.QGraphicsPixmapItem()
- self.displayBlank.setZValue(10)
- self.scene.addItem(self.displayBlank)
+ `slide`
+ The slide text to be displayed
+ """
+ log.debug(u'alert')
+ if self.height() != self.screen[u'size'].height() \
+ or not self.isVisible():
+ shrink = True
+ else:
+ shrink = False
+ js = u'show_alert("%s", "%s")' % (
+ text.replace(u'\\', u'\\\\').replace(u'\"', u'\\\"'),
+ u'top' if shrink else u'')
+ height = self.frame.evaluateJavaScript(js)
+ if shrink:
+ if text:
+ self.resize(self.width(), int(height.toString()))
+ self.setVisible(True)
+ else:
+ self.setGeometry(self.screen[u'size'])
+ self.setVisible(False)
-# def hideDisplayForVideo(self):
-# """
-# Hides the main display if for the video to be played
-# """
-# self.hideDisplay(HideMode.Screen)
+ def image(self, image):
+ """
+ Add an image as the background. The image is converted to a
+ bytestream on route.
+
+ `Image`
+ The Image to be displayed can be QImage or QPixmap
+ """
+ log.debug(u'image')
+ image = resize_image(image, self.screen[u'size'].width(),
+ self.screen[u'size'].height())
+ self.resetVideo()
+ self.displayImage(image)
+ # show screen
+ if self.isLive:
+ self.setVisible(True)
+
+ def displayImage(self, image):
+ """
+ Display an image, as is.
+ """
+ if image:
+ js = u'show_image("data:image/png;base64,%s");' % \
+ image_to_byte(image)
+ else:
+ js = u'show_image("");'
+ self.frame.evaluateJavaScript(js)
+
+ def resetImage(self):
+ """
+ Reset the backgound image to the service item image.
+ Used after Image plugin has changed the background
+ """
+ log.debug(u'resetImage')
+ self.displayImage(self.serviceItem.bg_frame)
+
+ def resetVideo(self):
+ """
+ Used after Video plugin has changed the background
+ """
+ log.debug(u'resetVideo')
+ self.frame.evaluateJavaScript(u'show_video("close");')
+
+ def videoPlay(self):
+ """
+ Responds to the request to play a loaded video
+ """
+ log.debug(u'videoPlay')
+ self.frame.evaluateJavaScript(u'show_video("play");')
+ # show screen
+ if self.isLive:
+ self.setVisible(True)
+
+ def videoPause(self):
+ """
+ Responds to the request to pause a loaded video
+ """
+ log.debug(u'videoPause')
+ self.frame.evaluateJavaScript(u'show_video("pause");')
+
+ def videoStop(self):
+ """
+ Responds to the request to stop a loaded video
+ """
+ log.debug(u'videoStop')
+ self.frame.evaluateJavaScript(u'show_video("stop");')
+
+ def videoVolume(self, volume):
+ """
+ Changes the volume of a running video
+ """
+ log.debug(u'videoVolume %d' % volume)
+ self.frame.evaluateJavaScript(u'show_video(null, null, %s);' %
+ str(float(volume)/float(10)))
+
+ def video(self, videoPath, volume):
+ """
+ Loads and starts a video to run with the option of sound
+ """
+ log.debug(u'video')
+ self.loaded = True
+ js = u'show_video("play", "%s", %s, true);' % \
+ (videoPath.replace(u'\\', u'\\\\'), str(float(volume)/float(10)))
+ self.frame.evaluateJavaScript(js)
+ return self.preview()
+
+ def isLoaded(self):
+ """
+ Called by webView event to show display is fully loaded
+ """
+ log.debug(u'loaded')
+ self.loaded = True
+
+ def preview(self):
+ """
+ Generates a preview of the image displayed.
+ """
+ log.debug(u'preview for %s', self.isLive)
+ # Wait for the fade to finish before geting the preview.
+ # Important otherwise preview will have incorrect text if at all !
+ if self.serviceItem.themedata and \
+ self.serviceItem.themedata.display_slideTransition:
+ while self.frame.evaluateJavaScript(u'show_text_complete()') \
+ .toString() == u'false':
+ Receiver.send_message(u'openlp_process_events')
+ # Wait for the webview to update before geting the preview.
+ # Important otherwise first preview will miss the background !
+ while not self.loaded:
+ Receiver.send_message(u'openlp_process_events')
+ preview = QtGui.QImage(self.screen[u'size'].width(),
+ self.screen[u'size'].height(),
+ QtGui.QImage.Format_ARGB32_Premultiplied)
+ painter = QtGui.QPainter(preview)
+ painter.setRenderHint(QtGui.QPainter.Antialiasing)
+ self.frame.render(painter)
+ painter.end()
+ # Make display show up if in single screen mode
+ if self.isLive:
+ self.setVisible(True)
+ # save preview for debugging
+ if log.isEnabledFor(logging.DEBUG):
+ preview.save(u'temp.png', u'png')
+ return preview
+
+ def buildHtml(self, serviceItem):
+ """
+ Store the serviceItem and build the new HTML from it. Add the
+ HTML to the display
+ """
+ log.debug(u'buildHtml')
+ self.loaded = False
+ self.initialFrame = False
+ self.serviceItem = serviceItem
+ html = build_html(self.serviceItem, self.screen, self.parent.alertTab)
+ self.webView.setHtml(html)
+ if serviceItem.foot_text and serviceItem.foot_text:
+ self.footer(serviceItem.foot_text)
+
+ def footer(self, text):
+ """
+ Display the Footer
+ """
+ log.debug(u'footer')
+ js = "show_footer('" + \
+ text.replace("\\", "\\\\").replace("\'", "\\\'") + "')"
+ self.frame.evaluateJavaScript(js)
def hideDisplay(self, mode=HideMode.Screen):
"""
@@ -343,20 +352,13 @@ class MainDisplay(DisplayWidget):
Store the images so they can be replaced when required
"""
log.debug(u'hideDisplay mode = %d', mode)
- #self.displayText.setPixmap(self.transparent)
if mode == HideMode.Screen:
- #self.display_image.setPixmap(self.transparent)
+ self.frame.evaluateJavaScript(u'show_blank("desktop");')
self.setVisible(False)
- elif mode == HideMode.Blank:
- self.displayBlank.setPixmap(
- QtGui.QPixmap.fromImage(self.blankFrame))
+ elif mode == HideMode.Blank or self.initialFrame:
+ self.frame.evaluateJavaScript(u'show_blank("black");')
else:
- if self.parent.renderManager.renderer.bg_frame:
- self.displayBlank.setPixmap(QtGui.QPixmap.fromImage(
- self.parent.renderManager.renderer.bg_frame))
- else:
- self.displayBlank.setPixmap(
- QtGui.QPixmap.fromImage(self.blankFrame))
+ self.frame.evaluateJavaScript(u'show_blank("theme");')
if mode != HideMode.Screen and self.isHidden():
self.setVisible(True)
@@ -367,275 +369,16 @@ class MainDisplay(DisplayWidget):
Make the stored images None to release memory.
"""
log.debug(u'showDisplay')
- self.displayBlank.setPixmap(self.transparent)
+ self.frame.evaluateJavaScript('show_blank("show");')
if self.isHidden():
self.setVisible(True)
- #Trigger actions when display is active again
+ # Trigger actions when display is active again
Receiver.send_message(u'maindisplay_active')
- def addImageWithText(self, frame):
- log.debug(u'addImageWithText')
- frame = resize_image(
- frame, self.screen[u'size'].width(), self.screen[u'size'].height())
- self.imageDisplay.setPixmap(QtGui.QPixmap.fromImage(frame))
- self.videoDisplay.setHtml(u'')
-
- 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'')
-
- def displayVideo(self, path):
- """
- Places the Video passed on the display screen
- ``path``
- The path to the image to be displayed
- """
- log.debug(u'adddisplayVideo')
- self.displayImage(self.transparent)
- self.videoDisplay.setHtml(HTMLVIDEO %
- (path, self.screen[u'size'].width(),
- self.screen[u'size'].height()))
-
- def frameView(self, frame, transition=False):
- """
- Called from a slide controller to display a frame
- if the alert is in progress the alert is added on top
- ``frame``
- Image frame to be rendered
- ``transition``
- Are transitions required.
- """
- log.debug(u'frameView')
- if transition:
- if self.frame is not None:
- self.displayText.setPixmap(
- QtGui.QPixmap.fromImage(self.frame))
- self.repaint()
- Receiver.send_message(u'openlp_process_events')
- time.sleep(0.1)
- self.frame = None
- if frame[u'trans'] is not None:
- self.displayText.setPixmap(
- QtGui.QPixmap.fromImage(frame[u'trans']))
- self.repaint()
- Receiver.send_message(u'openlp_process_events')
- time.sleep(0.1)
- self.frame = frame[u'trans']
- self.displayText.setPixmap(
- QtGui.QPixmap.fromImage(frame[u'main']))
- else:
- if isinstance(frame, QtGui.QPixmap):
- self.displayText.setPixmap(frame)
- else:
- self.displayText.setPixmap(QtGui.QPixmap.fromImage(frame))
- if not self.isVisible() and self.screens.current['primary']:
- self.setVisible(True)
-
-class VideoDisplay(Phonon.VideoWidget):
- """
- This is the form that is used to display videos on the projector.
- """
- log.info(u'VideoDisplay Loaded')
-
- def __init__(self, parent, screens,
- aspect=Phonon.VideoWidget.AspectRatioWidget):
- """
- The constructor for the display form.
-
- ``parent``
- The parent widget.
-
- ``screens``
- The list of screens.
- """
- log.debug(u'VideoDisplay Initialisation started')
- Phonon.VideoWidget.__init__(self)
- self.setWindowTitle(u'OpenLP Video Display')
- self.parent = parent
- self.screens = screens
- self.hidden = False
- self.message = None
- self.mediaActive = False
- self.mediaObject = Phonon.MediaObject()
- self.setAspectRatio(aspect)
- self.audioObject = Phonon.AudioOutput(Phonon.VideoCategory)
- Phonon.createPath(self.mediaObject, self)
- Phonon.createPath(self.mediaObject, self.audioObject)
- flags = QtCore.Qt.FramelessWindowHint | QtCore.Qt.Dialog
-## # WindowsStaysOnBottomHint is not available in QT4.4
-# try:
-# flags = flags | QtCore.Qt.WindowStaysOnBottomHint
-# except AttributeError:
-# pass
- self.setWindowFlags(flags)
- QtCore.QObject.connect(Receiver.get_receiver(),
- QtCore.SIGNAL(u'videodisplay_play'), self.onMediaPlay)
- QtCore.QObject.connect(Receiver.get_receiver(),
- QtCore.SIGNAL(u'videodisplay_pause'), self.onMediaPause)
-# QtCore.QObject.connect(Receiver.get_receiver(),
-# QtCore.SIGNAL(u'videodisplay_background'), self.onMediaBackground)
- QtCore.QObject.connect(Receiver.get_receiver(),
- QtCore.SIGNAL(u'config_updated'), self.setup)
- QtCore.QObject.connect(self.mediaObject,
- QtCore.SIGNAL(u'finished()'), self.onMediaStop)
- self.setVisible(False)
-
- def keyPressEvent(self, event):
- if isinstance(event, QtGui.QKeyEvent):
- #here accept the event and do something
- if event.key() == QtCore.Qt.Key_Escape:
- self.onMediaStop()
- event.accept()
- event.ignore()
- else:
- event.ignore()
-
- def setup(self):
- """
- Sets up the screen on a particular screen.
- """
- log.debug(u'VideoDisplay Setup %s for %s ' % (self.screens,
- self.screens.monitor_number))
- self.screen = self.screens.current
- #Sort out screen locations and sizes
- self.setGeometry(self.screen[u'size'])
- # To display or not to display?
- if not self.screen[u'primary']: # and self.isVisible():
- #self.showFullScreen()
- self.setVisible(False)
- self.primary = False
- else:
- self.setVisible(False)
- self.primary = True
-
- def closeEvent(self, event):
- """
- Shutting down so clean up connections
- """
- self.onMediaStop()
- for path in self.outputPaths():
- path.disconnect()
-
-# def onMediaBackground(self, message=None):
-# """
-# Play a video triggered from the video plugin with the
-# file name passed in on the event.
-# Also triggered from the Finish event so the video will loop
-# if it is triggered from the plugin
-# """
-# log.debug(u'VideoDisplay Queue new media message %s' % message)
-# #If not file take the stored one
-# if not message:
-# message = self.message
-# # still no file name then stop as it was a normal video stopping
-# if message:
-# self.mediaObject.setCurrentSource(Phonon.MediaSource(message))
-# self.message = message
-# self._play()
-
- def onMediaQueue(self, message):
- """
- Set up a video to play from the serviceitem.
- """
- log.debug(u'VideoDisplay Queue new media message %s' % message)
- file = os.path.join(message.get_frame_path(),
- message.get_frame_title())
- self.mediaObject.setCurrentSource(Phonon.MediaSource(file))
- self.mediaActive = True
- self._play()
-
- def onMediaPlay(self):
- """
- Respond to the Play button on the slide controller unless the display
- has been hidden by the slidecontroller
- """
- if not self.hidden:
- log.debug(u'VideoDisplay Play the new media, Live ')
- self._play()
-
- def _play(self):
- """
- We want to play the video so start it and display the screen
- """
- log.debug(u'VideoDisplay _play called')
- self.mediaObject.play()
- self.setVisible(True)
-
- def onMediaPause(self):
- """
- Pause the video and refresh the screen
- """
- log.debug(u'VideoDisplay Media paused by user')
- self.mediaObject.pause()
- self.show()
-
- def onMediaStop(self):
- """
- Stop the video and clean up
- """
- log.debug(u'VideoDisplay Media stopped by user')
- self.message = None
- self.mediaActive = False
- self.mediaObject.stop()
- self.onMediaFinish()
-
- def onMediaFinish(self):
- """
- Clean up the Object queue
- """
- log.debug(u'VideoDisplay Reached end of media playlist')
- self.mediaObject.clearQueue()
- self.setVisible(False)
-
- def mediaHide(self, message=u''):
- """
- Hide the video display
- """
- self.mediaObject.pause()
- self.hidden = True
- self.setVisible(False)
-
- def mediaShow(self):
- """
- Show the video display if it was already hidden
- """
- if self.hidden:
- self.hidden = False
- if self.mediaActive:
- self._play()
-
class AudioPlayer(QtCore.QObject):
"""
This Class will play audio only allowing components to work with a
- soundtrack which does not take over the user interface.
+ soundtrack independent of the user interface.
"""
log.info(u'AudioPlayer Loaded')
@@ -675,9 +418,9 @@ class AudioPlayer(QtCore.QObject):
Set up a video to play from the serviceitem.
"""
log.debug(u'AudioPlayer Queue new media message %s' % message)
- file = os.path.join(message[0].get_frame_path(),
+ mfile = os.path.join(message[0].get_frame_path(),
message[0].get_frame_title())
- self.mediaObject.setCurrentSource(Phonon.MediaSource(file))
+ self.mediaObject.setCurrentSource(Phonon.MediaSource(mfile))
self.onMediaPlay()
def onMediaPlay(self):
diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py
index 6f1a1f6c1..b408821cf 100644
--- a/openlp/core/ui/mainwindow.py
+++ b/openlp/core/ui/mainwindow.py
@@ -29,7 +29,7 @@ import logging
from PyQt4 import QtCore, QtGui
from openlp.core.ui import AboutForm, SettingsForm, ServiceManager, \
- ThemeManager, SlideController, PluginForm, MediaDockManager, DisplayManager
+ ThemeManager, SlideController, PluginForm, MediaDockManager
from openlp.core.lib import RenderManager, build_icon, OpenLPDockWidget, \
SettingsManager, PluginManager, Receiver, translate
from openlp.core.utils import AppLocation, add_actions, LanguageManager
@@ -94,8 +94,8 @@ class Ui_MainWindow(object):
self.ControlSplitter.setObjectName(u'ControlSplitter')
self.MainContentLayout.addWidget(self.ControlSplitter)
# Create slide controllers
- self.PreviewController = SlideController(self, self.settingsmanager)
- self.LiveController = SlideController(self, self.settingsmanager, True)
+ self.PreviewController = SlideController(self, self.settingsmanager, self.screens)
+ self.LiveController = SlideController(self, self.settingsmanager, self.screens, True)
# Create menu
self.MenuBar = QtGui.QMenuBar(MainWindow)
self.MenuBar.setGeometry(QtCore.QRect(0, 0, 1087, 27))
@@ -509,7 +509,6 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.songsSettingsSection = u'songs'
self.serviceNotSaved = False
self.settingsmanager = SettingsManager(screens)
- self.displayManager = DisplayManager(screens)
self.aboutForm = AboutForm(self, applicationVersion)
self.settingsForm = SettingsForm(self.screens, self, self)
self.recentFiles = QtCore.QStringList()
@@ -594,7 +593,6 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
#ThemeManager needs to call RenderManager
self.RenderManager = RenderManager(
self.ThemeManagerContents, self.screens)
- self.displayManager.renderManager = self.RenderManager
#Define the media Dock Manager
self.mediaDockManager = MediaDockManager(self.MediaToolBox)
log.info(u'Load Plugins')
@@ -605,7 +603,6 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.plugin_helpers[u'service'] = self.ServiceManagerContents
self.plugin_helpers[u'settings form'] = self.settingsForm
self.plugin_helpers[u'toolbox'] = self.mediaDockManager
- self.plugin_helpers[u'displaymanager'] = self.displayManager
self.plugin_helpers[u'pluginmanager'] = self.plugin_manager
self.plugin_helpers[u'formparent'] = self
self.plugin_manager.find_plugins(pluginpath, self.plugin_helpers)
@@ -652,8 +649,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
version_text = unicode(translate('OpenLP.MainWindow',
'Version %s of OpenLP is now available for download (you are '
'currently running version %s). \n\nYou can download the latest '
- 'version from '
- 'http://openlp.org/.'))
+ 'version from http://openlp.org/.'))
QtGui.QMessageBox.question(self,
translate('OpenLP.MainWindow', 'OpenLP Version Updated'),
version_text % (version, self.applicationVersion[u'full']))
@@ -663,9 +659,10 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
Show the main form, as well as the display form
"""
QtGui.QWidget.show(self)
- self.displayManager.setup()
- if self.displayManager.mainDisplay.isVisible():
- self.displayManager.mainDisplay.setFocus()
+ self.LiveController.display.setup()
+ self.PreviewController.display.setup()
+ if self.LiveController.display.isVisible():
+ self.LiveController.display.setFocus()
self.activateWindow()
if QtCore.QSettings().value(
self.generalSettingsSection + u'/auto open',
@@ -745,8 +742,8 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
The screen has changed to so tell the displays to update_display
their locations
"""
+ log.debug(u'screenChanged')
self.RenderManager.update_display()
- self.displayManager.setup()
self.setFocus()
self.activateWindow()
@@ -792,8 +789,8 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.plugin_manager.finalise_plugins()
# Save settings
self.saveSettings()
- #Close down the displays
- self.displayManager.close()
+ #Close down the display
+ self.LiveController.display.close()
def serviceChanged(self, reset=False, serviceName=None):
"""
diff --git a/openlp/core/ui/screen.py b/openlp/core/ui/screen.py
index ade157efa..1d4ad8c48 100644
--- a/openlp/core/ui/screen.py
+++ b/openlp/core/ui/screen.py
@@ -44,9 +44,9 @@ class ScreenList(object):
self.override = None
self.screen_list = []
self.display_count = 0
- #actual display number
+ # actual display number
self.current_display = 0
- #save config display number
+ # save config display number
self.monitor_number = 0
def add_screen(self, screen):
diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py
index 49f7607d5..f2961b717 100644
--- a/openlp/core/ui/servicemanager.py
+++ b/openlp/core/ui/servicemanager.py
@@ -317,9 +317,8 @@ class ServiceManager(QtGui.QWidget):
self.serviceItemEditForm.setServiceItem(
self.serviceItems[item][u'service_item'])
if self.serviceItemEditForm.exec_():
- self.serviceItems[item][u'service_item'] = \
- self.serviceItemEditForm.getServiceItem()
- self.repaintServiceList(item, 0)
+ self.addServiceItem(self.serviceItemEditForm.getServiceItem(),
+ replace=True)
def nextItem(self):
"""
@@ -780,7 +779,7 @@ class ServiceManager(QtGui.QWidget):
Rebuild the service list as things have changed and a
repaint is the easiest way to do this.
"""
- #force reset of renderer as theme data has changed
+ # force reset of renderer as theme data has changed
self.parent.RenderManager.themedata = None
if self.serviceItems:
tempServiceItems = self.serviceItems
@@ -790,8 +789,8 @@ class ServiceManager(QtGui.QWidget):
for item in tempServiceItems:
self.addServiceItem(
item[u'service_item'], False, item[u'expanded'])
- #Set to False as items may have changed rendering
- #does not impact the saved song so True may also be valid
+ # Set to False as items may have changed rendering
+ # does not impact the saved song so True may also be valid
self.parent.serviceChanged(False, self.serviceName)
def addServiceItem(self, item, rebuild=False, expand=True, replace=False):
@@ -873,6 +872,7 @@ class ServiceManager(QtGui.QWidget):
ItemCapabilities.AllowsPreview):
self.parent.PreviewController.addServiceManagerItem(
self.serviceItems[item][u'service_item'], 0)
+ self.parent.LiveController.PreviewListWidget.setFocus()
else:
QtGui.QMessageBox.critical(self,
translate('OpenLP.ServiceManager', 'Missing Display Handler'),
diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py
index e118036d2..bced92f99 100644
--- a/openlp/core/ui/slidecontroller.py
+++ b/openlp/core/ui/slidecontroller.py
@@ -25,36 +25,17 @@
###############################################################################
import logging
-import time
import os
from PyQt4 import QtCore, QtGui
from PyQt4.phonon import Phonon
-from openlp.core.ui import HideMode
+from openlp.core.ui import HideMode, MainDisplay
from openlp.core.lib import OpenLPToolbar, Receiver, resize_image, \
ItemCapabilities, translate
log = logging.getLogger(__name__)
-class SlideThread(QtCore.QThread):
- """
- A special Qt thread class to speed up the display of text based frames.
- This is threaded so it loads the frames in background
- """
- def __init__(self, parent, prefix, count):
- QtCore.QThread.__init__(self, parent)
- self.prefix = prefix
- self.count = count
-
- def run(self):
- """
- Run the thread.
- """
- time.sleep(1)
- for i in range(0, self.count):
- Receiver.send_message(u'%s_slide_cache' % self.prefix, i)
-
class SlideList(QtGui.QTableWidget):
"""
Customised version of QTableWidget which can respond to keyboard
@@ -97,7 +78,7 @@ class SlideController(QtGui.QWidget):
SlideController is the slide controller widget. This widget is what the
user uses to control the displaying of verses/slides/etc on the screen.
"""
- def __init__(self, parent, settingsmanager, isLive=False):
+ def __init__(self, parent, settingsmanager, screens, isLive=False):
"""
Set up the Slide Controller.
"""
@@ -105,8 +86,10 @@ class SlideController(QtGui.QWidget):
self.settingsmanager = settingsmanager
self.isLive = isLive
self.parent = parent
- self.mainDisplay = self.parent.displayManager.mainDisplay
- self.displayManager = self.parent.displayManager
+ self.screens = screens
+ self.ratio = float(self.screens.current[u'size'].width()) / \
+ float(self.screens.current[u'size'].height())
+ self.display = MainDisplay(self, screens, isLive)
self.loopList = [
u'Start Loop',
u'Loop Separator',
@@ -115,13 +98,14 @@ class SlideController(QtGui.QWidget):
self.songEditList = [
u'Edit Song',
]
+ self.volume = 10
self.timer_id = 0
self.songEdit = False
self.selectedRow = 0
self.serviceItem = None
+ self.alertTab = None
self.Panel = QtGui.QWidget(parent.ControlSplitter)
self.slideList = {}
- self.canDisplay = True
# Layout for holding panel
self.PanelLayout = QtGui.QVBoxLayout(self.Panel)
self.PanelLayout.setSpacing(0)
@@ -177,11 +161,11 @@ class SlideController(QtGui.QWidget):
sizeToolbarPolicy.setHeightForWidth(
self.Toolbar.sizePolicy().hasHeightForWidth())
self.Toolbar.setSizePolicy(sizeToolbarPolicy)
- if self.isLive:
- self.Toolbar.addToolbarButton(
- u'First Slide', u':/slides/slide_first.png',
- translate('OpenLP.SlideController', 'Move to first'),
- self.onSlideSelectedFirst)
+# if self.isLive:
+# self.Toolbar.addToolbarButton(
+# u'First Slide', u':/slides/slide_first.png',
+# translate('OpenLP.SlideController', 'Move to first'),
+# self.onSlideSelectedFirst)
self.Toolbar.addToolbarButton(
u'Previous Slide', u':/slides/slide_previous.png',
translate('OpenLP.SlideController', 'Move to previous'),
@@ -190,11 +174,11 @@ class SlideController(QtGui.QWidget):
u'Next Slide', u':/slides/slide_next.png',
translate('OpenLP.SlideController', 'Move to next'),
self.onSlideSelectedNext)
- if self.isLive:
- self.Toolbar.addToolbarButton(
- u'Last Slide', u':/slides/slide_last.png',
- translate('OpenLP.SlideController', 'Move to last'),
- self.onSlideSelectedLast)
+# if self.isLive:
+# self.Toolbar.addToolbarButton(
+# u'Last Slide', u':/slides/slide_last.png',
+# translate('OpenLP.SlideController', 'Move to last'),
+# self.onSlideSelectedLast)
if self.isLive:
self.Toolbar.addToolbarSeparator(u'Close Separator')
self.HideMenu = QtGui.QToolButton(self.Toolbar)
@@ -213,15 +197,17 @@ class SlideController(QtGui.QWidget):
self.ThemeScreen.setCheckable(True)
QtCore.QObject.connect(self.ThemeScreen,
QtCore.SIGNAL("triggered(bool)"), self.onThemeDisplay)
- self.DesktopScreen = QtGui.QAction(QtGui.QIcon(
- u':/slides/slide_desktop.png'), u'Show Desktop', self.HideMenu)
- self.DesktopScreen.setCheckable(True)
- QtCore.QObject.connect(self.DesktopScreen,
- QtCore.SIGNAL("triggered(bool)"), self.onHideDisplay)
+ if self.screens.display_count > 1:
+ self.DesktopScreen = QtGui.QAction(QtGui.QIcon(
+ u':/slides/slide_desktop.png'), u'Show Desktop', self.HideMenu)
+ self.DesktopScreen.setCheckable(True)
+ QtCore.QObject.connect(self.DesktopScreen,
+ QtCore.SIGNAL("triggered(bool)"), self.onHideDisplay)
self.HideMenu.setDefaultAction(self.BlankScreen)
self.HideMenu.menu().addAction(self.BlankScreen)
self.HideMenu.menu().addAction(self.ThemeScreen)
- self.HideMenu.menu().addAction(self.DesktopScreen)
+ if self.screens.display_count > 1:
+ self.HideMenu.menu().addAction(self.DesktopScreen)
if not self.isLive:
self.Toolbar.addToolbarSeparator(u'Close Separator')
self.Toolbar.addToolbarButton(
@@ -251,7 +237,7 @@ class SlideController(QtGui.QWidget):
self.DelaySpinBox.setToolTip(translate('OpenLP.SlideController',
'Delay between slides in seconds'))
self.ControllerLayout.addWidget(self.Toolbar)
- #Build a Media ToolBar
+ # Build a Media ToolBar
self.Mediabar = OpenLPToolbar(self)
self.Mediabar.addToolbarButton(
u'Media Start', u':/slides/media_playback_start.png',
@@ -271,10 +257,19 @@ class SlideController(QtGui.QWidget):
self.seekSlider.setObjectName(u'seekSlider')
self.Mediabar.addToolbarWidget(
u'Seek Slider', self.seekSlider)
- self.volumeSlider = Phonon.VolumeSlider()
- self.volumeSlider.setGeometry(QtCore.QRect(90, 260, 221, 24))
- self.volumeSlider.setObjectName(u'volumeSlider')
- self.Mediabar.addToolbarWidget(u'Audio Volume', self.volumeSlider)
+ self.volumeSlider = Phonon.VolumeSlider()
+ self.volumeSlider.setGeometry(QtCore.QRect(90, 260, 221, 24))
+ self.volumeSlider.setObjectName(u'volumeSlider')
+ self.Mediabar.addToolbarWidget(u'Audio Volume', self.volumeSlider)
+ else:
+ self.volumeSlider = QtGui.QSlider(QtCore.Qt.Horizontal)
+ self.volumeSlider.setTickInterval(1)
+ self.volumeSlider.setTickPosition(QtGui.QSlider.TicksAbove)
+ self.volumeSlider.setMinimum(0)
+ self.volumeSlider.setMaximum(10)
+ self.volumeSlider.setGeometry(QtCore.QRect(90, 260, 221, 24))
+ self.volumeSlider.setObjectName(u'volumeSlider')
+ self.Mediabar.addToolbarWidget(u'Audio Volume', self.volumeSlider)
self.ControllerLayout.addWidget(self.Mediabar)
# Build the Song Toolbar
if isLive:
@@ -322,7 +317,7 @@ class SlideController(QtGui.QWidget):
self.SlidePreview.setSizePolicy(sizePolicy)
self.SlidePreview.setFixedSize(
QtCore.QSize(self.settingsmanager.slidecontroller_image,
- self.settingsmanager.slidecontroller_image / 1.3 ))
+ self.settingsmanager.slidecontroller_image / self.ratio))
self.SlidePreview.setFrameShape(QtGui.QFrame.Box)
self.SlidePreview.setFrameShadow(QtGui.QFrame.Plain)
self.SlidePreview.setLineWidth(1)
@@ -390,17 +385,37 @@ class SlideController(QtGui.QWidget):
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'config_updated'), self.refreshServiceItem)
QtCore.QObject.connect(Receiver.get_receiver(),
- QtCore.SIGNAL(u'%s_slide_cache' % self.typePrefix), self.slideCache)
+ QtCore.SIGNAL(u'config_screen_changed'), self.screenSizeChanged)
+ if self.isLive:
+ QtCore.QObject.connect(self.volumeSlider,
+ QtCore.SIGNAL(u'sliderReleased()'), self.mediaVolume)
+
+ def screenSizeChanged(self):
+ """
+ Settings dialog has changed the screen size of adjust output and
+ screen previews
+ """
+ log.debug(u'screenSizeChanged live = %s' % self.isLive)
+ # rebuild display as screen size changed
+ self.display = MainDisplay(self, self.screens, self.isLive)
+ self.display.alertTab = self.alertTab
+ self.ratio = float(self.screens.current[u'size'].width()) / \
+ float(self.screens.current[u'size'].height())
+ self.display.setup()
+ self.SlidePreview.setFixedSize(
+ QtCore.QSize(self.settingsmanager.slidecontroller_image,
+ self.settingsmanager.slidecontroller_image / self.ratio))
def widthChanged(self):
"""
Handle changes of width from the splitter between the live and preview
controller. Event only issues when changes have finished
"""
+ log.debug(u'widthChanged live = %s' % self.isLive)
width = self.parent.ControlSplitter.sizes()[self.split]
height = width * self.parent.RenderManager.screen_ratio
self.PreviewListWidget.setColumnWidth(0, width)
- #Sort out image heights (Songs, bibles excluded)
+ # Sort out image heights (Songs, bibles excluded)
if self.serviceItem and not self.serviceItem.is_text():
for framenumber in range(len(self.serviceItem.get_frames())):
self.PreviewListWidget.setRowHeight(framenumber, height)
@@ -453,8 +468,6 @@ class SlideController(QtGui.QWidget):
if item.is_media():
self.Toolbar.setVisible(False)
self.Mediabar.setVisible(True)
- #self.volumeSlider.setAudioOutput(
- # self.mainDisplay.videoDisplay.audio)
def enablePreviewToolBar(self, item):
"""
@@ -474,22 +487,20 @@ class SlideController(QtGui.QWidget):
"""
Method to update the service item if the screen has changed
"""
- log.debug(u'refreshServiceItem')
+ log.debug(u'refreshServiceItem live = %s' % self.isLive)
if self.serviceItem:
if self.serviceItem.is_text() or self.serviceItem.is_image():
item = self.serviceItem
item.render()
- self.addServiceManagerItem(item, self.selectedRow)
+ self._processItem(item, self.selectedRow)
def addServiceItem(self, item):
"""
Method to install the service item into the controller
Called by plugins
"""
- log.debug(u'addServiceItem')
- before = time.time()
+ log.debug(u'addServiceItem live = %s' % self.isLive)
item.render()
- log.log(15, u'Rendering took %4s' % (time.time() - before))
slideno = 0
if self.songEdit:
slideno = self.selectedRow
@@ -509,8 +520,8 @@ class SlideController(QtGui.QWidget):
request the correct toolbar for the plugin.
Called by ServiceManager
"""
- log.debug(u'addServiceManagerItem')
- #If service item is the same as the current on only change slide
+ log.debug(u'addServiceManagerItem live = %s' % self.isLive)
+ # If service item is the same as the current on only change slide
if item.__eq__(self.serviceItem):
self.PreviewListWidget.selectRow(slideno)
self.onSlideSelected()
@@ -522,17 +533,15 @@ class SlideController(QtGui.QWidget):
Loads a ServiceItem into the system from ServiceManager
Display the slide number passed
"""
- log.debug(u'processManagerItem')
+ log.debug(u'processManagerItem live = %s' % self.isLive)
self.onStopLoop()
- #If old item was a command tell it to stop
+ # If old item was a command tell it to stop
if self.serviceItem:
if self.serviceItem.is_command():
Receiver.send_message(u'%s_stop' %
self.serviceItem.name.lower(), [serviceItem, self.isLive])
if self.serviceItem.is_media():
self.onMediaStop()
- if serviceItem.is_media():
- self.onMediaStart(serviceItem)
if self.isLive:
blanked = self.BlankScreen.isChecked()
else:
@@ -541,12 +550,8 @@ class SlideController(QtGui.QWidget):
[serviceItem, self.isLive, blanked, slideno])
self.slideList = {}
width = self.parent.ControlSplitter.sizes()[self.split]
- #Set pointing cursor when we have somthing to point at
+ # Set pointing cursor when we have somthing to point at
self.PreviewListWidget.setCursor(QtCore.Qt.PointingHandCursor)
- before = time.time()
- #Clear the old serviceItem cache to release memory
- if self.serviceItem and self.serviceItem is not serviceItem:
- self.serviceItem.clear_cache()
self.serviceItem = serviceItem
self.PreviewListWidget.clear()
self.PreviewListWidget.setRowCount(0)
@@ -560,20 +565,19 @@ class SlideController(QtGui.QWidget):
self.PreviewListWidget.rowCount() + 1)
item = QtGui.QTableWidgetItem()
slideHeight = 0
- #It is a based Text Render
if self.serviceItem.is_text():
if frame[u'verseTag']:
bits = frame[u'verseTag'].split(u':')
tag = u'%s\n%s' % (bits[0][0], bits[1][0:] )
tag1 = u'%s%s' % (bits[0][0], bits[1][0:] )
row = tag
+ if self.isLive:
+ if tag1 not in self.slideList:
+ self.slideList[tag1] = framenumber
+ self.SongMenu.menu().addAction(tag1,
+ self.onSongBarHandler)
else:
row += 1
- if self.isLive and frame[u'verseTag'] is not None:
- if tag1 not in self.slideList:
- self.slideList[tag1] = framenumber
- self.SongMenu.menu().addAction(tag1,
- self.onSongBarHandler)
item.setText(frame[u'text'])
else:
label = QtGui.QLabel()
@@ -600,15 +604,14 @@ class SlideController(QtGui.QWidget):
else:
self.PreviewListWidget.selectRow(slideno)
self.enableToolBar(serviceItem)
+ # Pass to display for viewing
+ self.display.buildHtml(self.serviceItem)
+ if serviceItem.is_media():
+ self.onMediaStart(serviceItem)
self.onSlideSelected()
self.PreviewListWidget.setFocus()
Receiver.send_message(u'slidecontroller_%s_started' % self.typePrefix,
[serviceItem])
- if self.serviceItem.is_text():
- st = SlideThread(
- self, self.typePrefix, len(self.serviceItem.get_frames()))
- st.start()
- log.log(15, u'Display Rendering took %4s' % (time.time() - before))
def onTextRequest(self):
"""
@@ -620,7 +623,7 @@ class SlideController(QtGui.QWidget):
dataItem = {}
if self.serviceItem.is_text():
dataItem[u'tag'] = unicode(frame[u'verseTag'])
- dataItem[u'text'] = unicode(frame[u'text'])
+ dataItem[u'text'] = unicode(frame[u'html'])
else:
dataItem[u'tag'] = unicode(framenumber)
dataItem[u'text'] = u''
@@ -630,7 +633,7 @@ class SlideController(QtGui.QWidget):
Receiver.send_message(u'slidecontroller_%s_text_response'
% self.typePrefix, data)
- #Screen event methods
+ # Screen event methods
def onSlideSelectedFirst(self):
"""
Go to the first slide.
@@ -664,9 +667,9 @@ class SlideController(QtGui.QWidget):
"""
Allow the main display to blank the main display at startup time
"""
- log.debug(u'mainDisplaySetBackground')
- if not self.mainDisplay.primary:
- self.onBlankDisplay(True)
+ log.debug(u'mainDisplaySetBackground live = %s' % self.isLive)
+ if not self.display.primary:
+ self.onHideDisplay(True)
def onSlideBlank(self):
"""
@@ -688,7 +691,8 @@ class SlideController(QtGui.QWidget):
self.HideMenu.setDefaultAction(self.BlankScreen)
self.BlankScreen.setChecked(checked)
self.ThemeScreen.setChecked(False)
- self.DesktopScreen.setChecked(False)
+ if self.screens.display_count > 1:
+ self.DesktopScreen.setChecked(False)
QtCore.QSettings().setValue(
self.parent.generalSettingsSection + u'/screen blank',
QtCore.QVariant(checked))
@@ -706,7 +710,8 @@ class SlideController(QtGui.QWidget):
self.HideMenu.setDefaultAction(self.ThemeScreen)
self.BlankScreen.setChecked(False)
self.ThemeScreen.setChecked(checked)
- self.DesktopScreen.setChecked(False)
+ if self.screens.display_count > 1:
+ self.DesktopScreen.setChecked(False)
if checked:
Receiver.send_message(u'maindisplay_hide', HideMode.Theme)
else:
@@ -721,7 +726,8 @@ class SlideController(QtGui.QWidget):
self.HideMenu.setDefaultAction(self.DesktopScreen)
self.BlankScreen.setChecked(False)
self.ThemeScreen.setChecked(False)
- self.DesktopScreen.setChecked(checked)
+ if self.screens.display_count > 1:
+ self.DesktopScreen.setChecked(checked)
if checked:
Receiver.send_message(u'maindisplay_hide', HideMode.Screen)
else:
@@ -758,13 +764,6 @@ class SlideController(QtGui.QWidget):
% self.serviceItem.name.lower(),
[self.serviceItem, self.isLive])
- def slideCache(self, slide):
- """
- Generate a slide cache item rendered and ready for use
- in the background.
- """
- self.serviceItem.get_rendered_frame(int(slide))
-
def onSlideSelected(self):
"""
Generate the preview when you click on a slide.
@@ -778,24 +777,15 @@ class SlideController(QtGui.QWidget):
if self.serviceItem.is_command() and self.isLive:
self.updatePreview()
else:
- before = time.time()
- frame = self.serviceItem.get_rendered_frame(row)
+ frame, raw_html = self.serviceItem.get_rendered_frame(row)
+ if self.serviceItem.is_text():
+ frame = self.display.text(raw_html)
+ else:
+ self.display.image(frame)
if isinstance(frame, QtGui.QImage):
self.SlidePreview.setPixmap(QtGui.QPixmap.fromImage(frame))
else:
- if isinstance(frame[u'main'], basestring):
- self.SlidePreview.setPixmap(
- QtGui.QPixmap(frame[u'main']))
- else:
- self.SlidePreview.setPixmap(
- QtGui.QPixmap.fromImage(frame[u'main']))
- log.log(
- 15, u'Slide Rendering took %4s' % (time.time() - before))
- if self.isLive:
- if self.serviceItem.is_text():
- self.mainDisplay.frameView(frame, True)
- else:
- self.displayManager.displayImage(frame[u'main'])
+ self.SlidePreview.setPixmap(QtGui.QPixmap(frame))
self.selectedRow = row
Receiver.send_message(u'slidecontroller_%s_changed' % self.typePrefix,
row)
@@ -810,8 +800,7 @@ class SlideController(QtGui.QWidget):
row)
def updatePreview(self):
- rm = self.parent.RenderManager
- if not rm.screens.current[u'primary']:
+ if not self.screens.current[u'primary']:
# Grab now, but try again in a couple of seconds if slide change
# is slow
QtCore.QTimer.singleShot(0.5, self.grabMainDisplay)
@@ -819,12 +808,12 @@ class SlideController(QtGui.QWidget):
else:
label = self.PreviewListWidget.cellWidget(
self.PreviewListWidget.currentRow(), 1)
- self.SlidePreview.setPixmap(label.pixmap())
+ if label:
+ self.SlidePreview.setPixmap(label.pixmap())
def grabMainDisplay(self):
- rm = self.parent.RenderManager
winid = QtGui.QApplication.desktop().winId()
- rect = rm.screens.current[u'size']
+ rect = self.screens.current[u'size']
winimg = QtGui.QPixmap.grabWindow(winid, rect.x(),
rect.y(), rect.width(), rect.height())
self.SlidePreview.setPixmap(winimg)
@@ -941,7 +930,9 @@ class SlideController(QtGui.QWidget):
"""
log.debug(u'SlideController onMediaStart')
if self.isLive:
- Receiver.send_message(u'videodisplay_start', item)
+ file = os.path.join(item.get_frame_path(), item.get_frame_title())
+ self.display.video(file, self.volume)
+ self.volumeSlider.setValue(self.volume)
else:
self.mediaObject.stop()
self.mediaObject.clearQueue()
@@ -951,13 +942,21 @@ class SlideController(QtGui.QWidget):
self.seekSlider.show()
self.onMediaPlay()
+ def mediaVolume(self):
+ """
+ Respond to the release of Volume Slider
+ """
+ log.debug(u'SlideController mediaVolume')
+ self.volume = self.volumeSlider.value()
+ self.display.videoVolume(self.volume)
+
def onMediaPause(self):
"""
Respond to the Pause from the media Toolbar
"""
log.debug(u'SlideController onMediaPause')
if self.isLive:
- Receiver.send_message(u'videodisplay_pause')
+ self.display.videoPause()
else:
self.mediaObject.pause()
@@ -967,7 +966,7 @@ class SlideController(QtGui.QWidget):
"""
log.debug(u'SlideController onMediaPlay')
if self.isLive:
- Receiver.send_message(u'videodisplay_play')
+ self.display.videoPlay()
else:
self.SlidePreview.hide()
self.video.show()
@@ -979,7 +978,7 @@ class SlideController(QtGui.QWidget):
"""
log.debug(u'SlideController onMediaStop')
if self.isLive:
- Receiver.send_message(u'videodisplay_stop')
+ self.display.videoStop()
else:
self.mediaObject.stop()
self.video.hide()
diff --git a/openlp/core/ui/thememanager.py b/openlp/core/ui/thememanager.py
index d48926606..5cd989a2a 100644
--- a/openlp/core/ui/thememanager.py
+++ b/openlp/core/ui/thememanager.py
@@ -139,13 +139,13 @@ class ThemeManager(QtGui.QWidget):
"""
log.debug(u'changeGlobalFromTab %s', themeName)
for count in range (0, self.themeListWidget.count()):
- #reset the old name
+ # reset the old name
item = self.themeListWidget.item(count)
oldName = item.text()
newName = unicode(item.data(QtCore.Qt.UserRole).toString())
if oldName != newName:
self.themeListWidget.item(count).setText(newName)
- #Set the new name
+ # Set the new name
if themeName == newName:
name = unicode(translate('OpenLP.ThemeManager',
'%s (default)')) % newName
@@ -161,11 +161,11 @@ class ThemeManager(QtGui.QWidget):
for count in range (0, self.themeListWidget.count()):
item = self.themeListWidget.item(count)
oldName = item.text()
- #reset the old name
+ # reset the old name
if oldName != unicode(item.data(QtCore.Qt.UserRole).toString()):
self.themeListWidget.item(count).setText(
unicode(item.data(QtCore.Qt.UserRole).toString()))
- #Set the new name
+ # Set the new name
if count == selected_row:
self.global_theme = unicode(
self.themeListWidget.item(count).text())
@@ -295,7 +295,7 @@ class ThemeManager(QtGui.QWidget):
path = unicode(path)
if path:
SettingsManager.set_last_dir(self.settingsSection, path, 1)
- themePath = os.path.join(path, theme + u'.theme')
+ themePath = os.path.join(path, theme + u'.thz')
zip = None
try:
zip = zipfile.ZipFile(themePath, u'w')
@@ -346,11 +346,10 @@ class ThemeManager(QtGui.QWidget):
log.debug(u'Load themes from dir')
self.themelist = []
self.themeListWidget.clear()
- #root, dirs, files = os.walk(self.path)
dirList = os.listdir(self.path)
for name in dirList:
if name.endswith(u'.png'):
- #check to see file is in theme root directory
+ # check to see file is in theme root directory
theme = os.path.join(self.path, name)
if os.path.exists(theme):
textName = os.path.splitext(name)[0]
@@ -660,9 +659,8 @@ class ThemeManager(QtGui.QWidget):
"""
Call the RenderManager to build a Sample Image
"""
- log.debug(u'generateImage %s ', themedata)
- frame = self.parent.RenderManager.generate_preview(themedata)
- return frame
+ log.debug(u'generateImage \n%s ', themedata)
+ return self.parent.RenderManager.generate_preview(themedata)
def getPreviewImage(self, theme):
"""
@@ -732,8 +730,6 @@ class ThemeManager(QtGui.QWidget):
theme.display_slideTransition = theme.display_slideTransition
theme.font_footer_color = theme.font_footer_color.strip()
theme.font_footer_height = int(theme.font_footer_height.strip())
- theme.font_footer_indentation = \
- int(theme.font_footer_indentation.strip())
theme.font_footer_italics = str_to_bool(theme.font_footer_italics)
theme.font_footer_name = theme.font_footer_name.strip()
#theme.font_footer_override
@@ -746,7 +742,6 @@ class ThemeManager(QtGui.QWidget):
theme.font_main_color = theme.font_main_color.strip()
theme.font_main_height = int(theme.font_main_height.strip())
theme.font_main_italics = str_to_bool(theme.font_main_italics)
- theme.font_main_indentation = int(theme.font_main_indentation)
theme.font_main_name = theme.font_main_name.strip()
#theme.font_main_override
theme.font_main_proportion = int(theme.font_main_proportion.strip())
@@ -757,3 +752,8 @@ class ThemeManager(QtGui.QWidget):
#theme.theme_mode
theme.theme_name = theme.theme_name.strip()
#theme.theme_version
+ # Remove the Transparent settings as they are not relevent
+ if theme.background_mode == u'transparent':
+ theme.background_mode = u'opaque'
+ theme.background_type = u'solid'
+ theme.background_startColor = u'#000000'
diff --git a/openlp/plugins/alerts/alertsplugin.py b/openlp/plugins/alerts/alertsplugin.py
index 6879d3475..9e1da2267 100644
--- a/openlp/plugins/alerts/alertsplugin.py
+++ b/openlp/plugins/alerts/alertsplugin.py
@@ -80,9 +80,10 @@ class AlertsPlugin(Plugin):
log.info(u'Alerts Initialising')
Plugin.initialise(self)
self.toolsAlertItem.setVisible(True)
+ self.liveController.alertTab = self.alertsTab
def finalise(self):
- log.info(u'Plugin Finalise')
+ log.info(u'Alerts Finalising')
Plugin.finalise(self)
self.toolsAlertItem.setVisible(False)
diff --git a/openlp/plugins/alerts/lib/alertsmanager.py b/openlp/plugins/alerts/lib/alertsmanager.py
index a6960fff0..a418c6fec 100644
--- a/openlp/plugins/alerts/lib/alertsmanager.py
+++ b/openlp/plugins/alerts/lib/alertsmanager.py
@@ -32,18 +32,9 @@ from openlp.core.lib import Receiver, translate
log = logging.getLogger(__name__)
-HTMLCODE = u"""
-
- %s
-
-"""
-
class AlertsManager(QtCore.QObject):
"""
- AlertsTab is the Alerts settings tab in the settings dialog.
+ AlertsManager manages the settings of Alerts.
"""
log.info(u'Alert Manager loaded')
@@ -94,10 +85,7 @@ class AlertsManager(QtCore.QObject):
return
text = self.alertList.pop(0)
alertTab = self.parent.alertsTab
- text = HTMLCODE % (alertTab.font_color, alertTab.bg_color,
- alertTab.font_face, alertTab.font_size, text)
- self.parent.previewController.parent.displayManager.addAlert(text,
- alertTab.location)
+ self.parent.liveController.display.alert(text)
# check to see if we have a timer running
if self.timer_id == 0:
self.timer_id = self.startTimer(int(alertTab.timeout) * 1000)
@@ -111,10 +99,8 @@ class AlertsManager(QtCore.QObject):
"""
log.debug(u'timer event')
- alertTab = self.parent.alertsTab
if event.timerId() == self.timer_id:
- self.parent.previewController.parent.displayManager.addAlert(u'',
- alertTab.location)
+ self.parent.liveController.display.alert(u'')
self.killTimer(self.timer_id)
self.timer_id = 0
self.generateAlert()
diff --git a/openlp/plugins/alerts/lib/alertstab.py b/openlp/plugins/alerts/lib/alertstab.py
index 7527c6a62..77b6e7fb6 100644
--- a/openlp/plugins/alerts/lib/alertstab.py
+++ b/openlp/plugins/alerts/lib/alertstab.py
@@ -261,7 +261,7 @@ class AlertsTab(SettingsTab):
self.font_face = unicode(settings.value(
u'font face', QtCore.QVariant(QtGui.QFont().family())).toString())
self.location = settings.value(
- u'location', QtCore.QVariant(0)).toInt()[0]
+ u'location', QtCore.QVariant(1)).toInt()[0]
settings.endGroup()
self.FontSizeSpinBox.setValue(self.font_size)
self.TimeoutSpinBox.setValue(self.timeout)
@@ -296,3 +296,4 @@ class AlertsTab(SettingsTab):
self.FontPreview.setFont(font)
self.FontPreview.setStyleSheet(u'background-color: %s; color: %s' %
(self.bg_color, self.font_color))
+
diff --git a/openlp/plugins/bibles/lib/mediaitem.py b/openlp/plugins/bibles/lib/mediaitem.py
index c08e62ef5..42129d784 100644
--- a/openlp/plugins/bibles/lib/mediaitem.py
+++ b/openlp/plugins/bibles/lib/mediaitem.py
@@ -504,16 +504,16 @@ class BibleMediaItem(MediaManagerItem):
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
@@ -532,7 +532,11 @@ class BibleMediaItem(MediaManagerItem):
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:
diff --git a/openlp/plugins/custom/forms/editcustomdialog.py b/openlp/plugins/custom/forms/editcustomdialog.py
index 20b7a2bee..d8557b5e2 100644
--- a/openlp/plugins/custom/forms/editcustomdialog.py
+++ b/openlp/plugins/custom/forms/editcustomdialog.py
@@ -27,6 +27,7 @@
from PyQt4 import QtCore, QtGui
from openlp.core.lib import build_icon, translate
+from openlp.core.ui import SpellTextEdit
class Ui_CustomEditDialog(object):
def setupUi(self, customEditDialog):
@@ -73,7 +74,7 @@ class Ui_CustomEditDialog(object):
self.editLayout3.setSpacing(8)
self.editLayout3.setMargin(0)
self.editLayout3.setObjectName(u'editLayout3')
- self.verseTextEdit = QtGui.QTextEdit(self.editWidget)
+ self.verseTextEdit = SpellTextEdit(self)
self.verseTextEdit.setObjectName(u'verseTextEdit')
self.editLayout3.addWidget(self.verseTextEdit)
self.buttonWidget = QtGui.QWidget(self.editWidget)
diff --git a/openlp/plugins/images/lib/mediaitem.py b/openlp/plugins/images/lib/mediaitem.py
index 38476362e..93271a604 100644
--- a/openlp/plugins/images/lib/mediaitem.py
+++ b/openlp/plugins/images/lib/mediaitem.py
@@ -110,8 +110,14 @@ class ImageMediaItem(MediaManagerItem):
u':/slides/slide_blank.png',
translate('ImagePlugin.MediaItem', 'Replace Live Background'),
self.onReplaceClick, False)
+ self.resetButton = self.toolbar.addToolbarButton(
+ translate('ImagePlugin.MediaItem', u'Reset Background'),
+ u':/system/system_close.png',
+ translate('ImagePlugin.MediaItem', 'Reset Live Background'),
+ self.onResetClick, False)
# Add the song widget to the page layout
self.pageLayout.addWidget(self.ImageWidget)
+ self.resetButton.setVisible(False)
def onDeleteClick(self):
"""
@@ -169,6 +175,10 @@ class ImageMediaItem(MediaManagerItem):
else:
return False
+ def onResetClick(self):
+ self.resetButton.setVisible(False)
+ self.parent.liveController.display.resetImage()
+
def onReplaceClick(self):
if check_item_selected(self.listView,
translate('ImagePlugin.MediaItem',
@@ -178,7 +188,8 @@ class ImageMediaItem(MediaManagerItem):
bitem = self.listView.item(item.row())
filename = unicode(bitem.data(QtCore.Qt.UserRole).toString())
frame = QtGui.QImage(unicode(filename))
- self.parent.displayManager.displayImageWithText(frame)
+ self.parent.liveController.display.image(frame)
+ self.resetButton.setVisible(True)
def onPreviewClick(self):
MediaManagerItem.onPreviewClick(self)
diff --git a/openlp/plugins/media/lib/mediaitem.py b/openlp/plugins/media/lib/mediaitem.py
index 72e5445ef..447d4ccb5 100644
--- a/openlp/plugins/media/lib/mediaitem.py
+++ b/openlp/plugins/media/lib/mediaitem.py
@@ -97,8 +97,17 @@ class MediaMediaItem(MediaManagerItem):
u':/slides/slide_blank.png',
translate('MediaPlugin.MediaItem', 'Replace Live Background'),
self.onReplaceClick, False)
+ self.resetButton = self.toolbar.addToolbarButton(
+ u'Reset Background', u':/system/system_close.png',
+ translate('ImagePlugin.MediaItem', 'Reset Live Background'),
+ self.onResetClick, False)
# Add the song widget to the page layout
self.pageLayout.addWidget(self.ImageWidget)
+ self.resetButton.setVisible(False)
+
+ def onResetClick(self):
+ self.resetButton.setVisible(False)
+ self.parent.liveController.display.resetVideo()
def onReplaceClick(self):
if check_item_selected(self.listView,
@@ -106,7 +115,8 @@ class MediaMediaItem(MediaManagerItem):
'You must select a media file to replace the background with.')):
item = self.listView.currentItem()
filename = unicode(item.data(QtCore.Qt.UserRole).toString())
- self.parent.displayManager.displayVideo(filename)
+ self.parent.liveController.display.video(filename, 0)
+ self.resetButton.setVisible(True)
def generateSlideData(self, service_item, item=None):
if item is None:
diff --git a/openlp/plugins/songs/forms/editsongform.py b/openlp/plugins/songs/forms/editsongform.py
index 1567fa62e..c98054c6e 100644
--- a/openlp/plugins/songs/forms/editsongform.py
+++ b/openlp/plugins/songs/forms/editsongform.py
@@ -314,7 +314,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
author = self.songmanager.get_object(Author, item_id)
if author in self.song.authors:
QtGui.QMessageBox.warning(self,
- translate('SongsPlugin.EditSongForm', 'Error'),
+ translate('SongsPlugin.EditSongForm', 'Error'),
translate('SongsPlugin.EditSongForm', 'This author is '
'already in the list.'))
else:
@@ -422,7 +422,9 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
self.VerseDeleteButton.setEnabled(True)
def onVerseAddButtonClicked(self):
- self.verse_form.setVerse(u'', True)
+ # Allow insert button as you do not know if multiple verses will
+ # be entered.
+ self.verse_form.setVerse(u'')
if self.verse_form.exec_():
afterText, verse, subVerse = self.verse_form.getVerse()
data = u'%s:%s' % (verse, subVerse)
diff --git a/openlp/plugins/songs/forms/editversedialog.py b/openlp/plugins/songs/forms/editversedialog.py
index 10c0d6849..e165b2b86 100644
--- a/openlp/plugins/songs/forms/editversedialog.py
+++ b/openlp/plugins/songs/forms/editversedialog.py
@@ -27,6 +27,7 @@
from PyQt4 import QtCore, QtGui
from openlp.core.lib import build_icon, translate
+from openlp.core.ui import SpellTextEdit
from openlp.plugins.songs.lib import VerseType
class Ui_EditVerseDialog(object):
@@ -38,7 +39,7 @@ class Ui_EditVerseDialog(object):
self.EditVerseLayout.setSpacing(8)
self.EditVerseLayout.setMargin(8)
self.EditVerseLayout.setObjectName(u'EditVerseLayout')
- self.VerseTextEdit = QtGui.QPlainTextEdit(EditVerseDialog)
+ self.VerseTextEdit = SpellTextEdit(EditVerseDialog)
self.VerseTextEdit.setObjectName(u'VerseTextEdit')
self.EditVerseLayout.addWidget(self.VerseTextEdit)
self.VerseTypeLayout = QtGui.QHBoxLayout()
diff --git a/openlp/plugins/songs/forms/editverseform.py b/openlp/plugins/songs/forms/editverseform.py
index 3622593a0..46d9f954c 100644
--- a/openlp/plugins/songs/forms/editverseform.py
+++ b/openlp/plugins/songs/forms/editverseform.py
@@ -45,6 +45,9 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog):
"""
QtGui.QDialog.__init__(self, parent)
self.setupUi(self)
+ QtCore.QObject.connect(self.VerseTextEdit,
+ QtCore.SIGNAL('customContextMenuRequested(QPoint)'),
+ self.contextMenu)
QtCore.QObject.connect(
self.InsertButton,
QtCore.SIGNAL(u'clicked()'),
@@ -57,6 +60,10 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog):
)
self.verse_regex = re.compile(r'---\[([-\w]+):([\d]+)\]---')
+ def contextMenu(self, point):
+ item = self.serviceManagerList.itemAt(point)
+ print item
+
def insertVerse(self, title, num=1):
if self.VerseTextEdit.textCursor().columnNumber() != 0:
self.VerseTextEdit.insertPlainText(u'\n')
diff --git a/openlp/plugins/songs/forms/songimportform.py b/openlp/plugins/songs/forms/songimportform.py
index b997238a9..68bba299d 100644
--- a/openlp/plugins/songs/forms/songimportform.py
+++ b/openlp/plugins/songs/forms/songimportform.py
@@ -302,8 +302,8 @@ class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard):
Stop the import on pressing the cancel button.
"""
log.debug('Cancel button pressed!')
- if self.currentId() == 3:
- Receiver.send_message(u'song_stop_import')
+ if self.currentId() == 2:
+ Receiver.send_message(u'songs_stop_import')
def onCurrentIdChanged(self, id):
if id == 2:
diff --git a/openlp/plugins/songs/lib/olpimport.py b/openlp/plugins/songs/lib/olpimport.py
index 63f99dc7b..6b993994c 100644
--- a/openlp/plugins/songs/lib/olpimport.py
+++ b/openlp/plugins/songs/lib/olpimport.py
@@ -86,7 +86,6 @@ class OpenLPSongImport(SongImport):
The database providing the data to import.
"""
SongImport.__init__(self, manager)
- #self.master_manager = master_manager
self.import_source = u'sqlite:///%s' % kwargs[u'filename']
log.debug(self.import_source)
self.source_session = None
@@ -145,7 +144,12 @@ class OpenLPSongImport(SongImport):
mapper(OldTopic, source_topics_table)
source_songs = self.source_session.query(OldSong).all()
+ song_total = len(source_songs)
+ self.import_wizard.importProgressBar.setMaximum(song_total)
+ song_count = 1
for song in source_songs:
+ self.import_wizard.incrementProgressBar(
+ u'Importing song %s of %s' % (song_count, song_total))
new_song = Song()
new_song.title = song.title
if has_media_files:
@@ -212,4 +216,8 @@ class OpenLPSongImport(SongImport):
# new_song.media_files.append(MediaFile.populate(
# file_name=media_file.file_name))
self.manager.save_object(new_song)
+ song_count += 1
+ if self.stop_import_flag:
+ return False
engine.dispose()
+ return True
diff --git a/openlp/plugins/songs/lib/songimport.py b/openlp/plugins/songs/lib/songimport.py
index 81c2d08e2..2ffb0beda 100644
--- a/openlp/plugins/songs/lib/songimport.py
+++ b/openlp/plugins/songs/lib/songimport.py
@@ -24,14 +24,18 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
+import logging
import re
+from PyQt4 import QtCore
-from openlp.core.lib import translate
+from openlp.core.lib import Receiver, translate
from openlp.plugins.songs.lib import VerseType
from openlp.plugins.songs.lib.db import Song, Author, Topic, Book
from openlp.plugins.songs.lib.xml import SongXMLBuilder
-class SongImport(object):
+log = logging.getLogger(__name__)
+
+class SongImport(QtCore.QObject):
"""
Helper class for import a song from a third party source into OpenLP
@@ -39,7 +43,6 @@ class SongImport(object):
whether the authors etc already exist and add them or refer to them
as necessary
"""
-
def __init__(self, manager):
"""
Initialise and create defaults for properties
@@ -48,6 +51,7 @@ class SongImport(object):
database access is performed
"""
self.manager = manager
+ self.stop_import_flag = False
self.title = u''
self.song_number = u''
self.alternate_title = u''
@@ -67,6 +71,15 @@ class SongImport(object):
'SongsPlugin.SongImport', 'copyright'))
self.copyright_symbol = unicode(translate(
'SongsPlugin.SongImport', '\xa9'))
+ QtCore.QObject.connect(Receiver.get_receiver(),
+ QtCore.SIGNAL(u'songs_stop_import'), self.stop_import)
+
+ def stop_import(self):
+ """
+ Sets the flag for importers to stop their import
+ """
+ log.debug(u'Stopping songs import')
+ self.stop_import_flag = True
def register(self, import_wizard):
self.import_wizard = import_wizard
diff --git a/resources/Fedora/191/OpenLP.spec b/resources/Fedora/191/OpenLP.spec
new file mode 100644
index 000000000..16c140ab8
--- /dev/null
+++ b/resources/Fedora/191/OpenLP.spec
@@ -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 1.9.1.1
+- Initial build version - Alpha 1 Release