This commit is contained in:
Raoul Snyman 2010-09-17 08:17:50 +02:00
commit e10f603d77
22 changed files with 572 additions and 324 deletions

View File

@ -147,6 +147,9 @@ class OpenLP(QtGui.QApplication):
return self.exec_() return self.exec_()
def hookException(self, exctype, value, traceback): 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'): if not hasattr(self, u'exceptionForm'):
self.exceptionForm = ExceptionForm(self.mainWindow) self.exceptionForm = ExceptionForm(self.mainWindow)
self.exceptionForm.exceptionTextEdit.setPlainText( self.exceptionForm.exceptionTextEdit.setPlainText(
@ -161,16 +164,16 @@ def main():
# Set up command line options. # Set up command line options.
usage = u'Usage: %prog [options] [qt-options]' usage = u'Usage: %prog [options] [qt-options]'
parser = OptionParser(usage=usage) parser = OptionParser(usage=usage)
parser.add_option("-l", "--log-level", dest="loglevel", parser.add_option(u'-e', u'--no-error-form', dest=u'no_error_form',
default="warning", metavar="LEVEL", action=u'store_true', help=u'Disable the error notification form.')
help="Set logging to LEVEL level. Valid values are " parser.add_option(u'-l', u'--log-level', dest=u'loglevel',
"\"debug\", \"info\", \"warning\".") default=u'warning', metavar=u'LEVEL', help=u'Set logging to LEVEL '
parser.add_option("-p", "--portable", dest="portable", u'level. Valid values are "debug", "info", "warning".')
action="store_true", parser.add_option(u'-p', u'--portable', dest=u'portable',
help="Specify if this should be run as a portable app, " action=u'store_true', help=u'Specify if this should be run as a '
"off a USB flash drive.") u'portable app, off a USB flash drive (not implemented).')
parser.add_option("-s", "--style", dest="style", parser.add_option(u'-s', u'--style', dest=u'style',
help="Set the Qt4 style (passed directly to Qt4).") help=u'Set the Qt4 style (passed directly to Qt4).')
# Set up logging # Set up logging
log_path = AppLocation.get_directory(AppLocation.CacheDir) log_path = AppLocation.get_directory(AppLocation.CacheDir)
if not os.path.exists(log_path): if not os.path.exists(log_path):
@ -203,6 +206,7 @@ def main():
language = LanguageManager.get_language() language = LanguageManager.get_language()
appTranslator = LanguageManager.get_translator(language) appTranslator = LanguageManager.get_translator(language)
app.installTranslator(appTranslator) app.installTranslator(appTranslator)
if not options.no_error_form:
sys.excepthook = app.hookException sys.excepthook = app.hookException
sys.exit(app.run()) sys.exit(app.run())

View File

@ -38,62 +38,47 @@ log = logging.getLogger(__name__)
# TODO make external and configurable in alpha 4 via a settings dialog # TODO make external and configurable in alpha 4 via a settings dialog
html_expands = [] html_expands = []
html_expands.append({u'desc':u'Red', u'start tag':u'{r}', \ html_expands.append({u'desc':u'Red', u'start tag':u'{r}',
u'start html':u'<span style="-webkit-text-fill-color:red">', \ u'start html':u'<span style="-webkit-text-fill-color:red">',
u'end tag':u'{/r}', u'end html':u'</span>', \ u'end tag':u'{/r}', u'end html':u'</span>', u'protected':False})
u'protected':False}) html_expands.append({u'desc':u'Black', u'start tag':u'{b}',
html_expands.append({u'desc':u'Black', u'start tag':u'{b}', \ u'start html':u'<span style="-webkit-text-fill-color:black">',
u'start html':u'<span style="-webkit-text-fill-color:black">', \ u'end tag':u'{/b}', u'end html':u'</span>', u'protected':False})
u'end tag':u'{/b}', u'end html':u'</span>', \ html_expands.append({u'desc':u'Blue', u'start tag':u'{bl}',
u'protected':False}) u'start html':u'<span style="-webkit-text-fill-color:blue">',
html_expands.append({u'desc':u'Blue', u'start tag':u'{bl}', \ u'end tag':u'{/bl}', u'end html':u'</span>', u'protected':False})
u'start html':u'<span style="-webkit-text-fill-color:blue">', \ html_expands.append({u'desc':u'Yellow', u'start tag':u'{y}',
u'end tag':u'{/bl}', u'end html':u'</span>', \ u'start html':u'<span style="-webkit-text-fill-color:yellow">',
u'protected':False}) u'end tag':u'{/y}', u'end html':u'</span>', u'protected':False})
html_expands.append({u'desc':u'Yellow', u'start tag':u'{y}', \ html_expands.append({u'desc':u'Green', u'start tag':u'{g}',
u'start html':u'<span style="-webkit-text-fill-color:yellow">', \ u'start html':u'<span style="-webkit-text-fill-color:green">',
u'end tag':u'{/y}', u'end html':u'</span>', \ u'end tag':u'{/g}', u'end html':u'</span>', u'protected':False})
u'protected':False}) html_expands.append({u'desc':u'Pink', u'start tag':u'{pk}',
html_expands.append({u'desc':u'Green', u'start tag':u'{g}', \ u'start html':u'<span style="-webkit-text-fill-color:#CC33CC">',
u'start html':u'<span style="-webkit-text-fill-color:green">', \ u'end tag':u'{/pk}', u'end html':u'</span>', u'protected':False})
u'end tag':u'{/g}', u'end html':u'</span>', \ html_expands.append({u'desc':u'Orange', u'start tag':u'{o}',
u'protected':False}) u'start html':u'<span style="-webkit-text-fill-color:#CC0033">',
html_expands.append({u'desc':u'Pink', u'start tag':u'{pk}', \ u'end tag':u'{/o}', u'end html':u'</span>', u'protected':False})
u'start html':u'<span style="-webkit-text-fill-color:#CC33CC">', \ html_expands.append({u'desc':u'Purple', u'start tag':u'{pp}',
u'end tag':u'{/pk}', u'end html':u'</span>', \ u'start html':u'<span style="-webkit-text-fill-color:#9900FF">',
u'protected':False}) u'end tag':u'{/pp}', u'end html':u'</span>', u'protected':False})
html_expands.append({u'desc':u'Orange', u'start tag':u'{o}', \ html_expands.append({u'desc':u'White', u'start tag':u'{w}',
u'start html':u'<span style="-webkit-text-fill-color:#CC0033">', \ u'start html':u'<span style="-webkit-text-fill-color:white">',
u'end tag':u'{/o}', u'end html':u'</span>', \ u'end tag':u'{/w}', u'end html':u'</span>', u'protected':False})
u'protected':False}) html_expands.append({u'desc':u'Superscript', u'start tag':u'{su}',
html_expands.append({u'desc':u'Purple', u'start tag':u'{pp}', \ u'start html':u'<sup>', u'end tag':u'{/su}', u'end html':u'</sup>',
u'start html':u'<span style="-webkit-text-fill-color:#9900FF">', \
u'end tag':u'{/pp}', u'end html':u'</span>', \
u'protected':False})
html_expands.append({u'desc':u'White', u'start tag':u'{w}', \
u'start html':u'<span style="-webkit-text-fill-color:white">', \
u'end tag':u'{/w}', u'end html':u'</span>', \
u'protected':False})
html_expands.append({u'desc':u'Superscript', u'start tag':u'{su}', \
u'start html':u'<sup>', \
u'end tag':u'{/su}', u'end html':u'</sup>', \
u'protected':True}) u'protected':True})
html_expands.append({u'desc':u'Subscript', u'start tag':u'{sb}', \ html_expands.append({u'desc':u'Subscript', u'start tag':u'{sb}',
u'start html':u'<sub>', \ u'start html':u'<sub>', u'end tag':u'{/sb}', u'end html':u'</sub>',
u'end tag':u'{/sb}', u'end html':u'</sub>', \
u'protected':True}) u'protected':True})
html_expands.append({u'desc':u'Paragraph', u'start tag':u'{p}', \ html_expands.append({u'desc':u'Paragraph', u'start tag':u'{p}',
u'start html':u'<p>', \ u'start html':u'<p>', u'end tag':u'{/p}', u'end html':u'</p>',
u'end tag':u'{/p}', u'end html':u'</p>', \
u'protected':True}) u'protected':True})
html_expands.append({u'desc':u'Bold', u'start tag':u'{st}', \ html_expands.append({u'desc':u'Bold', u'start tag':u'{st}',
u'start html':u'<strong>', \ u'start html':u'<strong>', u'end tag':u'{/st}', u'end html':u'</strong>',
u'end tag':u'{/st}', \
u'end html':u'</strong>', \
u'protected':True}) u'protected':True})
html_expands.append({u'desc':u'Italics', u'start tag':u'{it}', \ html_expands.append({u'desc':u'Italics', u'start tag':u'{it}',
u'start html':u'<em>', \ u'start html':u'<em>', u'end tag':u'{/it}', u'end html':u'</em>',
u'end tag':u'{/it}', u'end html':u'</em>', \
u'protected':True}) u'protected':True})
def translate(context, text, comment=None): def translate(context, text, comment=None):

View File

@ -432,7 +432,7 @@ class MediaManagerItem(QtGui.QWidget):
raise NotImplementedError(u'MediaManagerItem.onDeleteClick needs to ' raise NotImplementedError(u'MediaManagerItem.onDeleteClick needs to '
u'be defined by the plugin') 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 ' raise NotImplementedError(u'MediaManagerItem.generateSlideData needs '
u'to be defined by the plugin') u'to be defined by the plugin')

View File

@ -120,7 +120,7 @@ class MainDisplay(DisplayWidget):
self.setScene(self.scene) self.setScene(self.scene)
self.webView = QtWebKit.QGraphicsWebView() self.webView = QtWebKit.QGraphicsWebView()
self.scene.addItem(self.webView) 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.screen[u'size'].height())
self.page = self.webView.page() self.page = self.webView.page()
self.frame = self.page.mainFrame() self.frame = self.page.mainFrame()
@ -303,6 +303,9 @@ class MainDisplay(DisplayWidget):
Generates a preview of the image displayed. Generates a preview of the image displayed.
""" """
log.debug(u'preview for %s', self.isLive) 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: if self.isLive:
# Wait for the fade to finish before geting the preview. # Wait for the fade to finish before geting the preview.
# Important otherwise preview will have incorrect text if at all ! # Important otherwise preview will have incorrect text if at all !
@ -336,7 +339,7 @@ class MainDisplay(DisplayWidget):
self.loaded = False self.loaded = False
self.initialFrame = False self.initialFrame = False
self.serviceItem = serviceItem 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.isLive)
self.webView.setHtml(html) self.webView.setHtml(html)
if serviceItem.foot_text and serviceItem.foot_text: if serviceItem.foot_text and serviceItem.foot_text:

View File

@ -279,7 +279,8 @@ class ServiceManager(QtGui.QWidget):
self.editAction.setVisible(False) self.editAction.setVisible(False)
self.maintainAction.setVisible(False) self.maintainAction.setVisible(False)
self.notesAction.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) self.editAction.setVisible(True)
if serviceItem[u'service_item']\ if serviceItem[u'service_item']\
.is_capable(ItemCapabilities.AllowsMaintain): .is_capable(ItemCapabilities.AllowsMaintain):

View File

@ -112,7 +112,11 @@ class AppLocation(object):
The directory type you want, for instance the data directory. The directory type you want, for instance the data directory.
""" """
if dir_type == AppLocation.AppDir: 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: elif dir_type == AppLocation.ConfigDir:
if sys.platform == u'win32': if sys.platform == u'win32':
path = os.path.join(os.getenv(u'APPDATA'), u'openlp') path = os.path.join(os.getenv(u'APPDATA'), u'openlp')

View File

@ -55,7 +55,7 @@ class LanguageManager(object):
if LanguageManager.AutoLanguage: if LanguageManager.AutoLanguage:
language = QtCore.QLocale.system().name() language = QtCore.QLocale.system().name()
lang_path = AppLocation.get_directory(AppLocation.AppDir) 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() app_translator = QtCore.QTranslator()
if app_translator.load("openlp_" + language, lang_path): if app_translator.load("openlp_" + language, lang_path):
return app_translator return app_translator
@ -66,7 +66,7 @@ class LanguageManager(object):
Find all available language files in this OpenLP install Find all available language files in this OpenLP install
""" """
trans_dir = AppLocation.get_directory(AppLocation.AppDir) 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"), file_names = trans_dir.entryList(QtCore.QStringList("*.qm"),
QtCore.QDir.Files, QtCore.QDir.Name) QtCore.QDir.Files, QtCore.QDir.Name)
for name in file_names: for name in file_names:

View File

@ -678,7 +678,8 @@ class BibleMediaItem(MediaManagerItem):
self.dual_search_results[count].text) self.dual_search_results[count].text)
} }
bible_text = u' %s %d:%d (%s, %s)' % (verse.book.name, 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: else:
vdict = { vdict = {
'book': QtCore.QVariant(verse.book.name), 'book': QtCore.QVariant(verse.book.name),

View File

@ -89,7 +89,7 @@ class OpenSongBible(BibleDB):
Receiver.send_message(u'openlp_process_events') Receiver.send_message(u'openlp_process_events')
self.wizard.incrementProgressBar( self.wizard.incrementProgressBar(
QtCore.QString('%s %s %s' % ( QtCore.QString('%s %s %s' % (
translate('BiblesPlugin.Opensong', 'Importing'), \ translate('BiblesPlugin.Opensong', 'Importing'),
db_book.name, chapter.attrib[u'n']))) db_book.name, chapter.attrib[u'n'])))
self.session.commit() self.session.commit()
except IOError: except IOError:

View File

@ -57,6 +57,15 @@ class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard):
self.registerFields() self.registerFields()
self.finishButton = self.button(QtGui.QWizard.FinishButton) self.finishButton = self.button(QtGui.QWizard.FinishButton)
self.cancelButton = self.button(QtGui.QWizard.CancelButton) 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 self.plugin = plugin
QtCore.QObject.connect(self.openLP2BrowseButton, QtCore.QObject.connect(self.openLP2BrowseButton,
QtCore.SIGNAL(u'clicked()'), QtCore.SIGNAL(u'clicked()'),
@ -64,12 +73,12 @@ class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard):
QtCore.QObject.connect(self.openLP1BrowseButton, QtCore.QObject.connect(self.openLP1BrowseButton,
QtCore.SIGNAL(u'clicked()'), QtCore.SIGNAL(u'clicked()'),
self.onOpenLP1BrowseButtonClicked) self.onOpenLP1BrowseButtonClicked)
QtCore.QObject.connect(self.openLyricsAddButton, #QtCore.QObject.connect(self.openLyricsAddButton,
QtCore.SIGNAL(u'clicked()'), # QtCore.SIGNAL(u'clicked()'),
self.onOpenLyricsAddButtonClicked) # self.onOpenLyricsAddButtonClicked)
QtCore.QObject.connect(self.openLyricsRemoveButton, #QtCore.QObject.connect(self.openLyricsRemoveButton,
QtCore.SIGNAL(u'clicked()'), # QtCore.SIGNAL(u'clicked()'),
self.onOpenLyricsRemoveButtonClicked) # self.onOpenLyricsRemoveButtonClicked)
QtCore.QObject.connect(self.openSongAddButton, QtCore.QObject.connect(self.openSongAddButton,
QtCore.SIGNAL(u'clicked()'), QtCore.SIGNAL(u'clicked()'),
self.onOpenSongAddButtonClicked) self.onOpenSongAddButtonClicked)
@ -145,14 +154,15 @@ class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard):
self.openLP1BrowseButton.setFocus() self.openLP1BrowseButton.setFocus()
return False return False
elif source_format == SongFormat.OpenLyrics: elif source_format == SongFormat.OpenLyrics:
if self.openLyricsFileListWidget.count() == 0: #if self.openLyricsFileListWidget.count() == 0:
QtGui.QMessageBox.critical(self, # QtGui.QMessageBox.critical(self,
translate('SongsPlugin.ImportWizardForm', # translate('SongsPlugin.ImportWizardForm',
'No OpenLyrics Files Selected'), # 'No OpenLyrics Files Selected'),
translate('SongsPlugin.ImportWizardForm', # translate('SongsPlugin.ImportWizardForm',
'You need to add at least one OpenLyrics ' # 'You need to add at least one OpenLyrics '
'song file to import from.')) # 'song file to import from.'))
self.openLyricsAddButton.setFocus() # self.openLyricsAddButton.setFocus()
# return False
return False return False
elif source_format == SongFormat.OpenSong: elif source_format == SongFormat.OpenSong:
if self.openSongFileListWidget.count() == 0: if self.openSongFileListWidget.count() == 0:
@ -252,15 +262,15 @@ class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard):
self.openLP1FilenameEdit self.openLP1FilenameEdit
) )
def onOpenLyricsAddButtonClicked(self): #def onOpenLyricsAddButtonClicked(self):
self.getFiles( # self.getFiles(
translate('SongsPlugin.ImportWizardForm', # translate('SongsPlugin.ImportWizardForm',
'Select OpenLyrics Files'), # 'Select OpenLyrics Files'),
self.openLyricsFileListWidget # self.openLyricsFileListWidget
) # )
def onOpenLyricsRemoveButtonClicked(self): #def onOpenLyricsRemoveButtonClicked(self):
self.removeSelectedItems(self.openLyricsFileListWidget) # self.removeSelectedItems(self.openLyricsFileListWidget)
def onOpenSongAddButtonClicked(self): def onOpenSongAddButtonClicked(self):
self.getFiles( self.getFiles(
@ -334,7 +344,7 @@ class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard):
self.formatComboBox.setCurrentIndex(0) self.formatComboBox.setCurrentIndex(0)
self.openLP2FilenameEdit.setText(u'') self.openLP2FilenameEdit.setText(u'')
self.openLP1FilenameEdit.setText(u'') self.openLP1FilenameEdit.setText(u'')
self.openLyricsFileListWidget.clear() #self.openLyricsFileListWidget.clear()
self.openSongFileListWidget.clear() self.openSongFileListWidget.clear()
self.wordsOfWorshipFileListWidget.clear() self.wordsOfWorshipFileListWidget.clear()
self.ccliFileListWidget.clear() self.ccliFileListWidget.clear()

View File

@ -131,26 +131,43 @@ class Ui_SongImportWizard(object):
# openlp.org 1.x # openlp.org 1.x
self.openLP1Page = QtGui.QWidget() self.openLP1Page = QtGui.QWidget()
self.openLP1Page.setObjectName(u'openLP1Page') self.openLP1Page.setObjectName(u'openLP1Page')
self.openLP1Layout = QtGui.QFormLayout(self.openLP1Page) self.openLP1Layout = QtGui.QVBoxLayout(self.openLP1Page)
self.openLP1Layout.setMargin(0) self.openLP1Layout.setMargin(0)
self.openLP1Layout.setSpacing(8) self.openLP1Layout.setSpacing(0)
self.openLP1Layout.setObjectName(u'openLP1Layout') 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.openLP1FilenameLabel.setObjectName(u'openLP1FilenameLabel')
self.openLP1Layout.setWidget(0, QtGui.QFormLayout.LabelRole, self.openLP1ImportLayout.setWidget(0, QtGui.QFormLayout.LabelRole,
self.openLP1FilenameLabel) self.openLP1FilenameLabel)
self.openLP1FileLayout = QtGui.QHBoxLayout() self.openLP1FileLayout = QtGui.QHBoxLayout()
self.openLP1FileLayout.setSpacing(8) self.openLP1FileLayout.setSpacing(8)
self.openLP1FileLayout.setObjectName(u'openLP1FileLayout') self.openLP1FileLayout.setObjectName(u'openLP1FileLayout')
self.openLP1FilenameEdit = QtGui.QLineEdit(self.openLP1Page) self.openLP1FilenameEdit = QtGui.QLineEdit(self.openLP1ImportWidget)
self.openLP1FilenameEdit.setObjectName(u'openLP1FilenameEdit') self.openLP1FilenameEdit.setObjectName(u'openLP1FilenameEdit')
self.openLP1FileLayout.addWidget(self.openLP1FilenameEdit) self.openLP1FileLayout.addWidget(self.openLP1FilenameEdit)
self.openLP1BrowseButton = QtGui.QToolButton(self.openLP1Page) self.openLP1BrowseButton = QtGui.QToolButton(self.openLP1ImportWidget)
self.openLP1BrowseButton.setIcon(openIcon) self.openLP1BrowseButton.setIcon(openIcon)
self.openLP1BrowseButton.setObjectName(u'openLP1BrowseButton') self.openLP1BrowseButton.setObjectName(u'openLP1BrowseButton')
self.openLP1FileLayout.addWidget(self.openLP1BrowseButton) self.openLP1FileLayout.addWidget(self.openLP1BrowseButton)
self.openLP1Layout.setLayout(0, QtGui.QFormLayout.FieldRole, self.openLP1ImportLayout.setLayout(0, QtGui.QFormLayout.FieldRole,
self.openLP1FileLayout) self.openLP1FileLayout)
self.openLP1Layout.addWidget(self.openLP1ImportWidget)
self.formatStackedWidget.addWidget(self.openLP1Page) self.formatStackedWidget.addWidget(self.openLP1Page)
# OpenLyrics # OpenLyrics
self.openLyricsPage = QtGui.QWidget() self.openLyricsPage = QtGui.QWidget()
@ -159,26 +176,31 @@ class Ui_SongImportWizard(object):
self.openLyricsLayout.setSpacing(8) self.openLyricsLayout.setSpacing(8)
self.openLyricsLayout.setMargin(0) self.openLyricsLayout.setMargin(0)
self.openLyricsLayout.setObjectName(u'OpenLyricsLayout') self.openLyricsLayout.setObjectName(u'OpenLyricsLayout')
self.openLyricsFileListWidget = QtGui.QListWidget(self.openLyricsPage) self.openLyricsDisabledLabel = QtGui.QLabel(self.openLyricsPage)
self.openLyricsFileListWidget.setSelectionMode( self.openLyricsDisabledLabel.setWordWrap(True)
QtGui.QAbstractItemView.ExtendedSelection) self.openLyricsDisabledLabel.setObjectName(u'openLyricsDisabledLabel')
self.openLyricsFileListWidget.setObjectName(u'OpenLyricsFileListWidget') self.openLyricsLayout.addWidget(self.openLyricsDisabledLabel)
self.openLyricsLayout.addWidget(self.openLyricsFileListWidget) # Commented out for future use.
self.openLyricsButtonLayout = QtGui.QHBoxLayout() #self.openLyricsFileListWidget = QtGui.QListWidget(self.openLyricsPage)
self.openLyricsButtonLayout.setSpacing(8) #self.openLyricsFileListWidget.setSelectionMode(
self.openLyricsButtonLayout.setObjectName(u'OpenLyricsButtonLayout') # QtGui.QAbstractItemView.ExtendedSelection)
self.openLyricsAddButton = QtGui.QPushButton(self.openLyricsPage) #self.openLyricsFileListWidget.setObjectName(u'OpenLyricsFileListWidget')
self.openLyricsAddButton.setIcon(openIcon) #self.openLyricsLayout.addWidget(self.openLyricsFileListWidget)
self.openLyricsAddButton.setObjectName(u'OpenLyricsAddButton') #self.openLyricsButtonLayout = QtGui.QHBoxLayout()
self.openLyricsButtonLayout.addWidget(self.openLyricsAddButton) #self.openLyricsButtonLayout.setSpacing(8)
self.openLyricsButtonSpacer = QtGui.QSpacerItem(40, 20, #self.openLyricsButtonLayout.setObjectName(u'OpenLyricsButtonLayout')
QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) #self.openLyricsAddButton = QtGui.QPushButton(self.openLyricsPage)
self.openLyricsButtonLayout.addItem(self.openLyricsButtonSpacer) #self.openLyricsAddButton.setIcon(openIcon)
self.openLyricsRemoveButton = QtGui.QPushButton(self.openLyricsPage) #self.openLyricsAddButton.setObjectName(u'OpenLyricsAddButton')
self.openLyricsRemoveButton.setIcon(deleteIcon) #self.openLyricsButtonLayout.addWidget(self.openLyricsAddButton)
self.openLyricsRemoveButton.setObjectName(u'OpenLyricsRemoveButton') #self.openLyricsButtonSpacer = QtGui.QSpacerItem(40, 20,
self.openLyricsButtonLayout.addWidget(self.openLyricsRemoveButton) # QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.openLyricsLayout.addLayout(self.openLyricsButtonLayout) #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) self.formatStackedWidget.addWidget(self.openLyricsPage)
# Open Song # Open Song
self.openSongPage = QtGui.QWidget() self.openSongPage = QtGui.QWidget()
@ -277,22 +299,52 @@ class Ui_SongImportWizard(object):
self.songsOfFellowshipLayout = QtGui.QVBoxLayout( self.songsOfFellowshipLayout = QtGui.QVBoxLayout(
self.songsOfFellowshipPage) self.songsOfFellowshipPage)
self.songsOfFellowshipLayout.setMargin(0) self.songsOfFellowshipLayout.setMargin(0)
self.songsOfFellowshipLayout.setSpacing(8) self.songsOfFellowshipLayout.setSpacing(0)
self.songsOfFellowshipLayout.setObjectName(u'songsOfFellowshipLayout') self.songsOfFellowshipLayout.setObjectName(u'songsOfFellowshipLayout')
self.songsOfFellowshipFileListWidget = QtGui.QListWidget( self.songsOfFellowshipDisabledWidget = QtGui.QWidget(
self.songsOfFellowshipPage) 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( self.songsOfFellowshipFileListWidget.setSelectionMode(
QtGui.QAbstractItemView.ExtendedSelection) QtGui.QAbstractItemView.ExtendedSelection)
self.songsOfFellowshipFileListWidget.setObjectName( self.songsOfFellowshipFileListWidget.setObjectName(
u'songsOfFellowshipFileListWidget') u'songsOfFellowshipFileListWidget')
self.songsOfFellowshipLayout.addWidget( self.songsOfFellowshipImportLayout.addWidget(
self.songsOfFellowshipFileListWidget) self.songsOfFellowshipFileListWidget)
self.songsOfFellowshipButtonLayout = QtGui.QHBoxLayout() self.songsOfFellowshipButtonLayout = QtGui.QHBoxLayout()
self.songsOfFellowshipButtonLayout.setSpacing(8) self.songsOfFellowshipButtonLayout.setSpacing(8)
self.songsOfFellowshipButtonLayout.setObjectName( self.songsOfFellowshipButtonLayout.setObjectName(
u'songsOfFellowshipButtonLayout') u'songsOfFellowshipButtonLayout')
self.songsOfFellowshipAddButton = QtGui.QPushButton( self.songsOfFellowshipAddButton = QtGui.QPushButton(
self.songsOfFellowshipPage) self.songsOfFellowshipImportWidget)
self.songsOfFellowshipAddButton.setIcon(openIcon) self.songsOfFellowshipAddButton.setIcon(openIcon)
self.songsOfFellowshipAddButton.setObjectName( self.songsOfFellowshipAddButton.setObjectName(
u'songsOfFellowshipAddButton') u'songsOfFellowshipAddButton')
@ -303,42 +355,63 @@ class Ui_SongImportWizard(object):
self.songsOfFellowshipButtonLayout.addItem( self.songsOfFellowshipButtonLayout.addItem(
self.songsOfFellowshipButtonSpacer) self.songsOfFellowshipButtonSpacer)
self.songsOfFellowshipRemoveButton = QtGui.QPushButton( self.songsOfFellowshipRemoveButton = QtGui.QPushButton(
self.songsOfFellowshipPage) self.songsOfFellowshipImportWidget)
self.songsOfFellowshipRemoveButton.setIcon(deleteIcon) self.songsOfFellowshipRemoveButton.setIcon(deleteIcon)
self.songsOfFellowshipRemoveButton.setObjectName( self.songsOfFellowshipRemoveButton.setObjectName(
u'songsOfFellowshipRemoveButton') u'songsOfFellowshipRemoveButton')
self.songsOfFellowshipButtonLayout.addWidget( self.songsOfFellowshipButtonLayout.addWidget(
self.songsOfFellowshipRemoveButton) self.songsOfFellowshipRemoveButton)
self.songsOfFellowshipLayout.addLayout( self.songsOfFellowshipImportLayout.addLayout(
self.songsOfFellowshipButtonLayout) self.songsOfFellowshipButtonLayout)
self.songsOfFellowshipLayout.addWidget(
self.songsOfFellowshipImportWidget)
self.formatStackedWidget.addWidget(self.songsOfFellowshipPage) self.formatStackedWidget.addWidget(self.songsOfFellowshipPage)
# Generic Document/Presentation import # Generic Document/Presentation import
self.genericPage = QtGui.QWidget() self.genericPage = QtGui.QWidget()
self.genericPage.setObjectName(u'genericPage') self.genericPage.setObjectName(u'genericPage')
self.genericLayout = QtGui.QVBoxLayout(self.genericPage) self.genericLayout = QtGui.QVBoxLayout(self.genericPage)
self.genericLayout.setMargin(0) self.genericLayout.setMargin(0)
self.genericLayout.setSpacing(8) self.genericLayout.setSpacing(0)
self.genericLayout.setObjectName(u'genericLayout') 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( self.genericFileListWidget.setSelectionMode(
QtGui.QAbstractItemView.ExtendedSelection) QtGui.QAbstractItemView.ExtendedSelection)
self.genericFileListWidget.setObjectName(u'genericFileListWidget') self.genericFileListWidget.setObjectName(u'genericFileListWidget')
self.genericLayout.addWidget(self.genericFileListWidget) self.genericImportLayout.addWidget(self.genericFileListWidget)
self.genericButtonLayout = QtGui.QHBoxLayout() self.genericButtonLayout = QtGui.QHBoxLayout()
self.genericButtonLayout.setSpacing(8) self.genericButtonLayout.setSpacing(8)
self.genericButtonLayout.setObjectName(u'genericButtonLayout') self.genericButtonLayout.setObjectName(u'genericButtonLayout')
self.genericAddButton = QtGui.QPushButton(self.genericPage) self.genericAddButton = QtGui.QPushButton(self.genericImportWidget)
self.genericAddButton.setIcon(openIcon) self.genericAddButton.setIcon(openIcon)
self.genericAddButton.setObjectName(u'genericAddButton') self.genericAddButton.setObjectName(u'genericAddButton')
self.genericButtonLayout.addWidget(self.genericAddButton) self.genericButtonLayout.addWidget(self.genericAddButton)
self.genericButtonSpacer = QtGui.QSpacerItem(40, 20, self.genericButtonSpacer = QtGui.QSpacerItem(40, 20,
QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.genericButtonLayout.addItem(self.genericButtonSpacer) self.genericButtonLayout.addItem(self.genericButtonSpacer)
self.genericRemoveButton = QtGui.QPushButton(self.genericPage) self.genericRemoveButton = QtGui.QPushButton(self.genericImportWidget)
self.genericRemoveButton.setIcon(deleteIcon) self.genericRemoveButton.setIcon(deleteIcon)
self.genericRemoveButton.setObjectName(u'genericRemoveButton') self.genericRemoveButton.setObjectName(u'genericRemoveButton')
self.genericButtonLayout.addWidget(self.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) self.formatStackedWidget.addWidget(self.genericPage)
# Commented out for future use. # Commented out for future use.
# self.csvPage = QtGui.QWidget() # self.csvPage = QtGui.QWidget()
@ -434,10 +507,20 @@ class Ui_SongImportWizard(object):
translate('SongsPlugin.ImportWizardForm', 'Filename:')) translate('SongsPlugin.ImportWizardForm', 'Filename:'))
self.openLP1BrowseButton.setText( self.openLP1BrowseButton.setText(
translate('SongsPlugin.ImportWizardForm', 'Browse...')) translate('SongsPlugin.ImportWizardForm', 'Browse...'))
self.openLyricsAddButton.setText( self.openLP1DisabledLabel.setText(
translate('SongsPlugin.ImportWizardForm', 'Add Files...')) translate('SongsPlugin.ImportWizardForm', 'The openlp.org 1.x '
self.openLyricsRemoveButton.setText( 'importer has been disabled due to a missing Python module. If '
translate('SongsPlugin.ImportWizardForm', 'Remove File(s)')) '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( self.openSongAddButton.setText(
translate('SongsPlugin.ImportWizardForm', 'Add Files...')) translate('SongsPlugin.ImportWizardForm', 'Add Files...'))
self.openSongRemoveButton.setText( self.openSongRemoveButton.setText(
@ -454,10 +537,18 @@ class Ui_SongImportWizard(object):
translate('SongsPlugin.ImportWizardForm', 'Add Files...')) translate('SongsPlugin.ImportWizardForm', 'Add Files...'))
self.songsOfFellowshipRemoveButton.setText( self.songsOfFellowshipRemoveButton.setText(
translate('SongsPlugin.ImportWizardForm', 'Remove File(s)')) 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( self.genericAddButton.setText(
translate('SongsPlugin.ImportWizardForm', 'Add Files...')) translate('SongsPlugin.ImportWizardForm', 'Add Files...'))
self.genericRemoveButton.setText( self.genericRemoveButton.setText(
translate('SongsPlugin.ImportWizardForm', 'Remove File(s)')) 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( # self.csvFilenameLabel.setText(
# translate('SongsPlugin.ImportWizardForm', 'Filename:')) # translate('SongsPlugin.ImportWizardForm', 'Filename:'))
# self.csvBrowseButton.setText( # self.csvBrowseButton.setText(

View File

@ -81,14 +81,15 @@ class CCLIFileImport(SongImport):
lines = infile.readlines() lines = infile.readlines()
ext = os.path.splitext(filename)[1] ext = os.path.splitext(filename)[1]
if ext.lower() == ".usr": 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) self.do_import_usr_file(lines)
elif ext.lower() == ".txt": 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) self.do_import_txt_file(lines)
else: else:
log.info(u'Extension %s is not valid', filename) log.info(u'Extension %s is not valid', filename)
pass
song_count += 1 song_count += 1
if self.stop_import_flag: if self.stop_import_flag:
return False return False
@ -175,7 +176,7 @@ class CCLIFileImport(SongImport):
verse_text = unicode(words_list[counter]) verse_text = unicode(words_list[counter])
verse_text = verse_text.replace("/n", "\n") verse_text = verse_text.replace("/n", "\n")
if len(verse_text) > 0: if len(verse_text) > 0:
self.add_verse(verse_text, verse_type); self.add_verse(verse_text, verse_type)
#Handle multiple authors #Handle multiple authors
author_list = song_author.split(u'/') author_list = song_author.split(u'/')
if len(author_list) < 2: if len(author_list) < 2:
@ -238,7 +239,7 @@ class CCLIFileImport(SongImport):
line_number = 0 line_number = 0
verse_text = u'' verse_text = u''
song_comments = u'' song_comments = u''
song_copyright = u''; song_copyright = u''
verse_start = False verse_start = False
for line in textList: for line in textList:
clean_line = line.strip() clean_line = line.strip()
@ -293,7 +294,8 @@ class CCLIFileImport(SongImport):
line_number += 1 line_number += 1
song_author = clean_line song_author = clean_line
#line_number=4, comments lines before last line #line_number=4, comments lines before last line
elif (line_number==4) and (not clean_line.startswith(u'CCL')): elif (line_number == 4) and \
(not clean_line.startswith(u'CCL')):
song_comments = song_comments + clean_line song_comments = song_comments + clean_line
# split on known separators # split on known separators
author_list = song_author.split(u'/') author_list = song_author.split(u'/')
@ -307,4 +309,3 @@ class CCLIFileImport(SongImport):
self.ccli_number = song_ccli self.ccli_number = song_ccli
self.comments = song_comments self.comments = song_comments
self.finish() self.finish()

View File

@ -26,14 +26,24 @@
from opensongimport import OpenSongImport from opensongimport import OpenSongImport
from olpimport import OpenLPSongImport from olpimport import OpenLPSongImport
from wowimport import WowImport
from cclifileimport import CCLIFileImport
# Imports that might fail
try:
from olp1import import OpenLP1SongImport from olp1import import OpenLP1SongImport
has_openlp1 = True
except ImportError:
has_openlp1 = False
try: try:
from sofimport import SofImport from sofimport import SofImport
from oooimport import OooImport has_sof = True
from cclifileimport import CCLIFileImport
from wowimport import WowImport
except ImportError: except ImportError:
pass has_sof = False
try:
from oooimport import OooImport
has_ooo = True
except ImportError:
has_ooo = False
class SongFormat(object): class SongFormat(object):
""" """
@ -41,6 +51,7 @@ class SongFormat(object):
plus a few helper functions to facilitate generic handling of song types plus a few helper functions to facilitate generic handling of song types
for importing. for importing.
""" """
_format_availability = {}
Unknown = -1 Unknown = -1
OpenLP2 = 0 OpenLP2 = 0
OpenLP1 = 1 OpenLP1 = 1
@ -93,4 +104,16 @@ class SongFormat(object):
SongFormat.Generic 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'] __all__ = [u'SongFormat']

View File

@ -29,10 +29,7 @@ openlp.org 1.x song databases into the current installation database.
""" """
import logging import logging
import chardet import chardet
try:
import sqlite import sqlite
except:
pass
from openlp.core.lib import translate from openlp.core.lib import translate
from songimport import SongImport from songimport import SongImport

View File

@ -29,7 +29,9 @@ import os
from zipfile import ZipFile from zipfile import ZipFile
from lxml import objectify from lxml import objectify
from lxml.etree import Error, LxmlError from lxml.etree import Error, LxmlError
import re
from openlp.core.lib import translate
from openlp.plugins.songs.lib.songimport import SongImport from openlp.plugins.songs.lib.songimport import SongImport
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -112,12 +114,22 @@ class OpenSongImport(SongImport):
def do_import(self): def do_import(self):
""" """
Import either a single opensong file, or a zipfile containing multiple Import either each of the files in self.filenames - each element of
opensong files. If `self.commit` is set False, the import will not be which can be either a single opensong file, or a zipfile containing
committed to the database (useful for test scripts). multiple opensong files. If `self.commit` is set False, the
import will not be committed to the database (useful for test scripts).
""" """
success = True 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: for filename in self.filenames:
if self.stop_import_flag: if self.stop_import_flag:
success = False success = False
@ -126,9 +138,6 @@ class OpenSongImport(SongImport):
if ext.lower() == u'.zip': if ext.lower() == u'.zip':
log.debug(u'Zipfile found %s', filename) log.debug(u'Zipfile found %s', filename)
z = ZipFile(filename, u'r') z = ZipFile(filename, u'r')
self.import_wizard.importProgressBar.setMaximum(
self.import_wizard.importProgressBar.maximum() +
len(z.infolist()))
for song in z.infolist(): for song in z.infolist():
if self.stop_import_flag: if self.stop_import_flag:
success = False success = False
@ -137,6 +146,7 @@ class OpenSongImport(SongImport):
if parts[-1] == u'': if parts[-1] == u'':
#No final part => directory #No final part => directory
continue continue
log.info(u'Zip importing %s', parts[-1])
self.import_wizard.incrementProgressBar( self.import_wizard.incrementProgressBar(
unicode(translate('SongsPlugin.ImportWizardForm', unicode(translate('SongsPlugin.ImportWizardForm',
'Importing %s...')) % parts[-1]) 'Importing %s...')) % parts[-1])
@ -144,11 +154,11 @@ class OpenSongImport(SongImport):
self.do_import_file(songfile) self.do_import_file(songfile)
if self.commit: if self.commit:
self.finish() self.finish()
self.set_defaults()
if self.stop_import_flag: if self.stop_import_flag:
success = False success = False
break break
else: else:
# not a zipfile
log.info('Direct import %s', filename) log.info('Direct import %s', filename)
self.import_wizard.incrementProgressBar( self.import_wizard.incrementProgressBar(
unicode(translate('SongsPlugin.ImportWizardForm', unicode(translate('SongsPlugin.ImportWizardForm',
@ -157,9 +167,7 @@ class OpenSongImport(SongImport):
self.do_import_file(file) self.do_import_file(file)
if self.commit: if self.commit:
self.finish() self.finish()
self.set_defaults()
if not self.commit:
self.finish()
return success return success
def do_import_file(self, file): def do_import_file(self, file):
@ -167,10 +175,10 @@ class OpenSongImport(SongImport):
Process the OpenSong file - pass in a file-like object, Process the OpenSong file - pass in a file-like object,
not a filename not a filename
""" """
self.authors = [] self.set_defaults()
try: try:
tree = objectify.parse(file) tree = objectify.parse(file)
except Error, LxmlError: except (Error, LxmlError):
log.exception(u'Error parsing XML') log.exception(u'Error parsing XML')
return return
root = tree.getroot() root = tree.getroot()
@ -196,7 +204,6 @@ class OpenSongImport(SongImport):
self.topics.append(unicode(root.alttheme)) self.topics.append(unicode(root.alttheme))
# data storage while importing # data storage while importing
verses = {} verses = {}
lyrics = unicode(root.lyrics)
# keep track of a "default" verse order, in case none is specified # keep track of a "default" verse order, in case none is specified
our_verse_order = [] our_verse_order = []
verses_seen = {} verses_seen = {}
@ -204,6 +211,7 @@ class OpenSongImport(SongImport):
# erm, versetype! # erm, versetype!
versetype = u'V' versetype = u'V'
versenum = None versenum = None
lyrics = unicode(root.lyrics)
for thisline in lyrics.split(u'\n'): for thisline in lyrics.split(u'\n'):
# remove comments # remove comments
semicolon = thisline.find(u';') semicolon = thisline.find(u';')
@ -218,16 +226,18 @@ class OpenSongImport(SongImport):
continue continue
# verse/chorus/etc. marker # verse/chorus/etc. marker
if thisline[0] == u'[': if thisline[0] == u'[':
versetype = thisline[1].upper() # drop the square brackets
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']') right_bracket = thisline.find(u']')
versenum = thisline[2:right_bracket] 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: 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' versenum = u'1'
continue continue
words = None words = None
@ -235,10 +245,10 @@ class OpenSongImport(SongImport):
if thisline[0].isdigit(): if thisline[0].isdigit():
versenum = thisline[0] versenum = thisline[0]
words = thisline[1:].strip() words = thisline[1:].strip()
if words is None and \ if words is None:
versenum is not None and \
versetype is not None:
words = thisline words = thisline
if not versenum:
versenum = u'1'
if versenum is not None: if versenum is not None:
versetag = u'%s%s' % (versetype, versenum) versetag = u'%s%s' % (versetype, versenum)
if not verses.has_key(versetype): if not verses.has_key(versetype):
@ -259,10 +269,13 @@ class OpenSongImport(SongImport):
versetypes.sort() versetypes.sort()
versetags = {} versetags = {}
for versetype in versetypes: for versetype in versetypes:
our_verse_type = versetype
if our_verse_type == u'':
our_verse_type = u'V'
versenums = verses[versetype].keys() versenums = verses[versetype].keys()
versenums.sort() versenums.sort()
for num in versenums: 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]) lines = u'\n'.join(verses[versetype][num])
self.verses.append([versetag, lines]) self.verses.append([versetag, lines])
# Keep track of what we have for error checking later # Keep track of what we have for error checking later
@ -271,16 +284,23 @@ class OpenSongImport(SongImport):
order = [] order = []
if u'presentation' in fields and root.presentation != u'': if u'presentation' in fields and root.presentation != u'':
order = unicode(root.presentation) 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: else:
if len(our_verse_order) > 0: if len(our_verse_order) > 0:
order = our_verse_order order = our_verse_order
else: 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: for tag in order:
if len(tag) == 1: if tag[0].isdigit():
tag = tag + u'1' # Assume it's no.1 if it's not there # 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): 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: else:
self.verse_order_list.append(tag) self.verse_order_list.append(tag)

View File

@ -55,8 +55,12 @@ class SongImport(QtCore.QObject):
self.set_defaults() self.set_defaults()
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'songs_stop_import'), self.stop_import) QtCore.SIGNAL(u'songs_stop_import'), self.stop_import)
def set_defaults(self): 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.title = u''
self.song_number = u'' self.song_number = u''
self.alternate_title = u'' self.alternate_title = u''
@ -255,13 +259,16 @@ class SongImport(QtCore.QObject):
""" """
Write the song and its fields to disk Write the song and its fields to disk
""" """
log.info(u'commiting song %s to database', self.title)
song = Song() song = Song()
song.title = self.title song.title = self.title
song.search_title = self.remove_punctuation(self.title) \ song.search_title = self.remove_punctuation(self.title) \
+ '@' + self.alternate_title + '@' + self.alternate_title
song.song_number = self.song_number song.song_number = self.song_number
song.search_lyrics = u'' song.search_lyrics = u''
verses_changed_to_other = {}
sxml = SongXMLBuilder() sxml = SongXMLBuilder()
other_count = 1
for (versetag, versetext) in self.verses: for (versetag, versetext) in self.verses:
if versetag[0] == u'C': if versetag[0] == u'C':
versetype = VerseType.to_string(VerseType.Chorus) versetype = VerseType.to_string(VerseType.Chorus)
@ -276,10 +283,18 @@ class SongImport(QtCore.QObject):
elif versetag[0] == u'E': elif versetag[0] == u'E':
versetype = VerseType.to_string(VerseType.Ending) versetype = VerseType.to_string(VerseType.Ending)
else: else:
newversetag = u'O%d' % other_count
verses_changed_to_other[versetag] = newversetag
other_count += 1
versetype = VerseType.to_string(VerseType.Other) 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) sxml.add_verse_to_lyrics(versetype, versetag[1:], versetext)
song.search_lyrics += u' ' + self.remove_punctuation(versetext) song.search_lyrics += u' ' + self.remove_punctuation(versetext)
song.lyrics = unicode(sxml.extract_xml(), u'utf-8') 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.verse_order = u' '.join(self.verse_order_list)
song.copyright = self.copyright song.copyright = self.copyright
song.comments = self.comments song.comments = self.comments

View File

@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<song> <song>
<title>Martins Test</title> <title>Martins Test</title>
<author>MartiÑ Thómpson</author> <author>MartiÑ &amp; Martin2 Thómpson</author>
<copyright>2010 Martin Thompson</copyright> <copyright>2010 Martin Thompson</copyright>
<hymn_number>1</hymn_number> <hymn_number>1</hymn_number>
<presentation>V1 C V2 C2 V3 B1 V1</presentation> <presentation>V1 C V2 C2 3a B1 V1 T U Rap1 Rap2 Rap3</presentation>
<ccli>Blah</ccli> <ccli>Blah</ccli>
<capo print="false"></capo> <capo print="false"></capo>
<key></key> <key></key>
@ -17,7 +17,12 @@
<alttheme>TestAltTheme</alttheme> <alttheme>TestAltTheme</alttheme>
<tempo></tempo> <tempo></tempo>
<time_sig></time_sig> <time_sig></time_sig>
<lyrics>;Comment <lyrics>[3a]
. G A B
V3 Line 1
. G A B
V3 Line 2
. A B C . A B C
1 v1 Line 1___ 1 v1 Line 1___
2 v2 Line 1___ 2 v2 Line 1___
@ -25,10 +30,6 @@
1 V1 Line 2 1 V1 Line 2
2 V2 Line 2 2 V2 Line 2
[3]
V3 Line 1
V3 Line 2
[b1] [b1]
Bridge 1 Bridge 1
--- ---
@ -42,6 +43,23 @@
[C2] [C2]
. A B . A B
Chorus 2 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
</lyrics> </lyrics>
<style index="default_style"> <style index="default_style">
<title enabled="true" valign="bottom" align="center" include_verse="false" margin-left="0" margin-right="0" margin-top="0" margin-bottom="0" font="Helvetica" size="26" bold="true" italic="true" underline="false" color="#FFFFFF" border="true" border_color="#000000" shadow="true" shadow_color="#000000" fill="false" fill_color="#000000"/> <title enabled="true" valign="bottom" align="center" include_verse="false" margin-left="0" margin-right="0" margin-top="0" margin-bottom="0" font="Helvetica" size="26" bold="true" italic="true" underline="false" color="#FFFFFF" border="true" border_color="#000000" shadow="true" shadow_color="#000000" fill="false" fill_color="#000000"/>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<song>
<title>Test single verse</title>
<author>Martin Thompson</author>
<copyright>2010</copyright>
<ccli>123456</ccli>
<theme>Worship: Declaration</theme>
<lyrics> Line 1
Line 2
</lyrics></song>

View File

@ -0,0 +1,47 @@
# -*- 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 #
###############################################################################
import sys
from openlp.plugins.songs.lib.opensongimport import OpenSongImport
from openlp.core.lib.db import Manager
from openlp.plugins.songs.lib.db import init_schema
import logging
LOG_FILENAME = 'test_import_file.log'
logging.basicConfig(filename=LOG_FILENAME,level=logging.INFO)
from test_opensongimport import wizard_stub, progbar_stub
def test(filenames):
manager = Manager(u'songs', init_schema)
o = OpenSongImport(manager, filenames=filenames)
o.import_wizard = wizard_stub()
o.commit = False
o.do_import()
o.print_song()
if __name__ == "__main__":
test(sys.argv[1:])

View File

@ -8,50 +8,29 @@ from traceback import print_exc
import sys import sys
import codecs import codecs
import logging
LOG_FILENAME = 'import.log'
logging.basicConfig(filename=LOG_FILENAME,level=logging.INFO)
from test_opensongimport import wizard_stub, progbar_stub
# Useful test function for importing a variety of different files
# Uncomment below depending on what problem trying to make occur!
def opensong_import_lots(): def opensong_import_lots():
ziploc = u'/home/mjt/openlp/OpenSong_Data/' ziploc = u'/home/mjt/openlp/OpenSong_Data/'
files = [] files = []
#files = [u'test.opensong.zip', ziploc+u'ADond.zip'] files = [os.path.join(ziploc, u'RaoulSongs', u'Songs', u'Jesus Freak')]
files.extend(glob(ziploc+u'Songs.zip')) # files.extend(glob(ziploc+u'Songs.zip'))
# files.extend(glob(ziploc+u'RaoulSongs.zip'))
# files.extend(glob(ziploc+u'SOF.zip')) # files.extend(glob(ziploc+u'SOF.zip'))
# files.extend(glob(ziploc+u'spanish_songs_for_opensong.zip')) # files.extend(glob(ziploc+u'spanish_songs_for_opensong.zip'))
# files.extend(glob(ziploc+u'opensong_*.zip')) # files.extend(glob(ziploc+u'opensong_*.zip'))
errfile = codecs.open(u'import_lots_errors.txt', u'w', u'utf8') errfile = codecs.open(u'import_lots_errors.txt', u'w', u'utf8')
manager = Manager(u'songs', init_schema) manager = Manager(u'songs', init_schema)
for file in files: o = OpenSongImport(manager, filenames=files)
print u'Importing', file o.import_wizard=wizard_stub()
z = ZipFile(file, u'r') o.do_import()
for song in z.infolist():
# need to handle unicode filenames (CP437 - Winzip does this)
filename = song.filename#.decode('cp852')
parts = os.path.split(filename)
if parts[-1] == u'':
#No final part => directory
continue
print " ", file, ":",filename,
songfile = z.open(song)
#z.extract(song)
#songfile=open(filename, u'r')
o = OpenSongImport(manager)
try:
o.do_import_file(songfile)
# o.song_import.print_song()
except:
print "Failure",
errfile.write(u'Failure: %s:%s\n' %(file, filename.decode('cp437')))
songfile = z.open(song)
for l in songfile.readlines():
l = l.decode('utf8')
print(u' |%s\n' % l.strip())
errfile.write(u' |%s\n'%l.strip())
print_exc(3, file = errfile)
print_exc(3)
sys.exit(1)
# continue
#o.finish()
print "OK"
#os.unlink(filename)
# o.song_import.print_song()
if __name__ == "__main__": if __name__ == "__main__":
opensong_import_lots() opensong_import_lots()

View File

@ -28,62 +28,101 @@ from openlp.plugins.songs.lib.opensongimport import OpenSongImport
from openlp.core.lib.db import Manager from openlp.core.lib.db import Manager
from openlp.plugins.songs.lib.db import init_schema from openlp.plugins.songs.lib.db import init_schema
import logging
LOG_FILENAME = 'test.log'
logging.basicConfig(filename=LOG_FILENAME,level=logging.INFO)
# Stubs to replace the UI functions for raw testing
class wizard_stub:
def __init__(self):
self.importProgressBar=progbar_stub()
def incrementProgressBar(self, str):
pass
class progbar_stub:
def __init__(self):
pass
def setMaximum(self, arg):
pass
def test(): def test():
manager = Manager(u'songs', init_schema) manager = Manager(u'songs', init_schema)
o = OpenSongImport(manager) o = OpenSongImport(manager, filenames=[u'test.opensong'])
o.do_import(u'test.opensong', commit=False) o.import_wizard = wizard_stub()
o.song_import.print_song() o.commit = False
assert o.song_import.copyright == u'2010 Martin Thompson' o.do_import()
assert o.song_import.authors == [u'MartiÑ Thómpson'] o.print_song()
assert o.song_import.title == u'Martins Test' assert o.copyright == u'2010 Martin Thompson'
assert o.song_import.alternate_title == u'' assert o.authors == [u'MartiÑ Thómpson', u'Martin2 Thómpson']
assert o.song_import.song_number == u'1' assert o.title == u'Martins Test'
assert [u'C1', u'Chorus 1'] in o.song_import.verses assert o.alternate_title == u''
assert [u'C2', u'Chorus 2'] in o.song_import.verses assert o.song_number == u'1'
assert not [u'C3', u'Chorus 3'] in o.song_import.verses assert [u'C1', u'Chorus 1'] in o.verses
assert [u'B1', u'Bridge 1\nBridge 1 line 2'] in o.song_import.verses assert [u'C2', u'Chorus 2'] in o.verses
assert [u'V1', u'v1 Line 1\nV1 Line 2'] in o.song_import.verses assert not [u'C3', u'Chorus 3'] in o.verses
assert [u'V2', u'v2 Line 1\nV2 Line 2'] in o.song_import.verses assert [u'B1', u'Bridge 1\nBridge 1 line 2'] in o.verses
assert o.song_import.verse_order_list == [u'V1', u'C1', u'V2', u'C2', u'V3', u'B1', u'V1'] assert [u'V1', u'v1 Line 1\nV1 Line 2'] in o.verses
assert o.song_import.ccli_number == u'Blah' assert [u'V2', u'v2 Line 1\nV2 Line 2'] in o.verses
assert o.song_import.topics == [u'TestTheme', u'TestAltTheme'] assert [u'V3A', u'V3 Line 1\nV3 Line 2'] in o.verses
o.do_import(u'test.opensong.zip', commit=False) assert [u'RAP1', u'Rap 1 Line 1\nRap 1 Line 2'] in o.verses
o.song_import.print_song() assert [u'RAP2', u'Rap 2 Line 1\nRap 2 Line 2'] in o.verses
o.finish() assert [u'RAP3', u'Rap 3 Line 1\nRap 3 Line 2'] in o.verses
assert o.song_import.copyright == u'2010 Martin Thompson' assert [u'X1', u'Unreferenced verse line 1'] in o.verses
assert o.song_import.authors == [u'MartiÑ Thómpson'] assert o.verse_order_list == [u'V1', u'C1', u'V2', u'C2', u'V3A', u'B1', u'V1', u'T1', u'RAP1', u'RAP2', u'RAP3']
assert o.song_import.title == u'Martins Test' assert o.ccli_number == u'Blah'
assert o.song_import.alternate_title == u'' assert o.topics == [u'TestTheme', u'TestAltTheme']
assert o.song_import.song_number == u'1'
assert [u'B1', u'Bridge 1\nBridge 1 line 2'] in o.song_import.verses
assert [u'C1', u'Chorus 1'] in o.song_import.verses
assert [u'C2', u'Chorus 2'] in o.song_import.verses
assert not [u'C3', u'Chorus 3'] in o.song_import.verses
assert [u'V1', u'v1 Line 1\nV1 Line 2'] in o.song_import.verses
assert [u'V2', u'v2 Line 1\nV2 Line 2'] in o.song_import.verses
assert o.song_import.verse_order_list == [u'V1', u'C1', u'V2', u'C2', u'V3', u'B1', u'V1']
o = OpenSongImport(manager) o.filenames = [u'test.opensong.zip']
o.do_import(u'test2.opensong', commit=False) o.set_defaults()
# o.finish() o.do_import()
o.song_import.print_song() o.print_song()
assert o.song_import.copyright == u'2010 Martin Thompson' assert o.copyright == u'2010 Martin Thompson'
assert o.song_import.authors == [u'Martin Thompson'] assert o.authors == [u'MartiÑ Thómpson']
assert o.song_import.title == u'Martins 2nd Test' assert o.title == u'Martins Test'
assert o.song_import.alternate_title == u'' assert o.alternate_title == u''
assert o.song_import.song_number == u'2' assert o.song_number == u'1'
print o.song_import.verses assert [u'B1', u'Bridge 1\nBridge 1 line 2'] in o.verses
assert [u'B1', u'Bridge 1\nBridge 1 line 2'] in o.song_import.verses assert [u'C1', u'Chorus 1'] in o.verses
assert [u'C1', u'Chorus 1'] in o.song_import.verses assert [u'C2', u'Chorus 2'] in o.verses
assert [u'C2', u'Chorus 2'] in o.song_import.verses assert not [u'C3', u'Chorus 3'] in o.verses
assert not [u'C3', u'Chorus 3'] in o.song_import.verses assert [u'V1', u'v1 Line 1\nV1 Line 2'] in o.verses
assert [u'V1', u'v1 Line 1\nV1 Line 2'] in o.song_import.verses assert [u'V2', u'v2 Line 1\nV2 Line 2'] in o.verses
assert [u'V2', u'v2 Line 1\nV2 Line 2'] in o.song_import.verses print o.verse_order_list
print o.song_import.verse_order_list assert o.verse_order_list == [u'V1', u'C1', u'V2', u'C2', u'V3', u'B1', u'V1']
assert o.song_import.verse_order_list == [u'V1', u'V2', u'B1', u'C1', u'C2']
o.filenames = [u'test2.opensong']
o.set_defaults()
o.do_import()
o.print_song()
assert o.copyright == u'2010 Martin Thompson'
assert o.authors == [u'Martin Thompson']
assert o.title == u'Martins 2nd Test'
assert o.alternate_title == u''
assert o.song_number == u'2'
print o.verses
assert [u'B1', u'Bridge 1\nBridge 1 line 2'] in o.verses
assert [u'C1', u'Chorus 1'] in o.verses
assert [u'C2', u'Chorus 2'] in o.verses
assert not [u'C3', u'Chorus 3'] in o.verses
assert [u'V1', u'v1 Line 1\nV1 Line 2'] in o.verses
assert [u'V2', u'v2 Line 1\nV2 Line 2'] in o.verses
print o.verse_order_list
assert o.verse_order_list == [u'V1', u'V2', u'B1', u'C1', u'C2']
o.filenames = [u'test3.opensong']
o.set_defaults()
o.do_import()
o.print_song()
assert o.copyright == u'2010'
assert o.authors == [u'Martin Thompson']
assert o.title == u'Test single verse'
assert o.alternate_title == u''
assert o.ccli_number == u'123456'
assert o.verse_order_list == [u'V1']
assert o.topics == [u'Worship: Declaration']
print o.verses[0]
assert [u'V1', u'Line 1\nLine 2'] in o.verses
print "Tests passed" print "Tests passed"
pass
if __name__ == "__main__": if __name__ == "__main__":
test() test()