This commit is contained in:
Tim Bentley 2011-02-18 17:38:56 +00:00
commit f1850d4147
22 changed files with 548 additions and 382 deletions

View File

@ -239,7 +239,8 @@ def resize_image(image, width, height, background=QtCore.Qt.black):
Resize an image to fit on the current screen.
``image``
The image to resize.
The image to resize. It has to be either a ``QImage`` instance or the
path to the image.
``width``
The new image width.

View File

@ -85,8 +85,7 @@ class ImageManager(QtCore.QObject):
for key in self._cache.keys():
image = self._cache[key]
image.dirty = True
image.image = resize_image(image.path,
self.width, self.height)
image.image = resize_image(image.path, self.width, self.height)
self._cache_dirty = True
# only one thread please
if not self._thread_running:
@ -128,8 +127,7 @@ class ImageManager(QtCore.QObject):
image = Image()
image.name = name
image.path = path
image.image = resize_image(path,
self.width, self.height)
image.image = resize_image(path, self.width, self.height)
self._cache[name] = image
else:
log.debug(u'Image in cache %s:%s' % (name, path))

View File

@ -240,7 +240,7 @@ class MediaManagerItem(QtGui.QWidget):
Creates the main widget for listing items the media item is tracking
"""
# Add the List widget
self.listView = ListWidgetWithDnD(self, self.title)
self.listView = ListWidgetWithDnD(self, self.plugin.name)
self.listView.uniformItemSizes = True
self.listView.setSpacing(1)
self.listView.setSelectionMode(

View File

@ -203,12 +203,12 @@ class RenderManager(object):
# set the default image size for previews
self.calculate_default(self.screens.preview[u'size'])
verse = u'The Lord said to {r}Noah{/r}: \n' \
'There\'s gonna be a {su}floody{/su}, {sb}floody{/sb}\n' \
'The Lord said to {g}Noah{/g}:\n' \
'There\'s gonna be a {st}floody{/st}, {it}floody{/it}\n' \
'Get those children out of the muddy, muddy \n' \
'{r}C{/r}{b}h{/b}{bl}i{/bl}{y}l{/y}{g}d{/g}{pk}' \
'r{/pk}{o}e{/o}{pp}n{/pp} of the Lord\n'
'There\'s gonna be a {su}floody{/su}, {sb}floody{/sb}\n' \
'The Lord said to {g}Noah{/g}:\n' \
'There\'s gonna be a {st}floody{/st}, {it}floody{/it}\n' \
'Get those children out of the muddy, muddy \n' \
'{r}C{/r}{b}h{/b}{bl}i{/bl}{y}l{/y}{g}d{/g}{pk}' \
'r{/pk}{o}e{/o}{pp}n{/pp} of the Lord\n'
# make big page for theme edit dialog to get line count
if self.force_page:
verse = verse + verse + verse

View File

@ -36,7 +36,7 @@ class Ui_ShortcutListDialog(object):
self.treeWidget = QtGui.QTreeWidget(shortcutListDialog)
self.treeWidget.setAlternatingRowColors(True)
self.treeWidget.setObjectName(u'treeWidget')
self.treeWidget.setColumnCount(2)
self.treeWidget.setColumnCount(3)
self.dialogLayout.addWidget(self.treeWidget)
self.defaultButton = QtGui.QRadioButton(shortcutListDialog)
self.defaultButton.setChecked(True)
@ -78,7 +78,8 @@ class Ui_ShortcutListDialog(object):
translate('OpenLP.ShortcutListDialog', 'Customize Shortcuts'))
self.treeWidget.setHeaderLabels([
translate('OpenLP.ShortcutListDialog', 'Action'),
translate('OpenLP.ShortcutListDialog', 'Shortcut')])
translate('OpenLP.ShortcutListDialog', 'Shortcut'),
translate('OpenLP.ShortcutListDialog', 'Alternate')])
self.defaultButton.setText(
translate('OpenLP.ShortcutListDialog', 'Default: %s'))
self.customButton.setText(

View File

@ -95,8 +95,13 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
item = QtGui.QTreeWidgetItem([category.name])
for action in category.actions:
actionText = REMOVE_AMPERSAND.sub('', unicode(action.text()))
shortcutText = action.shortcut().toString()
actionItem = QtGui.QTreeWidgetItem([actionText, shortcutText])
if (len(action.shortcuts()) == 2):
shortcutText = action.shortcuts()[0].toString()
alternateText = action.shortcuts()[1].toString()
else:
shortcutText = action.shortcut().toString()
alternateText = u''
actionItem = QtGui.QTreeWidgetItem([actionText, shortcutText, alternateText])
actionItem.setIcon(0, action.icon())
item.addChild(actionItem)
item.setExpanded(True)

View File

@ -380,7 +380,7 @@ class SlideController(QtGui.QWidget):
self.previousItem.setShortcuts([QtCore.Qt.Key_Up, QtCore.Qt.Key_PageUp])
self.previousItem.setShortcutContext(
QtCore.Qt.WidgetWithChildrenShortcut)
actionList.add_action(self.nextItem, u'Live')
actionList.add_action(self.previousItem, u'Live')
self.nextItem.setShortcuts([QtCore.Qt.Key_Down, QtCore.Qt.Key_PageDown])
self.nextItem.setShortcutContext(QtCore.Qt.WidgetWithChildrenShortcut)
actionList.add_action(self.nextItem, u'Live')
@ -603,14 +603,15 @@ class SlideController(QtGui.QWidget):
slideHeight = 0
if self.serviceItem.is_text():
if frame[u'verseTag']:
bits = frame[u'verseTag'].split(u':')
tag = u'%s\n%s' % (bits[0][0], bits[1][0:] )
tag1 = u'%s%s' % (bits[0][0], bits[1][0:] )
row = tag
# These tags are already translated.
verse_def = frame[u'verseTag']
verse_def = u'%s%s' % (verse_def[0].upper(), verse_def[1:])
two_line_def = u'%s\n%s' % (verse_def[0], verse_def[1:] )
row = two_line_def
if self.isLive:
if tag1 not in self.slideList:
self.slideList[tag1] = framenumber
self.songMenu.menu().addAction(tag1,
if verse_def not in self.slideList:
self.slideList[verse_def] = framenumber
self.songMenu.menu().addAction(verse_def,
self.onSongBarHandler)
else:
row += 1

View File

@ -405,8 +405,8 @@ class ThemeManager(QtGui.QWidget):
files = QtGui.QFileDialog.getOpenFileNames(self,
translate('OpenLP.ThemeManager', 'Select Theme Import File'),
SettingsManager.get_last_dir(self.settingsSection),
unicode(translate('OpenLP.ThemeManager', 'Theme v1 (*.theme);;'
'Theme v2 (*.otz);;%s (*.*)')) % UiStrings.AllFiles)
unicode(translate('OpenLP.ThemeManager',
'OpenLP Themes (*.theme *.otz)')))
log.info(u'New Themes %s', unicode(files))
if files:
for file in files:
@ -529,6 +529,18 @@ class ThemeManager(QtGui.QWidget):
else:
outfile = open(fullpath, u'wb')
outfile.write(zip.read(file))
except (IOError, NameError):
critical_error_message_box(
translate('OpenLP.ThemeManager', 'Validation Error'),
translate('OpenLP.ThemeManager', 'File is not a valid theme.'))
log.exception(u'Importing theme from zip failed %s' % filename)
finally:
# Close the files, to be able to continue creating the theme.
if zip:
zip.close()
if outfile:
outfile.close()
# As all files are closed, we can create the Theme.
if filexml:
theme = self._createThemeFromXml(filexml, self.path)
self.generateAndSaveImage(dir, themename, theme)
@ -539,17 +551,6 @@ class ThemeManager(QtGui.QWidget):
'File is not a valid theme.'))
log.exception(u'Theme file does not contain XML data %s' %
filename)
except (IOError, NameError):
critical_error_message_box(
translate('OpenLP.ThemeManager', 'Validation Error'),
translate('OpenLP.ThemeManager',
'File is not a valid theme.'))
log.exception(u'Importing theme from zip failed %s' % filename)
finally:
if zip:
zip.close()
if outfile:
outfile.close()
def checkIfThemeExists(self, themeName):
"""

View File

@ -164,27 +164,34 @@ def _get_os_dir_path(dir_type):
"""
Return a path based on which OS and environment we are running in.
"""
encoding = sys.getfilesystemencoding()
if sys.platform == u'win32':
if dir_type == AppLocation.DataDir:
return os.path.join(os.getenv(u'APPDATA'), u'openlp', u'data')
return os.path.join(os.getenv(u'APPDATA'), u'openlp')
return os.path.join(unicode(os.getenv(u'APPDATA'), encoding),
u'openlp', u'data')
return os.path.join(unicode(os.getenv(u'APPDATA'), encoding),
u'openlp')
elif sys.platform == u'darwin':
if dir_type == AppLocation.DataDir:
return os.path.join(os.getenv(u'HOME'), u'Library',
u'Application Support', u'openlp', u'Data')
return os.path.join(os.getenv(u'HOME'), u'Library',
u'Application Support', u'openlp')
return os.path.join(unicode(os.getenv(u'HOME'), encoding),
u'Library', u'Application Support', u'openlp', u'Data')
return os.path.join(unicode(os.getenv(u'HOME'), encoding),
u'Library', u'Application Support', u'openlp')
else:
if XDG_BASE_AVAILABLE:
if dir_type == AppLocation.ConfigDir:
return os.path.join(BaseDirectory.xdg_config_home, u'openlp')
return os.path.join(unicode(BaseDirectory.xdg_config_home,
encoding), u'openlp')
elif dir_type == AppLocation.DataDir:
return os.path.join(BaseDirectory.xdg_data_home, u'openlp')
return os.path.join(
unicode(BaseDirectory.xdg_data_home, encoding), u'openlp')
elif dir_type == AppLocation.CacheDir:
return os.path.join(BaseDirectory.xdg_cache_home, u'openlp')
return os.path.join(unicode(BaseDirectory.xdg_cache_home,
encoding), u'openlp')
if dir_type == AppLocation.DataDir:
return os.path.join(os.getenv(u'HOME'), u'.openlp', u'data')
return os.path.join(os.getenv(u'HOME'), u'.openlp')
return os.path.join(unicode(os.getenv(u'HOME'), encoding),
u'.openlp', u'data')
return os.path.join(unicode(os.getenv(u'HOME'), encoding), u'.openlp')
def _get_frozen_path(frozen_option, non_frozen_option):
"""
@ -375,13 +382,13 @@ def get_uno_command():
"""
Returns the UNO command to launch an openoffice.org instance.
"""
COMMAND = u'soffice'
OPTIONS = u'-nologo -norestore -minimized -invisible -nofirststartwizard'
if UNO_CONNECTION_TYPE == u'pipe':
return u'openoffice.org -nologo -norestore -minimized -invisible ' \
+ u'-nofirststartwizard -accept=pipe,name=openlp_pipe;urp;'
CONNECTION = u'"-accept=pipe,name=openlp_pipe;urp;"'
else:
return u'openoffice.org -nologo -norestore -minimized ' \
+ u'-invisible -nofirststartwizard ' \
+ u'-accept=socket,host=localhost,port=2002;urp;'
CONNECTION = u'"-accept=socket,host=localhost,port=2002;urp;"'
return u'%s %s %s' % (COMMAND, OPTIONS, CONNECTION)
def get_uno_instance(resolver):
"""

View File

@ -147,8 +147,10 @@ class PowerpointDocument(PresentationDocument):
"""
if self.check_thumbnails():
return
self.presentation.Export(os.path.join(self.get_thumbnail_folder(), ''),
'png', 320, 240)
for num in range(0, self.presentation.Slides.Count):
self.presentation.Slides(num + 1).Export(os.path.join(
self.get_thumbnail_folder(), 'slide%d.png' % (num + 1)),
'png', 320, 240)
def close_presentation(self):
"""

View File

@ -154,8 +154,9 @@ class PptviewDocument(PresentationDocument):
being shut down
"""
log.debug(u'ClosePresentation')
self.controller.process.ClosePPT(self.pptid)
self.pptid = -1
if self.controller.process:
self.controller.process.ClosePPT(self.pptid)
self.pptid = -1
self.controller.remove_doc(self)
def is_loaded(self):

View File

@ -227,10 +227,6 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
self.copyrightEdit.setText(u'')
self.verseListWidget.clear()
self.verseListWidget.setRowCount(0)
if self.song.verse_order:
self.verseOrderEdit.setText(self.song.verse_order)
else:
self.verseOrderEdit.setText(u'')
if self.song.comments:
self.commentsEdit.setPlainText(self.song.comments)
else:
@ -250,15 +246,31 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
# This is just because occasionally the lyrics come back as a "buffer"
if isinstance(self.song.lyrics, buffer):
self.song.lyrics = unicode(self.song.lyrics)
verse_tags_translated = False
if self.song.lyrics.startswith(u'<?xml version='):
songXML = SongXML()
verseList = songXML.get_verses(self.song.lyrics)
for count, verse in enumerate(verseList):
self.verseListWidget.setRowCount(
self.verseListWidget.rowCount() + 1)
variant = u'%s:%s' % (verse[0][u'type'], verse[0][u'label'])
# This silently migrates from localized verse type markup.
# If we trusted the database, this would be unnecessary.
verse_tag = verse[0][u'type']
index = None
if len(verse_tag) > 1:
index = VerseType.from_translated_string(verse_tag)
if index is None:
index = VerseType.from_string(verse_tag)
else:
verse_tags_translated = True
if index is None:
index = VerseType.from_tag(verse_tag)
if index is None:
index = VerseType.Other
verse[0][u'type'] = VerseType.Tags[index]
verse_def = u'%s%s' % (verse[0][u'type'], verse[0][u'label'])
item = QtGui.QTableWidgetItem(verse[1])
item.setData(QtCore.Qt.UserRole, QtCore.QVariant(variant))
item.setData(QtCore.Qt.UserRole, QtCore.QVariant(verse_def))
self.verseListWidget.setItem(count, 0, item)
else:
verses = self.song.lyrics.split(u'\n\n')
@ -266,10 +278,24 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
self.verseListWidget.setRowCount(
self.verseListWidget.rowCount() + 1)
item = QtGui.QTableWidgetItem(verse)
variant = u'%s:%s' % \
(VerseType.to_string(VerseType.Verse), unicode(count + 1))
item.setData(QtCore.Qt.UserRole, QtCore.QVariant(variant))
verse_def = u'%s%s' % \
(VerseType.Tags[VerseType.Verse], unicode(count + 1))
item.setData(QtCore.Qt.UserRole, QtCore.QVariant(verse_def))
self.verseListWidget.setItem(count, 0, item)
if self.song.verse_order:
# we translate verse order
translated = []
for verse_def in self.song.verse_order.split():
verse_index = None
if verse_tags_translated:
verse_index = VerseType.from_translated_tag(verse_def[0])
if verse_index is None:
verse_index = VerseType.from_tag(verse_def[0])
verse_tag = VerseType.TranslatedTags[verse_index].upper()
translated.append(u'%s%s' % (verse_tag, verse_def[1:]))
self.verseOrderEdit.setText(u' '.join(translated))
else:
self.verseOrderEdit.setText(u'')
self.verseListWidget.resizeRowsToContents()
self.tagRows()
# clear the results
@ -294,14 +320,14 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
"""
Tag the Song List rows based on the verse list
"""
rowLabel = []
row_label = []
for row in range(0, self.verseListWidget.rowCount()):
item = self.verseListWidget.item(row, 0)
data = unicode(item.data(QtCore.Qt.UserRole).toString())
bit = data.split(u':')
rowTag = u'%s%s' % (bit[0][0:1], bit[1])
rowLabel.append(rowTag)
self.verseListWidget.setVerticalHeaderLabels(rowLabel)
verse_def = unicode(item.data(QtCore.Qt.UserRole).toString())
verse_tag = VerseType.translated_tag(verse_def[0])
row_def = u'%s%s' % (verse_tag, verse_def[1:])
row_label.append(row_def)
self.verseListWidget.setVerticalHeaderLabels(row_label)
def onAuthorAddButtonClicked(self):
item = int(self.authorsComboBox.currentIndex())
@ -420,11 +446,11 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
def onVerseAddButtonClicked(self):
self.verse_form.setVerse(u'', True)
if self.verse_form.exec_():
afterText, verse, subVerse = self.verse_form.getVerse()
data = u'%s:%s' % (verse, subVerse)
item = QtGui.QTableWidgetItem(afterText)
item.setData(QtCore.Qt.UserRole, QtCore.QVariant(data))
item.setText(afterText)
after_text, verse_tag, verse_num = self.verse_form.getVerse()
verse_def = u'%s%s' % (verse_tag, verse_num)
item = QtGui.QTableWidgetItem(after_text)
item.setData(QtCore.Qt.UserRole, QtCore.QVariant(verse_def))
item.setText(after_text)
self.verseListWidget.setRowCount(
self.verseListWidget.rowCount() + 1)
self.verseListWidget.setItem(
@ -440,12 +466,12 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
verseId = unicode(item.data(QtCore.Qt.UserRole).toString())
self.verse_form.setVerse(tempText, True, verseId)
if self.verse_form.exec_():
afterText, verse, subVerse = self.verse_form.getVerse()
data = u'%s:%s' % (verse, subVerse)
item.setData(QtCore.Qt.UserRole, QtCore.QVariant(data))
item.setText(afterText)
after_text, verse_tag, verse_num = self.verse_form.getVerse()
verse_def = u'%s%s' % (verse_tag, verse_num)
item.setData(QtCore.Qt.UserRole, QtCore.QVariant(verse_def))
item.setText(after_text)
# number of lines has change so repaint the list moving the data
if len(tempText.split(u'\n')) != len(afterText.split(u'\n')):
if len(tempText.split(u'\n')) != len(after_text.split(u'\n')):
tempList = {}
tempId = {}
for row in range(0, self.verseListWidget.rowCount()):
@ -467,7 +493,9 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
for row in range(0, self.verseListWidget.rowCount()):
item = self.verseListWidget.item(row, 0)
field = unicode(item.data(QtCore.Qt.UserRole).toString())
verse_list += u'---[%s]---\n' % field
verse_tag = VerseType.translated_name(field[0])
verse_num = field[1:]
verse_list += u'---[%s:%s]---\n' % (verse_tag, verse_num)
verse_list += item.text()
verse_list += u'\n'
self.verse_form.setVerse(verse_list)
@ -483,15 +511,32 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
for count, parts in enumerate(match.split(u']---\n')):
if len(parts) > 1:
if count == 0:
# make sure the tag is correctly cased
variant = u'%s%s' % \
(parts[0:1].upper(), parts[1:].lower())
# handling carefully user inputted versetags
separator = parts.find(u':')
if separator >= 0:
verse_name = parts[0:separator].strip()
verse_num = parts[separator+1:].strip()
else:
verse_name = parts
verse_num = u'1'
verse_index = \
VerseType.from_loose_input(verse_name)
verse_tag = VerseType.Tags[verse_index]
# Later we need to handle v1a as well.
#regex = re.compile(r'(\d+\w.)')
regex = re.compile(r'\D*(\d+)\D*')
match = regex.match(verse_num)
if match:
verse_num = match.group(1)
else:
verse_num = u'1'
verse_def = u'%s%s' % (verse_tag, verse_num)
else:
if parts.endswith(u'\n'):
parts = parts.rstrip(u'\n')
item = QtGui.QTableWidgetItem(parts)
item.setData(QtCore.Qt.UserRole,
QtCore.QVariant(variant))
QtCore.QVariant(verse_def))
self.verseListWidget.setRowCount(
self.verseListWidget.rowCount() + 1)
self.verseListWidget.setItem(
@ -543,25 +588,31 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
order_names = unicode(self.verseOrderEdit.text()).split()
for item in order_names:
if len(item) == 1:
order.append(item.lower() + u'1')
verse_index = VerseType.from_translated_tag(item)
if verse_index is not None:
order.append(VerseType.Tags[verse_index] + u'1')
else:
order.append(u'') # it matches no verses anyway
else:
order.append(item.lower())
verse_index = VerseType.from_translated_tag(item[0])
if verse_index is None:
order.append(u'') # same as above
else:
verse_tag = VerseType.Tags[verse_index]
verse_num = item[1:].lower()
order.append(verse_tag + verse_num)
verses = []
verse_names = []
for index in range (0, self.verseListWidget.rowCount()):
for index in range(0, self.verseListWidget.rowCount()):
verse = self.verseListWidget.item(index, 0)
verse = unicode(verse.data(QtCore.Qt.UserRole).toString())
if verse not in verse_names:
verses.append(
re.sub(r'(.)[^:]*:(.*)', r'\1\2', verse.lower()))
verse_names.append(verse)
verses.append(verse)
verse_names.append(u'%s%s' % (
VerseType.translated_tag(verse[0]), verse[1:]))
for count, item in enumerate(order):
if item not in verses:
self.songTabWidget.setCurrentIndex(0)
self.verseOrderEdit.setFocus()
valid = verses.pop(0)
for verse in verses:
valid = valid + u', ' + verse
valid = u', '.join(verse_names)
critical_error_message_box(
message=unicode(translate('SongsPlugin.EditSongForm',
'The verse order is invalid. There is no verse '
@ -577,7 +628,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
unicode(translate('SongsPlugin.EditSongForm',
'You have not used %s anywhere in the verse '
'order. Are you sure you want to save the song '
'like this?')) % verse_names[count].replace(u':', u' '),
'like this?')) % verse_names[count],
QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)
if answer == QtGui.QMessageBox.No:
return False
@ -684,7 +735,14 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
else:
self.song.search_title = self.song.title
self.song.comments = unicode(self.commentsEdit.toPlainText())
self.song.verse_order = unicode(self.verseOrderEdit.text())
ordertext = unicode(self.verseOrderEdit.text())
order = []
for item in ordertext.split():
verse_tag = VerseType.Tags[
VerseType.from_translated_tag(item[0])]
verse_num = item[1:].lower()
order.append(u'%s%s' % (verse_tag, verse_num))
self.song.verse_order = u' '.join(order)
self.song.ccli_number = unicode(self.CCLNumberEdit.text())
self.song.song_number = unicode(self.songBookNumberEdit.text())
book_name = unicode(self.songBookComboBox.currentText())
@ -727,12 +785,14 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
for i in range(0, self.verseListWidget.rowCount()):
item = self.verseListWidget.item(i, 0)
verseId = unicode(item.data(QtCore.Qt.UserRole).toString())
bits = verseId.split(u':')
sxml.add_verse_to_lyrics(bits[0], bits[1], unicode(item.text()))
verse_tag = verseId[0]
verse_num = verseId[1:]
sxml.add_verse_to_lyrics(verse_tag, verse_num,
unicode(item.text()))
text = text + self.whitespace.sub(u' ',
unicode(self.verseListWidget.item(i, 0).text())) + u' '
if (bits[1] > u'1') and (bits[0][0] not in multiple):
multiple.append(bits[0][0])
if (verse_num > u'1') and (verse_tag not in multiple):
multiple.append(verse_tag)
self.song.search_lyrics = text.lower()
self.song.lyrics = unicode(sxml.extract_xml(), u'utf-8')
for verse in multiple:

View File

@ -70,19 +70,19 @@ class Ui_EditVerseDialog(object):
translate('SongsPlugin.EditVerseForm', 'Edit Verse'))
self.verseTypeLabel.setText(
translate('SongsPlugin.EditVerseForm', '&Verse type:'))
self.verseTypeComboBox.setItemText(0,
VerseType.to_string(VerseType.Verse))
self.verseTypeComboBox.setItemText(1,
VerseType.to_string(VerseType.Chorus))
self.verseTypeComboBox.setItemText(2,
VerseType.to_string(VerseType.Bridge))
self.verseTypeComboBox.setItemText(3,
VerseType.to_string(VerseType.PreChorus))
self.verseTypeComboBox.setItemText(4,
VerseType.to_string(VerseType.Intro))
self.verseTypeComboBox.setItemText(5,
VerseType.to_string(VerseType.Ending))
self.verseTypeComboBox.setItemText(6,
VerseType.to_string(VerseType.Other))
self.verseTypeComboBox.setItemText(VerseType.Verse,
VerseType.TranslatedNames[VerseType.Verse])
self.verseTypeComboBox.setItemText(VerseType.Chorus,
VerseType.TranslatedNames[VerseType.Chorus])
self.verseTypeComboBox.setItemText(VerseType.Bridge,
VerseType.TranslatedNames[VerseType.Bridge])
self.verseTypeComboBox.setItemText(VerseType.PreChorus,
VerseType.TranslatedNames[VerseType.PreChorus])
self.verseTypeComboBox.setItemText(VerseType.Intro,
VerseType.TranslatedNames[VerseType.Intro])
self.verseTypeComboBox.setItemText(VerseType.Ending,
VerseType.TranslatedNames[VerseType.Ending])
self.verseTypeComboBox.setItemText(VerseType.Other,
VerseType.TranslatedNames[VerseType.Other])
self.insertButton.setText(
translate('SongsPlugin.EditVerseForm', '&Insert'))

View File

@ -57,22 +57,23 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog):
QtCore.QObject.connect(self.verseTypeComboBox,
QtCore.SIGNAL(u'currentIndexChanged(int)'),
self.onVerseTypeComboBoxChanged)
self.verse_regex = re.compile(r'---\[([-\w]+):([\d]+)\]---')
self.verse_regex = re.compile(r'---\[(.+):\D*(\d*)\D*.*\]---')
def contextMenu(self, point):
item = self.serviceManagerList.itemAt(point)
def insertVerse(self, title, num=1):
def insertVerse(self, verse_tag, verse_num=1):
if self.verseTextEdit.textCursor().columnNumber() != 0:
self.verseTextEdit.insertPlainText(u'\n')
self.verseTextEdit.insertPlainText(u'---[%s:%s]---\n' % (title, num))
verse_tag = VerseType.translated_name(verse_tag)
self.verseTextEdit.insertPlainText(u'---[%s:%s]---\n' %
(verse_tag, verse_num))
self.verseTextEdit.setFocus()
def onInsertButtonClicked(self):
verse_type = self.verseTypeComboBox.currentIndex()
if VerseType.to_string(verse_type) is not None:
self.insertVerse(VerseType.to_string(verse_type),
self.verseNumberBox.value())
verse_type_index = self.verseTypeComboBox.currentIndex()
self.insertVerse(VerseType.Tags[verse_type_index],
self.verseNumberBox.value())
def onVerseTypeComboBoxChanged(self):
"""
@ -81,10 +82,11 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog):
"""
position = self.verseTextEdit.textCursor().position()
text = unicode(self.verseTextEdit.toPlainText())
verse_type = VerseType.to_string(self.verseTypeComboBox.currentIndex())
verse_name = VerseType.TranslatedNames[
self.verseTypeComboBox.currentIndex()]
if not text:
return
position = text.rfind(u'---[%s' % verse_type, 0, position)
position = text.rfind(u'---[%s' % verse_name, 0, position)
if position == -1:
self.verseNumberBox.setValue(1)
return
@ -95,11 +97,11 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog):
text = text[:position + 4]
match = self.verse_regex.match(text)
if match:
verse_type = match.group(1)
verse_number = int(match.group(2))
verse_type_index = VerseType.from_string(verse_type)
verse_tag = match.group(1)
verse_num = int(match.group(2))
verse_type_index = VerseType.from_loose_input(verse_tag)
if verse_type_index is not None:
self.verseNumberBox.setValue(verse_number)
self.verseNumberBox.setValue(verse_num)
def onCursorPositionChanged(self):
"""
@ -124,25 +126,26 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog):
match = self.verse_regex.match(text)
if match:
verse_type = match.group(1)
verse_type_index = VerseType.from_loose_input(verse_type)
verse_number = int(match.group(2))
verse_type_index = VerseType.from_string(verse_type)
if verse_type_index is not None:
self.verseTypeComboBox.setCurrentIndex(verse_type_index)
self.verseNumberBox.setValue(verse_number)
def setVerse(self, text, single=False,
tag=u'%s:1' % VerseType.to_string(VerseType.Verse)):
tag=u'%s1' % VerseType.Tags[VerseType.Verse]):
self.hasSingleVerse = single
if single:
verse_type, verse_number = tag.split(u':')
verse_type_index = VerseType.from_string(verse_type)
verse_type_index = VerseType.from_tag(tag[0])
verse_number = tag[1:]
if verse_type_index is not None:
self.verseTypeComboBox.setCurrentIndex(verse_type_index)
self.verseNumberBox.setValue(int(verse_number))
self.insertButton.setVisible(False)
else:
if not text:
text = u'---[%s:1]---\n' % VerseType.to_string(VerseType.Verse)
text = u'---[%s:1]---\n' % \
VerseType.TranslatedNames[VerseType.Verse]
self.verseTypeComboBox.setCurrentIndex(0)
self.verseNumberBox.setValue(1)
self.insertButton.setVisible(True)
@ -152,14 +155,14 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog):
def getVerse(self):
return self.verseTextEdit.toPlainText(), \
VerseType.to_string(self.verseTypeComboBox.currentIndex()), \
VerseType.Tags[self.verseTypeComboBox.currentIndex()], \
unicode(self.verseNumberBox.value())
def getVerseAll(self):
text = self.verseTextEdit.toPlainText()
if not text.startsWith(u'---['):
text = u'---[%s:1]---\n%s' % (VerseType.to_string(VerseType.Verse),
text)
text = u'---[%s:1]---\n%s' % \
(VerseType.TranslatedNames[VerseType.Verse], text)
return text
def accept(self):

View File

@ -252,6 +252,7 @@ class SongExportForm(OpenLPWizard):
self.availableListWidget.clear()
self.selectedListWidget.clear()
self.directoryLineEdit.clear()
self.searchLineEdit.clear()
# Load the list of songs.
Receiver.send_message(u'cursor_busy')
songs = self.plugin.manager.get_all_objects(Song)
@ -340,19 +341,21 @@ class SongExportForm(OpenLPWizard):
def onUncheckButtonClicked(self):
"""
The *uncheckButton* has been clicked. Set all songs unchecked.
The *uncheckButton* has been clicked. Set all visible songs unchecked.
"""
for row in range(self.availableListWidget.count()):
item = self.availableListWidget.item(row)
item.setCheckState(QtCore.Qt.Unchecked)
if not item.isHidden():
item.setCheckState(QtCore.Qt.Unchecked)
def onCheckButtonClicked(self):
"""
The *checkButton* has been clicked. Set all songs checked.
The *checkButton* has been clicked. Set all visible songs checked.
"""
for row in range(self.availableListWidget.count()):
item = self.availableListWidget.item(row)
item.setCheckState(QtCore.Qt.Checked)
if not item.isHidden():
item.setCheckState(QtCore.Qt.Checked)
def onDirectoryButtonClicked(self):
"""

View File

@ -40,68 +40,147 @@ class VerseType(object):
Ending = 5
Other = 6
@staticmethod
def to_string(verse_type):
"""
Return a string for a given VerseType
Names = [
u'Verse',
u'Chorus',
u'Bridge',
u'Pre-Chorus',
u'Intro',
u'Ending',
u'Other']
Tags = [name[0].lower() for name in Names]
``verse_type``
The type to return a string for
"""
if not isinstance(verse_type, int):
verse_type = verse_type.lower()
if verse_type == VerseType.Verse or verse_type == \
unicode(VerseType.to_string(VerseType.Verse)).lower()[0]:
return translate('SongsPlugin.VerseType', 'Verse')
elif verse_type == VerseType.Chorus or verse_type == \
unicode(VerseType.to_string(VerseType.Chorus)).lower()[0]:
return translate('SongsPlugin.VerseType', 'Chorus')
elif verse_type == VerseType.Bridge or verse_type == \
unicode(VerseType.to_string(VerseType.Bridge)).lower()[0]:
return translate('SongsPlugin.VerseType', 'Bridge')
elif verse_type == VerseType.PreChorus or verse_type == \
unicode(VerseType.to_string(VerseType.PreChorus)).lower()[0]:
return translate('SongsPlugin.VerseType', 'Pre-Chorus')
elif verse_type == VerseType.Intro or verse_type == \
unicode(VerseType.to_string(VerseType.Intro)).lower()[0]:
return translate('SongsPlugin.VerseType', 'Intro')
elif verse_type == VerseType.Ending or verse_type == \
unicode(VerseType.to_string(VerseType.Ending)).lower()[0]:
return translate('SongsPlugin.VerseType', 'Ending')
elif verse_type == VerseType.Other or verse_type == \
unicode(VerseType.to_string(VerseType.Other)).lower()[0]:
return translate('SongsPlugin.VerseType', 'Other')
TranslatedNames = [
unicode(translate('SongsPlugin.VerseType', 'Verse')),
unicode(translate('SongsPlugin.VerseType', 'Chorus')),
unicode(translate('SongsPlugin.VerseType', 'Bridge')),
unicode(translate('SongsPlugin.VerseType', 'Pre-Chorus')),
unicode(translate('SongsPlugin.VerseType', 'Intro')),
unicode(translate('SongsPlugin.VerseType', 'Ending')),
unicode(translate('SongsPlugin.VerseType', 'Other'))]
TranslatedTags = [name[0].lower() for name in TranslatedNames]
@staticmethod
def from_string(verse_type):
def translated_tag(verse_tag, strict=False):
"""
Return the translated UPPERCASE tag for a given tag,
used to show translated verse tags in UI
``verse_tag``
The string to return a VerseType for
``strict``
Determines if the default Other or None should be returned
"""
if strict:
not_found_value = None
else:
not_found_value = VerseType.TranslatedTags[VerseType.Other].upper()
verse_tag = verse_tag[0].lower()
for num, tag in enumerate(VerseType.Tags):
if verse_tag == tag:
return VerseType.TranslatedTags[num].upper()
return not_found_value
@staticmethod
def translated_name(verse_tag, strict=False):
"""
Return the translated name for a given tag
``verse_tag``
The string to return a VerseType for
``strict``
Determines if the default Other or None should be returned
"""
if strict:
not_found_value = None
else:
not_found_value = VerseType.TranslatedNames[VerseType.Other]
verse_tag = verse_tag[0].lower()
for num, tag in enumerate(VerseType.Tags):
if verse_tag == tag:
return VerseType.TranslatedNames[num]
return not_found_value
@staticmethod
def from_tag(verse_tag, strict=False):
"""
Return the VerseType for a given tag
``verse_tag``
The string to return a VerseType for
``strict``
Determines if the default Other or None should be returned
"""
if strict:
no_return_value = None
else:
no_return_value = VerseType.Other
verse_tag = verse_tag[0].lower()
for num, tag in enumerate(VerseType.Tags):
if verse_tag == tag:
return num
return no_return_value
@staticmethod
def from_translated_tag(verse_tag):
"""
Return the VerseType for a given tag
``verse_tag``
The string to return a VerseType for
"""
verse_tag = verse_tag[0].lower()
for num, tag in enumerate(VerseType.TranslatedTags):
if verse_tag == tag:
return num
@staticmethod
def from_string(verse_name):
"""
Return the VerseType for a given string
``verse_type``
``verse_name``
The string to return a VerseType for
"""
verse_type = verse_type.lower()
if verse_type == unicode(VerseType.to_string(VerseType.Verse)).lower():
return VerseType.Verse
elif verse_type == \
unicode(VerseType.to_string(VerseType.Chorus)).lower():
return VerseType.Chorus
elif verse_type == \
unicode(VerseType.to_string(VerseType.Bridge)).lower():
return VerseType.Bridge
elif verse_type == \
unicode(VerseType.to_string(VerseType.PreChorus)).lower():
return VerseType.PreChorus
elif verse_type == \
unicode(VerseType.to_string(VerseType.Intro)).lower():
return VerseType.Intro
elif verse_type == \
unicode(VerseType.to_string(VerseType.Ending)).lower():
return VerseType.Ending
elif verse_type == \
unicode(VerseType.to_string(VerseType.Other)).lower():
return VerseType.Other
verse_name = verse_name.lower()
for num, name in enumerate(VerseType.Names):
if verse_name == name.lower():
return num
@staticmethod
def from_translated_string(verse_name):
"""
Return the VerseType for a given string
``verse_name``
The string to return a VerseType for
"""
verse_name = verse_name.lower()
for num, translation in enumerate(VerseType.TranslatedNames):
if verse_name == translation.lower():
return num
@staticmethod
def from_loose_input(verse_name):
"""
Return the VerseType for a given string, Other if not found
``verse_name``
The string to return a VerseType for
"""
verse_index = None
if len(verse_name) > 1:
verse_index = VerseType.from_translated_string(verse_name)
if verse_index is None:
verse_index = VerseType.from_string(verse_name)
if verse_index is None:
verse_index = VerseType.from_translated_tag(verse_name)
if verse_index is None:
verse_index = VerseType.from_tag(verse_name)
return verse_index
def retrieve_windows_encoding(recommendation=None):
"""

View File

@ -81,14 +81,16 @@ class EasiSlidesImport(SongImport):
def _parse_song(self, song):
self._success = True
self._add_unicode_attribute(self.title, song.Title1, True)
self._add_unicode_attribute(self.alternate_title, song.Title2)
self._add_unicode_attribute(self.song_number, song.SongNumber)
self._add_unicode_attribute(u'title', song.Title1, True)
self._add_unicode_attribute(u'alternate_title', song.Title2)
self._add_unicode_attribute(u'song_number', song.SongNumber)
if self.song_number == u'0':
self.song_number = u''
self._add_authors(song)
self._add_copyright(song)
self._add_unicode_attribute(self.song_book_name, song.BookReference)
self._add_copyright(song.Copyright)
self._add_copyright(song.LicenceAdmin1)
self._add_copyright(song.LicenceAdmin2)
self._add_unicode_attribute(u'song_book_name', song.BookReference)
self._parse_and_add_lyrics(song)
return self._success
@ -110,7 +112,7 @@ class EasiSlidesImport(SongImport):
Signals that this attribute must exist in a valid song.
"""
try:
self_attribute = unicode(import_attribute).strip()
setattr(self, self_attribute, unicode(import_attribute).strip())
except UnicodeDecodeError:
log.exception(u'UnicodeDecodeError decoding %s' % import_attribute)
self._success = False
@ -124,7 +126,7 @@ class EasiSlidesImport(SongImport):
authors = unicode(song.Writer).split(u',')
for author in authors:
author = author.strip()
if len(author) > 0:
if len(author):
self.authors.append(author)
except UnicodeDecodeError:
log.exception(u'Unicode decode error while decoding Writer')
@ -132,35 +134,18 @@ class EasiSlidesImport(SongImport):
except AttributeError:
pass
def _add_copyright(self, song):
"""
Assign the copyright information from the import to the song being
created.
``song``
The current song being imported.
"""
copyright_list = []
self.__add_copyright_element(copyright_list, song.Copyright)
self.__add_copyright_element(copyright_list, song.LicenceAdmin1)
self.__add_copyright_element(copyright_list, song.LicenceAdmin2)
self.add_copyright(u' '.join(copyright_list))
def __add_copyright_element(self, copyright_list, element):
def _add_copyright(self, element):
"""
Add a piece of copyright to the total copyright information for the
song.
``copyright_list``
The array to add the information to.
``element``
The imported variable to get the data from.
"""
try:
copyright_list.append(unicode(element).strip())
self.add_copyright(unicode(element).strip())
except UnicodeDecodeError:
log.exception(u'Unicode error decoding %s' % element)
log.exception(u'Unicode error on decoding copyright: %s' % element)
self._success = False
except AttributeError:
pass
@ -285,10 +270,12 @@ class EasiSlidesImport(SongImport):
# as these appeared originally in the file
for [reg, vt, vn, inst] in our_verse_order:
if self._listHas(verses, [reg, vt, vn, inst]):
# this is false, but needs user input
lang = None
versetag = u'%s%s' % (vt, vn)
versetags.append(versetag)
lines = u'\n'.join(verses[reg][vt][vn][inst])
self.verses.append([versetag, lines])
self.verses.append([versetag, lines, lang])
SeqTypes = {
u'p': u'P1',

View File

@ -36,7 +36,7 @@ from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, \
from openlp.core.lib.ui import UiStrings
from openlp.plugins.songs.forms import EditSongForm, SongMaintenanceForm, \
SongImportForm, SongExportForm
from openlp.plugins.songs.lib import OpenLyrics, SongXML
from openlp.plugins.songs.lib import OpenLyrics, SongXML, VerseType
from openlp.plugins.songs.lib.db import Author, Song
from openlp.core.lib.searchedit import SearchEdit
@ -344,24 +344,49 @@ class SongMediaItem(MediaManagerItem):
if song.lyrics.startswith(u'<?xml version='):
verseList = SongXML().get_verses(song.lyrics)
# no verse list or only 1 space (in error)
if not song.verse_order or not song.verse_order.strip():
verse_tags_translated = False
if VerseType.from_translated_string(unicode(
verseList[0][0][u'type'])) is not None:
verse_tags_translated = True
if not song.verse_order.strip():
for verse in verseList:
verseTag = u'%s:%s' % (
verse[0][u'type'], verse[0][u'label'])
# We cannot use from_loose_input() here, because database
# is supposed to contain English lowercase singlechar tags.
verse_tag = verse[0][u'type']
verse_index = None
if len(verse_tag) > 1:
verse_index = \
VerseType.from_translated_string(verse_tag)
if verse_index is None:
verse_index = VerseType.from_string(verse_tag)
if verse_index is None:
verse_index = VerseType.from_tag(verse_tag)
verse_tag = VerseType.TranslatedTags[verse_index].upper()
verse_def = u'%s%s' % (verse_tag, verse[0][u'label'])
service_item.add_from_text(
verse[1][:30], unicode(verse[1]), verseTag)
verse[1][:30], unicode(verse[1]), verse_def)
else:
# Loop through the verse list and expand the song accordingly.
for order in song.verse_order.upper().split():
for order in song.verse_order.lower().split():
if len(order) == 0:
break
for verse in verseList:
if verse[0][u'type'][0] == order[0] and \
(verse[0][u'label'] == order[1:] or not order[1:]):
verseTag = u'%s:%s' % \
(verse[0][u'type'], verse[0][u'label'])
if verse[0][u'type'][0].lower() == order[0] and \
(verse[0][u'label'].lower() == order[1:] or \
not order[1:]):
if verse_tags_translated:
verse_index = VerseType.from_translated_tag(
verse[0][u'type'])
else:
verse_index = VerseType.from_tag(
verse[0][u'type'])
if verse_index is None:
verse_index = VerseType.Other
verse_tag = VerseType.TranslatedTags[verse_index]
verse_def = u'%s%s' % (verse_tag,
verse[0][u'label'])
service_item.add_from_text(
verse[1][:30], verse[1], verseTag)
verse[1][:30], verse[1], verse_def)
else:
verses = song.lyrics.split(u'\n\n')
for slide in verses:

View File

@ -149,23 +149,25 @@ class OpenSongImport(SongImport):
unicode(translate('SongsPlugin.ImportWizardForm',
'Importing %s...')) % parts[-1])
songfile = z.open(song)
self.do_import_file(songfile)
if self.commit:
if self.do_import_file(songfile) and self.commit and \
not self.stop_import_flag:
self.finish()
if self.stop_import_flag:
success = False
break
else:
success = False
break
else:
# not a zipfile
log.info(u'Direct import %s', filename)
self.import_wizard.incrementProgressBar(
unicode(translate('SongsPlugin.ImportWizardForm',
'Importing %s...')) % os.path.split(filename)[-1])
file = open(filename)
self.do_import_file(file)
if self.commit:
song_file = open(filename)
if self.do_import_file(song_file) and self.commit and \
not self.stop_import_flag:
self.finish()
else:
success = False
break
return success
def do_import_file(self, file):
@ -178,7 +180,7 @@ class OpenSongImport(SongImport):
tree = objectify.parse(file)
except (Error, LxmlError):
log.exception(u'Error parsing XML')
return
return False
root = tree.getroot()
fields = dir(root)
decode = {
@ -196,114 +198,103 @@ class OpenSongImport(SongImport):
setattr(self, fn_or_string, ustring)
else:
fn_or_string(ustring)
if not len(self.title):
# to prevent creation of empty songs from wrong files
return False
if u'theme' in fields and unicode(root.theme) not in self.topics:
self.topics.append(unicode(root.theme))
if u'alttheme' in fields and unicode(root.alttheme) not in self.topics:
self.topics.append(unicode(root.alttheme))
# data storage while importing
verses = {}
# keep track of a "default" verse order, in case none is specified
# keep track of verses appearance order
our_verse_order = []
verses_seen = {}
# in the absence of any other indication, verses are the default,
# erm, versetype!
versetype = u'V'
versenum = None
# default verse
verse_tag = u'v'
verse_num = u'1'
# for the case where song has several sections with same marker
inst = 1
lyrics = unicode(root.lyrics)
for thisline in lyrics.split(u'\n'):
for this_line in lyrics.split(u'\n'):
# remove comments
semicolon = thisline.find(u';')
semicolon = this_line.find(u';')
if semicolon >= 0:
thisline = thisline[:semicolon]
thisline = thisline.strip()
if len(thisline) == 0:
this_line = this_line[:semicolon]
this_line = this_line.strip()
if not len(this_line):
continue
# skip inthisline guitar chords and page and column breaks
if thisline[0] == u'.' or thisline.startswith(u'---') \
or thisline.startswith(u'-!!'):
# skip guitar chords and page and column breaks
if this_line.startswith(u'.') or this_line.startswith(u'---') \
or this_line.startswith(u'-!!'):
continue
# verse/chorus/etc. marker
if thisline[0] == u'[':
if this_line.startswith(u'['):
# drop the square brackets
right_bracket = thisline.find(u']')
content = thisline[1:right_bracket].upper()
right_bracket = this_line.find(u']')
content = this_line[1:right_bracket].lower()
# have we got any digits?
# If so, versenumber is everything from the digits
# If so, verse number 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)
verse_tag = match.group(1)
verse_num = match.group(2)
else:
# otherwise we assume number 1 and take the whole prefix as
# the versetype
versetype = content
versenum = u'1'
# the verse tag
verse_tag = content
verse_num = u'1'
inst = 1
if [verse_tag, verse_num, inst] in our_verse_order \
and verses.has_key(verse_tag) \
and verses[verse_tag].has_key(verse_num):
inst = len(verses[verse_tag][verse_num])+1
our_verse_order.append([verse_tag, verse_num, inst])
continue
words = None
# number at start of line.. it's verse number
if thisline[0].isdigit():
versenum = thisline[0]
words = thisline[1:].strip()
if words is None:
words = thisline
if not versenum:
versenum = u'1'
if versenum is not None:
versetag = u'%s%s' % (versetype, versenum)
if not verses.has_key(versetype):
verses[versetype] = {}
if not verses[versetype].has_key(versenum):
# storage for lines in this verse
verses[versetype][versenum] = []
if not verses_seen.has_key(versetag):
verses_seen[versetag] = 1
our_verse_order.append(versetag)
if words:
# Tidy text and remove the ____s from extended words
words = self.tidy_text(words)
words = words.replace('_', '')
verses[versetype][versenum].append(words)
if this_line[0].isdigit():
verse_num = this_line[0]
this_line = this_line[1:].strip()
our_verse_order.append([verse_tag, verse_num, inst])
if not verses.has_key(verse_tag):
verses[verse_tag] = {}
if not verses[verse_tag].has_key(verse_num):
verses[verse_tag][verse_num] = {}
if not verses[verse_tag][verse_num].has_key(inst):
verses[verse_tag][verse_num][inst] = []
# Tidy text and remove the ____s from extended words
this_line = self.tidy_text(this_line)
this_line = this_line.replace(u'_', u'')
this_line = this_line.replace(u'|', u'\n')
verses[verse_tag][verse_num][inst].append(this_line)
# done parsing
versetypes = verses.keys()
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' % (our_verse_type, num)
lines = u'\n'.join(verses[versetype][num])
self.add_verse(lines, versetag)
# Keep track of what we have for error checking later
versetags[versetag] = 1
# now figure out the presentation order
order = []
# add verses in original order
for (verse_tag, verse_num, inst) in our_verse_order:
verse_def = u'%s%s' % (verse_tag, verse_num)
lines = u'\n'.join(verses[verse_tag][verse_num][inst])
self.add_verse(lines, verse_def)
# figure out the presentation order, if present
if u'presentation' in fields and root.presentation != u'':
order = unicode(root.presentation)
# We make all the tags in the lyrics upper case, so match that here
# We make all the tags in the lyrics lower 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)
# TODO: make sure that the default order list will be overwritten, if
# the songs provides its own order list.
for tag in order:
if tag[0].isdigit():
# Assume it's a verse if it has no prefix
tag = u'V' + tag
elif not re.search('\d+', tag):
# Assume it's no.1 if there's no digits
tag = tag + u'1'
if not versetags.has_key(tag):
log.info(u'Got order %s but not in versetags, dropping this'
u'item from presentation order', tag)
else:
self.verse_order_list.append(tag)
order = order.lower().split()
for verse_def in order:
match = re.match(u'(.*)(\d+.*)', verse_def)
if match is not None:
verse_tag = match.group(1)
verse_num = match.group(2)
if not len(verse_tag):
verse_tag = u'v'
else:
# Assume it's no.1 if there are no digits
verse_tag = verse_def
verse_num = u'1'
verse_def = u'%s%s' % (verse_tag, verse_num)
if verses.has_key(verse_tag) \
and verses[verse_tag].has_key(verse_num):
self.verse_order_list.append(verse_def)
else:
log.info(u'Got order %s but not in verse tags, dropping'
u'this item from presentation order', verse_def)
return True

View File

@ -75,9 +75,11 @@ class SongImport(QtCore.QObject):
self.media_files = []
self.song_book_name = u''
self.song_book_pub = u''
self.verse_order_list_generated_useful = False
self.verse_order_list_generated = []
self.verse_order_list = []
self.verses = []
self.versecounts = {}
self.verse_counts = {}
self.copyright_string = unicode(translate(
'SongsPlugin.SongImport', 'copyright'))
self.copyright_symbol = unicode(translate(
@ -128,20 +130,20 @@ class SongImport(QtCore.QObject):
return text
def process_song_text(self, text):
versetexts = text.split(u'\n\n')
for versetext in versetexts:
if versetext.strip() != u'':
self.process_verse_text(versetext.strip())
verse_texts = text.split(u'\n\n')
for verse_text in verse_texts:
if verse_text.strip() != u'':
self.process_verse_text(verse_text.strip())
def process_verse_text(self, text):
lines = text.split(u'\n')
if text.lower().find(self.copyright_string) >= 0 \
or text.lower().find(self.copyright_symbol) >= 0:
or text.find(self.copyright_symbol) >= 0:
copyright_found = False
for line in lines:
if (copyright_found or
line.lower().find(self.copyright_string) >= 0 or
line.lower().find(self.copyright_symbol) >= 0):
line.find(self.copyright_symbol) >= 0):
copyright_found = True
self.add_copyright(line)
else:
@ -198,45 +200,46 @@ class SongImport(QtCore.QObject):
return
self.media_files.append(filename)
def add_verse(self, versetext, versetag=u'V', lang=None):
def add_verse(self, verse_text, verse_def=u'v', lang=None):
"""
Add a verse. This is the whole verse, lines split by \\n. It will also
attempt to detect duplicates. In this case it will just add to the verse
order.
``versetext``
``verse_text``
The text of the verse.
``versetag``
The verse tag can be V1/C1/B etc, or 'V' and 'C' (will count the
``verse_def``
The verse tag can be v1/c1/b etc, or 'v' and 'c' (will count the
verses/choruses itself) or None, where it will assume verse.
``lang``
The language code (ISO-639) of the verse, for example *en* or *de*.
"""
for (oldversetag, oldverse, oldlang) in self.verses:
if oldverse.strip() == versetext.strip():
self.verse_order_list.append(oldversetag)
for (old_verse_def, old_verse, old_lang) in self.verses:
if old_verse.strip() == verse_text.strip():
self.verse_order_list_generated.append(old_verse_def)
self.verse_order_list_generated_useful = True
return
if versetag[0] in self.versecounts:
self.versecounts[versetag[0]] += 1
if verse_def[0] in self.verse_counts:
self.verse_counts[verse_def[0]] += 1
else:
self.versecounts[versetag[0]] = 1
if len(versetag) == 1:
versetag += unicode(self.versecounts[versetag[0]])
elif int(versetag[1:]) > self.versecounts[versetag[0]]:
self.versecounts[versetag[0]] = int(versetag[1:])
self.verses.append([versetag, versetext.rstrip(), lang])
self.verse_order_list.append(versetag)
if versetag.startswith(u'V') and u'C1' in self.verse_order_list:
self.verse_order_list.append(u'C1')
self.verse_counts[verse_def[0]] = 1
if len(verse_def) == 1:
verse_def += unicode(self.verse_counts[verse_def[0]])
elif int(verse_def[1:]) > self.verse_counts[verse_def[0]]:
self.verse_counts[verse_def[0]] = int(verse_def[1:])
self.verses.append([verse_def, verse_text.rstrip(), lang])
self.verse_order_list_generated.append(verse_def)
def repeat_verse(self):
"""
Repeat the previous verse in the verse order
"""
self.verse_order_list.append(self.verse_order_list[-1])
self.verse_order_list_generated.append(
self.verse_order_list_generated[-1])
self.verse_order_list_generated_useful = True
def check_complete(self):
"""
@ -273,34 +276,29 @@ class SongImport(QtCore.QObject):
verses_changed_to_other = {}
sxml = SongXML()
other_count = 1
for (versetag, versetext, lang) in self.verses:
if versetag[0] == u'C':
versetype = VerseType.to_string(VerseType.Chorus)
elif versetag[0] == u'V':
versetype = VerseType.to_string(VerseType.Verse)
elif versetag[0] == u'B':
versetype = VerseType.to_string(VerseType.Bridge)
elif versetag[0] == u'I':
versetype = VerseType.to_string(VerseType.Intro)
elif versetag[0] == u'P':
versetype = VerseType.to_string(VerseType.PreChorus)
elif versetag[0] == u'E':
versetype = VerseType.to_string(VerseType.Ending)
for (verse_def, verse_text, lang) in self.verses:
if verse_def[0].lower() in VerseType.Tags:
verse_tag = verse_def[0].lower()
else:
newversetag = u'O%d' % other_count
verses_changed_to_other[versetag] = newversetag
new_verse_def = u'%s%d' % (VerseType.Tags[VerseType.Other],
other_count)
verses_changed_to_other[verse_def] = new_verse_def
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, lang)
song.search_lyrics += u' ' + self.remove_punctuation(versetext)
verse_tag = VerseType.Tags[VerseType.Other]
log.info(u'Versetype %s changing to %s' , verse_def,
new_verse_def)
verse_def = new_verse_def
sxml.add_verse_to_lyrics(verse_tag, verse_def[1:], verse_text, lang)
song.search_lyrics += u' ' + self.remove_punctuation(verse_text)
song.search_lyrics = song.search_lyrics.lower()
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):
if not len(self.verse_order_list) and \
self.verse_order_list_generated_useful:
self.verse_order_list = self.verse_order_list_generated
for i, current_verse_def in enumerate(self.verse_order_list):
if verses_changed_to_other.has_key(current_verse_def):
self.verse_order_list[i] = \
verses_changed_to_other[current_verse_tag]
verses_changed_to_other[current_verse_def]
song.verse_order = u' '.join(self.verse_order_list)
song.copyright = self.copyright
song.comments = self.comments
@ -345,9 +343,10 @@ class SongImport(QtCore.QObject):
+ u'========================================'
print u'TITLE: ' + self.title
print u'ALT TITLE: ' + self.alternate_title
for (versetag, versetext, lang) in self.verses:
print u'VERSE ' + versetag + u': ' + versetext
for (verse_def, verse_text, lang) in self.verses:
print u'VERSE ' + verse_def + u': ' + verse_text
print u'ORDER: ' + u' '.join(self.verse_order_list)
print u'GENERATED ORDER: ' + u' '.join(self.verse_order_list_generated)
for author in self.authors:
print u'AUTHOR: ' + author
if self.copyright:

View File

@ -464,7 +464,8 @@ class OpenLyrics(object):
text += u'\n'
text += u'\n'.join([unicode(line) for line in lines.line])
verse_name = self._get(verse, u'name')
verse_type = unicode(VerseType.to_string(verse_name[0]))
verse_type_index = VerseType.from_tag(verse_name[0])
verse_type = VerseType.Names[verse_type_index]
verse_number = re.compile(u'[a-zA-Z]*').sub(u'', verse_name)
verse_part = re.compile(u'[0-9]*').sub(u'', verse_name[1:])
# OpenLyrics allows e. g. "c", but we need "c1".

View File

@ -68,6 +68,7 @@ Source: ..\..\dist\OpenLP\*; DestDir: {app}; Flags: ignoreversion recursesubdirs
[Icons]
Name: {group}\{#AppName}; Filename: {app}\{#AppExeName}
Name: {group}\{#AppName} (Debug); Filename: {app}\{#AppExeName}; Parameters: -l debug
Name: {group}\{cm:ProgramOnTheWeb,{#AppName}}; Filename: {#AppURL}
Name: {group}\{cm:UninstallProgram,{#AppName}}; Filename: {uninstallexe}
Name: {commondesktop}\{#AppName}; Filename: {app}\{#AppExeName}; Tasks: desktopicon