first working example

This commit is contained in:
Mattias Põldaru 2011-01-12 10:59:14 +02:00
parent 807b1f2be1
commit 39bd27d0df
4 changed files with 365 additions and 5 deletions

View File

@ -109,6 +109,9 @@ class SongImportForm(QtGui.QWizard, Ui_SongImportWizard):
QtCore.QObject.connect(self.genericRemoveButton,
QtCore.SIGNAL(u'clicked()'),
self.onGenericRemoveButtonClicked)
QtCore.QObject.connect(self.easiSlidesBrowseButton,
QtCore.SIGNAL(u'clicked()'),
self.onEasiSlidesBrowseButtonClicked)
QtCore.QObject.connect(self.ewBrowseButton,
QtCore.SIGNAL(u'clicked()'),
self.onEWBrowseButtonClicked)
@ -226,6 +229,16 @@ class SongImportForm(QtGui.QWizard, Ui_SongImportWizard):
'presentation file to import from.'))
self.genericAddButton.setFocus()
return False
elif source_format == SongFormat.EasiSlides:
if self.easiSlidesFilenameEdit.text().isEmpty():
QtGui.QMessageBox.critical(self,
translate('SongsPlugin.ImportWizardForm',
'No Easislides Song selected'),
translate('SongsPlugin.ImportWizardForm',
'You need to select an xml song file exported from '
'EasiSlides, to import from.'))
self.easiSlidesBrowseButton.setFocus()
return False
elif source_format == SongFormat.EasyWorship:
if self.ewFilenameEdit.text().isEmpty():
QtGui.QMessageBox.critical(self,
@ -400,6 +413,13 @@ class SongImportForm(QtGui.QWizard, Ui_SongImportWizard):
def onGenericRemoveButtonClicked(self):
self.removeSelectedItems(self.genericFileListWidget)
def onEasiSlidesBrowseButtonClicked(self):
self.getFileName(
translate('SongsPlugin.ImportWizardForm',
'Select EasiSlides songfile'),
self.easiSlidesFilenameEdit
)
def onEWBrowseButtonClicked(self):
self.getFileName(
translate('SongsPlugin.ImportWizardForm',
@ -440,6 +460,7 @@ class SongImportForm(QtGui.QWizard, Ui_SongImportWizard):
self.ccliFileListWidget.clear()
self.songsOfFellowshipFileListWidget.clear()
self.genericFileListWidget.clear()
self.easiSlidesFilenameEdit.setText(u'')
self.ewFilenameEdit.setText(u'')
self.songBeamerFileListWidget.clear()
#self.csvFilenameEdit.setText(u'')
@ -512,8 +533,13 @@ class SongImportForm(QtGui.QWizard, Ui_SongImportWizard):
importer = self.plugin.importSongs(SongFormat.Generic,
filenames=self.getListOfFiles(self.genericFileListWidget)
)
elif source_format == SongFormat.EasiSlides:
# Import an EasiSlides export file
importer = self.plugin.importSongs(SongFormat.EasiSlides,
filename=unicode(self.easiSlidesFilenameEdit.text())
)
elif source_format == SongFormat.EasyWorship:
# Import an OpenLP 2.0 database
# Import an EasyWorship database
importer = self.plugin.importSongs(SongFormat.EasyWorship,
filename=unicode(self.ewFilenameEdit.text())
)

View File

@ -92,6 +92,8 @@ class Ui_SongImportWizard(object):
# Generic Document/Presentation import
self.addMultiFileSelectItem(u'generic', None, True)
# EasyWorship
self.addSingleFileSelectItem(u'easiSlides')
# EasyWorship
self.addSingleFileSelectItem(u'ew')
# Words of Worship
self.addMultiFileSelectItem(u'songBeamer')
@ -156,8 +158,10 @@ class Ui_SongImportWizard(object):
translate('SongsPlugin.ImportWizardForm',
'Generic Document/Presentation'))
self.formatComboBox.setItemText(8,
translate('SongsPlugin.ImportWizardForm', 'EasyWorship'))
translate('SongsPlugin.ImportWizardForm', 'EasiSlides'))
self.formatComboBox.setItemText(9,
translate('SongsPlugin.ImportWizardForm', 'EasyWorship'))
self.formatComboBox.setItemText(10,
translate('SongsPlugin.ImportWizardForm', 'SongBeamer'))
# self.formatComboBox.setItemText(9,
# translate('SongsPlugin.ImportWizardForm', 'CSV'))
@ -211,6 +215,10 @@ class Ui_SongImportWizard(object):
translate('SongsPlugin.ImportWizardForm', 'The generic document/'
'presentation importer has been disabled because OpenLP cannot '
'find OpenOffice.org on your computer.'))
self.easiSlidesFilenameLabel.setText(
translate('SongsPlugin.ImportWizardForm', 'Filename:'))
self.easiSlidesBrowseButton.setText(
translate('SongsPlugin.ImportWizardForm', 'Browse...'))
self.ewFilenameLabel.setText(
translate('SongsPlugin.ImportWizardForm', 'Filename:'))
self.ewBrowseButton.setText(
@ -241,6 +249,8 @@ class Ui_SongImportWizard(object):
QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
self.openLP1FormLabelSpacer.changeSize(width, 0,
QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
self.easiSlidesFormLabelSpacer.changeSize(width, 0, QtGui.QSizePolicy.Fixed,
QtGui.QSizePolicy.Fixed)
self.ewFormLabelSpacer.changeSize(width, 0, QtGui.QSizePolicy.Fixed,
QtGui.QSizePolicy.Fixed)
# self.csvFormLabelSpacer.changeSize(width, 0, QtGui.QSizePolicy.Fixed,

View File

@ -0,0 +1,319 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2011 Raoul Snyman #
# Portions copyright (c) 2008-2011 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 logging
import os
from lxml import etree
from lxml.etree import Error, LxmlError
import re
from openlp.core.lib import translate
from openlp.plugins.songs.lib.songimport import SongImport
log = logging.getLogger(__name__)
class EasiSlidesImportError(Exception):
pass
class EasiSlidesImport(SongImport):
"""
Import songs exported from EasiSlides
The format example is here:
http://wiki.openlp.org/Development:EasiSlides_-_Song_Data_Format
"""
def __init__(self, manager, **kwargs):
"""
Initialise the class.
"""
SongImport.__init__(self, manager)
self.filename = kwargs[u'filename']
self.song = None
self.commit = True
def do_import(self):
"""
Import either each of the files in self.filenames - each element of
which can be either a single opensong file, or a zipfile containing
multiple opensong files. If `self.commit` is set False, the
import will not be committed to the database (useful for test scripts).
"""
success = True
self.import_wizard.importProgressBar.setMaximum(1)
log.info(u'Direct import %s', self.filename)
self.import_wizard.incrementProgressBar(
unicode(translate('SongsPlugin.ImportWizardForm',
'Importing %s...')) % os.path.split(self.filename)[-1])
file = open(self.filename)
count = file.read().count('<Item>')
file.seek(0)
self.import_wizard.importProgressBar.setMaximum(count)
self.do_import_file(file)
return success
def do_import_file(self, file):
"""
Process the EasiSlides file - pass in a file-like object,
not a filename
"""
self.set_defaults()
try:
context = etree.iterparse(file)
except (Error, LxmlError):
log.exception(u'Error parsing XML')
return
song_dict = {}
for action, elem in context:
if not elem.text:
text = None
else:
text = elem.text
song_dict[elem.tag] = text
if elem.tag.lower() == u"item":
self.parse_song(song_dict)
self.import_wizard.incrementProgressBar(
unicode(translate('SongsPlugin.ImportWizardForm',
'Importing %s, song %s...')) %
(os.path.split(self.filename)[-1], self.title))
if self.commit:
self.finish()
song_dict = {}
def notCapsLock(self, string):
if string.upper() == string:
return string.lower()
else:
return string
def notCapsLockTitle(self, string):
if string.upper() == string:
ret = string.lower()
return u"%s%s" % (ret[0].upper(), ret[1:])
else:
return string
def parse_song(self, song_dict):
#for i in song_dict:
#if i != 'Contents' and song_dict[i] != None:
#print u"%s = '%s'" % (i, song_dict[i])
toLower = True
title = unicode(song_dict['Title1'])
if toLower:
self.title = self.notCapsLockTitle(title)
if song_dict['Title2'] != None:
alttitle = unicode(song_dict['Title2'])
if toLower:
self.alternate_title = self.notCapsLockTitle(alttitle)
if song_dict['SongNumber'] != None:
self.song_number = int(song_dict['SongNumber'])
else:
self.song_number = 0
#song_dict['Notations']
if song_dict['Sequence'] != None:
seq = song_dict['Sequence'].split(",")
print seq
if song_dict['Writer'] != None:
self.authors.append(song_dict['Writer'])
lyrics = unicode(song_dict['Contents'])
titleIsFirstLine = True
if titleIsFirstLine:
lyrics = u"%s\n%s" % (self.title, lyrics)
# data storage while importing
verses = {}
# keep track of a "default" verse order, in case none is specified
our_verse_order = []
verses_seen = {}
# in the absence of any other indication, verses are the default,
# erm, versetype!
versetype = u'V'
versenum = None
seenorder = []
lines = lyrics.split(u'\n')
length = len(lines)
regions = 0
separators = 0
if lyrics.find(u'[') != -1:
match = -1
while True:
match = lyrics.find(u'[', match+1)
if match == -1:
break
if lyrics[match:match+7].lower() == u'[region':
regions = regions+1
else:
separators = separators+1
for i in range(length):
thisline = lines[i].strip()
if i < length-1:
nextline = lines[i+1].strip()
# we don't care about nextline at the last line
else:
nextline = False
if len(thisline) is 0:
if separators == 0:
# empty line starts a new verse or chorus
if nextline and nextline is nextline.upper():
# the next line is all uppercase, it is chorus
versetype = u'C'
else:
# if the next line is not uppercase, it must be verse
versetype = u'V'
if verses.has_key(versetype):
keys = verses[versetype].keys()
#print keys
versenum = len(keys)+1
else:
versenum = u'1'
seenorder.append([versetype, versenum])
continue
# verse/chorus/etc. marker
if thisline[0] == u'[':
if regions > 1:
# region markers are inside verse markers
if thisline[0:6] == u'[region':
# this is a region marker inside verse
# by now we do nothing
print 'region inside verse markers'
continue
elif regions == 0:
# there is only one region marker
if thisline[0:6] == u'[region':
# we should restart verse count
# by now we do nothing
continue
# this is to be handled as normal marker
# drop the square brackets
right_bracket = thisline.find(u']')
content = thisline[1:right_bracket].upper()
# have we got any digits?
# If so, versenumber is everything from the digits
# to the end (even if there are some alpha chars on the end)
match = re.match(u'(.*)(\d+.*)', content)
if match is not None:
versetype = match.group(1)
versenum = match.group(2)
else:
# otherwise we assume number 1 and take the whole prefix as
# the versetype
versetype = content
versenum = u'1'
seenorder.append([versetype, versenum])
continue
if i == 0:
# this is the first line, but no separator is found,
# let's say it's V1
versetype = u'V'
versenum = u'1'
seenorder.append([versetype, versenum])
words = None
# number at start of line.. it's verse number
if thisline[0].isdigit():
versenum = thisline[0]
words = thisline[1:].strip()
if words is None:
words = thisline
if not versenum:
versenum = u'1'
if versenum is not None:
versetag = u'%s%s' % (versetype, versenum)
if not verses.has_key(versetype):
verses[versetype] = {}
if not verses[versetype].has_key(versenum):
# storage for lines in this verse
verses[versetype][versenum] = []
if not verses_seen.has_key(versetag):
verses_seen[versetag] = 1
our_verse_order.append(versetag)
if words:
# Tidy text and remove the ____s from extended words
words = self.tidy_text(words)
words = words.replace('_', '')
if toLower:
words = self.notCapsLock(words)
verses[versetype][versenum].append(words)
# done parsing
versetypes = verses.keys()
versetags = {}
for tag in seenorder:
vtype = tag[0]
vnum = tag[1]
if not vtype in verses:
# something may have gone wrong
continue
if not vnum in verses[vtype]:
# this most likely is caused by an extra empty line at the end,
# to be debugged later
continue
versetag = u'%s%s' % (vtype, vnum)
lines = u'\n'.join(verses[vtype][vnum])
self.verses.append([versetag, lines])
if song_dict['Sequence'] != None:
order = song_dict['Sequence'].split(u',')
for tag in order:
if tag[0].isdigit():
# Assume it's a verse if it has no prefix
tag = u'V' + tag
elif not re.search('\d+', tag):
# Assume it's no.1 if there's no digits
tag = tag + u'1'
if not versetags.has_key(tag):
log.info(u'Got order %s but not in versetags, dropping this'
u'item from presentation order', tag)
else:
self.verse_order_list.append(tag)
else:
for tag in seenorder:
self.verse_order_list.append(u'%s%s' % (tag[0], tag[1]))

View File

@ -25,6 +25,7 @@
###############################################################################
from opensongimport import OpenSongImport
from easislidesimport import EasiSlidesImport
from olpimport import OpenLPSongImport
from openlyricsimport import OpenLyricsImport
from wowimport import WowImport
@ -65,8 +66,9 @@ class SongFormat(object):
SongsOfFellowship = 6
Generic = 7
#CSV = 8
EasyWorship = 8
SongBeamer = 9
EasiSlides = 8
EasyWorship = 9
SongBeamer = 10
@staticmethod
def get_class(format):
@ -92,6 +94,8 @@ class SongFormat(object):
return OooImport
elif format == SongFormat.CCLI:
return CCLIFileImport
elif format == SongFormat.EasiSlides:
return EasiSlidesImport
elif format == SongFormat.EasyWorship:
return EasyWorshipSongImport
elif format == SongFormat.SongBeamer:
@ -112,6 +116,7 @@ class SongFormat(object):
SongFormat.CCLI,
SongFormat.SongsOfFellowship,
SongFormat.Generic,
SongFormat.EasiSlides,
SongFormat.EasyWorship,
SongFormat.SongBeamer
]
@ -128,4 +133,4 @@ SongFormat.set_availability(SongFormat.OpenLP1, has_openlp1)
SongFormat.set_availability(SongFormat.SongsOfFellowship, has_sof)
SongFormat.set_availability(SongFormat.Generic, has_ooo)
__all__ = [u'SongFormat']
__all__ = [u'SongFormat']