merged classes together

This commit is contained in:
Andreas Preikschat 2011-01-09 17:52:31 +01:00
parent f2784fc4dd
commit ce1241aa0f
7 changed files with 109 additions and 244 deletions

View File

@ -31,7 +31,7 @@ from PyQt4 import QtCore, QtGui
from openlp.core.lib import Receiver, translate from openlp.core.lib import Receiver, translate
from openlp.plugins.songs.forms import EditVerseForm from openlp.plugins.songs.forms import EditVerseForm
from openlp.plugins.songs.lib import SongXMLBuilder, SongXMLParser, VerseType from openlp.plugins.songs.lib import SongXML, VerseType
from openlp.plugins.songs.lib.db import Book, Song, Author, Topic from openlp.plugins.songs.lib.db import Book, Song, Author, Topic
from editsongdialog import Ui_EditSongDialog from editsongdialog import Ui_EditSongDialog
@ -263,8 +263,8 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
if isinstance(self.song.lyrics, buffer): if isinstance(self.song.lyrics, buffer):
self.song.lyrics = unicode(self.song.lyrics) self.song.lyrics = unicode(self.song.lyrics)
if self.song.lyrics.startswith(u'<?xml version='): if self.song.lyrics.startswith(u'<?xml version='):
songXML = SongXMLParser(self.song.lyrics) songXML = SongXML()
verseList = songXML.get_verses() verseList = songXML.get_verses(self.song.lyrics)
for count, verse in enumerate(verseList): for count, verse in enumerate(verseList):
self.verseListWidget.setRowCount( self.verseListWidget.setRowCount(
self.verseListWidget.rowCount() + 1) self.verseListWidget.rowCount() + 1)
@ -731,7 +731,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
def processLyrics(self): def processLyrics(self):
log.debug(u'processLyrics') log.debug(u'processLyrics')
try: try:
sxml = SongXMLBuilder() sxml = SongXML()
text = u'' text = u''
multiple = [] multiple = []
for i in range(0, self.verseListWidget.rowCount()): for i in range(0, self.verseListWidget.rowCount()):

View File

@ -175,7 +175,6 @@ def retrieve_windows_encoding(recommendation=None):
return None return None
return filter(lambda item: item[1] == choice[0], encodings)[0][0] return filter(lambda item: item[1] == choice[0], encodings)[0][0]
from xml import OpenLyricsBuilder, OpenLyricsParser, SongXMLBuilder, \ from xml import OpenLyrics, SongXML
SongXMLParser
from songstab import SongsTab from songstab import SongsTab
from mediaitem import SongMediaItem from mediaitem import SongMediaItem

View File

@ -35,8 +35,7 @@ from openlp.core.lib import MediaManagerItem, BaseListWithDnD, Receiver, \
ItemCapabilities, translate, check_item_selected ItemCapabilities, translate, check_item_selected
from openlp.plugins.songs.forms import EditSongForm, SongMaintenanceForm, \ from openlp.plugins.songs.forms import EditSongForm, SongMaintenanceForm, \
SongImportForm SongImportForm
from openlp.plugins.songs.lib import OpenLyricsBuilder, OpenLyricsParser, \ from openlp.plugins.songs.lib import OpenLyrics, SongXML
SongXMLParser
from openlp.plugins.songs.lib.db import Author, Song from openlp.plugins.songs.lib.db import Author, Song
from openlp.core.lib.searchedit import SearchEdit from openlp.core.lib.searchedit import SearchEdit
@ -59,8 +58,7 @@ class SongMediaItem(MediaManagerItem):
self.ListViewWithDnD_class = SongListView self.ListViewWithDnD_class = SongListView
MediaManagerItem.__init__(self, parent, self, icon) MediaManagerItem.__init__(self, parent, self, icon)
self.edit_song_form = EditSongForm(self, self.parent.manager) self.edit_song_form = EditSongForm(self, self.parent.manager)
self.openLyricsParser = OpenLyricsParser(self.parent.manager) self.openLyrics = OpenLyrics(self.parent.manager)
self.openLyricsBuilder = OpenLyricsBuilder(self.parent.manager)
self.singleServiceItem = False self.singleServiceItem = False
self.song_maintenance_form = SongMaintenanceForm( self.song_maintenance_form = SongMaintenanceForm(
self.parent.manager, self) self.parent.manager, self)
@ -353,8 +351,8 @@ class SongMediaItem(MediaManagerItem):
service_item.theme = song.theme_name service_item.theme = song.theme_name
service_item.edit_id = item_id service_item.edit_id = item_id
if song.lyrics.startswith(u'<?xml version='): if song.lyrics.startswith(u'<?xml version='):
songXML = SongXMLParser(song.lyrics) songXML = SongXML()
verseList = songXML.get_verses() verseList = songXML.get_verses(song.lyrics)
# 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(): if not song.verse_order or not song.verse_order.strip():
for verse in verseList: for verse in verseList:
@ -397,7 +395,7 @@ class SongMediaItem(MediaManagerItem):
] ]
service_item.data_string = {u'title': song.search_title, service_item.data_string = {u'title': song.search_title,
u'authors': author_list} u'authors': author_list}
service_item.xml_version = self.openLyricsBuilder.song_to_xml(song) service_item.xml_version = self.openLyrics.song_to_xml(song)
return True return True
def serviceLoad(self, item): def serviceLoad(self, item):
@ -439,7 +437,7 @@ class SongMediaItem(MediaManagerItem):
break break
if add_song: if add_song:
if self.addSongFromService: if self.addSongFromService:
editId = self.openLyricsParser.xml_to_song(item.xml_version) editId = self.openLyrics.xml_to_song(item.xml_version)
# Update service with correct song id. # Update service with correct song id.
if editId != 0: if editId != 0:
Receiver.send_message(u'service_item_update', Receiver.send_message(u'service_item_update',

View File

@ -35,7 +35,7 @@ from lxml import etree
from openlp.core.lib import translate from openlp.core.lib import translate
from openlp.plugins.songs.lib.songimport import SongImport from openlp.plugins.songs.lib.songimport import SongImport
from openlp.plugins.songs.lib import OpenLyricsParser from openlp.plugins.songs.lib import OpenLyrics
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -50,7 +50,7 @@ class OpenLyricsImport(SongImport):
log.debug(u'initialise OpenLyricsImport') log.debug(u'initialise OpenLyricsImport')
SongImport.__init__(self, master_manager) SongImport.__init__(self, master_manager)
self.master_manager = master_manager self.master_manager = master_manager
self.openLyricsParser = OpenLyricsParser(master_manager) self.openLyrics = OpenLyrics(master_manager)
if kwargs.has_key(u'filename'): if kwargs.has_key(u'filename'):
self.import_source = kwargs[u'filename'] self.import_source = kwargs[u'filename']
if kwargs.has_key(u'filenames'): if kwargs.has_key(u'filenames'):
@ -70,7 +70,7 @@ class OpenLyricsImport(SongImport):
parser = etree.XMLParser(remove_blank_text=True) parser = etree.XMLParser(remove_blank_text=True)
file = etree.parse(file_path, parser) file = etree.parse(file_path, parser)
xml = unicode(etree.tostring(file)) xml = unicode(etree.tostring(file))
if self.openLyricsParser.xml_to_song(xml) == 0: if self.openLyrics.xml_to_song(xml) == 0:
log.debug(u'File could not be imported: %s' % file_path) log.debug(u'File could not be imported: %s' % file_path)
# Importing this song failed! For now we stop import. # Importing this song failed! For now we stop import.
return False return False

View File

@ -31,7 +31,7 @@ from PyQt4 import QtCore
from openlp.core.lib import Receiver, translate from openlp.core.lib import Receiver, translate
from openlp.plugins.songs.lib import VerseType from openlp.plugins.songs.lib import VerseType
from openlp.plugins.songs.lib.db import Song, Author, Topic, Book, MediaFile from openlp.plugins.songs.lib.db import Song, Author, Topic, Book, MediaFile
from openlp.plugins.songs.lib.xml import SongXMLBuilder from openlp.plugins.songs.lib.xml import SongXML
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -270,7 +270,7 @@ class SongImport(QtCore.QObject):
song.song_number = self.song_number song.song_number = self.song_number
song.search_lyrics = u'' song.search_lyrics = u''
verses_changed_to_other = {} verses_changed_to_other = {}
sxml = SongXMLBuilder() sxml = SongXML()
other_count = 1 other_count = 1
for (versetag, versetext) in self.verses: for (versetag, versetext) in self.verses:
if versetag[0] == u'C': if versetag[0] == u'C':

View File

@ -30,7 +30,7 @@ The basic XML for storing the lyrics in the song database is of the format::
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<song version="1.0"> <song version="1.0">
<lyrics language="en"> <lyrics>
<verse type="chorus" label="1"> <verse type="chorus" label="1">
<![CDATA[ ... ]]> <![CDATA[ ... ]]>
</verse> </verse>
@ -71,32 +71,26 @@ from openlp.plugins.songs.lib.db import Author, Book, Song, Topic
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class SongXMLBuilder(object): class SongXML(object):
""" """
This class builds the XML used to describe songs. This class builds and parses the XML used to describe songs.
""" """
log.info(u'SongXMLBuilder Loaded') log.info(u'SongXML Loaded')
def __init__(self, song_language=None): def __init__(self):
""" """
Set up the song builder. Set up the default variables.
``song_language``
The language used in this song
""" """
lang = u'en'
if song_language:
lang = song_language
self.song_xml = objectify.fromstring(u'<song version="1.0" />') self.song_xml = objectify.fromstring(u'<song version="1.0" />')
self.lyrics = etree.SubElement(self.song_xml, u'lyrics', language=lang) self.lyrics = etree.SubElement(self.song_xml, u'lyrics')
def add_verse_to_lyrics(self, type, number, content): def add_verse_to_lyrics(self, type, number, content):
""" """
Add a verse to the ``<lyrics>`` tag. Add a verse to the *<lyrics>* tag.
``type`` ``type``
A string denoting the type of verse. Possible values are "Chorus", A string denoting the type of verse. Possible values are "V",
"Verse", "Bridge", and "Custom". "C", "B", "P", "I", "E" and "O".
``number`` ``number``
An integer denoting the number of the item, for example: verse 1. An integer denoting the number of the item, for example: verse 1.
@ -109,13 +103,6 @@ class SongXMLBuilder(object):
verse.text = etree.CDATA(content) verse.text = etree.CDATA(content)
self.lyrics.append(verse) self.lyrics.append(verse)
def dump_xml(self):
"""
Debugging aid to dump XML so that we can see what we have.
"""
return etree.tostring(self.song_xml, encoding=u'UTF-8',
xml_declaration=True, pretty_print=True)
def extract_xml(self): def extract_xml(self):
""" """
Extract our newly created XML song. Extract our newly created XML song.
@ -123,16 +110,10 @@ class SongXMLBuilder(object):
return etree.tostring(self.song_xml, encoding=u'UTF-8', return etree.tostring(self.song_xml, encoding=u'UTF-8',
xml_declaration=True) xml_declaration=True)
def get_verses(self, xml):
class SongXMLParser(object):
"""
A class to read in and parse a song's XML.
"""
log.info(u'SongXMLParser Loaded')
def __init__(self, xml):
""" """
Set up our song XML parser. Iterates through the verses in the XML and returns a list of verses
and their attributes.
``xml`` ``xml``
The XML of the song to be parsed. The XML of the song to be parsed.
@ -144,12 +125,6 @@ class SongXMLParser(object):
self.song_xml = objectify.fromstring(xml) self.song_xml = objectify.fromstring(xml)
except etree.XMLSyntaxError: except etree.XMLSyntaxError:
log.exception(u'Invalid xml %s', xml) 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() xml_iter = self.song_xml.getiterator()
verse_list = [] verse_list = []
for element in xml_iter: for element in xml_iter:
@ -166,191 +141,9 @@ class SongXMLParser(object):
return etree.dump(self.song_xml) return etree.dump(self.song_xml)
#class LyricsXML(object): class OpenLyrics(object):
# """
# This class represents the XML in the ``lyrics`` field of a song.
# """
# def __init__(self, song=None):
# if song:
# if song.lyrics.startswith(u'<?xml'):
# self.parse(song.lyrics)
# else:
# self.extract(song.lyrics)
# else:
# self.languages = []
#
# def parse(self, xml):
# """
# Parse XML from the ``lyrics`` field in the database, and set the list
# of verses from it.
#
# ``xml``
# The XML to parse.
# """
# try:
# self.languages = []
# song = objectify.fromstring(xml)
# for lyrics in song.lyrics:
# language = {
# u'language': lyrics.attrib[u'language'],
# u'verses': []
# }
# for verse in lyrics.verse:
# language[u'verses'].append({
# u'type': verse.attrib[u'type'],
# u'label': verse.attrib[u'label'],
# u'text': unicode(verse.text)
# })
# self.lyrics.append(language)
# return True
# except etree.XMLSyntaxError:
# return False
#
# def extract(self, text):
# """
# If the ``lyrics`` field in the database is not XML, this method is
# called and used to construct the verse structure similar to the output
# of the ``parse`` function.
#
# ``text``
# The text to pull verses out of.
# """
# text = text.replace('\r\n', '\n')
# verses = text.split('\n\n')
# self.languages = [{u'language': u'en', u'verses': []}]
# for counter, verse in enumerate(verses):
# self.languages[0][u'verses'].append({
# u'type': u'verse',
# u'label': unicode(counter),
# u'text': verse
# })
# return True
#
# def add_verse(self, type, label, text):
# """
# Add a verse to the list of verses.
#
# ``type``
# The type of list, one of "verse", "chorus", "bridge", "pre-chorus",
# "intro", "outtro".
#
# ``label``
# The number associated with this verse, like 1 or 2.
#
# ``text``
# The text of the verse.
# """
# self.verses.append({
# u'type': type,
# u'label': label,
# u'text': text
# })
#
# def export(self):
# """
# Build up the XML for the verse structure.
# """
# lyrics_output = u''
# for language in self.languages:
# verse_output = u''
# for verse in language[u'verses']:
# verse_output = verse_output + \
# u'<verse type="%s" label="%s"><![CDATA[%s]]></verse>' % \
# (verse[u'type'], verse[u'label'], verse[u'text'])
# lyrics_output = lyrics_output + \
# u'<lyrics language="%s">%s</lyrics>' % \
# (language[u'language'], verse_output)
# song_output = u'<?xml version="1.0" encoding="UTF-8"?>' + \
# u'<song version="1.0">%s</song>' % lyrics_output
# return song_output
class OpenLyricsBuilder(object):
""" """
This class represents the converter for song to OpenLyrics XML. This class represents the converter for OpenLyrics XML to/from a song.
"""
def __init__(self, manager):
self.manager = manager
def song_to_xml(self, song, pretty_print=False):
"""
Convert the song to OpenLyrics Format.
"""
song_xml_parser = SongXMLParser(song.lyrics)
verse_list = song_xml_parser.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.comments:
comments = etree.SubElement(properties, u'comments')
self._add_text_to_element(u'comment', comments, song.comments)
if song.copyright:
self._add_text_to_element(u'copyright', properties, song.copyright)
if song.verse_order:
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)
if song.authors:
authors = etree.SubElement(properties, u'authors')
for author in song.authors:
self._add_text_to_element(
u'author', authors, author.display_name)
book = self.manager.get_object_filtered(
Book, Book.id == song.song_book_id)
if book is not None:
book = book.name
songbooks = etree.SubElement(properties, u'songbooks')
element = self._add_text_to_element(
u'songbook', songbooks, None, book)
element.set(u'entry', song.song_number)
if song.topics:
themes = etree.SubElement(properties, u'themes')
for topic in song.topics:
self._add_text_to_element(u'theme', themes, topic.name)
lyrics = etree.SubElement(song_xml, u'lyrics')
for verse in verse_list:
verse_tag = u'%s%s' % (
verse[0][u'type'][0].lower(), verse[0][u'label'])
element = \
self._add_text_to_element(u'verse', lyrics, None, verse_tag)
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)
return self._extract_xml(song_xml, pretty_print)
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 _extract_xml(self, xml, pretty_print):
"""
Extract our newly created XML song.
"""
return etree.tostring(xml, encoding=u'UTF-8',
xml_declaration=True, pretty_print=pretty_print)
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)
class OpenLyricsParser(object):
"""
This class represents the converter for OpenLyrics XML to a song.
As OpenLyrics has a rich set of different features, we cannot support them As OpenLyrics has a rich set of different features, we cannot support them
all. The following features are supported by the :class:`OpenLyricsParser`:: all. The following features are supported by the :class:`OpenLyricsParser`::
@ -410,6 +203,57 @@ class OpenLyricsParser(object):
def __init__(self, manager): def __init__(self, manager):
self.manager = manager self.manager = manager
def song_to_xml(self, song, pretty_print=False):
"""
Convert the song to OpenLyrics Format.
"""
sxml = SongXML()
verse_list = sxml.get_verses(song.lyrics)
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.comments:
comments = etree.SubElement(properties, u'comments')
self._add_text_to_element(u'comment', comments, song.comments)
if song.copyright:
self._add_text_to_element(u'copyright', properties, song.copyright)
if song.verse_order:
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)
if song.authors:
authors = etree.SubElement(properties, u'authors')
for author in song.authors:
self._add_text_to_element(
u'author', authors, author.display_name)
book = self.manager.get_object_filtered(
Book, Book.id == song.song_book_id)
if book is not None:
book = book.name
songbooks = etree.SubElement(properties, u'songbooks')
element = self._add_text_to_element(
u'songbook', songbooks, None, book)
element.set(u'entry', song.song_number)
if song.topics:
themes = etree.SubElement(properties, u'themes')
for topic in song.topics:
self._add_text_to_element(u'theme', themes, topic.name)
lyrics = etree.SubElement(song_xml, u'lyrics')
for verse in verse_list:
verse_tag = u'%s%s' % (
verse[0][u'type'][0].lower(), verse[0][u'label'])
element = \
self._add_text_to_element(u'verse', lyrics, None, verse_tag)
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)
return self._extract_xml(song_xml, pretty_print)
def xml_to_song(self, xml): def xml_to_song(self, xml):
""" """
Create and save a song from OpenLyrics format xml to the database. Since Create and save a song from OpenLyrics format xml to the database. Since
@ -441,6 +285,23 @@ class OpenLyricsParser(object):
self.manager.save_object(song) self.manager.save_object(song)
return song.id return song.id
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 _extract_xml(self, xml, pretty_print):
"""
Extract our newly created XML song.
"""
return etree.tostring(xml, encoding=u'UTF-8',
xml_declaration=True, pretty_print=pretty_print)
def _get(self, element, attribute): def _get(self, element, attribute):
""" """
This returns the element's attribute as unicode string. This returns the element's attribute as unicode string.
@ -562,7 +423,7 @@ class OpenLyricsParser(object):
``song`` ``song``
The song object. The song object.
""" """
sxml = SongXMLBuilder() sxml = SongXML()
search_text = u'' search_text = u''
temp_verse_order = [] temp_verse_order = []
for verse in lyrics.verse: for verse in lyrics.verse:
@ -682,3 +543,10 @@ class OpenLyricsParser(object):
song.topics.append(topic) song.topics.append(topic)
except AttributeError: except AttributeError:
pass pass
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)

View File

@ -31,7 +31,7 @@ from PyQt4 import QtCore, QtGui
from openlp.core.lib import Plugin, StringContent, build_icon, translate from openlp.core.lib import Plugin, StringContent, build_icon, translate
from openlp.core.lib.db import Manager from openlp.core.lib.db import Manager
from openlp.plugins.songs.lib import SongMediaItem, SongsTab, SongXMLParser from openlp.plugins.songs.lib import SongMediaItem, SongsTab, SongXML
from openlp.plugins.songs.lib.db import init_schema, Song from openlp.plugins.songs.lib.db import init_schema, Song
from openlp.plugins.songs.lib.importer import SongFormat from openlp.plugins.songs.lib.importer import SongFormat
@ -153,7 +153,7 @@ class SongsPlugin(Plugin):
song.search_title = self.whitespace.sub(u' ', song.title.lower() + \ song.search_title = self.whitespace.sub(u' ', song.title.lower() + \
u' ' + song.alternate_title.lower()) u' ' + song.alternate_title.lower())
lyrics = u'' lyrics = u''
verses = SongXMLParser(song.lyrics).get_verses() verses = SongXML().get_verses(song.lyrics)
for verse in verses: for verse in verses:
lyrics = lyrics + self.whitespace.sub(u' ', verse[1]) + u' ' lyrics = lyrics + self.whitespace.sub(u' ', verse[1]) + u' '
song.search_lyrics = lyrics.lower() song.search_lyrics = lyrics.lower()