diff --git a/openlp.pyw b/openlp.pyw index 9327a1168..80b49321e 100755 --- a/openlp.pyw +++ b/openlp.pyw @@ -162,18 +162,18 @@ def main(): the PyQt4 Application. """ # Set up command line options. - usage = u'Usage: %prog [options] [qt-options]' + usage = 'Usage: %prog [options] [qt-options]' parser = OptionParser(usage=usage) - parser.add_option(u'-e', u'--no-error-form', dest=u'no_error_form', - action=u'store_true', help=u'Disable the error notification form.') - parser.add_option(u'-l', u'--log-level', dest=u'loglevel', - default=u'warning', metavar=u'LEVEL', help=u'Set logging to LEVEL ' - u'level. Valid values are "debug", "info", "warning".') - parser.add_option(u'-p', u'--portable', dest=u'portable', - action=u'store_true', help=u'Specify if this should be run as a ' - u'portable app, off a USB flash drive (not implemented).') - parser.add_option(u'-s', u'--style', dest=u'style', - help=u'Set the Qt4 style (passed directly to Qt4).') + parser.add_option('-e', '--no-error-form', dest='no_error_form', + action='store_true', help='Disable the error notification form.') + parser.add_option('-l', '--log-level', dest='loglevel', + default='warning', metavar='LEVEL', help='Set logging to LEVEL ' + 'level. Valid values are "debug", "info", "warning".') + parser.add_option('-p', '--portable', dest='portable', + action='store_true', help='Specify if this should be run as a ' + 'portable app, off a USB flash drive (not implemented).') + parser.add_option('-s', '--style', dest='style', + help='Set the Qt4 style (passed directly to Qt4).') # Set up logging log_path = AppLocation.get_directory(AppLocation.CacheDir) if not os.path.exists(log_path): diff --git a/openlp/core/ui/exceptiondialog.py b/openlp/core/ui/exceptiondialog.py index 28097e938..49e2c8151 100644 --- a/openlp/core/ui/exceptiondialog.py +++ b/openlp/core/ui/exceptiondialog.py @@ -73,7 +73,7 @@ class Ui_ExceptionDialog(object): def retranslateUi(self, exceptionDialog): exceptionDialog.setWindowTitle( - translate('OpenLP.ExceptionDialog', 'Error Occured')) + translate('OpenLP.ExceptionDialog', 'Error Occurred')) self.messageLabel.setText(translate('OpenLP.ExceptionDialog', 'Oops! ' 'OpenLP hit a problem, and couldn\'t recover. The text in the box ' 'below contains information that might be helpful to the OpenLP ' diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index 60a6ae2b7..0d158d042 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -575,7 +575,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): QtCore.SIGNAL(u'toggled(bool)'), self.setAutoLanguage) self.LanguageGroup.triggered.connect(LanguageManager.set_language) QtCore.QObject.connect(self.ModeDefaultItem, - QtCore.SIGNAL(u'triggered()'), self.setViewMode) + QtCore.SIGNAL(u'triggered()'), self.onModeDefaultItemClicked) QtCore.QObject.connect(self.ModeSetupItem, QtCore.SIGNAL(u'triggered()'), self.onModeSetupItemClicked) QtCore.QObject.connect(self.ModeLiveItem, @@ -670,6 +670,16 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): self.generalSettingsSection + u'/auto open', QtCore.QVariant(False)).toBool(): self.ServiceManagerContents.onLoadService(True) + view_mode = QtCore.QSettings().value(u'%s/view mode' % \ + self.generalSettingsSection, u'default') + if view_mode == u'default': + self.ModeDefaultItem.setChecked(True) + elif view_mode == u'setup': + self.setViewMode(True, True, False, True, False) + self.ModeSetupItem.setChecked(True) + elif view_mode == u'live': + self.setViewMode(False, True, False, False, True) + self.ModeLiveItem.setChecked(True) def blankCheck(self): """ @@ -677,8 +687,8 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): Triggered by delay thread. """ settings = QtCore.QSettings() - settings.beginGroup(self.generalSettingsSection) - if settings.value(u'screen blank', QtCore.QVariant(False)).toBool(): + if settings.value(u'%s/screen blank' % self.generalSettingsSection, + QtCore.QVariant(False)).toBool(): self.LiveController.mainDisplaySetBackground() if settings.value(u'blank warning', QtCore.QVariant(False)).toBool(): @@ -687,7 +697,6 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): 'OpenLP Main Display Blanked'), translate('OpenLP.MainWindow', 'The Main Display has been blanked out')) - settings.endGroup() def onHelpWebSiteClicked(self): """ @@ -716,16 +725,31 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): """ self.settingsForm.exec_() + def onModeDefaultItemClicked(self): + """ + Put OpenLP into "Default" view mode. + """ + settings = QtCore.QSettings() + settings.setValue(u'%s/view mode' % self.generalSettingsSection, + u'default') + self.setViewMode(True, True, True, True, True) + def onModeSetupItemClicked(self): """ Put OpenLP into "Setup" view mode. """ + settings = QtCore.QSettings() + settings.setValue(u'%s/view mode' % self.generalSettingsSection, + u'setup') self.setViewMode(True, True, False, True, False) def onModeLiveItemClicked(self): """ Put OpenLP into "Live" view mode. """ + settings = QtCore.QSettings() + settings.setValue(u'%s/view mode' % self.generalSettingsSection, + u'live') self.setViewMode(False, True, False, False, True) def setViewMode(self, media=True, service=True, theme=True, preview=True, diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index b2058a2e1..8db14956d 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -884,7 +884,8 @@ class ServiceManager(QtGui.QWidget): QtGui.QMessageBox.critical(self, translate('OpenLP.ServiceManager', 'Missing Display Handler'), translate('OpenLP.ServiceManager', 'Your item cannot be ' - 'displayed as there is no handler to display it')) + 'displayed as the plugin required to display it is missing ' + 'or inactive')) def remoteEdit(self): """ diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py index 9f9b4d433..7a2e3ccf0 100644 --- a/openlp/core/ui/slidecontroller.py +++ b/openlp/core/ui/slidecontroller.py @@ -209,7 +209,8 @@ class SlideController(QtGui.QWidget): self.Toolbar.addToolbarSeparator(u'Close Separator') self.Toolbar.addToolbarButton( u'Edit Song', u':/general/general_edit.png', - translate('OpenLP.SlideController', 'Edit and re-preview song'), + translate('OpenLP.SlideController', + 'Edit and reload song preview'), self.onEditSong) if isLive: self.Toolbar.addToolbarSeparator(u'Loop Separator') diff --git a/openlp/core/ui/thememanager.py b/openlp/core/ui/thememanager.py index 3ad6b5c8d..d8324f977 100644 --- a/openlp/core/ui/thememanager.py +++ b/openlp/core/ui/thememanager.py @@ -242,14 +242,14 @@ class ThemeManager(QtGui.QWidget): QtGui.QMessageBox.critical(self, translate('OpenLP.ThemeManager', 'Error'), unicode(translate('OpenLP.ThemeManager', - 'Theme %s is use in %s plugin.')) % \ + 'Theme %s is used in the %s plugin.')) % \ (theme, plugin.name)) return if unicode(self.serviceComboBox.currentText()) == theme: QtGui.QMessageBox.critical(self, translate('OpenLP.ThemeManager', 'Error'), unicode(translate('OpenLP.ThemeManager', - 'Theme %s is use by the service manager.')) % theme) + 'Theme %s is used by the service manager.')) % theme) return row = self.themeListWidget.row(item) self.themeListWidget.takeItem(row) diff --git a/openlp/plugins/bibles/forms/importwizardform.py b/openlp/plugins/bibles/forms/importwizardform.py index 67f3756dc..84f0f41ee 100644 --- a/openlp/plugins/bibles/forms/importwizardform.py +++ b/openlp/plugins/bibles/forms/importwizardform.py @@ -182,7 +182,7 @@ class ImportWizardForm(QtGui.QWizard, Ui_BibleImportWizard): translate('BiblesPlugin.ImportWizardForm', 'Empty Copyright'), translate('BiblesPlugin.ImportWizardForm', - 'You need to set a copyright for your Bible! ' + 'You need to set a copyright for your Bible. ' 'Bibles in the Public Domain need to be marked as ' 'such.')) self.CopyrightEdit.setFocus() @@ -192,7 +192,7 @@ class ImportWizardForm(QtGui.QWizard, Ui_BibleImportWizard): translate('BiblesPlugin.ImportWizardForm', 'Bible Exists'), translate('BiblesPlugin.ImportWizardForm', - 'This Bible already exists! Please import ' + 'This Bible already exists. Please import ' 'a different Bible or first delete the existing one.')) self.VersionNameEdit.setFocus() return False diff --git a/openlp/plugins/bibles/lib/manager.py b/openlp/plugins/bibles/lib/manager.py index 4f35556f1..fd2c2adff 100644 --- a/openlp/plugins/bibles/lib/manager.py +++ b/openlp/plugins/bibles/lib/manager.py @@ -246,7 +246,7 @@ class BibleManager(object): translate('BiblesPlugin.BibleManager', 'Scripture Reference Error'), translate('BiblesPlugin.BibleManager', 'Your scripture ' - 'reference is either not supported by OpenLP or invalid. ' + 'reference is either not supported by OpenLP or is invalid. ' 'Please make sure your reference conforms to one of the ' 'following patterns:\n\n' 'Book Chapter\n' diff --git a/openlp/plugins/presentations/lib/impresscontroller.py b/openlp/plugins/presentations/lib/impresscontroller.py index 9ada43a5a..d054c3e9c 100644 --- a/openlp/plugins/presentations/lib/impresscontroller.py +++ b/openlp/plugins/presentations/lib/impresscontroller.py @@ -74,6 +74,7 @@ class ImpressController(PresentationController): self.process = None self.desktop = None self.manager = None + self.uno_connection_type = u'pipe' #u'socket' def check_available(self): """ @@ -98,7 +99,14 @@ class ImpressController(PresentationController): self.manager._FlagAsMethod(u'Bridge_GetValueObject') else: # -headless - cmd = u'openoffice.org -nologo -norestore -minimized -invisible -nofirststartwizard -accept="socket,host=localhost,port=2002;urp;"' + if self.uno_connection_type == u'pipe': + cmd = u'openoffice.org -nologo -norestore -minimized ' \ + + u'-invisible -nofirststartwizard ' \ + + u'-accept=pipe,name=openlp_pipe;urp;' + else: + cmd = u'openoffice.org -nologo -norestore -minimized ' \ + + u'-invisible -nofirststartwizard ' \ + + u'-accept=socket,host=localhost,port=2002;urp;' self.process = QtCore.QProcess() self.process.startDetached(cmd) self.process.waitForStarted() @@ -120,8 +128,14 @@ class ImpressController(PresentationController): while ctx is None and loop < 3: try: log.debug(u'get UNO Desktop Openoffice - resolve') - ctx = resolver.resolve(u'uno:socket,host=localhost,port=2002;' - u'urp;StarOffice.ComponentContext') + if self.uno_connection_type == u'pipe': + ctx = resolver.resolve(u'uno:' \ + + u'pipe,name=openlp_pipe;' \ + + u'urp;StarOffice.ComponentContext') + else: + ctx = resolver.resolve(u'uno:' \ + + u'socket,host=localhost,port=2002;' \ + + u'urp;StarOffice.ComponentContext') except: log.exception(u'Unable to find running instance ') self.start_process() diff --git a/openlp/plugins/songs/forms/authorsform.py b/openlp/plugins/songs/forms/authorsform.py index c7d1b0396..1dacd82cc 100644 --- a/openlp/plugins/songs/forms/authorsform.py +++ b/openlp/plugins/songs/forms/authorsform.py @@ -97,8 +97,7 @@ class AuthorsForm(QtGui.QDialog, Ui_AuthorsDialog): self, translate('SongsPlugin.AuthorsForm', 'Error'), translate('SongsPlugin.AuthorsForm', 'You have not set a display name for the ' - 'author, would you like me to combine the first and ' - 'last names for you?'), + 'author, combine the first and last names?'), QtGui.QMessageBox.StandardButtons( QtGui.QMessageBox.Yes | QtGui.QMessageBox.No) ) == QtGui.QMessageBox.Yes: diff --git a/openlp/plugins/songs/forms/editsongform.py b/openlp/plugins/songs/forms/editsongform.py index 458e7200c..ae9938ab4 100644 --- a/openlp/plugins/songs/forms/editsongform.py +++ b/openlp/plugins/songs/forms/editsongform.py @@ -621,6 +621,10 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog): self.close() def saveSong(self): + """ + Get all the data from the widgets on the form, and then save it to the + database. + """ self.song.title = unicode(self.TitleEditItem.text()) self.song.alternate_title = unicode(self.AlternativeEdit.text()) self.song.copyright = unicode(self.CopyrightEditItem.text()) @@ -646,6 +650,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog): self.song.topics.append(self.songmanager.get_object(Topic, topicId)) self.songmanager.save_object(self.song) + self.song = None return True return False diff --git a/openlp/plugins/songs/forms/songimportwizard.py b/openlp/plugins/songs/forms/songimportwizard.py index 9ae6d7348..37ee10612 100644 --- a/openlp/plugins/songs/forms/songimportwizard.py +++ b/openlp/plugins/songs/forms/songimportwizard.py @@ -519,7 +519,7 @@ class Ui_SongImportWizard(object): self.openLyricsDisabledLabel.setText( translate('SongsPlugin.ImportWizardForm', 'The OpenLyrics ' 'importer has not yet been developed, but as you can see, we are ' - 'still intendeding to do so. Hopefully it will be in the next ' + 'still intending to do so. Hopefully it will be in the next ' 'release.')) self.openSongAddButton.setText( translate('SongsPlugin.ImportWizardForm', 'Add Files...')) diff --git a/openlp/plugins/songs/forms/songmaintenanceform.py b/openlp/plugins/songs/forms/songmaintenanceform.py index a2c12a6d6..48f9a5a55 100644 --- a/openlp/plugins/songs/forms/songmaintenanceform.py +++ b/openlp/plugins/songs/forms/songmaintenanceform.py @@ -324,8 +324,8 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog): QtGui.QMessageBox.critical(self, translate('SongsPlugin.SongMaintenanceForm', 'Error'), translate('SongsPlugin.SongMaintenanceForm', - 'Could not save your modified author, because he ' - 'already exists.')) + 'Could not save your modified author, because the ' + 'author already exists.')) def onTopicEditButtonClick(self): topic_id = self._getCurrentItemId(self.TopicsListWidget) diff --git a/openlp/plugins/songs/forms/topicsform.py b/openlp/plugins/songs/forms/topicsform.py index a618dd9db..c45228527 100644 --- a/openlp/plugins/songs/forms/topicsform.py +++ b/openlp/plugins/songs/forms/topicsform.py @@ -51,7 +51,7 @@ class TopicsForm(QtGui.QDialog, Ui_TopicsDialog): QtGui.QMessageBox.critical( self, translate('SongsPlugin.TopicsForm', 'Error'), translate('SongsPlugin.TopicsForm', - 'You need to type in a topic name!')) + 'You need to type in a topic name.')) self.NameEdit.setFocus() return False else: diff --git a/openlp/plugins/songs/lib/olp1import.py b/openlp/plugins/songs/lib/olp1import.py index 692c6792e..de750cb24 100644 --- a/openlp/plugins/songs/lib/olp1import.py +++ b/openlp/plugins/songs/lib/olp1import.py @@ -41,6 +41,8 @@ class OpenLP1SongImport(SongImport): The :class:`OpenLP1SongImport` class provides OpenLP with the ability to import song databases from installations of openlp.org 1.x. """ + last_encoding = u'windows-1252' + def __init__(self, manager, **kwargs): """ Initialise the import. @@ -54,20 +56,33 @@ class OpenLP1SongImport(SongImport): SongImport.__init__(self, manager) self.import_source = kwargs[u'filename'] - def decode_string(self, raw): + def decode_string(self, raw, guess): """ Use chardet to detect the encoding of the raw string, and convert it to unicode. ``raw`` The raw bytestring to decode. + ``guess`` + What chardet guessed the encoding to be. """ - detection = chardet.detect(raw) - if detection[u'confidence'] < 0.8: + if guess[u'confidence'] < 0.8: codec = u'windows-1252' else: - codec = detection[u'encoding'] - return unicode(raw, codec) + codec = guess[u'encoding'] + try: + decoded = unicode(raw, codec) + self.last_encoding = codec + except UnicodeDecodeError: + log.exception(u'Error in detecting openlp.org 1.x database encoding.') + try: + decoded = unicode(raw, self.last_encoding) + except UnicodeDecodeError: + # possibly show an error form + #self.import_wizard.showError(u'There was a problem ' + # u'detecting the encoding of a string') + decoded = raw + return decoded def do_import(self): """ @@ -103,9 +118,10 @@ class OpenLP1SongImport(SongImport): success = False break song_id = song[0] - title = self.decode_string(song[1]) - lyrics = self.decode_string(song[2]).replace(u'\r', u'') - copyright = self.decode_string(song[3]) + guess = chardet.detect(song[2]) + title = self.decode_string(song[1], guess) + lyrics = self.decode_string(song[2], guess).replace(u'\r', u'') + copyright = self.decode_string(song[3], guess) self.import_wizard.incrementProgressBar( unicode(translate('SongsPlugin.ImportWizardForm', 'Importing "%s"...')) % title) @@ -121,7 +137,7 @@ class OpenLP1SongImport(SongImport): break for author in authors: if author[0] == author_id[0]: - self.parse_author(self.decode_string(author[1])) + self.parse_author(self.decode_string(author[1], guess)) break if self.stop_import_flag: success = False @@ -136,7 +152,7 @@ class OpenLP1SongImport(SongImport): break for track in tracks: if track[0] == track_id[0]: - self.add_media_file(self.decode_string(track[1])) + self.add_media_file(self.decode_string(track[1], guess)) break if self.stop_import_flag: success = False diff --git a/openlp/plugins/songs/lib/oooimport.py b/openlp/plugins/songs/lib/oooimport.py index e8c723c0e..26a0abfcc 100644 --- a/openlp/plugins/songs/lib/oooimport.py +++ b/openlp/plugins/songs/lib/oooimport.py @@ -59,6 +59,7 @@ class OooImport(SongImport): self.document = None self.process_started = False self.filenames = kwargs[u'filenames'] + self.uno_connection_type = u'pipe' #u'socket' QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'song_stop_import'), self.stop_import) @@ -106,8 +107,14 @@ class OooImport(SongImport): loop = 0 while ctx is None and loop < 5: try: - ctx = resolver.resolve(u'uno:socket,host=localhost,' \ - + 'port=2002;urp;StarOffice.ComponentContext') + if self.uno_connection_type == u'pipe': + ctx = resolver.resolve(u'uno:' \ + + u'pipe,name=openlp_pipe;' \ + + u'urp;StarOffice.ComponentContext') + else: + ctx = resolver.resolve(u'uno:' \ + + u'socket,host=localhost,port=2002;' \ + + u'urp;StarOffice.ComponentContext') except: pass self.start_ooo_process() @@ -123,9 +130,14 @@ class OooImport(SongImport): self.manager._FlagAsMethod(u'Bridge_GetStruct') self.manager._FlagAsMethod(u'Bridge_GetValueObject') else: - cmd = u'openoffice.org -nologo -norestore -minimized ' \ - + u'-invisible -nofirststartwizard ' \ - + '-accept="socket,host=localhost,port=2002;urp;"' + if self.uno_connection_type == u'pipe': + cmd = u'openoffice.org -nologo -norestore -minimized ' \ + + u'-invisible -nofirststartwizard ' \ + + u'-accept=pipe,name=openlp_pipe;urp;' + else: + cmd = u'openoffice.org -nologo -norestore -minimized ' \ + + u'-invisible -nofirststartwizard ' \ + + u'-accept=socket,host=localhost,port=2002;urp;' process = QtCore.QProcess() process.startDetached(cmd) process.waitForStarted() diff --git a/openlp/plugins/songs/lib/opensongimport.py b/openlp/plugins/songs/lib/opensongimport.py index 86ccb5933..f4be0dc87 100644 --- a/openlp/plugins/songs/lib/opensongimport.py +++ b/openlp/plugins/songs/lib/opensongimport.py @@ -29,6 +29,7 @@ import os from zipfile import ZipFile from lxml import objectify from lxml.etree import Error, LxmlError +import re from openlp.core.lib import translate from openlp.plugins.songs.lib.songimport import SongImport @@ -113,12 +114,22 @@ class OpenSongImport(SongImport): def do_import(self): """ - Import 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). + 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(len(self.filenames)) + numfiles = 0 + for filename in self.filenames: + ext = os.path.splitext(filename)[1] + if ext.lower() == u'.zip': + z = ZipFile(filename, u'r') + numfiles += len(z.infolist()) + else: + numfiles += 1 + log.debug("Total number of files: %d", numfiles) + self.import_wizard.importProgressBar.setMaximum(numfiles) for filename in self.filenames: if self.stop_import_flag: success = False @@ -127,9 +138,6 @@ class OpenSongImport(SongImport): if ext.lower() == u'.zip': log.debug(u'Zipfile found %s', filename) z = ZipFile(filename, u'r') - self.import_wizard.importProgressBar.setMaximum( - self.import_wizard.importProgressBar.maximum() + - len(z.infolist())) for song in z.infolist(): if self.stop_import_flag: success = False @@ -138,6 +146,7 @@ class OpenSongImport(SongImport): if parts[-1] == u'': #No final part => directory continue + log.info(u'Zip importing %s', parts[-1]) self.import_wizard.incrementProgressBar( unicode(translate('SongsPlugin.ImportWizardForm', 'Importing %s...')) % parts[-1]) @@ -145,11 +154,11 @@ class OpenSongImport(SongImport): self.do_import_file(songfile) if self.commit: self.finish() - self.set_defaults() if self.stop_import_flag: success = False break else: + # not a zipfile log.info('Direct import %s', filename) self.import_wizard.incrementProgressBar( unicode(translate('SongsPlugin.ImportWizardForm', @@ -158,9 +167,7 @@ class OpenSongImport(SongImport): self.do_import_file(file) if self.commit: self.finish() - self.set_defaults() - if not self.commit: - self.finish() + return success def do_import_file(self, file): @@ -168,7 +175,7 @@ class OpenSongImport(SongImport): Process the OpenSong file - pass in a file-like object, not a filename """ - self.authors = [] + self.set_defaults() try: tree = objectify.parse(file) except (Error, LxmlError): @@ -197,7 +204,6 @@ class OpenSongImport(SongImport): self.topics.append(unicode(root.alttheme)) # data storage while importing verses = {} - lyrics = unicode(root.lyrics) # keep track of a "default" verse order, in case none is specified our_verse_order = [] verses_seen = {} @@ -205,6 +211,7 @@ class OpenSongImport(SongImport): # erm, versetype! versetype = u'V' versenum = None + lyrics = unicode(root.lyrics) for thisline in lyrics.split(u'\n'): # remove comments semicolon = thisline.find(u';') @@ -219,16 +226,18 @@ class OpenSongImport(SongImport): continue # verse/chorus/etc. marker if thisline[0] == u'[': - versetype = thisline[1].upper() - if versetype.isdigit(): - versenum = versetype - versetype = u'V' - elif thisline[2] != u']': - # there's a number to go with it - extract that as well - right_bracket = thisline.find(u']') - versenum = thisline[2:right_bracket] + # 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: - # if there's no number, assume it's no.1 + # otherwise we assume number 1 and take the whole prefix as versetype + versetype = content versenum = u'1' continue words = None @@ -236,10 +245,10 @@ class OpenSongImport(SongImport): if thisline[0].isdigit(): versenum = thisline[0] words = thisline[1:].strip() - if words is None and \ - versenum is not None and \ - versetype is not None: + 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): @@ -260,10 +269,13 @@ class OpenSongImport(SongImport): versetypes.sort() versetags = {} for versetype in versetypes: + our_verse_type = versetype + if our_verse_type == u'': + our_verse_type = u'V' versenums = verses[versetype].keys() versenums.sort() for num in versenums: - versetag = u'%s%s' % (versetype, num) + versetag = u'%s%s' % (our_verse_type, num) lines = u'\n'.join(verses[versetype][num]) self.verses.append([versetag, lines]) # Keep track of what we have for error checking later @@ -272,7 +284,9 @@ class OpenSongImport(SongImport): order = [] if u'presentation' in fields and root.presentation != u'': order = unicode(root.presentation) - order = order.split() + # We make all the tags in the lyrics upper case, so match that here + # and then split into a list on the whitespace + order = order.upper().split() else: if len(our_verse_order) > 0: order = our_verse_order @@ -280,9 +294,13 @@ class OpenSongImport(SongImport): log.warn(u'No verse order available for %s, skipping.', self.title) for tag in order: - if len(tag) == 1: - tag = tag + u'1' # Assume it's no.1 if it's not there + 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.warn(u'Got order %s but not in versetags, skipping', tag) + log.info(u'Got order %s but not in versetags, dropping this item from presentation order', tag) else: self.verse_order_list.append(tag) diff --git a/openlp/plugins/songs/lib/songimport.py b/openlp/plugins/songs/lib/songimport.py index 30c1865a7..dcf4ed8d8 100644 --- a/openlp/plugins/songs/lib/songimport.py +++ b/openlp/plugins/songs/lib/songimport.py @@ -55,8 +55,12 @@ class SongImport(QtCore.QObject): self.set_defaults() QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'songs_stop_import'), self.stop_import) - def set_defaults(self): + """ + Create defaults for properties - call this before each song + if importing many songs at once to ensure a clean beginning + """ + self.authors = [] self.title = u'' self.song_number = u'' self.alternate_title = u'' @@ -255,13 +259,16 @@ class SongImport(QtCore.QObject): """ Write the song and its fields to disk """ + log.info(u'commiting song %s to database', self.title) song = Song() song.title = self.title song.search_title = self.remove_punctuation(self.title) \ + '@' + self.alternate_title song.song_number = self.song_number song.search_lyrics = u'' + verses_changed_to_other = {} sxml = SongXMLBuilder() + other_count = 1 for (versetag, versetext) in self.verses: if versetag[0] == u'C': versetype = VerseType.to_string(VerseType.Chorus) @@ -276,10 +283,18 @@ class SongImport(QtCore.QObject): elif versetag[0] == u'E': versetype = VerseType.to_string(VerseType.Ending) else: + newversetag = u'O%d' % other_count + verses_changed_to_other[versetag] = newversetag + other_count += 1 versetype = VerseType.to_string(VerseType.Other) + log.info(u'Versetype %s changing to %s' , versetag, newversetag) + versetag = newversetag sxml.add_verse_to_lyrics(versetype, versetag[1:], versetext) song.search_lyrics += u' ' + self.remove_punctuation(versetext) song.lyrics = unicode(sxml.extract_xml(), u'utf-8') + for i, current_verse_tag in enumerate(self.verse_order_list): + if verses_changed_to_other.has_key(current_verse_tag): + self.verse_order_list[i] = verses_changed_to_other[current_verse_tag] song.verse_order = u' '.join(self.verse_order_list) song.copyright = self.copyright song.comments = self.comments diff --git a/openlp/plugins/songs/lib/test/test.opensong b/openlp/plugins/songs/lib/test/test.opensong index 1ce60cf3b..c75951492 100644 --- a/openlp/plugins/songs/lib/test/test.opensong +++ b/openlp/plugins/songs/lib/test/test.opensong @@ -1,10 +1,10 @@ Martins Test - MartiÑ Thómpson + MartiÑ & Martin2 Thómpson 2010 Martin Thompson 1 - V1 C V2 C2 V3 B1 V1 + V1 C V2 C2 3a B1 V1 T U Rap1 Rap2 Rap3 Blah @@ -17,7 +17,12 @@ TestAltTheme - ;Comment + [3a] +. G A B + V3 Line 1 +. G A B + V3 Line 2 + . A B C 1 v1 Line 1___ 2 v2 Line 1___ @@ -25,10 +30,6 @@ 1 V1 Line 2 2 V2 Line 2 -[3] - V3 Line 1 - V3 Line 2 - [b1] Bridge 1 --- @@ -36,12 +37,29 @@ Bridge 1 line 2 [C] -. A B + . A B Chorus 1 [C2] . A B Chorus 2 + +[T] + T Line 1 + +[Rap] +1 Rap 1 Line 1 +2 Rap 2 Line 1 +1 Rap 1 Line 2 +2 Rap 2 Line 2 + +[rap3] + Rap 3 Line 1 + Rap 3 Line 2 + + +[X] + Unreferenced verse line 1