diff --git a/openlp/core/lib/__init__.py b/openlp/core/lib/__init__.py index 25f7630f9..1f911491f 100644 --- a/openlp/core/lib/__init__.py +++ b/openlp/core/lib/__init__.py @@ -316,6 +316,7 @@ def expand_tags(text): text = text.replace(tag[u'end tag'], tag[u'end html']) return text +from spelltextedit import SpellTextEdit from eventreceiver import Receiver from settingsmanager import SettingsManager from plugin import PluginStatus, Plugin diff --git a/openlp/core/lib/htmlbuilder.py b/openlp/core/lib/htmlbuilder.py index e6a7857ff..2d9323a8b 100644 --- a/openlp/core/lib/htmlbuilder.py +++ b/openlp/core/lib/htmlbuilder.py @@ -24,10 +24,13 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### +import logging from PyQt4 import QtWebKit from openlp.core.lib import image_to_byte +log = logging.getLogger(__name__) + HTMLSRC = u""" @@ -39,7 +42,7 @@ HTMLSRC = u""" border: 0; } body { - background-color: black; + %s; } .size { position: absolute; @@ -192,7 +195,7 @@ body { function show_text(newtext){ if(timer != null) clearTimeout(timer); - text_fade('lyricsmain', newtext); + text_fade('lyricsmain', newtext); text_fade('lyricsoutline', newtext); text_fade('lyricsshadow', newtext); if(text_opacity()==1) return; @@ -233,7 +236,7 @@ body { var text = document.getElementById('lyricsmain'); return getComputedStyle(text, '').opacity; } - + function show_text_complete(){ return (text_opacity()==1); } @@ -271,53 +274,89 @@ def build_html(item, screen, alert, islive): image = u'data:image/png;base64,%s' % image_to_byte(item.bg_frame) else: image = u'' - html = HTMLSRC % (width, height, + html = HTMLSRC % (build_background_css(item, width, height), + width, height, build_alert_css(alert, width), build_footer_css(item), build_lyrics_css(item, webkitvers), u'true' if theme and theme.display_slideTransition and islive \ else u'false', - image, + image, build_lyrics_html(item, webkitvers)) return html def webkit_version(): try: webkitvers = float(QtWebKit.qWebKitVersion()) + log.debug(u'Webkit version = %s' % webkitvers) except AttributeError: webkitvers = 0 return webkitvers +def build_background_css(item, width, height): + """ + Build the background css + + `item` + Service Item containing theme and location information + + """ + width = int(width) / 2 + theme = item.themedata + background = u'background-color: black' + if theme: + if theme.background_type == u'solid': + background = u'background-color: %s' % theme.background_color + else: + if theme.background_direction == u'horizontal': + background = \ + u'background: ' \ + u'-webkit-gradient(linear, left top, left bottom, ' \ + 'from(%s), to(%s))' % (theme.background_startColor, + theme.background_endColor) + elif theme.background_direction == u'vertical': + background = \ + u'background: -webkit-gradient(linear, left top, ' \ + u'right top, from(%s), to(%s))' % \ + (theme.background_startColor, theme.background_endColor) + else: + background = \ + u'background: -webkit-gradient(radial, %s 50%%, 100, %s ' \ + u'50%%, %s, from(%s), to(%s))' % (width, width, width, + theme.background_startColor, theme.background_endColor) + return background + def build_lyrics_css(item, webkitvers): """ Build the lyrics display css `item` Service Item containing theme and location information - + `webkitvers` The version of qtwebkit we're using """ style = """ -.lyricstable { - z-index:4; - position: absolute; - display: table; - %s -} -.lyricscell { - display:table-cell; +.lyricstable { + z-index:4; + position: absolute; + display: table; %s } -.lyricsmain { -%s +.lyricscell { + display:table-cell; + word-wrap: break-word; + %s } -.lyricsoutline { -%s +.lyricsmain { +%s } -.lyricsshadow { -%s +.lyricsoutline { +%s +} +.lyricsshadow { +%s } """ theme = item.themedata @@ -332,19 +371,19 @@ def build_lyrics_css(item, webkitvers): lyrics = build_lyrics_format_css(theme, item.main.width(), item.main.height()) # For performance reasons we want to show as few DIV's as possible, - # especially when animating/transitions. - # However some bugs in older versions of qtwebkit mean we need to + # especially when animating/transitions. + # However some bugs in older versions of qtwebkit mean we need to # perform workarounds and add extra divs. Only do these when needed. # - # Before 533.3 the webkit-text-fill colour wasn't displayed, only the + # Before 533.3 the webkit-text-fill colour wasn't displayed, only the # stroke (outline) color. So put stroke layer underneath the main text. # - # Before 534.4 the webkit-text-stroke was sometimes out of alignment + # Before 534.4 the webkit-text-stroke was sometimes out of alignment # with the fill, or normal text. letter-spacing=1 is workaround # https://bugs.webkit.org/show_bug.cgi?id=44403 # - # Before 534.4 the text-shadow didn't get displayed when - # webkit-text-stroke was used. So use an offset text layer underneath. + # Before 534.4 the text-shadow didn't get displayed when + # webkit-text-stroke was used. So use an offset text layer underneath. # https://bugs.webkit.org/show_bug.cgi?id=19728 if webkitvers >= 533.3: lyricsmain += build_lyrics_outline_css(theme) @@ -422,11 +461,11 @@ def build_lyrics_html(item, webkitvers): `item` Service Item containing theme and location information - + `webkitvers` The version of qtwebkit we're using """ - # Bugs in some versions of QtWebKit mean we sometimes need additional + # Bugs in some versions of QtWebKit mean we sometimes need additional # divs for outline and shadow, since the CSS doesn't work. # To support vertical alignment middle and bottom, nested div's using # display:table/display:table-cell are required for each lyric block. @@ -444,7 +483,7 @@ def build_lyrics_html(item, webkitvers): u'
' return lyrics - + def build_footer_css(item): """ Build the display of the item footer diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index 46e0452ac..1b1605e00 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -185,44 +185,47 @@ class Renderer(object): 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_type == u'solid': - painter.fillRect(self.frame.rect(), - QtGui.QColor(self._theme.background_color)) + self.bg_frame = None +# painter.fillRect(self.frame.rect(), +# QtGui.QColor(self._theme.background_color)) elif self._theme.background_type == u'gradient': + self.bg_frame = None # 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) +# 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) +# painter.end() elif self._theme.background_type == u'image': # image + painter = QtGui.QPainter() + painter.begin(self.bg_frame) painter.fillRect(self.frame.rect(), QtCore.Qt.black) if self.bg_image: painter.drawImage(0, 0, self.bg_image) - painter.end() + painter.end() diff --git a/openlp/core/lib/spelltextedit.py b/openlp/core/lib/spelltextedit.py new file mode 100644 index 000000000..7d227079b --- /dev/null +++ b/openlp/core/lib/spelltextedit.py @@ -0,0 +1,155 @@ +# -*- 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 # +############################################################################### + +import re +import sys +try: + import enchant + enchant_available = True +except ImportError: + enchant_available = False + +# based on code from +# http://john.nachtimwald.com/2009/08/22/qplaintextedit-with-in-line-spell-check/ + +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() + # only select text if not already selected + if not cursor.hasSelection(): + 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()))) diff --git a/openlp/core/ui/__init__.py b/openlp/core/ui/__init__.py index dad79cb7b..33ba25046 100644 --- a/openlp/core/ui/__init__.py +++ b/openlp/core/ui/__init__.py @@ -27,141 +27,6 @@ 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. diff --git a/openlp/core/ui/maindisplay.py b/openlp/core/ui/maindisplay.py index 868399f83..2c9472414 100644 --- a/openlp/core/ui/maindisplay.py +++ b/openlp/core/ui/maindisplay.py @@ -138,7 +138,7 @@ class MainDisplay(DisplayWidget): painter_image = QtGui.QPainter() painter_image.begin(self.black) painter_image.fillRect(self.black.rect(), QtCore.Qt.black) - #Build the initial frame. + # Build the initial frame. initialFrame = QtGui.QImage( self.screens.current[u'size'].width(), self.screens.current[u'size'].height(), diff --git a/openlp/plugins/custom/forms/editcustomdialog.py b/openlp/plugins/custom/forms/editcustomdialog.py index d8557b5e2..84a310cb9 100644 --- a/openlp/plugins/custom/forms/editcustomdialog.py +++ b/openlp/plugins/custom/forms/editcustomdialog.py @@ -26,8 +26,7 @@ from PyQt4 import QtCore, QtGui -from openlp.core.lib import build_icon, translate -from openlp.core.ui import SpellTextEdit +from openlp.core.lib import build_icon, translate, SpellTextEdit class Ui_CustomEditDialog(object): def setupUi(self, customEditDialog): diff --git a/openlp/plugins/songs/forms/editversedialog.py b/openlp/plugins/songs/forms/editversedialog.py index 64d56322f..43dc8b96d 100644 --- a/openlp/plugins/songs/forms/editversedialog.py +++ b/openlp/plugins/songs/forms/editversedialog.py @@ -26,8 +26,7 @@ from PyQt4 import QtCore, QtGui -from openlp.core.lib import build_icon, translate -from openlp.core.ui import SpellTextEdit +from openlp.core.lib import build_icon, translate, SpellTextEdit from openlp.plugins.songs.lib import VerseType class Ui_EditVerseDialog(object):