Documentation fixups and \nstart to add OpenlLyrics export for songs

This commit is contained in:
Tim Bentley 2010-11-27 15:25:00 +00:00
parent 771c86783e
commit 90c631ce87
11 changed files with 123 additions and 39 deletions

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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.

View File

@ -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

View File

@ -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(

View File

@ -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:

View File

@ -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.

View File

@ -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

View File

@ -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'<?xml version='):
songXML = SongXMLParser(song.lyrics)
verseList = songXML.get_verses()
#no verse list or only 1 space (in error)
# no verse list or only 1 space (in error)
if not song.verse_order or not song.verse_order.strip():
for verse in verseList:
verseTag = u'%s:%s' % (
@ -397,6 +396,7 @@ class SongMediaItem(MediaManagerItem):
]
service_item.data_string = {u'title':song.search_title,
u'authors':author_list}
service_item.xml_version = OpenLyricsParser().songToXml(song)
return True
def serviceLoad(self, item):
@ -411,16 +411,26 @@ class SongMediaItem(MediaManagerItem):
Song.search_title.asc())
author_list = item.data_string[u'authors'].split(u', ')
editId = 0
uuid = 0
uuid = item._uuid
if search_results:
for song in search_results:
count = 0
for author in song.authors:
if author.display_name in author_list:
count += 1
# All Authors the same
if count == len(author_list):
editId = song.id
uuid = item._uuid
else:
# Authors different
if self.addSongFromService:
editId = OpenLyricsParser(). \
xmlToSong(item.xml_version)
else:
# Title does not match
if self.addSongFromService:
editId = OpenLyricsParser().xmlToSong(item.xml_version)
# Update service with correct song id
if editId != 0:
Receiver.send_message(u'service_item_update',
u'%s:%s' %(editId, uuid))

View File

@ -97,7 +97,6 @@ class SongXMLBuilder(object):
return etree.tostring(self.song_xml, encoding=u'UTF-8',
xml_declaration=True)
class SongXMLParser(object):
"""
A class to read in and parse a song's XML.
@ -239,3 +238,71 @@ class LyricsXML(object):
song_output = u'<?xml version="1.0" encoding="UTF-8"?>' + \
u'<song version="1.0">%s</song>' % 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'<song version="0.7" createdIn="OpenLP 2.0"/>')
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)