From 3447c7fed617e32d36a2b72c4b9a4eac6122c45d Mon Sep 17 00:00:00 2001 From: Jon Tibble Date: Fri, 2 Jul 2010 15:57:48 +0100 Subject: [PATCH 01/21] XML: Start refactoring --- documentation/source/core/lib.rst | 6 -- openlp/core/lib/__init__.py | 1 - openlp/core/lib/xmlrootclass.py | 104 ---------------------------- openlp/plugins/songs/lib/songxml.py | 79 +++++++++++++++++++-- 4 files changed, 72 insertions(+), 118 deletions(-) delete mode 100644 openlp/core/lib/xmlrootclass.py diff --git a/documentation/source/core/lib.rst b/documentation/source/core/lib.rst index 12c7b702c..dd90b24a9 100644 --- a/documentation/source/core/lib.rst +++ b/documentation/source/core/lib.rst @@ -84,9 +84,3 @@ .. autoclass:: openlp.core.lib.toolbar.OpenLPToolbar :members: -:mod:`XmlRootClass` -------------------- - -.. autoclass:: openlp.core.lib.xmlrootclass.XmlRootClass - :members: - diff --git a/openlp/core/lib/__init__.py b/openlp/core/lib/__init__.py index d6f805c98..5a4725c80 100644 --- a/openlp/core/lib/__init__.py +++ b/openlp/core/lib/__init__.py @@ -216,7 +216,6 @@ from settingsmanager import SettingsManager from plugin import PluginStatus, Plugin from pluginmanager import PluginManager from settingstab import SettingsTab -from xmlrootclass import XmlRootClass from serviceitem import ServiceItem from serviceitem import ServiceItemType from serviceitem import ItemCapabilities diff --git a/openlp/core/lib/xmlrootclass.py b/openlp/core/lib/xmlrootclass.py deleted file mode 100644 index 1ea1d41a2..000000000 --- a/openlp/core/lib/xmlrootclass.py +++ /dev/null @@ -1,104 +0,0 @@ -# -*- 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, Christian Richter, Maikel Stuivenberg, Martin # -# Thompson, Jon Tibble, Carsten Tinggaard # -# --------------------------------------------------------------------------- # -# 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 os -import sys - -from xml.etree.ElementTree import ElementTree, XML - -sys.path.append(os.path.abspath(os.path.join(u'.', u'..', u'..'))) - -class XmlRootClass(object): - """ - Root class for themes, songs etc - - This class provides interface for parsing xml files into object attributes. - - If you overload this class and provide a function called `post_tag_hook`, - it will be called thusly for each `tag, value` pair:: - - (element.tag, val) = self.post_tag_hook(element.tag, val) - """ - def _set_from_xml(self, xml, root_tag): - """ - Set song properties from given xml content. - - ``xml`` - Formatted xml tags and values. - ``root_tag`` - The root tag of the xml. - """ - root = ElementTree(element=XML(xml)) - xml_iter = root.getiterator() - for element in xml_iter: - if element.tag != root_tag: - text = element.text - if text is None: - val = text - elif isinstance(text, basestring): - # Strings need special handling to sort the colours out - if text[0] == u'$': - # This might be a hex number, let's try to convert it. - try: - val = int(text[1:], 16) - except ValueError: - pass - else: - # Let's just see if it's a integer. - try: - val = int(text) - except ValueError: - # Ok, it seems to be a string. - val = text - if hasattr(self, u'post_tag_hook'): - (element.tag, val) = \ - self.post_tag_hook(element.tag, val) - setattr(self, element.tag, val) - - def __str__(self): - """ - Return string with all public attributes - - The string is formatted with one attribute per line - If the string is split on newline then the length of the - list is equal to the number of attributes - """ - attributes = [] - for attrib in dir(self): - if not attrib.startswith(u'_'): - attributes.append( - u'%30s : %s' % (attrib, getattr(self, attrib))) - return u'\n'.join(attributes) - - def _get_as_string(self): - """ - Return one string with all public attributes - """ - result = u'' - for attrib in dir(self): - if not attrib.startswith(u'_'): - result += u'_%s_' % getattr(self, attrib) - return result - diff --git a/openlp/plugins/songs/lib/songxml.py b/openlp/plugins/songs/lib/songxml.py index 2f13e5f60..c4683533d 100644 --- a/openlp/plugins/songs/lib/songxml.py +++ b/openlp/plugins/songs/lib/songxml.py @@ -28,10 +28,12 @@ import sys import os from types import ListType +from xml.etree.ElementTree import ElementTree, XML -sys.path.append(os.path.abspath(u'./../../../..')) +# Do we need these two lines? +#sys.path.append(os.path.abspath(u'./../../../..')) +#sys.path.append(os.path.abspath(os.path.join(u'.', u'..', u'..'))) -from openlp.core.lib import XmlRootClass log = logging.getLogger(__name__) @@ -74,14 +76,77 @@ _BLANK_OPENSONG_XML = \ ''' -class _OpenSong(XmlRootClass): - """Class for import of OpenSong""" - +class _OpenSong(object): + """ + Class for import of OpenSong + """ def __init__(self, xmlContent = None): - """Initialize from given xml content""" - super(_OpenSong, self).__init__() + """ + Initialize from given xml content + """ self.from_buffer(xmlContent) + def _set_from_xml(self, xml, root_tag): + """ + Set song properties from given xml content. + + ``xml`` + Formatted xml tags and values. + ``root_tag`` + The root tag of the xml. + """ + root = ElementTree(element=XML(xml)) + xml_iter = root.getiterator() + for element in xml_iter: + if element.tag != root_tag: + text = element.text + if text is None: + val = text + elif isinstance(text, basestring): + # Strings need special handling to sort the colours out + if text[0] == u'$': + # This might be a hex number, let's try to convert it. + try: + val = int(text[1:], 16) + except ValueError: + pass + else: + # Let's just see if it's a integer. + try: + val = int(text) + except ValueError: + # Ok, it seems to be a string. + val = text + if hasattr(self, u'post_tag_hook'): + (element.tag, val) = \ + self.post_tag_hook(element.tag, val) + setattr(self, element.tag, val) + + def __str__(self): + """ + Return string with all public attributes + + The string is formatted with one attribute per line + If the string is split on newline then the length of the + list is equal to the number of attributes + """ + attributes = [] + for attrib in dir(self): + if not attrib.startswith(u'_'): + attributes.append( + u'%30s : %s' % (attrib, getattr(self, attrib))) + return u'\n'.join(attributes) + + def _get_as_string(self): + """ + Return one string with all public attributes + """ + result = u'' + for attrib in dir(self): + if not attrib.startswith(u'_'): + result += u'_%s_' % getattr(self, attrib) + return result + def _reset(self): """Reset all song attributes""" self._setFromXml(_BLANK_OPENSONG_XML, 'song') From 0c184d5e601ccf3e83207d61cf36c21305ae7837 Mon Sep 17 00:00:00 2001 From: Jon Tibble Date: Sat, 3 Jul 2010 02:07:36 +0100 Subject: [PATCH 02/21] Remove some unused methods --- openlp/plugins/songs/lib/songxml.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/openlp/plugins/songs/lib/songxml.py b/openlp/plugins/songs/lib/songxml.py index e26a06e90..08234f093 100644 --- a/openlp/plugins/songs/lib/songxml.py +++ b/openlp/plugins/songs/lib/songxml.py @@ -317,14 +317,6 @@ class Song(object): self.set_lyrics(u'') return - def set_songid(self, songid): - """Set the songid for the database""" - self.songid = songid - - def get_songid(self): - """Return the songid for the database""" - return self.songid - def from_opensong_buffer(self, xmlcontent): """Initialize from buffer(string) of xml lines in opensong format""" self._reset() @@ -388,10 +380,6 @@ class Song(object): """Return title value""" return self.title - def get_search_title(self): - """Return search_title""" - return self.search_title - def from_ccli_text_buffer(self, textList): """ Create song from a list of texts (strings) - CCLI text format expected From 497d1c9dc99c9b56e46a92f6134fdafbeb3ebe59 Mon Sep 17 00:00:00 2001 From: Jon Tibble Date: Sat, 3 Jul 2010 02:33:40 +0100 Subject: [PATCH 03/21] XML: Put it where it should be --- documentation/source/core/lib.rst | 13 -- openlp/core/lib/__init__.py | 1 - openlp/plugins/custom/forms/editcustomform.py | 9 +- openlp/plugins/custom/lib/__init__.py | 1 + openlp/plugins/custom/lib/customxmlhandler.py | 156 ++++++++++++++++++ openlp/plugins/custom/lib/mediaitem.py | 7 +- openlp/plugins/songs/forms/editsongform.py | 4 +- openlp/plugins/songs/lib/__init__.py | 1 + openlp/plugins/songs/lib/mediaitem.py | 5 +- openlp/plugins/songs/lib/songimport.py | 4 +- .../songs}/lib/songxmlhandler.py | 0 11 files changed, 174 insertions(+), 27 deletions(-) create mode 100644 openlp/plugins/custom/lib/customxmlhandler.py rename openlp/{core => plugins/songs}/lib/songxmlhandler.py (100%) diff --git a/documentation/source/core/lib.rst b/documentation/source/core/lib.rst index dd90b24a9..43ca90b3b 100644 --- a/documentation/source/core/lib.rst +++ b/documentation/source/core/lib.rst @@ -60,18 +60,6 @@ .. autoclass:: openlp.core.lib.settingstab.SettingsTab :members: -:mod:`SongXMLBuilder` ---------------------- - -.. autoclass:: openlp.core.lib.songxmlhandler.SongXMLBuilder - :members: - -:mod:`SongXMLParser` --------------------- - -.. autoclass:: openlp.core.lib.songxmlhandler.SongXMLParser - :members: - :mod:`ThemeXML` --------------- @@ -83,4 +71,3 @@ .. autoclass:: openlp.core.lib.toolbar.OpenLPToolbar :members: - diff --git a/openlp/core/lib/__init__.py b/openlp/core/lib/__init__.py index 5a4725c80..11ba7e2dc 100644 --- a/openlp/core/lib/__init__.py +++ b/openlp/core/lib/__init__.py @@ -221,7 +221,6 @@ from serviceitem import ServiceItemType from serviceitem import ItemCapabilities from toolbar import OpenLPToolbar from dockwidget import OpenLPDockWidget -from songxmlhandler import SongXMLBuilder, SongXMLParser from themexmlhandler import ThemeXML from renderer import Renderer from rendermanager import RenderManager diff --git a/openlp/plugins/custom/forms/editcustomform.py b/openlp/plugins/custom/forms/editcustomform.py index a266c44c5..24810eb0b 100644 --- a/openlp/plugins/custom/forms/editcustomform.py +++ b/openlp/plugins/custom/forms/editcustomform.py @@ -28,7 +28,8 @@ import logging from PyQt4 import QtCore, QtGui from editcustomdialog import Ui_customEditDialog -from openlp.core.lib import SongXMLBuilder, SongXMLParser, Receiver, translate +from openlp.core.lib import Receiver, translate +from openlp.plugins.custom.lib import CustomXMLBuilder, CustomXMLParser from openlp.plugins.custom.lib.db import CustomSlide log = logging.getLogger(__name__) @@ -119,8 +120,8 @@ class EditCustomForm(QtGui.QDialog, Ui_customEditDialog): self.customSlide = self.custommanager.get_object(CustomSlide, id) self.TitleEdit.setText(self.customSlide.title) self.CreditEdit.setText(self.customSlide.credits) - songXML = SongXMLParser(self.customSlide.text) - verseList = songXML.get_verses() + customXML = CustomXMLParser(self.customSlide.text) + verseList = customXML.get_verses() for verse in verseList: self.VerseListView.addItem(verse[1]) theme = self.customSlide.theme_name @@ -152,7 +153,7 @@ class EditCustomForm(QtGui.QDialog, Ui_customEditDialog): translate('CustomPlugin.EditCustomForm', 'Error'), message, QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok)) return False - sxml = SongXMLBuilder() + sxml = CustomXMLBuilder() sxml.new_document() sxml.add_lyrics_to_song() count = 1 diff --git a/openlp/plugins/custom/lib/__init__.py b/openlp/plugins/custom/lib/__init__.py index 0d9de3173..1eea5e32d 100644 --- a/openlp/plugins/custom/lib/__init__.py +++ b/openlp/plugins/custom/lib/__init__.py @@ -23,5 +23,6 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### +from customxmlhandler import CustomXMLBuilder, CustomXMLParser from mediaitem import CustomMediaItem from customtab import CustomTab diff --git a/openlp/plugins/custom/lib/customxmlhandler.py b/openlp/plugins/custom/lib/customxmlhandler.py new file mode 100644 index 000000000..ebb8b1685 --- /dev/null +++ b/openlp/plugins/custom/lib/customxmlhandler.py @@ -0,0 +1,156 @@ +# -*- 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, Christian Richter, Maikel Stuivenberg, Martin # +# Thompson, Jon Tibble, Carsten Tinggaard # +# --------------------------------------------------------------------------- # +# 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 # +############################################################################### +""" +The :mod:`customxmlhandler` module provides the XML functionality for custom +slides + +The basic XML is of the format:: + + + + + + + + + +""" + +import logging + +from xml.dom.minidom import Document +from xml.etree.ElementTree import ElementTree, XML, dump +from xml.parsers.expat import ExpatError + +log = logging.getLogger(__name__) + +class CustomXMLBuilder(object): + """ + This class builds the XML used to describe songs. + """ + log.info(u'CustomXMLBuilder Loaded') + + def __init__(self): + """ + Set up the song builder. + """ + # Create the minidom document + self.song_xml = Document() + + def new_document(self): + """ + Create a new song XML document. + """ + # Create the base element + self.song = self.song_xml.createElement(u'song') + self.song_xml.appendChild(self.song) + self.song.setAttribute(u'version', u'1.0') + + def add_lyrics_to_song(self): + """ + Set up and add a ```` tag which contains the lyrics of the + song. + """ + # Create the main element + self.lyrics = self.song_xml.createElement(u'lyrics') + self.lyrics.setAttribute(u'language', u'en') + self.song.appendChild(self.lyrics) + + def add_verse_to_lyrics(self, type, number, content): + """ + Add a verse to the ```` tag. + + ``type`` + A string denoting the type of verse. Possible values are "Chorus", + "Verse", "Bridge", and "Custom". + + ``number`` + An integer denoting the number of the item, for example: verse 1. + + ``content`` + The actual text of the verse to be stored. + """ + #log.debug(u'add_verse_to_lyrics %s, %s\n%s' % (type, number, content)) + verse = self.song_xml.createElement(u'verse') + verse.setAttribute(u'type', type) + verse.setAttribute(u'label', number) + self.lyrics.appendChild(verse) + # add data as a CDATA section to protect the XML from special chars + cds = self.song_xml.createCDATASection(content) + verse.appendChild(cds) + + def dump_xml(self): + """ + Debugging aid to dump XML so that we can see what we have. + """ + return self.song_xml.toprettyxml(indent=u' ') + + def extract_xml(self): + """ + Extract our newly created XML song. + """ + return self.song_xml.toxml(u'utf-8') + + +class CustomXMLParser(object): + """ + A class to read in and parse a song's XML. + """ + log.info(u'CustomXMLParser Loaded') + + def __init__(self, xml): + """ + Set up our song XML parser. + + ``xml`` + The XML of the song to be parsed. + """ + self.song_xml = None + try: + self.song_xml = ElementTree( + element=XML(unicode(xml).encode('unicode-escape'))) + except ExpatError: + log.exception(u'Invalid xml %s', xml) + + def get_verses(self): + """ + Iterates through the verses in the XML and returns a list of verses + and their attributes. + """ + xml_iter = self.song_xml.getiterator() + verse_list = [] + for element in xml_iter: + if element.tag == u'verse': + if element.text is None: + element.text = u'' + verse_list.append([element.attrib, + unicode(element.text).decode('unicode-escape')]) + return verse_list + + def dump_xml(self): + """ + Debugging aid to dump XML so that we can see what we have. + """ + return dump(self.song_xml) diff --git a/openlp/plugins/custom/lib/mediaitem.py b/openlp/plugins/custom/lib/mediaitem.py index 8f4cf6a7f..9cc5627ed 100644 --- a/openlp/plugins/custom/lib/mediaitem.py +++ b/openlp/plugins/custom/lib/mediaitem.py @@ -27,8 +27,9 @@ import logging from PyQt4 import QtCore, QtGui -from openlp.core.lib import MediaManagerItem, SongXMLParser, BaseListWithDnD, \ +from openlp.core.lib import MediaManagerItem, BaseListWithDnD, \ Receiver, ItemCapabilities, translate, check_item_selected +from openlp.plugins.custom.lib import CustomXMLParser from openlp.plugins.custom.lib.db import CustomSlide log = logging.getLogger(__name__) @@ -170,8 +171,8 @@ class CustomMediaItem(MediaManagerItem): theme = customSlide.theme_name if theme: service_item.theme = theme - songXML = SongXMLParser(customSlide.text) - verseList = songXML.get_verses() + customXML = CustomXMLParser(customSlide.text) + verseList = customXML.get_verses() for verse in verseList: raw_slides.append(verse[1]) service_item.title = title diff --git a/openlp/plugins/songs/forms/editsongform.py b/openlp/plugins/songs/forms/editsongform.py index 8c39a2fe8..18c613abf 100644 --- a/openlp/plugins/songs/forms/editsongform.py +++ b/openlp/plugins/songs/forms/editsongform.py @@ -28,9 +28,9 @@ import re from PyQt4 import QtCore, QtGui -from openlp.core.lib import SongXMLBuilder, SongXMLParser, Receiver, translate +from openlp.core.lib import Receiver, translate from openlp.plugins.songs.forms import EditVerseForm -from openlp.plugins.songs.lib import VerseType +from openlp.plugins.songs.lib import SongXMLBuilder, SongXMLParser, VerseType from openlp.plugins.songs.lib.db import Book, Song, Author, Topic from editsongdialog import Ui_EditSongDialog diff --git a/openlp/plugins/songs/lib/__init__.py b/openlp/plugins/songs/lib/__init__.py index 8c07c31c7..85206f5be 100644 --- a/openlp/plugins/songs/lib/__init__.py +++ b/openlp/plugins/songs/lib/__init__.py @@ -137,6 +137,7 @@ class VerseType(object): unicode(VerseType.to_string(VerseType.Other)).lower(): return VerseType.Other +from songxmlhandler import SongXMLBuilder, SongXMLParser from songstab import SongsTab from mediaitem import SongMediaItem from songimport import SongImport diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index 4557f53fa..496840412 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -27,10 +27,11 @@ import logging from PyQt4 import QtCore, QtGui -from openlp.core.lib import MediaManagerItem, SongXMLParser, \ - BaseListWithDnD, Receiver, ItemCapabilities, translate, check_item_selected +from openlp.core.lib import MediaManagerItem, BaseListWithDnD, Receiver, \ + ItemCapabilities, translate, check_item_selected from openlp.plugins.songs.forms import EditSongForm, SongMaintenanceForm, \ ImportWizardForm +from openlp.plugins.songs.lib import SongXMLParser from openlp.plugins.songs.lib.db import Song log = logging.getLogger(__name__) diff --git a/openlp/plugins/songs/lib/songimport.py b/openlp/plugins/songs/lib/songimport.py index 115f52e58..5b083c7c5 100644 --- a/openlp/plugins/songs/lib/songimport.py +++ b/openlp/plugins/songs/lib/songimport.py @@ -25,8 +25,8 @@ import re -from openlp.core.lib import SongXMLBuilder, translate -from openlp.plugins.songs.lib import VerseType +from openlp.core.lib import translate +from openlp.plugins.songs.lib import SongXMLBuilder, VerseType from openlp.plugins.songs.lib.db import Song, Author, Topic, Book class SongImport(object): diff --git a/openlp/core/lib/songxmlhandler.py b/openlp/plugins/songs/lib/songxmlhandler.py similarity index 100% rename from openlp/core/lib/songxmlhandler.py rename to openlp/plugins/songs/lib/songxmlhandler.py From fda7412f75dfa20062cf213747b2320f7ba6499e Mon Sep 17 00:00:00 2001 From: Phill Ridout Date: Sat, 3 Jul 2010 04:06:02 +0100 Subject: [PATCH 04/21] added css to remove white space arround background video adjusted spacing, added escapes to double quotes and moved the > on the body tag to its proper place! --- openlp/core/ui/maindisplay.py | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/openlp/core/ui/maindisplay.py b/openlp/core/ui/maindisplay.py index aaef47612..36df43988 100644 --- a/openlp/core/ui/maindisplay.py +++ b/openlp/core/ui/maindisplay.py @@ -43,19 +43,27 @@ HTMLIMAGE = """ #http://www.steveheffernan.com/html5-video-player/demo-video-player.html HTMLVIDEO = u""" - - \" - - + + + + """ class DisplayManager(QtGui.QWidget): From 5f15b2fd7ddf4f635f6fa993a16fbc7b213e199f Mon Sep 17 00:00:00 2001 From: Phill Ridout Date: Sat, 3 Jul 2010 06:41:24 +0100 Subject: [PATCH 05/21] added missing --- openlp/core/ui/maindisplay.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openlp/core/ui/maindisplay.py b/openlp/core/ui/maindisplay.py index 36df43988..c397b570c 100644 --- a/openlp/core/ui/maindisplay.py +++ b/openlp/core/ui/maindisplay.py @@ -57,6 +57,7 @@ HTMLVIDEO = u""" video.volume = 0; } +