diff --git a/openlp.pyw b/openlp.pyw index 805181c11..9327a1168 100755 --- a/openlp.pyw +++ b/openlp.pyw @@ -147,6 +147,9 @@ class OpenLP(QtGui.QApplication): return self.exec_() def hookException(self, exctype, value, traceback): + if not hasattr(self, u'mainWindow'): + log.exception(''.join(format_exception(exctype, value, traceback))) + return if not hasattr(self, u'exceptionForm'): self.exceptionForm = ExceptionForm(self.mainWindow) self.exceptionForm.exceptionTextEdit.setPlainText( @@ -161,16 +164,16 @@ def main(): # Set up command line options. usage = u'Usage: %prog [options] [qt-options]' parser = OptionParser(usage=usage) - 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.") - parser.add_option("-s", "--style", dest="style", - help="Set the Qt4 style (passed directly to Qt4).") + 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).') # Set up logging log_path = AppLocation.get_directory(AppLocation.CacheDir) if not os.path.exists(log_path): @@ -203,7 +206,8 @@ def main(): language = LanguageManager.get_language() appTranslator = LanguageManager.get_translator(language) app.installTranslator(appTranslator) - sys.excepthook = app.hookException + if not options.no_error_form: + sys.excepthook = app.hookException sys.exit(app.run()) if __name__ == u'__main__': diff --git a/openlp/core/lib/__init__.py b/openlp/core/lib/__init__.py index 1f911491f..b325f0c6c 100644 --- a/openlp/core/lib/__init__.py +++ b/openlp/core/lib/__init__.py @@ -38,63 +38,48 @@ log = logging.getLogger(__name__) # TODO make external and configurable in alpha 4 via a settings dialog html_expands = [] -html_expands.append({u'desc':u'Red', u'start tag':u'{r}', \ - u'start html':u'', \ - u'end tag':u'{/r}', u'end html':u'', \ - u'protected':False}) -html_expands.append({u'desc':u'Black', u'start tag':u'{b}', \ - u'start html':u'', \ - u'end tag':u'{/b}', u'end html':u'', \ - u'protected':False}) -html_expands.append({u'desc':u'Blue', u'start tag':u'{bl}', \ - u'start html':u'', \ - u'end tag':u'{/bl}', u'end html':u'', \ - u'protected':False}) -html_expands.append({u'desc':u'Yellow', u'start tag':u'{y}', \ - u'start html':u'', \ - u'end tag':u'{/y}', u'end html':u'', \ - u'protected':False}) -html_expands.append({u'desc':u'Green', u'start tag':u'{g}', \ - u'start html':u'', \ - u'end tag':u'{/g}', u'end html':u'', \ - u'protected':False}) -html_expands.append({u'desc':u'Pink', u'start tag':u'{pk}', \ - u'start html':u'', \ - u'end tag':u'{/pk}', u'end html':u'', \ - u'protected':False}) -html_expands.append({u'desc':u'Orange', u'start tag':u'{o}', \ - u'start html':u'', \ - u'end tag':u'{/o}', u'end html':u'', \ - u'protected':False}) -html_expands.append({u'desc':u'Purple', u'start tag':u'{pp}', \ - u'start html':u'', \ - u'end tag':u'{/pp}', u'end html':u'', \ - u'protected':False}) -html_expands.append({u'desc':u'White', u'start tag':u'{w}', \ - u'start html':u'', \ - u'end tag':u'{/w}', u'end html':u'', \ - u'protected':False}) -html_expands.append({u'desc':u'Superscript', u'start tag':u'{su}', \ - u'start html':u'', \ - u'end tag':u'{/su}', u'end html':u'', \ - u'protected':True}) -html_expands.append({u'desc':u'Subscript', u'start tag':u'{sb}', \ - u'start html':u'', \ - u'end tag':u'{/sb}', u'end html':u'', \ - u'protected':True}) -html_expands.append({u'desc':u'Paragraph', u'start tag':u'{p}', \ - u'start html':u'

', \ - u'end tag':u'{/p}', u'end html':u'

', \ - u'protected':True}) -html_expands.append({u'desc':u'Bold', u'start tag':u'{st}', \ - u'start html':u'', \ - u'end tag':u'{/st}', \ - u'end html':u'', \ - u'protected':True}) -html_expands.append({u'desc':u'Italics', u'start tag':u'{it}', \ - u'start html':u'', \ - u'end tag':u'{/it}', u'end html':u'', \ - u'protected':True}) +html_expands.append({u'desc':u'Red', u'start tag':u'{r}', + u'start html':u'', + u'end tag':u'{/r}', u'end html':u'', u'protected':False}) +html_expands.append({u'desc':u'Black', u'start tag':u'{b}', + u'start html':u'', + u'end tag':u'{/b}', u'end html':u'', u'protected':False}) +html_expands.append({u'desc':u'Blue', u'start tag':u'{bl}', + u'start html':u'', + u'end tag':u'{/bl}', u'end html':u'', u'protected':False}) +html_expands.append({u'desc':u'Yellow', u'start tag':u'{y}', + u'start html':u'', + u'end tag':u'{/y}', u'end html':u'', u'protected':False}) +html_expands.append({u'desc':u'Green', u'start tag':u'{g}', + u'start html':u'', + u'end tag':u'{/g}', u'end html':u'', u'protected':False}) +html_expands.append({u'desc':u'Pink', u'start tag':u'{pk}', + u'start html':u'', + u'end tag':u'{/pk}', u'end html':u'', u'protected':False}) +html_expands.append({u'desc':u'Orange', u'start tag':u'{o}', + u'start html':u'', + u'end tag':u'{/o}', u'end html':u'', u'protected':False}) +html_expands.append({u'desc':u'Purple', u'start tag':u'{pp}', + u'start html':u'', + u'end tag':u'{/pp}', u'end html':u'', u'protected':False}) +html_expands.append({u'desc':u'White', u'start tag':u'{w}', + u'start html':u'', + u'end tag':u'{/w}', u'end html':u'', u'protected':False}) +html_expands.append({u'desc':u'Superscript', u'start tag':u'{su}', + u'start html':u'', u'end tag':u'{/su}', u'end html':u'', + u'protected':True}) +html_expands.append({u'desc':u'Subscript', u'start tag':u'{sb}', + u'start html':u'', u'end tag':u'{/sb}', u'end html':u'', + u'protected':True}) +html_expands.append({u'desc':u'Paragraph', u'start tag':u'{p}', + u'start html':u'

', u'end tag':u'{/p}', u'end html':u'

', + u'protected':True}) +html_expands.append({u'desc':u'Bold', u'start tag':u'{st}', + u'start html':u'', u'end tag':u'{/st}', u'end html':u'', + u'protected':True}) +html_expands.append({u'desc':u'Italics', u'start tag':u'{it}', + u'start html':u'', u'end tag':u'{/it}', u'end html':u'', + u'protected':True}) def translate(context, text, comment=None): """ diff --git a/openlp/core/lib/mediamanageritem.py b/openlp/core/lib/mediamanageritem.py index a6d62f618..625a74842 100644 --- a/openlp/core/lib/mediamanageritem.py +++ b/openlp/core/lib/mediamanageritem.py @@ -432,7 +432,7 @@ class MediaManagerItem(QtGui.QWidget): raise NotImplementedError(u'MediaManagerItem.onDeleteClick needs to ' u'be defined by the plugin') - def generateSlideData(self, service_item, item): + def generateSlideData(self, service_item, item=None): raise NotImplementedError(u'MediaManagerItem.generateSlideData needs ' u'to be defined by the plugin') diff --git a/openlp/core/ui/maindisplay.py b/openlp/core/ui/maindisplay.py index 3e0b070b9..a2b9dd81a 100644 --- a/openlp/core/ui/maindisplay.py +++ b/openlp/core/ui/maindisplay.py @@ -120,7 +120,7 @@ class MainDisplay(DisplayWidget): self.setScene(self.scene) self.webView = QtWebKit.QGraphicsWebView() self.scene.addItem(self.webView) - self.webView.resize(self.screen[u'size'].width(), \ + self.webView.resize(self.screen[u'size'].width(), self.screen[u'size'].height()) self.page = self.webView.page() self.frame = self.page.mainFrame() @@ -303,6 +303,9 @@ class MainDisplay(DisplayWidget): Generates a preview of the image displayed. """ log.debug(u'preview for %s', self.isLive) + # We must have a service item to preview + if not hasattr(self, u'serviceItem'): + return if self.isLive: # Wait for the fade to finish before geting the preview. # Important otherwise preview will have incorrect text if at all ! @@ -336,7 +339,7 @@ class MainDisplay(DisplayWidget): self.loaded = False self.initialFrame = False self.serviceItem = serviceItem - html = build_html(self.serviceItem, self.screen, self.parent.alertTab,\ + html = build_html(self.serviceItem, self.screen, self.parent.alertTab, self.isLive) self.webView.setHtml(html) if serviceItem.foot_text and serviceItem.foot_text: diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index b6b915b7f..b2058a2e1 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -279,7 +279,8 @@ class ServiceManager(QtGui.QWidget): self.editAction.setVisible(False) self.maintainAction.setVisible(False) self.notesAction.setVisible(False) - if serviceItem[u'service_item'].is_capable(ItemCapabilities.AllowsEdit): + if serviceItem[u'service_item'].is_capable(ItemCapabilities.AllowsEdit) \ + and hasattr(serviceItem[u'service_item'], u'editId'): self.editAction.setVisible(True) if serviceItem[u'service_item']\ .is_capable(ItemCapabilities.AllowsMaintain): diff --git a/openlp/core/utils/__init__.py b/openlp/core/utils/__init__.py index e728fb544..ea14b2259 100644 --- a/openlp/core/utils/__init__.py +++ b/openlp/core/utils/__init__.py @@ -112,7 +112,11 @@ class AppLocation(object): The directory type you want, for instance the data directory. """ if dir_type == AppLocation.AppDir: - return os.path.abspath(os.path.split(sys.argv[0])[0]) + if hasattr(sys, u'frozen') and sys.frozen == 1: + app_path = os.path.abspath(os.path.split(sys.argv[0])[0]) + else: + app_path = os.path.split(openlp.__file__)[0] + return app_path elif dir_type == AppLocation.ConfigDir: if sys.platform == u'win32': path = os.path.join(os.getenv(u'APPDATA'), u'openlp') diff --git a/openlp/core/utils/languagemanager.py b/openlp/core/utils/languagemanager.py index bcb16e7cc..a264e15a9 100644 --- a/openlp/core/utils/languagemanager.py +++ b/openlp/core/utils/languagemanager.py @@ -55,7 +55,7 @@ class LanguageManager(object): if LanguageManager.AutoLanguage: language = QtCore.QLocale.system().name() lang_path = AppLocation.get_directory(AppLocation.AppDir) - lang_path = os.path.join(lang_path, u'resources', u'i18n') + lang_path = os.path.join(lang_path, u'i18n') app_translator = QtCore.QTranslator() if app_translator.load("openlp_" + language, lang_path): return app_translator @@ -66,7 +66,7 @@ class LanguageManager(object): Find all available language files in this OpenLP install """ trans_dir = AppLocation.get_directory(AppLocation.AppDir) - trans_dir = QtCore.QDir(os.path.join(trans_dir, u'openlp', u'i18n')) + trans_dir = QtCore.QDir(os.path.join(trans_dir, u'i18n')) file_names = trans_dir.entryList(QtCore.QStringList("*.qm"), QtCore.QDir.Files, QtCore.QDir.Name) for name in file_names: diff --git a/openlp/plugins/bibles/lib/mediaitem.py b/openlp/plugins/bibles/lib/mediaitem.py index 57e70617a..fa954d2a0 100644 --- a/openlp/plugins/bibles/lib/mediaitem.py +++ b/openlp/plugins/bibles/lib/mediaitem.py @@ -678,7 +678,8 @@ class BibleMediaItem(MediaManagerItem): self.dual_search_results[count].text) } bible_text = u' %s %d:%d (%s, %s)' % (verse.book.name, - verse.chapter, verse.verse, version.value, dual_version.value) + verse.chapter, verse.verse, version.value, + dual_version.value) else: vdict = { 'book': QtCore.QVariant(verse.book.name), diff --git a/openlp/plugins/bibles/lib/opensong.py b/openlp/plugins/bibles/lib/opensong.py index 7acb7e2f2..f1d3efd74 100644 --- a/openlp/plugins/bibles/lib/opensong.py +++ b/openlp/plugins/bibles/lib/opensong.py @@ -89,7 +89,7 @@ class OpenSongBible(BibleDB): Receiver.send_message(u'openlp_process_events') self.wizard.incrementProgressBar( QtCore.QString('%s %s %s' % ( - translate('BiblesPlugin.Opensong', 'Importing'), \ + translate('BiblesPlugin.Opensong', 'Importing'), db_book.name, chapter.attrib[u'n']))) self.session.commit() except IOError: diff --git a/openlp/plugins/songs/forms/songimportform.py b/openlp/plugins/songs/forms/songimportform.py index 0c58b8650..29cc42ec5 100644 --- a/openlp/plugins/songs/forms/songimportform.py +++ b/openlp/plugins/songs/forms/songimportform.py @@ -57,6 +57,15 @@ class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard): self.registerFields() self.finishButton = self.button(QtGui.QWizard.FinishButton) self.cancelButton = self.button(QtGui.QWizard.CancelButton) + if not SongFormat.get_availability(SongFormat.OpenLP1): + self.openLP1DisabledWidget.setVisible(True) + self.openLP1ImportWidget.setVisible(False) + if not SongFormat.get_availability(SongFormat.SongsOfFellowship): + self.songsOfFellowshipDisabledWidget.setVisible(True) + self.songsOfFellowshipImportWidget.setVisible(False) + if not SongFormat.get_availability(SongFormat.Generic): + self.genericDisabledWidget.setVisible(True) + self.genericImportWidget.setVisible(False) self.plugin = plugin QtCore.QObject.connect(self.openLP2BrowseButton, QtCore.SIGNAL(u'clicked()'), @@ -64,12 +73,12 @@ class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard): QtCore.QObject.connect(self.openLP1BrowseButton, QtCore.SIGNAL(u'clicked()'), self.onOpenLP1BrowseButtonClicked) - QtCore.QObject.connect(self.openLyricsAddButton, - QtCore.SIGNAL(u'clicked()'), - self.onOpenLyricsAddButtonClicked) - QtCore.QObject.connect(self.openLyricsRemoveButton, - QtCore.SIGNAL(u'clicked()'), - self.onOpenLyricsRemoveButtonClicked) + #QtCore.QObject.connect(self.openLyricsAddButton, + # QtCore.SIGNAL(u'clicked()'), + # self.onOpenLyricsAddButtonClicked) + #QtCore.QObject.connect(self.openLyricsRemoveButton, + # QtCore.SIGNAL(u'clicked()'), + # self.onOpenLyricsRemoveButtonClicked) QtCore.QObject.connect(self.openSongAddButton, QtCore.SIGNAL(u'clicked()'), self.onOpenSongAddButtonClicked) @@ -145,15 +154,16 @@ class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard): self.openLP1BrowseButton.setFocus() return False elif source_format == SongFormat.OpenLyrics: - if self.openLyricsFileListWidget.count() == 0: - QtGui.QMessageBox.critical(self, - translate('SongsPlugin.ImportWizardForm', - 'No OpenLyrics Files Selected'), - translate('SongsPlugin.ImportWizardForm', - 'You need to add at least one OpenLyrics ' - 'song file to import from.')) - self.openLyricsAddButton.setFocus() - return False + #if self.openLyricsFileListWidget.count() == 0: + # QtGui.QMessageBox.critical(self, + # translate('SongsPlugin.ImportWizardForm', + # 'No OpenLyrics Files Selected'), + # translate('SongsPlugin.ImportWizardForm', + # 'You need to add at least one OpenLyrics ' + # 'song file to import from.')) + # self.openLyricsAddButton.setFocus() + # return False + return False elif source_format == SongFormat.OpenSong: if self.openSongFileListWidget.count() == 0: QtGui.QMessageBox.critical(self, @@ -252,15 +262,15 @@ class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard): self.openLP1FilenameEdit ) - def onOpenLyricsAddButtonClicked(self): - self.getFiles( - translate('SongsPlugin.ImportWizardForm', - 'Select OpenLyrics Files'), - self.openLyricsFileListWidget - ) + #def onOpenLyricsAddButtonClicked(self): + # self.getFiles( + # translate('SongsPlugin.ImportWizardForm', + # 'Select OpenLyrics Files'), + # self.openLyricsFileListWidget + # ) - def onOpenLyricsRemoveButtonClicked(self): - self.removeSelectedItems(self.openLyricsFileListWidget) + #def onOpenLyricsRemoveButtonClicked(self): + # self.removeSelectedItems(self.openLyricsFileListWidget) def onOpenSongAddButtonClicked(self): self.getFiles( @@ -334,7 +344,7 @@ class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard): self.formatComboBox.setCurrentIndex(0) self.openLP2FilenameEdit.setText(u'') self.openLP1FilenameEdit.setText(u'') - self.openLyricsFileListWidget.clear() + #self.openLyricsFileListWidget.clear() self.openSongFileListWidget.clear() self.wordsOfWorshipFileListWidget.clear() self.ccliFileListWidget.clear() diff --git a/openlp/plugins/songs/forms/songimportwizard.py b/openlp/plugins/songs/forms/songimportwizard.py index f174d5ce3..9ae6d7348 100644 --- a/openlp/plugins/songs/forms/songimportwizard.py +++ b/openlp/plugins/songs/forms/songimportwizard.py @@ -131,26 +131,43 @@ class Ui_SongImportWizard(object): # openlp.org 1.x self.openLP1Page = QtGui.QWidget() self.openLP1Page.setObjectName(u'openLP1Page') - self.openLP1Layout = QtGui.QFormLayout(self.openLP1Page) + self.openLP1Layout = QtGui.QVBoxLayout(self.openLP1Page) self.openLP1Layout.setMargin(0) - self.openLP1Layout.setSpacing(8) + self.openLP1Layout.setSpacing(0) self.openLP1Layout.setObjectName(u'openLP1Layout') - self.openLP1FilenameLabel = QtGui.QLabel(self.openLP1Page) + self.openLP1DisabledWidget = QtGui.QWidget(self.openLP1Page) + self.openLP1DisabledLayout = QtGui.QVBoxLayout(self.openLP1DisabledWidget) + self.openLP1DisabledLayout.setMargin(0) + self.openLP1DisabledLayout.setSpacing(8) + self.openLP1DisabledLayout.setObjectName(u'openLP1DisabledLayout') + self.openLP1DisabledLabel = QtGui.QLabel(self.openLP1DisabledWidget) + self.openLP1DisabledLabel.setWordWrap(True) + self.openLP1DisabledLabel.setObjectName(u'openLP1DisabledLabel') + self.openLP1DisabledLayout.addWidget(self.openLP1DisabledLabel) + self.openLP1DisabledWidget.setVisible(False) + self.openLP1Layout.addWidget(self.openLP1DisabledWidget) + self.openLP1ImportWidget = QtGui.QWidget(self.openLP1Page) + self.openLP1ImportLayout = QtGui.QFormLayout(self.openLP1ImportWidget) + self.openLP1ImportLayout.setMargin(0) + self.openLP1ImportLayout.setSpacing(8) + self.openLP1ImportLayout.setObjectName(u'openLP1ImportLayout') + self.openLP1FilenameLabel = QtGui.QLabel(self.openLP1ImportWidget) self.openLP1FilenameLabel.setObjectName(u'openLP1FilenameLabel') - self.openLP1Layout.setWidget(0, QtGui.QFormLayout.LabelRole, + self.openLP1ImportLayout.setWidget(0, QtGui.QFormLayout.LabelRole, self.openLP1FilenameLabel) self.openLP1FileLayout = QtGui.QHBoxLayout() self.openLP1FileLayout.setSpacing(8) self.openLP1FileLayout.setObjectName(u'openLP1FileLayout') - self.openLP1FilenameEdit = QtGui.QLineEdit(self.openLP1Page) + self.openLP1FilenameEdit = QtGui.QLineEdit(self.openLP1ImportWidget) self.openLP1FilenameEdit.setObjectName(u'openLP1FilenameEdit') self.openLP1FileLayout.addWidget(self.openLP1FilenameEdit) - self.openLP1BrowseButton = QtGui.QToolButton(self.openLP1Page) + self.openLP1BrowseButton = QtGui.QToolButton(self.openLP1ImportWidget) self.openLP1BrowseButton.setIcon(openIcon) self.openLP1BrowseButton.setObjectName(u'openLP1BrowseButton') self.openLP1FileLayout.addWidget(self.openLP1BrowseButton) - self.openLP1Layout.setLayout(0, QtGui.QFormLayout.FieldRole, + self.openLP1ImportLayout.setLayout(0, QtGui.QFormLayout.FieldRole, self.openLP1FileLayout) + self.openLP1Layout.addWidget(self.openLP1ImportWidget) self.formatStackedWidget.addWidget(self.openLP1Page) # OpenLyrics self.openLyricsPage = QtGui.QWidget() @@ -159,26 +176,31 @@ class Ui_SongImportWizard(object): self.openLyricsLayout.setSpacing(8) self.openLyricsLayout.setMargin(0) self.openLyricsLayout.setObjectName(u'OpenLyricsLayout') - self.openLyricsFileListWidget = QtGui.QListWidget(self.openLyricsPage) - self.openLyricsFileListWidget.setSelectionMode( - QtGui.QAbstractItemView.ExtendedSelection) - self.openLyricsFileListWidget.setObjectName(u'OpenLyricsFileListWidget') - self.openLyricsLayout.addWidget(self.openLyricsFileListWidget) - self.openLyricsButtonLayout = QtGui.QHBoxLayout() - self.openLyricsButtonLayout.setSpacing(8) - self.openLyricsButtonLayout.setObjectName(u'OpenLyricsButtonLayout') - self.openLyricsAddButton = QtGui.QPushButton(self.openLyricsPage) - self.openLyricsAddButton.setIcon(openIcon) - self.openLyricsAddButton.setObjectName(u'OpenLyricsAddButton') - self.openLyricsButtonLayout.addWidget(self.openLyricsAddButton) - self.openLyricsButtonSpacer = QtGui.QSpacerItem(40, 20, - QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) - self.openLyricsButtonLayout.addItem(self.openLyricsButtonSpacer) - self.openLyricsRemoveButton = QtGui.QPushButton(self.openLyricsPage) - self.openLyricsRemoveButton.setIcon(deleteIcon) - self.openLyricsRemoveButton.setObjectName(u'OpenLyricsRemoveButton') - self.openLyricsButtonLayout.addWidget(self.openLyricsRemoveButton) - self.openLyricsLayout.addLayout(self.openLyricsButtonLayout) + self.openLyricsDisabledLabel = QtGui.QLabel(self.openLyricsPage) + self.openLyricsDisabledLabel.setWordWrap(True) + self.openLyricsDisabledLabel.setObjectName(u'openLyricsDisabledLabel') + self.openLyricsLayout.addWidget(self.openLyricsDisabledLabel) + # Commented out for future use. + #self.openLyricsFileListWidget = QtGui.QListWidget(self.openLyricsPage) + #self.openLyricsFileListWidget.setSelectionMode( + # QtGui.QAbstractItemView.ExtendedSelection) + #self.openLyricsFileListWidget.setObjectName(u'OpenLyricsFileListWidget') + #self.openLyricsLayout.addWidget(self.openLyricsFileListWidget) + #self.openLyricsButtonLayout = QtGui.QHBoxLayout() + #self.openLyricsButtonLayout.setSpacing(8) + #self.openLyricsButtonLayout.setObjectName(u'OpenLyricsButtonLayout') + #self.openLyricsAddButton = QtGui.QPushButton(self.openLyricsPage) + #self.openLyricsAddButton.setIcon(openIcon) + #self.openLyricsAddButton.setObjectName(u'OpenLyricsAddButton') + #self.openLyricsButtonLayout.addWidget(self.openLyricsAddButton) + #self.openLyricsButtonSpacer = QtGui.QSpacerItem(40, 20, + # QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) + #self.openLyricsButtonLayout.addItem(self.openLyricsButtonSpacer) + #self.openLyricsRemoveButton = QtGui.QPushButton(self.openLyricsPage) + #self.openLyricsRemoveButton.setIcon(deleteIcon) + #self.openLyricsRemoveButton.setObjectName(u'OpenLyricsRemoveButton') + #self.openLyricsButtonLayout.addWidget(self.openLyricsRemoveButton) + #self.openLyricsLayout.addLayout(self.openLyricsButtonLayout) self.formatStackedWidget.addWidget(self.openLyricsPage) # Open Song self.openSongPage = QtGui.QWidget() @@ -277,22 +299,52 @@ class Ui_SongImportWizard(object): self.songsOfFellowshipLayout = QtGui.QVBoxLayout( self.songsOfFellowshipPage) self.songsOfFellowshipLayout.setMargin(0) - self.songsOfFellowshipLayout.setSpacing(8) + self.songsOfFellowshipLayout.setSpacing(0) self.songsOfFellowshipLayout.setObjectName(u'songsOfFellowshipLayout') - self.songsOfFellowshipFileListWidget = QtGui.QListWidget( + self.songsOfFellowshipDisabledWidget = QtGui.QWidget( self.songsOfFellowshipPage) + self.songsOfFellowshipDisabledWidget.setVisible(False) + self.songsOfFellowshipDisabledWidget.setObjectName( + u'songsOfFellowshipDisabledWidget') + self.songsOfFellowshipDisabledLayout = QtGui.QVBoxLayout( + self.songsOfFellowshipDisabledWidget) + self.songsOfFellowshipDisabledLayout.setMargin(0) + self.songsOfFellowshipDisabledLayout.setSpacing(8) + self.songsOfFellowshipDisabledLayout.setObjectName( + u'songsOfFellowshipDisabledLayout') + self.songsOfFellowshipDisabledLabel = QtGui.QLabel( + self.songsOfFellowshipDisabledWidget) + self.songsOfFellowshipDisabledLabel.setWordWrap(True) + self.songsOfFellowshipDisabledLabel.setObjectName( + u'songsOfFellowshipDisabledLabel') + self.songsOfFellowshipDisabledLayout.addWidget( + self.songsOfFellowshipDisabledLabel) + self.songsOfFellowshipLayout.addWidget( + self.songsOfFellowshipDisabledWidget) + self.songsOfFellowshipImportWidget = QtGui.QWidget( + self.songsOfFellowshipPage) + self.songsOfFellowshipImportWidget.setObjectName( + u'songsOfFellowshipImportWidget') + self.songsOfFellowshipImportLayout = QtGui.QVBoxLayout( + self.songsOfFellowshipImportWidget) + self.songsOfFellowshipImportLayout.setMargin(0) + self.songsOfFellowshipImportLayout.setSpacing(8) + self.songsOfFellowshipImportLayout.setObjectName( + u'songsOfFellowshipImportLayout') + self.songsOfFellowshipFileListWidget = QtGui.QListWidget( + self.songsOfFellowshipImportWidget) self.songsOfFellowshipFileListWidget.setSelectionMode( QtGui.QAbstractItemView.ExtendedSelection) self.songsOfFellowshipFileListWidget.setObjectName( u'songsOfFellowshipFileListWidget') - self.songsOfFellowshipLayout.addWidget( + self.songsOfFellowshipImportLayout.addWidget( self.songsOfFellowshipFileListWidget) self.songsOfFellowshipButtonLayout = QtGui.QHBoxLayout() self.songsOfFellowshipButtonLayout.setSpacing(8) self.songsOfFellowshipButtonLayout.setObjectName( u'songsOfFellowshipButtonLayout') self.songsOfFellowshipAddButton = QtGui.QPushButton( - self.songsOfFellowshipPage) + self.songsOfFellowshipImportWidget) self.songsOfFellowshipAddButton.setIcon(openIcon) self.songsOfFellowshipAddButton.setObjectName( u'songsOfFellowshipAddButton') @@ -303,42 +355,63 @@ class Ui_SongImportWizard(object): self.songsOfFellowshipButtonLayout.addItem( self.songsOfFellowshipButtonSpacer) self.songsOfFellowshipRemoveButton = QtGui.QPushButton( - self.songsOfFellowshipPage) + self.songsOfFellowshipImportWidget) self.songsOfFellowshipRemoveButton.setIcon(deleteIcon) self.songsOfFellowshipRemoveButton.setObjectName( u'songsOfFellowshipRemoveButton') self.songsOfFellowshipButtonLayout.addWidget( self.songsOfFellowshipRemoveButton) - self.songsOfFellowshipLayout.addLayout( + self.songsOfFellowshipImportLayout.addLayout( self.songsOfFellowshipButtonLayout) + self.songsOfFellowshipLayout.addWidget( + self.songsOfFellowshipImportWidget) self.formatStackedWidget.addWidget(self.songsOfFellowshipPage) # Generic Document/Presentation import self.genericPage = QtGui.QWidget() self.genericPage.setObjectName(u'genericPage') self.genericLayout = QtGui.QVBoxLayout(self.genericPage) self.genericLayout.setMargin(0) - self.genericLayout.setSpacing(8) + self.genericLayout.setSpacing(0) self.genericLayout.setObjectName(u'genericLayout') - self.genericFileListWidget = QtGui.QListWidget(self.genericPage) + self.genericDisabledWidget = QtGui.QWidget(self.genericPage) + self.genericDisabledWidget.setObjectName(u'genericDisabledWidget') + self.genericDisabledLayout = QtGui.QVBoxLayout(self.genericDisabledWidget) + self.genericDisabledLayout.setMargin(0) + self.genericDisabledLayout.setSpacing(8) + self.genericDisabledLayout.setObjectName(u'genericDisabledLayout') + self.genericDisabledLabel = QtGui.QLabel(self.genericDisabledWidget) + self.genericDisabledLabel.setWordWrap(True) + self.genericDisabledLabel.setObjectName(u'genericDisabledLabel') + self.genericDisabledWidget.setVisible(False) + self.genericDisabledLayout.addWidget(self.genericDisabledLabel) + self.genericLayout.addWidget(self.genericDisabledWidget) + self.genericImportWidget = QtGui.QWidget(self.genericPage) + self.genericImportWidget.setObjectName(u'genericImportWidget') + self.genericImportLayout = QtGui.QVBoxLayout(self.genericImportWidget) + self.genericImportLayout.setMargin(0) + self.genericImportLayout.setSpacing(8) + self.genericImportLayout.setObjectName(u'genericImportLayout') + self.genericFileListWidget = QtGui.QListWidget(self.genericImportWidget) self.genericFileListWidget.setSelectionMode( QtGui.QAbstractItemView.ExtendedSelection) self.genericFileListWidget.setObjectName(u'genericFileListWidget') - self.genericLayout.addWidget(self.genericFileListWidget) + self.genericImportLayout.addWidget(self.genericFileListWidget) self.genericButtonLayout = QtGui.QHBoxLayout() self.genericButtonLayout.setSpacing(8) self.genericButtonLayout.setObjectName(u'genericButtonLayout') - self.genericAddButton = QtGui.QPushButton(self.genericPage) + self.genericAddButton = QtGui.QPushButton(self.genericImportWidget) self.genericAddButton.setIcon(openIcon) self.genericAddButton.setObjectName(u'genericAddButton') self.genericButtonLayout.addWidget(self.genericAddButton) self.genericButtonSpacer = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) self.genericButtonLayout.addItem(self.genericButtonSpacer) - self.genericRemoveButton = QtGui.QPushButton(self.genericPage) + self.genericRemoveButton = QtGui.QPushButton(self.genericImportWidget) self.genericRemoveButton.setIcon(deleteIcon) self.genericRemoveButton.setObjectName(u'genericRemoveButton') self.genericButtonLayout.addWidget(self.genericRemoveButton) - self.genericLayout.addLayout(self.genericButtonLayout) + self.genericImportLayout.addLayout(self.genericButtonLayout) + self.genericLayout.addWidget(self.genericImportWidget) self.formatStackedWidget.addWidget(self.genericPage) # Commented out for future use. # self.csvPage = QtGui.QWidget() @@ -434,10 +507,20 @@ class Ui_SongImportWizard(object): translate('SongsPlugin.ImportWizardForm', 'Filename:')) self.openLP1BrowseButton.setText( translate('SongsPlugin.ImportWizardForm', 'Browse...')) - self.openLyricsAddButton.setText( - translate('SongsPlugin.ImportWizardForm', 'Add Files...')) - self.openLyricsRemoveButton.setText( - translate('SongsPlugin.ImportWizardForm', 'Remove File(s)')) + self.openLP1DisabledLabel.setText( + translate('SongsPlugin.ImportWizardForm', 'The openlp.org 1.x ' + 'importer has been disabled due to a missing Python module. If ' + 'you want to use this importer, you will need to install the ' + '"python-sqlite" module.')) + #self.openLyricsAddButton.setText( + # translate('SongsPlugin.ImportWizardForm', 'Add Files...')) + #self.openLyricsRemoveButton.setText( + # translate('SongsPlugin.ImportWizardForm', 'Remove File(s)')) + 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 ' + 'release.')) self.openSongAddButton.setText( translate('SongsPlugin.ImportWizardForm', 'Add Files...')) self.openSongRemoveButton.setText( @@ -454,10 +537,18 @@ class Ui_SongImportWizard(object): translate('SongsPlugin.ImportWizardForm', 'Add Files...')) self.songsOfFellowshipRemoveButton.setText( translate('SongsPlugin.ImportWizardForm', 'Remove File(s)')) + self.songsOfFellowshipDisabledLabel.setText( + translate('SongsPlugin.ImportWizardForm', 'The Songs of ' + 'Fellowship importer has been disabled because OpenLP cannot ' + 'find OpenOffice.org on your computer.')) self.genericAddButton.setText( translate('SongsPlugin.ImportWizardForm', 'Add Files...')) self.genericRemoveButton.setText( translate('SongsPlugin.ImportWizardForm', 'Remove File(s)')) + self.genericDisabledLabel.setText( + translate('SongsPlugin.ImportWizardForm', 'The generic document/' + 'presentation importer has been disabled because OpenLP cannot ' + 'find OpenOffice.org on your computer.')) # self.csvFilenameLabel.setText( # translate('SongsPlugin.ImportWizardForm', 'Filename:')) # self.csvBrowseButton.setText( diff --git a/openlp/plugins/songs/lib/cclifileimport.py b/openlp/plugins/songs/lib/cclifileimport.py index 08bccef79..9d0da5cfa 100755 --- a/openlp/plugins/songs/lib/cclifileimport.py +++ b/openlp/plugins/songs/lib/cclifileimport.py @@ -57,7 +57,7 @@ class CCLIFileImport(SongImport): self.filenames = kwargs[u'filenames'] log.debug(self.filenames) else: - raise KeyError(u'Keyword argument "filenames" not supplied.') + raise KeyError(u'Keyword argument "filenames" not supplied.') def do_import(self): """ @@ -66,11 +66,11 @@ class CCLIFileImport(SongImport): log.debug(u'Starting CCLI File Import') song_total = len(self.filenames) self.import_wizard.importProgressBar.setMaximum(song_total) - song_count = 1 + song_count = 1 for filename in self.filenames: self.import_wizard.incrementProgressBar( - u'Importing song %s of %s' % (song_count, song_total)) - filename = unicode(filename) + u'Importing song %s of %s' % (song_count, song_total)) + filename = unicode(filename) log.debug(u'Importing CCLI File: %s', filename) lines = [] if os.path.isfile(filename): @@ -81,33 +81,34 @@ class CCLIFileImport(SongImport): lines = infile.readlines() ext = os.path.splitext(filename)[1] if ext.lower() == ".usr": - log.info(u'SongSelect .usr format file found %s: ' , filename) + log.info(u'SongSelect .usr format file found %s: ', + filename) self.do_import_usr_file(lines) elif ext.lower() == ".txt": - log.info(u'SongSelect .txt format file found %s: ', filename) + log.info(u'SongSelect .txt format file found %s: ', + filename) self.do_import_txt_file(lines) else: log.info(u'Extension %s is not valid', filename) - pass song_count += 1 if self.stop_import_flag: - return False + return False return True def do_import_usr_file(self, textList): """ The :method:`do_import_usr_file` method provides OpenLP with the ability to import CCLI SongSelect songs in - *USR* file format - + *USR* file format + ``textList`` An array of strings containing the usr file content. - + **SongSelect .usr file format** ``[File]`` USR file format first line ``Type=`` - Indicates the file type + Indicates the file type e.g. *Type=SongSelect Import File* ``Version=3.0`` File format version @@ -116,7 +117,7 @@ class CCLIFileImport(SongImport): ``Title=`` Contains the song title (e.g. *Title=Above All*) ``Author=`` - Contains a | delimited list of the song authors + Contains a | delimited list of the song authors e.g. *Author=LeBlanc, Lenny | Baloche, Paul* ``Copyright=`` Contains a | delimited list of the song copyrights @@ -136,7 +137,7 @@ class CCLIFileImport(SongImport): Contains a list of the songs fields in order /t delimited e.g. *Fields=Vers 1/tVers 2/tChorus 1/tAndere 1* ``Words=`` - Contains the songs various lyrics in order as shown by the + Contains the songs various lyrics in order as shown by the *Fields* description e.g. *Words=Above all powers....* [/n = CR, /n/t = CRLF] """ @@ -174,8 +175,8 @@ class CCLIFileImport(SongImport): verse_type = u'O' verse_text = unicode(words_list[counter]) verse_text = verse_text.replace("/n", "\n") - if len(verse_text) > 0: - self.add_verse(verse_text, verse_type); + if len(verse_text) > 0: + self.add_verse(verse_text, verse_type) #Handle multiple authors author_list = song_author.split(u'/') if len(author_list) < 2: @@ -192,10 +193,10 @@ class CCLIFileImport(SongImport): """ The :method:`do_import_txt_file` method provides OpenLP with the ability to import CCLI SongSelect songs in - *TXT* file format - + *TXT* file format + ``textList`` - An array of strings containing the txt file content. + An array of strings containing the txt file content. **SongSelect .txt file format** @@ -225,38 +226,38 @@ class CCLIFileImport(SongImport): e.g. CCLI Number (e.g.CCLI-Liednummer: 2672885) ``Song Copyright`` e.g. © 1999 Integrity's Hosanna! Music | LenSongs Publishing - ``Song Authors`` + ``Song Authors`` e.g. Lenny LeBlanc | Paul Baloche ``Licencing info`` - e.g. For use solely with the SongSelect Terms of Use. + e.g. For use solely with the SongSelect Terms of Use. All rights Reserved. www.ccli.com - ``CCLI Licence number of user`` - e.g. CCL-Liedlizenznummer: 14 / CCLI License No. 14 + ``CCLI Licence number of user`` + e.g. CCL-Liedlizenznummer: 14 / CCLI License No. 14 """ log.debug(u'TXT file text: %s', textList) self.set_defaults() line_number = 0 verse_text = u'' song_comments = u'' - song_copyright = u''; + song_copyright = u'' verse_start = False for line in textList: clean_line = line.strip() if not clean_line: - if line_number==0: + if line_number == 0: continue elif verse_start: - if verse_text: + if verse_text: self.add_verse(verse_text, verse_type) verse_text = '' verse_start = False else: #line_number=0, song title - if line_number==0: + if line_number == 0: song_name = clean_line line_number += 1 - #line_number=1, verses - elif line_number==1: + #line_number=1, verses + elif line_number == 1: #line_number=1, ccli number, first line after verses if clean_line.startswith(u'CCLI'): line_number += 1 @@ -285,15 +286,16 @@ class CCLIFileImport(SongImport): verse_text = verse_text + line else: #line_number=2, copyright - if line_number==2: + if line_number == 2: line_number += 1 song_copyright = clean_line - #n=3, authors - elif line_number==3: + #n=3, authors + elif line_number == 3: line_number += 1 song_author = clean_line - #line_number=4, comments lines before last line - elif (line_number==4) and (not clean_line.startswith(u'CCL')): + #line_number=4, comments lines before last line + elif (line_number == 4) and \ + (not clean_line.startswith(u'CCL')): song_comments = song_comments + clean_line # split on known separators author_list = song_author.split(u'/') @@ -307,4 +309,3 @@ class CCLIFileImport(SongImport): self.ccli_number = song_ccli self.comments = song_comments self.finish() - diff --git a/openlp/plugins/songs/lib/importer.py b/openlp/plugins/songs/lib/importer.py index da9618ef2..2d00c6523 100644 --- a/openlp/plugins/songs/lib/importer.py +++ b/openlp/plugins/songs/lib/importer.py @@ -26,14 +26,24 @@ from opensongimport import OpenSongImport from olpimport import OpenLPSongImport -from olp1import import OpenLP1SongImport +from wowimport import WowImport +from cclifileimport import CCLIFileImport +# Imports that might fail +try: + from olp1import import OpenLP1SongImport + has_openlp1 = True +except ImportError: + has_openlp1 = False try: from sofimport import SofImport - from oooimport import OooImport - from cclifileimport import CCLIFileImport - from wowimport import WowImport + has_sof = True except ImportError: - pass + has_sof = False +try: + from oooimport import OooImport + has_ooo = True +except ImportError: + has_ooo = False class SongFormat(object): """ @@ -41,6 +51,7 @@ class SongFormat(object): plus a few helper functions to facilitate generic handling of song types for importing. """ + _format_availability = {} Unknown = -1 OpenLP2 = 0 OpenLP1 = 1 @@ -93,4 +104,16 @@ class SongFormat(object): SongFormat.Generic ] + @staticmethod + def set_availability(format, available): + SongFormat._format_availability[format] = available + + @staticmethod + def get_availability(format): + return SongFormat._format_availability.get(format, True) + +SongFormat.set_availability(SongFormat.OpenLP1, has_openlp1) +SongFormat.set_availability(SongFormat.SongsOfFellowship, has_sof) +SongFormat.set_availability(SongFormat.Generic, has_ooo) + __all__ = [u'SongFormat'] diff --git a/openlp/plugins/songs/lib/olp1import.py b/openlp/plugins/songs/lib/olp1import.py index 68bd3ef06..692c6792e 100644 --- a/openlp/plugins/songs/lib/olp1import.py +++ b/openlp/plugins/songs/lib/olp1import.py @@ -29,10 +29,7 @@ openlp.org 1.x song databases into the current installation database. """ import logging import chardet -try: - import sqlite -except: - pass +import sqlite from openlp.core.lib import translate from songimport import SongImport @@ -93,9 +90,9 @@ class OpenLP1SongImport(SongImport): cursor.execute(u'SELECT authorid, authorname FROM authors') authors = cursor.fetchall() if new_db: - # "cache" our list of tracks - cursor.execute(u'SELECT trackid, fulltrackname FROM tracks') - tracks = cursor.fetchall() + # "cache" our list of tracks + cursor.execute(u'SELECT trackid, fulltrackname FROM tracks') + tracks = cursor.fetchall() # Import the songs cursor.execute(u'SELECT songid, songtitle, lyrics || \'\' AS lyrics, ' u'copyrightinfo FROM songs') diff --git a/openlp/plugins/songs/lib/opensongimport.py b/openlp/plugins/songs/lib/opensongimport.py index f6048d566..f4be0dc87 100644 --- a/openlp/plugins/songs/lib/opensongimport.py +++ b/openlp/plugins/songs/lib/opensongimport.py @@ -29,7 +29,9 @@ 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 log = logging.getLogger(__name__) @@ -112,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 @@ -126,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 @@ -137,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]) @@ -144,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', @@ -157,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): @@ -167,10 +175,10 @@ 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: + except (Error, LxmlError): log.exception(u'Error parsing XML') return root = tree.getroot() @@ -196,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 = {} @@ -204,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';') @@ -218,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 @@ -235,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): @@ -259,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 @@ -271,16 +284,23 @@ 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 else: - log.warn(u'No verse order available for %s, skipping.', self.title) + 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