diff --git a/openlp/plugins/songs/forms/songimportform.py b/openlp/plugins/songs/forms/songimportform.py index 68bba299d..6fb6b38a0 100644 --- a/openlp/plugins/songs/forms/songimportform.py +++ b/openlp/plugins/songs/forms/songimportform.py @@ -160,7 +160,7 @@ class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard): self.openSongAddButton.setFocus() return False elif source_format == SongFormat.WordsOfWorship: - if self.wordsOfWorshipListWidget.count() == 0: + if self.wordsOfWorshipFileListWidget.count() == 0: QtGui.QMessageBox.critical(self, translate('SongsPlugin.ImportWizardForm', 'No Words of Worship Files Selected'), @@ -315,6 +315,7 @@ class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard): pass def setDefaults(self): + self.restart() self.formatComboBox.setCurrentIndex(0) self.openLP2FilenameEdit.setText(u'') self.openLP1FilenameEdit.setText(u'') diff --git a/openlp/plugins/songs/lib/importer.py b/openlp/plugins/songs/lib/importer.py index 7410a5184..ae18f4389 100644 --- a/openlp/plugins/songs/lib/importer.py +++ b/openlp/plugins/songs/lib/importer.py @@ -29,6 +29,7 @@ from olpimport import OpenLPSongImport try: from sofimport import SofImport from oooimport import OooImport + from wowimport import WowImport except ImportError: pass @@ -63,6 +64,8 @@ class SongFormat(object): return OpenSongImport elif format == SongFormat.SongsOfFellowship: return SofImport + elif format == SongFormat.WordsOfWorship: + return WowImport elif format == SongFormat.Generic: return OooImport # else: diff --git a/openlp/plugins/songs/lib/opensongimport.py b/openlp/plugins/songs/lib/opensongimport.py index 1f495013c..58af0edd4 100644 --- a/openlp/plugins/songs/lib/opensongimport.py +++ b/openlp/plugins/songs/lib/opensongimport.py @@ -160,7 +160,7 @@ class OpenSongImport(SongImport): Process the OpenSong file - pass in a file-like object, not a filename """ - self.set_defaults() + # self.setDefaults() # Setup blank storage to append to verse_order_list = [] topics = [] @@ -296,3 +296,5 @@ class OpenSongImport(SongImport): self.topics = topics self.verse_order_list = verse_order_list self.verses = verselist + xxx sort out where to call setdefaults + xxx need to make calls to insert to database here diff --git a/openlp/plugins/songs/lib/songimport.py b/openlp/plugins/songs/lib/songimport.py index 169ecf75c..4ee174db6 100644 --- a/openlp/plugins/songs/lib/songimport.py +++ b/openlp/plugins/songs/lib/songimport.py @@ -43,6 +43,12 @@ class SongImport(QtCore.QObject): whether the authors etc already exist and add them or refer to them as necessary """ + + COPYRIGHT_STRING = unicode(translate( + 'SongsPlugin.SongImport', 'copyright')) + COPYRIGHT_SYMBOL = unicode(translate( + 'SongsPlugin.SongImport', '\xa9')) + def __init__(self, manager): """ Initialise and create defaults for properties @@ -52,8 +58,11 @@ class SongImport(QtCore.QObject): """ self.manager = manager self.stop_import_flag = False - self.set_defaults() - def set_defaults(self): + QtCore.QObject.connect(Receiver.get_receiver(), + QtCore.SIGNAL(u'songs_stop_import'), self.stop_import) + self.setDefaults() + + def setDefaults(self): """ Create defaults for properties - call this before each song if importing many songs at once to ensure a clean beginning @@ -73,13 +82,7 @@ class SongImport(QtCore.QObject): self.verses = [] self.versecount = 0 self.choruscount = 0 - self.copyright_string = unicode(translate( - 'SongsPlugin.SongImport', 'copyright')) - self.copyright_symbol = unicode(translate( - 'SongsPlugin.SongImport', '\xa9')) - QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'songs_stop_import'), self.stop_import) - + def stop_import(self): """ Sets the flag for importers to stop their import @@ -132,13 +135,13 @@ class SongImport(QtCore.QObject): def process_verse_text(self, text): lines = text.split(u'\n') - if text.lower().find(self.copyright_string) >= 0 \ - or text.lower().find(self.copyright_symbol) >= 0: + if text.lower().find(COPYRIGHT_STRING) >= 0 \ + or text.lower().find(COPYRIGHT_SYMBOL) >= 0: copyright_found = False for line in lines: if (copyright_found or - line.lower().find(self.copyright_string) >= 0 or - line.lower().find(self.copyright_symbol) >= 0): + line.lower().find(COPYRIGHT_STRING) >= 0 or + line.lower().find(COPYRIGHT_SYMBOL) >= 0): copyright_found = True self.add_copyright(line) else: @@ -303,6 +306,7 @@ class SongImport(QtCore.QObject): topic = Topic.populate(name=topictext) song.topics.append(topic) self.manager.save_object(song) + self.setDefaults() def print_song(self): """ diff --git a/openlp/plugins/songs/lib/test/test_opensongimport.py b/openlp/plugins/songs/lib/test/test_opensongimport.py index c994d8685..f2fcb8cd2 100644 --- a/openlp/plugins/songs/lib/test/test_opensongimport.py +++ b/openlp/plugins/songs/lib/test/test_opensongimport.py @@ -43,7 +43,6 @@ class progbar_stub: pass def setMaximum(self, arg): pass - def test(): manager = Manager(u'songs', init_schema) diff --git a/openlp/plugins/songs/lib/wowimport.py b/openlp/plugins/songs/lib/wowimport.py new file mode 100644 index 000000000..dd09034d1 --- /dev/null +++ b/openlp/plugins/songs/lib/wowimport.py @@ -0,0 +1,173 @@ +# -*- 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, 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 # +############################################################################### +""" +The :mod:`wowimport` module provides the functionality for importing Words of +Worship songs into the OpenLP database. +""" +import os +import logging + +from openlp.plugins.songs.lib.songimport import SongImport + +BLOCK_TYPES = (u'V', u'C', u'B') + +log = logging.getLogger(__name__) + +class WowImport(SongImport): + """ + The :class:`WowImport` class provides the ability to import song files from + Words of Worship. + + Words Of Worship Song File Format + ````````````````````````````````` + + The Words Of Worship song file format is as follows: + + * The song title is the file name minus the extension. + * The song has a header, a number of blocks, followed by footer containing + the author and the copyright. + * A block can be a verse, chorus or bridge. + + File Header: + Bytes are counted from one, i.e. the first byte is byte 1. These bytes, + up to the 56 byte, can change but no real meaning has been found. The + 56th byte specifies how many blocks there are. The first block starts + with byte 83 after the "CSongDoc::CBlock" declaration. + + Blocks: + Each block has a starting header, some lines of text, and an ending + footer. Each block starts with 4 bytes, the first byte specifies how + many lines are in that block, the next three bytes are null bytes. + + Each block ends with 4 bytes, the first of which defines what type of + block it is, and the rest which are null bytes: + + * ``NUL`` (\x00) - Verse + * ``SOH`` (\x01) - Chorus + * ``STX`` (\x02) - Bridge + + Blocks are seperated by two bytes. The first byte is ``SOH`` (\x01), + and the second byte is ``€`` (\x80). + + Lines: + Each line starts with a byte which specifies how long that line is, + the line text, and ends with a null byte. + + + Footer: + The footer follows on after the last block, the first byte specifies + the length of the author text, followed by the author text, if + this byte is null, then there is no author text. The byte after the + author text specifies the length of the copyright text, followed + by the copyright text. + + The file is ended with four null bytes. + + Valid extensions for a Words of Worship song file are: + + * .wsg + * .wow-song + """ + + def __init__(self, master_manager, **kwargs): + """ + Initialise the import. + + ``master_manager`` + The song manager for the running OpenLP installation. + """ + SongImport.__init__(self, master_manager) + self.master_manager = master_manager + if kwargs.has_key(u'filename'): + self.import_source = kwargs[u'filename'] + if kwargs.has_key(u'filenames'): + self.import_source = kwargs[u'filenames'] + log.debug(self.import_source) + + def do_import(self): + """ + Recieve a single file, or a list of files to import. + """ + + if isinstance(self.import_source, list): + self.import_wizard.importProgressBar.setMaximum( + len(self.import_source)) + for file in self.import_source: + # TODO: check that it is a valid words of worship file (could + # check header for WoW File Song Word) + self.author = u'' + self.copyright= u'' + # Get the song title + self.file_name = os.path.split(file)[1] + self.import_wizard.incrementProgressBar( + "Importing %s" % (self.file_name), 0) + self.title = self.file_name.rpartition(u'.')[0] + self.songData = open(file, 'rb') + # Seek to byte which stores number of blocks in the song + self.songData.seek(56) + self.no_of_blocks = ord(self.songData.read(1)) + # Seek to the beging of the first block + self.songData.seek(82) + for block in range(self.no_of_blocks): + self.lines_to_read = ord(self.songData.read(1)) + # Skip 3 nulls to the beginnig of the 1st line + self.songData.seek(3, os.SEEK_CUR) + self.block_text = u'' + while self.lines_to_read: + self.length_of_line = ord(self.songData.read(1)) + self.line_text = unicode( + self.songData.read(self.length_of_line), u'cp1252') + self.songData.seek(1, os.SEEK_CUR) + if self.block_text != u'': + self.block_text += u'\n' + self.block_text += self.line_text + self.lines_to_read -= 1 + self.block_type = BLOCK_TYPES[ord(self.songData.read(1))] + # Skip 3 nulls at the end of the block + self.songData.seek(3, os.SEEK_CUR) + # Blocks are seperated by 2 bytes, skip them, but not if + # this is the last block! + if (block + 1) < self.no_of_blocks: + self.songData.seek(2, os.SEEK_CUR) + self.add_verse(self.block_text, self.block_type) + # Now to extact the author + self.author_length = ord(self.songData.read(1)) + if self.author_length != 0: + self.author = unicode( + self.songData.read(self.author_length), u'cp1252') + # Finally the copyright + self.copyright_length = ord(self.songData.read(1)) + if self.copyright_length != 0: + self.copyright = unicode( + self.songData.read(self.copyright_length), u'cp1252') + self.parse_author(self.author) + self.add_copyright(self.copyright) + self.songData.close() + self.finish() + self.import_wizard.incrementProgressBar( + "Importing %s" % (self.file_name)) + return True +