From 90c631ce87a195b54537276cbd2416c2dca72ca9 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sat, 27 Nov 2010 15:25:00 +0000 Subject: [PATCH] Documentation fixups and \nstart to add OpenlLyrics export for songs --- documentation/manual/source/songusage.rst | 32 +++++---- openlp/core/lib/mediamanageritem.py | 10 +-- openlp/core/lib/serviceitem.py | 6 +- openlp/plugins/bibles/lib/mediaitem.py | 2 +- openlp/plugins/custom/lib/mediaitem.py | 2 +- openlp/plugins/images/lib/mediaitem.py | 2 +- openlp/plugins/media/lib/mediaitem.py | 2 +- openlp/plugins/presentations/lib/mediaitem.py | 10 +-- openlp/plugins/songs/lib/__init__.py | 3 +- openlp/plugins/songs/lib/mediaitem.py | 24 +++++-- openlp/plugins/songs/lib/xml.py | 69 ++++++++++++++++++- 11 files changed, 123 insertions(+), 39 deletions(-) diff --git a/documentation/manual/source/songusage.rst b/documentation/manual/source/songusage.rst index df6d930f3..6e439ce6c 100644 --- a/documentation/manual/source/songusage.rst +++ b/documentation/manual/source/songusage.rst @@ -5,18 +5,30 @@ Song Usage The Songusage plugin records the usage of Songs when they are used in a **Live** situation. If the plugin is active all songs sent to the Live Service Manager are recorded by this plugin. Once the plugin has been activated by the plugin -menu it can be turned on and off by use of the``F4`` key or the SongUsage menus. +menu it can be turned on and off by use of the :guilabel:`F4` key or the +SongUsage menus. The image below shows the menu items and how to access them. .. image:: pics/songusage.png +Delete Tracking Data +^^^^^^^^^^^^^^^^^^^^ +This option allows the removal of stored data use is no longer required. +Select the date you wish to remove data up to and press :guilabel:`Ok`. + +This option is not reversable. + +.. image:: pics/songusagedelete.png + +Extract Tracking Data +^^^^^^^^^^^^^^^^^^^^^ +This option allows reports to be generated between any two dates. + +The system automatically defaults to dates between the 1st September last year +and 31st August this year. The data is written to a file in the selected +directory. -Generating reports ------------------- -This option allows reports to be generated between any two dates. The system -automatically defaults to dates between the 1st September last year and 31st -August this year. The data is written to a file in a selectable directory. The file name is **usage_detail_fromdate_todate.txt**. .. image:: pics/songusagereport.png @@ -27,11 +39,3 @@ The details extracted are: - Song Title - Song Copyright - Song CCLI. - -Removing data -------------- -This option allows the removal of stored data use is no longer required. -Select the date you wish to remove data up to and press``Ok``. This option is -not reversable. - -.. image:: pics/songusagedelete.png diff --git a/openlp/core/lib/mediamanageritem.py b/openlp/core/lib/mediamanageritem.py index 749543fd9..58b69bf83 100644 --- a/openlp/core/lib/mediamanageritem.py +++ b/openlp/core/lib/mediamanageritem.py @@ -420,7 +420,7 @@ class MediaManagerItem(QtGui.QWidget): raise NotImplementedError(u'MediaManagerItem.onDeleteClick needs to ' u'be defined by the plugin') - def generateSlideData(self, service_item, item=None): + def generateSlideData(self, service_item, item=None, xmlVersion=False): raise NotImplementedError(u'MediaManagerItem.generateSlideData needs ' u'to be defined by the plugin') @@ -482,7 +482,7 @@ class MediaManagerItem(QtGui.QWidget): # service items? if self.singleServiceItem or self.remoteTriggered: log.debug(self.plugin.name + u' Add requested') - service_item = self.buildServiceItem() + service_item = self.buildServiceItem(None, True) if service_item: service_item.from_plugin = False self.parent.serviceManager.addServiceItem(service_item, @@ -490,7 +490,7 @@ class MediaManagerItem(QtGui.QWidget): else: items = self.listView.selectedIndexes() for item in items: - service_item = self.buildServiceItem(item) + service_item = self.buildServiceItem(item, True) if service_item: service_item.from_plugin = False self.parent.serviceManager.addServiceItem(service_item) @@ -525,7 +525,7 @@ class MediaManagerItem(QtGui.QWidget): unicode(translate('OpenLP.MediaManagerItem', 'You must select a %s service item.')) % self.title) - def buildServiceItem(self, item=None): + def buildServiceItem(self, item=None, xmlVersion=False): """ Common method for generating a service item """ @@ -534,7 +534,7 @@ class MediaManagerItem(QtGui.QWidget): service_item.add_icon(self.serviceItemIconName) else: service_item.add_icon(self.parent.icon_path) - if self.generateSlideData(service_item, item): + if self.generateSlideData(service_item, item, xmlVersion): return service_item else: return None diff --git a/openlp/core/lib/serviceitem.py b/openlp/core/lib/serviceitem.py index 0cbc34de5..585a89276 100644 --- a/openlp/core/lib/serviceitem.py +++ b/openlp/core/lib/serviceitem.py @@ -101,6 +101,7 @@ class ServiceItem(object): self.search_string = u'' self.data_string = u'' self.edit_id = None + self.xml_version = None self._new_item() def _new_item(self): @@ -252,7 +253,8 @@ class ServiceItem(object): u'from_plugin': self.from_plugin, u'capabilities': self.capabilities, u'search': self.search_string, - u'data': self.data_string + u'data': self.data_string, + u'xmlVersion': self.xml_version } service_data = [] if self.service_item_type == ServiceItemType.Text: @@ -294,6 +296,8 @@ class ServiceItem(object): if u'search' in header: self.search_string = header[u'search'] self.data_string = header[u'data'] + if u'xmlVersion' in header: + self.xml_version = header[u'xmlVersion'] if self.service_item_type == ServiceItemType.Text: for slide in serviceitem[u'serviceitem'][u'data']: self._raw_frames.append(slide) diff --git a/openlp/plugins/bibles/lib/mediaitem.py b/openlp/plugins/bibles/lib/mediaitem.py index bb3c1b26d..25edb4926 100644 --- a/openlp/plugins/bibles/lib/mediaitem.py +++ b/openlp/plugins/bibles/lib/mediaitem.py @@ -651,7 +651,7 @@ class BibleMediaItem(MediaManagerItem): obj = obj.toPyObject() return unicode(obj) - def generateSlideData(self, service_item, item=None): + def generateSlideData(self, service_item, item=None, xmlVersion=False): """ Generates and formats the slides for the service item as well as the service item's title. diff --git a/openlp/plugins/custom/lib/mediaitem.py b/openlp/plugins/custom/lib/mediaitem.py index 8549e6449..83a43fba8 100644 --- a/openlp/plugins/custom/lib/mediaitem.py +++ b/openlp/plugins/custom/lib/mediaitem.py @@ -144,7 +144,7 @@ class CustomMediaItem(MediaManagerItem): for row in row_list: self.listView.takeItem(row) - def generateSlideData(self, service_item, item=None): + def generateSlideData(self, service_item, item=None, xmlVersion=False): raw_slides = [] raw_footer = [] slide = None diff --git a/openlp/plugins/images/lib/mediaitem.py b/openlp/plugins/images/lib/mediaitem.py index 7394758c3..4f1e9378e 100644 --- a/openlp/plugins/images/lib/mediaitem.py +++ b/openlp/plugins/images/lib/mediaitem.py @@ -154,7 +154,7 @@ class ImageMediaItem(MediaManagerItem): item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(file)) self.listView.addItem(item_name) - def generateSlideData(self, service_item, item=None): + def generateSlideData(self, service_item, item=None, xmlVersion=False): items = self.listView.selectedIndexes() if items: service_item.title = unicode( diff --git a/openlp/plugins/media/lib/mediaitem.py b/openlp/plugins/media/lib/mediaitem.py index 030f67153..11e00628e 100644 --- a/openlp/plugins/media/lib/mediaitem.py +++ b/openlp/plugins/media/lib/mediaitem.py @@ -116,7 +116,7 @@ class MediaMediaItem(MediaManagerItem): self.parent.liveController.display.video(filename, 0, True) self.resetButton.setVisible(True) - def generateSlideData(self, service_item, item=None): + def generateSlideData(self, service_item, item=None, xmlVersion=False): if item is None: item = self.listView.currentItem() if item is None: diff --git a/openlp/plugins/presentations/lib/mediaitem.py b/openlp/plugins/presentations/lib/mediaitem.py index e6f456e5c..8e3a2fc36 100644 --- a/openlp/plugins/presentations/lib/mediaitem.py +++ b/openlp/plugins/presentations/lib/mediaitem.py @@ -38,7 +38,7 @@ log = logging.getLogger(__name__) class PresentationListView(BaseListWithDnD): """ Class for the list of Presentations - + We have to explicitly create separate classes for each plugin in order for DnD to the Service manager to work correctly. """ @@ -67,7 +67,7 @@ class PresentationMediaItem(MediaManagerItem): self.message_listener = MessageListener(self) QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'mediaitem_presentation_rebuild'), self.rebuild) - + def retranslateUi(self): """ The name of the plugin media displayed in UI @@ -159,7 +159,7 @@ class PresentationMediaItem(MediaManagerItem): if self.DisplayTypeComboBox.count() > 1: self.DisplayTypeComboBox.insertItem(0, self.Automatic) self.DisplayTypeComboBox.setCurrentIndex(0) - if QtCore.QSettings().value(self.settingsSection + u'/override app', + if QtCore.QSettings().value(self.settingsSection + u'/override app', QtCore.QVariant(QtCore.Qt.Unchecked)) == QtCore.Qt.Checked: self.PresentationWidget.show() else: @@ -238,7 +238,7 @@ class PresentationMediaItem(MediaManagerItem): SettingsManager.set_list(self.settingsSection, self.settingsSection, self.getFileList()) - def generateSlideData(self, service_item, item=None): + def generateSlideData(self, service_item, item=None, xmlVersion=False): """ Load the relevant information for displaying the presentation in the slidecontroller. In the case of powerpoints, an image @@ -277,7 +277,7 @@ class PresentationMediaItem(MediaManagerItem): def findControllerByType(self, filename): """ Determine the default application controller to use for the selected - file type. This is used if "Automatic" is set as the preferred + file type. This is used if "Automatic" is set as the preferred controller. Find the first (alphabetic) enabled controller which "supports" the extension. If none found, then look for a controller which "alsosupports" it instead. diff --git a/openlp/plugins/songs/lib/__init__.py b/openlp/plugins/songs/lib/__init__.py index 351d50071..bb9c6ebf9 100644 --- a/openlp/plugins/songs/lib/__init__.py +++ b/openlp/plugins/songs/lib/__init__.py @@ -92,7 +92,6 @@ class VerseType(object): unicode(VerseType.to_string(VerseType.Other)).lower(): return VerseType.Other - -from xml import LyricsXML, SongXMLBuilder, SongXMLParser +from xml import LyricsXML, SongXMLBuilder, SongXMLParser, OpenLyricsParser from songstab import SongsTab from mediaitem import SongMediaItem diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index cb2d6a6e0..546751a48 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -32,7 +32,7 @@ from openlp.core.lib import MediaManagerItem, BaseListWithDnD, Receiver, \ ItemCapabilities, translate, check_item_selected from openlp.plugins.songs.forms import EditSongForm, SongMaintenanceForm, \ SongImportForm -from openlp.plugins.songs.lib import SongXMLParser +from openlp.plugins.songs.lib import SongXMLParser, OpenLyricsParser from openlp.plugins.songs.lib.db import Author, Song log = logging.getLogger(__name__) @@ -54,7 +54,6 @@ class SongMediaItem(MediaManagerItem): MediaManagerItem.__init__(self, parent, self, icon) self.edit_song_form = EditSongForm(self, self.parent.manager) self.singleServiceItem = False - #self.edit_song_form = EditSongForm(self.parent.manager, self) self.song_maintenance_form = SongMaintenanceForm( self.parent.manager, self) # Holds information about whether the edit is remotly triggered and @@ -141,7 +140,7 @@ class SongMediaItem(MediaManagerItem): self.updateServiceOnEdit = QtCore.QSettings().value( self.settingsSection + u'/update service on edit', QtCore.QVariant(u'False')).toBool() - self.AddSongFromServide = QtCore.QSettings().value( + self.addSongFromService = QtCore.QSettings().value( self.settingsSection + u'/add song from service', QtCore.QVariant(u'True')).toBool() @@ -328,7 +327,7 @@ class SongMediaItem(MediaManagerItem): self.parent.manager.delete_object(Song, item_id) self.onSearchTextButtonClick() - def generateSlideData(self, service_item, item=None): + def generateSlideData(self, service_item, item=None, xmlVersion=False): log.debug(u'generateSlideData (%s:%s)' % (service_item, item)) raw_footer = [] author_list = u'' @@ -355,7 +354,7 @@ class SongMediaItem(MediaManagerItem): if song.lyrics.startswith(u'' + \ u'%s' % lyrics_output return song_output + +class OpenLyricsParser(object): + """ + This class represents the converter for Song to/from OpenLyrics XML. + """ + def songToXml(self, song): + """ + Convert the song to OpenLyrics Format + """ + songXML = SongXMLParser(song.lyrics) + verseList = songXML.get_verses() + song_xml = objectify.fromstring( + u'') + properties = etree.SubElement(song_xml, u'properties') + titles = etree.SubElement(properties, u'titles') + self.add_text_to_element(u'title', titles, song.title) + if song.alternate_title: + self.add_text_to_element(u'title', titles, song.alternate_title) + if song.theme_name: + themes = etree.SubElement(properties, u'themes') + self.add_text_to_element(u'theme', themes, song.theme_name) + self.add_text_to_element(u'copyright', properties, song.copyright) + self.add_text_to_element(u'verseOrder', properties, song.verse_order) + if song.ccli_number: + self.add_text_to_element(u'ccliNo', properties, song.ccli_number) + authors = etree.SubElement(properties, u'authors') + for author in song.authors: + self.add_text_to_element(u'author', authors, author.display_name) + lyrics = etree.SubElement(song_xml, u'lyrics') + for verse in verseList: + verseTag = u'%s%s' % ( + verse[0][u'type'][0].lower(), verse[0][u'label']) + element = self.add_text_to_element(u'verse', lyrics, None, verseTag) + element = self.add_text_to_element(u'lines', element) + for line in unicode(verse[1]).split(u'\n'): + self.add_text_to_element(u'line', element, line) + #print self.dump_xml(song_xml) + return u'' #self.extract_xml(song_xml) + + def add_text_to_element(self, tag, parent, text=None, label=None): + if label: + element = etree.Element(tag, name = unicode(label)) + else: + element = etree.Element(tag) + if text: + element.text = unicode(text) + parent.append(element) + return element + + def xmlToSong(self, xml): + """ + Create a Song from OpenLyrics format xml + """ + return 0 + + def dump_xml(self, xml): + """ + Debugging aid to dump XML so that we can see what we have. + """ + return etree.tostring(xml, encoding=u'UTF-8', + xml_declaration=True, pretty_print=True) + + def extract_xml(self, xml): + """ + Extract our newly created XML song. + """ + return etree.tostring(xml, encoding=u'UTF-8', + xml_declaration=True)