diff --git a/copyright.txt b/copyright.txt
index c99a64287..6882a7282 100644
--- a/copyright.txt
+++ b/copyright.txt
@@ -4,8 +4,8 @@
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
-# Copyright (c) 2008-2010 Raoul Snyman #
-# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
+# Copyright (c) 2008-2011 Raoul Snyman #
+# Portions copyright (c) 2008-2011 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 #
diff --git a/openlp/core/ui/__init__.py b/openlp/core/ui/__init__.py
index eb0e89775..d820c9a5b 100644
--- a/openlp/core/ui/__init__.py
+++ b/openlp/core/ui/__init__.py
@@ -28,7 +28,7 @@ The :mod:`ui` module provides the core user interface for OpenLP
"""
from PyQt4 import QtGui
-from openlp.core.lib import translate, Receiver
+from openlp.core.lib import translate
class HideMode(object):
"""
diff --git a/openlp/core/ui/aboutdialog.py b/openlp/core/ui/aboutdialog.py
index 597d3fb24..bb09ab91f 100644
--- a/openlp/core/ui/aboutdialog.py
+++ b/openlp/core/ui/aboutdialog.py
@@ -164,9 +164,10 @@ class Ui_AboutDialog(object):
self.licenseTextEdit.setPlainText(translate('OpenLP.AboutForm',
'Copyright \xa9 2004-2011 Raoul Snyman\n'
'Portions copyright \xa9 2004-2011 '
- 'Tim Bentley, Jonathan Corwin, Michael Gorven, Scott Guerrieri, '
- 'Christian Richter, Maikel Stuivenberg, Martin Thompson, Jon '
- 'Tibble, Carsten Tinggaard\n'
+ 'Tim Bentley, Jonathan Corwin, Michael Gorven, Scott Guerrieri,\n'
+ 'Meinert Jordan, Andreas Preikschat, Christian Richter, Philip\n'
+ 'Ridout, Maikel Stuivenberg, Martin Thompson, Jon Tibble, Carstenn'
+ 'Tinggaard, Frode Woldsund\n'
'\n'
'This program is free software; you can redistribute it and/or '
'modify it under the terms of the GNU General Public License as '
diff --git a/openlp/plugins/songs/forms/__init__.py b/openlp/plugins/songs/forms/__init__.py
index 160a014ac..e75f9fe04 100644
--- a/openlp/plugins/songs/forms/__init__.py
+++ b/openlp/plugins/songs/forms/__init__.py
@@ -57,4 +57,6 @@ from songbookform import SongBookForm
from editverseform import EditVerseForm
from editsongform import EditSongForm
from songmaintenanceform import SongMaintenanceForm
-from songimportform import SongImportForm
\ No newline at end of file
+from songimportform import SongImportForm
+from songexportform import SongExportForm
+
diff --git a/openlp/plugins/songs/forms/songexportform.py b/openlp/plugins/songs/forms/songexportform.py
new file mode 100644
index 000000000..5d5b9a8b1
--- /dev/null
+++ b/openlp/plugins/songs/forms/songexportform.py
@@ -0,0 +1,372 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2011 Raoul Snyman #
+# Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael #
+# Gorven, Scott Guerrieri, Meinert Jordan, Andreas Preikschat, Christian #
+# Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon Tibble, #
+# Carsten Tinggaard, Frode Woldsund #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it #
+# under the terms of the GNU General Public License as published by the Free #
+# Software Foundation; version 2 of the License. #
+# #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
+# more details. #
+# #
+# You should have received a copy of the GNU General Public License along #
+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
+###############################################################################
+"""
+The :mod:`songexportform` module provides the wizard for exporting songs to the
+OpenLyrics format.
+"""
+import logging
+
+from PyQt4 import QtCore, QtGui
+
+from openlp.core.lib import build_icon, Receiver, SettingsManager, translate
+from openlp.core.lib.ui import critical_error_message_box
+from openlp.core.ui.wizard import OpenLPWizard
+from openlp.plugins.songs.lib.db import Song
+from openlp.plugins.songs.lib.openlyricsexport import OpenLyricsExport
+
+log = logging.getLogger(__name__)
+
+class SongExportForm(OpenLPWizard):
+ """
+ This is the Song Export Wizard, which allows easy exporting of Songs to the
+ OpenLyrics format.
+ """
+ log.info(u'SongExportForm loaded')
+
+ def __init__(self, parent, plugin):
+ """
+ Instantiate the wizard, and run any extra setup we need to.
+
+ ``parent``
+ The QWidget-derived parent of the wizard.
+
+ ``plugin``
+ The songs plugin.
+ """
+ self.plugin = plugin
+ OpenLPWizard.__init__(self, parent, plugin, u'songExportWizard',
+ u':/wizards/wizard_exportsong.bmp')
+ self.stop_export_flag = False
+ QtCore.QObject.connect(Receiver.get_receiver(),
+ QtCore.SIGNAL(u'openlp_stop_wizard'), self.stop_export)
+
+ def stop_export(self):
+ """
+ Sets the flag for the exporter to stop the export.
+ """
+ log.debug(u'Stopping songs export')
+ self.stop_export_flag = True
+
+ def setupUi(self, image):
+ """
+ Set up the song wizard UI.
+ """
+ OpenLPWizard.setupUi(self, image)
+
+ def customInit(self):
+ """
+ Song wizard specific initialisation.
+ """
+ pass
+
+ def customSignals(self):
+ """
+ Song wizard specific signals.
+ """
+ QtCore.QObject.connect(self.availableListWidget,
+ QtCore.SIGNAL(u'itemActivated(QListWidgetItem*)'), self.onItemPressed)
+ QtCore.QObject.connect(self.searchLineEdit,
+ QtCore.SIGNAL(u'textEdited(const QString&)'),
+ self.onSearchLineEditChanged)
+ QtCore.QObject.connect(self.uncheckButton,
+ QtCore.SIGNAL(u'clicked()'), self.onUncheckButtonClicked)
+ QtCore.QObject.connect(self.checkButton,
+ QtCore.SIGNAL(u'clicked()'), self.onCheckButtonClicked)
+ QtCore.QObject.connect(self.directoryButton,
+ QtCore.SIGNAL(u'clicked()'), self.onDirectoryButtonClicked)
+
+ def addCustomPages(self):
+ """
+ Add song wizard specific pages.
+ """
+ # The page with all available songs.
+ self.availableSongsPage = QtGui.QWizardPage()
+ self.availableSongsPage.setObjectName(u'availableSongsPage')
+ self.availableSongsLayout = QtGui.QHBoxLayout(self.availableSongsPage)
+ self.availableSongsLayout.setObjectName(u'availableSongsLayout')
+ self.verticalLayout = QtGui.QVBoxLayout()
+ self.verticalLayout.setObjectName(u'verticalLayout')
+ self.availableListWidget = QtGui.QListWidget(self.availableSongsPage)
+ self.availableListWidget.setObjectName(u'availableListWidget')
+ self.verticalLayout.addWidget(self.availableListWidget)
+ self.horizontalLayout = QtGui.QHBoxLayout()
+ self.horizontalLayout.setObjectName(u'horizontalLayout')
+ self.searchLabel = QtGui.QLabel(self.availableSongsPage)
+ self.searchLabel.setObjectName(u'searchLabel')
+ self.horizontalLayout.addWidget(self.searchLabel)
+ self.searchLineEdit = QtGui.QLineEdit(self.availableSongsPage)
+ self.searchLineEdit.setObjectName(u'searchLineEdit')
+ self.horizontalLayout.addWidget(self.searchLineEdit)
+ spacerItem = QtGui.QSpacerItem(40, 20,
+ QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
+ self.horizontalLayout.addItem(spacerItem)
+ self.uncheckButton = QtGui.QPushButton(self.availableSongsPage)
+ self.uncheckButton.setObjectName(u'uncheckButton')
+ self.horizontalLayout.addWidget(self.uncheckButton)
+ self.checkButton = QtGui.QPushButton(self.availableSongsPage)
+ self.checkButton.setObjectName(u'selectButton')
+ self.horizontalLayout.addWidget(self.checkButton)
+ self.verticalLayout.addLayout(self.horizontalLayout)
+ self.availableSongsLayout.addLayout(self.verticalLayout)
+ self.addPage(self.availableSongsPage)
+ # The page with the selected songs.
+ self.exportSongPage = QtGui.QWizardPage()
+ self.exportSongPage.setObjectName(u'availableSongsPage')
+ self.exportSongLayout = QtGui.QHBoxLayout(self.exportSongPage)
+ self.exportSongLayout.setObjectName(u'exportSongLayout')
+ self.gridLayout = QtGui.QGridLayout()
+ self.gridLayout.setObjectName(u'gridLayout')
+ self.selectedListWidget = QtGui.QListWidget(self.exportSongPage)
+ self.selectedListWidget.setObjectName(u'selectedListWidget')
+ self.gridLayout.addWidget(self.selectedListWidget, 1, 0, 1, 1)
+ self.horizontalLayout = QtGui.QHBoxLayout()
+ self.horizontalLayout.setObjectName(u'horizontalLayout')
+ self.directoryLabel = QtGui.QLabel(self.exportSongPage)
+ self.directoryLabel.setObjectName(u'directoryLabel')
+ self.horizontalLayout.addWidget(self.directoryLabel)
+ self.directoryLineEdit = QtGui.QLineEdit(self.exportSongPage)
+ self.directoryLineEdit.setObjectName(u'directoryLineEdit')
+ self.horizontalLayout.addWidget(self.directoryLineEdit)
+ self.directoryButton = QtGui.QToolButton(self.exportSongPage)
+ self.directoryButton.setIcon(build_icon(u':/exports/export_load.png'))
+ self.directoryButton.setObjectName(u'directoryButton')
+ self.horizontalLayout.addWidget(self.directoryButton)
+ self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 1)
+ self.exportSongLayout.addLayout(self.gridLayout)
+ self.addPage(self.exportSongPage)
+
+ def retranslateUi(self):
+ """
+ Song wizard localisation.
+ """
+ self.setWindowTitle(
+ translate('SongsPlugin.ExportWizardForm', 'Song Export Wizard'))
+ self.titleLabel.setText(
+ u'%s' %
+ translate('SongsPlugin.ExportWizardForm',
+ 'Welcome to the Song Export Wizard'))
+ self.informationLabel.setText(
+ translate('SongsPlugin.ExportWizardForm', 'This wizard will help to'
+ ' export your songs to the open and free OpenLyrics worship song '
+ 'format.'))
+ self.availableSongsPage.setTitle(
+ translate('SongsPlugin.ExportWizardForm', 'Select Songs'))
+ self.availableSongsPage.setSubTitle(
+ translate('SongsPlugin.ExportWizardForm',
+ 'Check the songs, you want to export.'))
+ self.searchLabel.setText(
+ translate('SongsPlugin.ExportWizardForm', 'Search:'))
+ self.uncheckButton.setText(
+ translate('SongsPlugin.ExportWizardForm', 'Uncheck All'))
+ self.checkButton.setText(
+ translate('SongsPlugin.ExportWizardForm', 'Check All'))
+ self.exportSongPage.setTitle(
+ translate('SongsPlugin.ExportWizardForm', 'Select Directory'))
+ self.exportSongPage.setSubTitle(
+ translate('SongsPlugin.ExportWizardForm',
+ 'Select the directory you want the songs to be saved.'))
+ self.directoryLabel.setText(
+ translate('SongsPlugin.ExportWizardForm', 'Directory:'))
+ self.progressPage.setTitle(
+ translate('SongsPlugin.ExportWizardForm', 'Exporting'))
+ self.progressPage.setSubTitle(
+ translate('SongsPlugin.ExportWizardForm',
+ 'Please wait while your songs are exported.'))
+ self.progressLabel.setText(
+ translate('SongsPlugin.ExportWizardForm', 'Ready.'))
+ self.progressBar.setFormat(
+ translate('SongsPlugin.ExportWizardForm', '%p%'))
+
+ def validateCurrentPage(self):
+ """
+ Validate the current page before moving on to the next page.
+ """
+ if self.currentPage() == self.welcomePage:
+ return True
+ elif self.currentPage() == self.availableSongsPage:
+ items = [
+ item for item in self._findListWidgetItems(
+ self.availableListWidget) if item.checkState()
+ ]
+ if not items:
+ critical_error_message_box(
+ translate('SongsPlugin.ExportWizardForm',
+ 'No Song Selected'),
+ translate('SongsPlugin.ExportWizardForm',
+ 'You need to add at least one Song to export.'))
+ return False
+ self.selectedListWidget.clear()
+ # Add the songs to the list of selected songs.
+ for item in items:
+ song = QtGui.QListWidgetItem(item.text())
+ song.setData(QtCore.Qt.UserRole,
+ QtCore.QVariant(item.data(QtCore.Qt.UserRole).toPyObject()))
+ song.setFlags(QtCore.Qt.ItemIsEnabled)
+ self.selectedListWidget.addItem(song)
+ return True
+ elif self.currentPage() == self.exportSongPage:
+ if not self.directoryLineEdit.text():
+ critical_error_message_box(
+ translate('SongsPlugin.ExportWizardForm',
+ 'No Save Location specified'),
+ translate('SongsPlugin.ExportWizardForm',
+ 'You need to specified a directory to save the songs in.'))
+ return False
+ return True
+ elif self.currentPage() == self.progressPage:
+ self.availableListWidget.clear()
+ self.selectedListWidget.clear()
+ return True
+
+ def registerFields(self):
+ """
+ Register song export wizard fields.
+ """
+ pass
+
+ def setDefaults(self):
+ """
+ Set default form values for the song export wizard.
+ """
+ self.restart()
+ self.finishButton.setVisible(False)
+ self.cancelButton.setVisible(True)
+ self.availableListWidget.clear()
+ self.selectedListWidget.clear()
+ self.directoryLineEdit.clear()
+ # Load the list of songs.
+ Receiver.send_message(u'cursor_busy')
+ songs = self.plugin.manager.get_all_objects(Song)
+ for song in songs:
+ authors = u', '.join([author.display_name
+ for author in song.authors])
+ title = u'%s (%s)' % (unicode(song.title), authors)
+ item = QtGui.QListWidgetItem(title)
+ item.setData(QtCore.Qt.UserRole, QtCore.QVariant(song))
+ item.setFlags(QtCore.Qt.ItemIsSelectable|
+ QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEnabled)
+ item.setCheckState(QtCore.Qt.Unchecked)
+ self.availableListWidget.addItem(item)
+ Receiver.send_message(u'cursor_normal')
+
+ def preWizard(self):
+ """
+ Perform pre export tasks.
+ """
+ OpenLPWizard.preWizard(self)
+ self.progressLabel.setText(
+ translate('SongsPlugin.ExportWizardForm', 'Starting export...'))
+ Receiver.send_message(u'openlp_process_events')
+
+ def performWizard(self):
+ """
+ Perform the actual export. This creates an *openlyricsexport* instance
+ and calls the *do_export* method.
+ """
+ songs = [
+ song.data(QtCore.Qt.UserRole).toPyObject()
+ for song in self._findListWidgetItems(self.selectedListWidget)
+ ]
+ exporter = OpenLyricsExport(
+ self, songs, unicode(self.directoryLineEdit.text()))
+ if exporter.do_export():
+ self.progressLabel.setText(
+ translate('SongsPlugin.SongExportForm', 'Finished export.'))
+ else:
+ self.progressLabel.setText(
+ translate('SongsPlugin.SongExportForm',
+ 'Your song export failed.'))
+
+ def _findListWidgetItems(self, listWidget, text=u''):
+ """
+ Returns a list of *QListWidgetItem*s of the ``listWidget``. Note, that
+ hidden items are included.
+
+ ``listWidget``
+ The widget to get all items from. (QListWidget)
+
+ ``text``
+ The text to search for. (unicode string)
+ """
+ return [item for item in listWidget.findItems(
+ QtCore.QString(unicode(text)), QtCore.Qt.MatchContains)
+ ]
+
+ def onItemPressed(self, item):
+ """
+ Called, when an item in the *availableListWidget* has been pressed. Thes
+ item is check if it was not checked, whereas it is unchecked when it was
+ checked.
+
+ ``item``
+ The *QListWidgetItem* which was pressed.
+ """
+ item.setCheckState(
+ QtCore.Qt.Unchecked if item.checkState() else QtCore.Qt.Checked)
+
+ def onSearchLineEditChanged(self, text):
+ """
+ The *searchLineEdit*'s text has been changed. Update the list of
+ available songs. Note that any song, which does not match the ``text``
+ will be hidden, but not unchecked!
+
+ ``text``
+ The text of the *searchLineEdit*. (QString)
+ """
+ search_result = [
+ song for song in self._findListWidgetItems(
+ self.availableListWidget, unicode(text))
+ ]
+ for item in self._findListWidgetItems(self.availableListWidget):
+ item.setHidden(False if item in search_result else True)
+
+ def onUncheckButtonClicked(self):
+ """
+ The *uncheckButton* has been clicked. Set all songs unchecked.
+ """
+ for row in range(self.availableListWidget.count()):
+ item = self.availableListWidget.item(row)
+ item.setCheckState(QtCore.Qt.Unchecked)
+
+ def onCheckButtonClicked(self):
+ """
+ The *checkButton* has been clicked. Set all songs checked.
+ """
+ for row in range(self.availableListWidget.count()):
+ item = self.availableListWidget.item(row)
+ item.setCheckState(QtCore.Qt.Checked)
+
+ def onDirectoryButtonClicked(self):
+ """
+ Called when the *directoryButton* was clicked. Opens a dialog and writes
+ the path to *directoryLineEdit*.
+ """
+ path = unicode(QtGui.QFileDialog.getExistingDirectory(self,
+ translate('SongsPlugin.ExportWizardForm', 'Selecte to Folder'),
+ SettingsManager.get_last_dir(self.plugin.settingsSection, 1),
+ options=QtGui.QFileDialog.ShowDirsOnly))
+ SettingsManager.set_last_dir(self.plugin.settingsSection, path, 1)
+ self.directoryLineEdit.setText(path)
diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py
index 312d0d6e7..aaa26b1c0 100644
--- a/openlp/plugins/songs/lib/mediaitem.py
+++ b/openlp/plugins/songs/lib/mediaitem.py
@@ -35,7 +35,7 @@ from openlp.core.lib import MediaManagerItem, BaseListWithDnD, Receiver, \
ItemCapabilities, translate, check_item_selected, PluginStatus
from openlp.core.lib.ui import UiStrings
from openlp.plugins.songs.forms import EditSongForm, SongMaintenanceForm, \
- SongImportForm
+ SongImportForm, SongExportForm
from openlp.plugins.songs.lib import OpenLyrics, SongXML
from openlp.plugins.songs.lib.db import Author, Song
from openlp.core.lib.searchedit import SearchEdit
@@ -265,6 +265,11 @@ class SongMediaItem(MediaManagerItem):
if self.import_wizard.exec_() == QtGui.QDialog.Accepted:
Receiver.send_message(u'songs_load_list')
+ def onExportClick(self):
+ if not hasattr(self, u'export_wizard'):
+ self.export_wizard = SongExportForm(self, self.parent)
+ self.export_wizard.exec_()
+
def onNewClick(self):
log.debug(u'onNewClick')
self.edit_song_form.newSong()
diff --git a/openlp/plugins/songs/lib/openlyricsexport.py b/openlp/plugins/songs/lib/openlyricsexport.py
new file mode 100755
index 000000000..ffb1a2d6f
--- /dev/null
+++ b/openlp/plugins/songs/lib/openlyricsexport.py
@@ -0,0 +1,74 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2011 Raoul Snyman #
+# Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael #
+# Gorven, Scott Guerrieri, Meinert Jordan, Andreas Preikschat, Christian #
+# Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon Tibble, #
+# Carsten Tinggaard, Frode Woldsund #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it #
+# under the terms of the GNU General Public License as published by the Free #
+# Software Foundation; version 2 of the License. #
+# #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
+# more details. #
+# #
+# You should have received a copy of the GNU General Public License along #
+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
+###############################################################################
+"""
+The :mod:`openlyricsexport` module provides the functionality for exporting
+songs from the database to the OpenLyrics format.
+"""
+import logging
+import os
+
+from lxml import etree
+
+from openlp.core.lib import Receiver, translate
+from openlp.plugins.songs.lib import OpenLyrics
+
+log = logging.getLogger(__name__)
+
+class OpenLyricsExport(object):
+ """
+ This provides the Openlyrics export.
+ """
+ def __init__(self, parent, songs, save_path):
+ """
+ Initialise the export.
+ """
+ log.debug(u'initialise OpenLyricsExport')
+ self.parent = parent
+ self.manager = parent.plugin.manager
+ self.songs = songs
+ self.save_path = save_path
+ if not os.path.exists(self.save_path):
+ os.mkdir(self.save_path)
+
+ def do_export(self):
+ """
+ Export the songs.
+ """
+ log.debug(u'started OpenLyricsExport')
+ openLyrics = OpenLyrics(self.manager)
+ self.parent.progressBar.setMaximum(len(self.songs))
+ for song in self.songs:
+ Receiver.send_message(u'openlp_process_events')
+ if self.parent.stop_export_flag:
+ return False
+ self.parent.incrementProgressBar(unicode(translate(
+ 'SongsPlugin.OpenLyricsExport', 'Exporting "%s"...')) %
+ song.title)
+ xml = openLyrics.song_to_xml(song)
+ tree = etree.ElementTree(etree.fromstring(xml))
+ tree.write(os.path.join(self.save_path, song.title + u'.xml'),
+ encoding=u'utf-8', xml_declaration=True, pretty_print=True)
+ return True
diff --git a/openlp/plugins/songs/lib/opensongimport.py b/openlp/plugins/songs/lib/opensongimport.py
index e7557f952..8c6d283e3 100644
--- a/openlp/plugins/songs/lib/opensongimport.py
+++ b/openlp/plugins/songs/lib/opensongimport.py
@@ -36,6 +36,7 @@ from openlp.plugins.songs.lib.songimport import SongImport
log = logging.getLogger(__name__)
+#TODO: Use lxml for parsing and make sure we use methods of "SongImport" .
class OpenSongImport(SongImport):
"""
Import songs exported from OpenSong
@@ -146,7 +147,7 @@ class OpenSongImport(SongImport):
log.info(u'Zip importing %s', parts[-1])
self.import_wizard.incrementProgressBar(
unicode(translate('SongsPlugin.ImportWizardForm',
- 'Importing %s...')) % parts[-1])
+ 'Importing %s...')) % parts[-1])
songfile = z.open(song)
self.do_import_file(songfile)
if self.commit:
@@ -276,7 +277,7 @@ class OpenSongImport(SongImport):
for num in versenums:
versetag = u'%s%s' % (our_verse_type, num)
lines = u'\n'.join(verses[versetype][num])
- self.verses.append([versetag, lines])
+ self.add_verse(lines, versetag)
# Keep track of what we have for error checking later
versetags[versetag] = 1
# now figure out the presentation order
@@ -292,6 +293,8 @@ class OpenSongImport(SongImport):
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
diff --git a/openlp/plugins/songs/lib/xml.py b/openlp/plugins/songs/lib/xml.py
index 4bf11887a..73ac8120c 100644
--- a/openlp/plugins/songs/lib/xml.py
+++ b/openlp/plugins/songs/lib/xml.py
@@ -60,6 +60,7 @@ The XML of an `OpenLyrics `_ song looks like this::
"""
+import datetime
import logging
import re
@@ -89,8 +90,10 @@ class SongXML(object):
Add a verse to the ```` tag.
``type``
- A string denoting the type of verse. Possible values are "V",
- "C", "B", "P", "I", "E" and "O".
+ A string denoting the type of verse. Possible values are *Verse*,
+ *Chorus*, *Bridge*, *Pre-Chorus*, *Intro*, *Ending* and *Other*.
+ Any other type is **not** allowed, this also includes translated
+ types.
``number``
An integer denoting the number of the item, for example: verse 1.
@@ -126,8 +129,8 @@ class SongXML(object):
The returned list has the following format::
- [[{'lang': 'en', 'type': 'V', 'label': '1'}, u"The English verse."],
- [{'lang': 'en', 'type': 'C', 'label': '1'}, u"The English chorus."]]
+ [[{'lang': 'en', 'type': 'Verse', 'label': '1'}, u"English verse"],
+ [{'lang': 'en', 'type': 'Chorus', 'label': '1'}, u"English chorus"]]
"""
self.song_xml = None
if xml[:5] == u'``
- The attribute *translit* is not supported.
+ The attribute *translit* is not supported. Note, the attribute *lang* is
+ considered, but there is not further functionality implemented yet.
````
OpenLP supports this property.
"""
+ IMPLEMENTED_VERSION = u'0.7'
def __init__(self, manager):
self.manager = manager
@@ -222,8 +227,14 @@ class OpenLyrics(object):
"""
sxml = SongXML()
verse_list = sxml.get_verses(song.lyrics)
- song_xml = objectify.fromstring(
- u'')
+ song_xml = objectify.fromstring(u'')
+ # Append the necessary meta data to the song.
+ song_xml.set(u'xmlns', u'http://openlyrics.info/namespace/2009/song')
+ song_xml.set(u'version', OpenLyrics.IMPLEMENTED_VERSION)
+ song_xml.set(u'createdIn', u'OpenLP 1.9.4') # Use variable
+ song_xml.set(u'modifiedIn', u'OpenLP 1.9.4') # Use variable
+ song_xml.set(u'modifiedDate',
+ datetime.datetime.now().strftime(u'%Y-%m-%dT%H:%M:%S'))
properties = etree.SubElement(song_xml, u'properties')
titles = etree.SubElement(properties, u'titles')
self._add_text_to_element(u'title', titles, song.title.strip())
@@ -237,7 +248,7 @@ class OpenLyrics(object):
self._add_text_to_element(u'copyright', properties, song.copyright)
if song.verse_order:
self._add_text_to_element(
- u'verseOrder', properties, song.verse_order)
+ u'verseOrder', properties, song.verse_order.lower())
if song.ccli_number:
self._add_text_to_element(u'ccliNo', properties, song.ccli_number)
if song.authors:
@@ -263,6 +274,8 @@ class OpenLyrics(object):
verse[0][u'type'][0].lower(), verse[0][u'label'])
element = \
self._add_text_to_element(u'verse', lyrics, None, verse_tag)
+ if verse[0].has_key(u'lang'):
+ element.set(u'lang', verse[0][u'lang'])
element = self._add_text_to_element(u'lines', element)
for line in unicode(verse[1]).split(u'\n'):
self._add_text_to_element(u'line', element, line)
@@ -450,7 +463,7 @@ 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]))[0]
+ verse_type = unicode(VerseType.to_string(verse_name[0]))
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".
@@ -478,9 +491,9 @@ class OpenLyrics(object):
for name in temp_verse_order:
if name[0] == previous_type:
if name[1] != previous_number:
- verse_order.append(u''.join((name[0], name[1])))
+ verse_order.append(u''.join((name[0][0], name[1])))
else:
- verse_order.append(u''.join((name[0], name[1])))
+ verse_order.append(u''.join((name[0][0], name[1])))
previous_type = name[0]
previous_number = name[1]
previous_part = name[2]
diff --git a/openlp/plugins/songs/songsplugin.py b/openlp/plugins/songs/songsplugin.py
index 74991fe37..1c1d319cf 100644
--- a/openlp/plugins/songs/songsplugin.py
+++ b/openlp/plugins/songs/songsplugin.py
@@ -107,8 +107,17 @@ class SongsPlugin(Plugin):
The actual **Export** menu item, so that your actions can
use it as their parent.
"""
- # No menu items for now.
- pass
+ # Main song import menu item - will eventually be the only one
+ self.SongExportItem = QtGui.QAction(export_menu)
+ self.SongExportItem.setObjectName(u'SongExportItem')
+ self.SongExportItem.setText(translate(
+ 'SongsPlugin', '&Song'))
+ self.SongExportItem.setToolTip(translate('SongsPlugin',
+ 'Exports songs using the export wizard.'))
+ export_menu.addAction(self.SongExportItem)
+ # Signals and slots
+ QtCore.QObject.connect(self.SongExportItem,
+ QtCore.SIGNAL(u'triggered()'), self.onSongExportItemClicked)
def addToolsMenuItem(self, tools_menu):
"""
@@ -173,6 +182,10 @@ class SongsPlugin(Plugin):
if self.mediaItem:
self.mediaItem.onImportClick()
+ def onSongExportItemClicked(self):
+ if self.mediaItem:
+ self.mediaItem.onExportClick()
+
def about(self):
about_text = translate('SongsPlugin', 'Songs Plugin'
'
The songs plugin provides the ability to display and '
diff --git a/resources/forms/songexport.ui b/resources/forms/songexport.ui
deleted file mode 100644
index 9830db3ef..000000000
--- a/resources/forms/songexport.ui
+++ /dev/null
@@ -1,241 +0,0 @@
-
- SongExportDialog
-
-
-
- 0
- 0
- 641
- 607
-
-
-
- Dialog
-
-
-
- 8
-
-
- 8
-
- -
-
-
-
- 8
-
-
- 0
-
-
-
-
-
- Available Songs
-
-
-
-
-
-
- -
-
-
- Select All
-
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 30
- 16777215
-
-
-
-
- 8
-
-
- QLayout::SetMinimumSize
-
-
- 0
-
-
-
-
-
- Qt::Vertical
-
-
- QSizePolicy::MinimumExpanding
-
-
-
- 20
- 132
-
-
-
-
- -
-
-
- Select Songs
-
-
-
- :/exports/export_move_to_list.png:/exports/export_move_to_list.png
-
-
-
- 20
- 20
-
-
-
-
- -
-
-
- Deselect Songs
-
-
-
- :/exports/export_remove.png:/exports/export_remove.png
-
-
-
- 20
- 20
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
- QSizePolicy::MinimumExpanding
-
-
-
- 20
- 131
-
-
-
-
-
-
-
- -
-
-
- Selected Songs
-
-
-
-
-
-
- -
-
-
- Select All
-
-
-
-
-
-
-
-
-
- -
-
-
- 0
-
-
-
- OpenLyric Format
-
-
-
-
- Text File
-
-
-
-
- -
-
-
- Qt::Horizontal
-
-
- QDialogButtonBox::Cancel|QDialogButtonBox::Ok
-
-
-
-
-
-
- SongExportButtonBox
- AvailableListWidget
- AvailableAllToolButton
- SelectToolButton
- DeselectToolButton
- SelectedListWidget
- SelectedAllToolButton
- ExportTabWidget
-
-
-
-
-
-
- SongExportButtonBox
- accepted()
- SongExportDialog
- accept()
-
-
- 248
- 254
-
-
- 157
- 274
-
-
-
-
- SongExportButtonBox
- rejected()
- SongExportDialog
- reject()
-
-
- 316
- 260
-
-
- 286
- 274
-
-
-
-
-
diff --git a/resources/images/export_move_to_list.png b/resources/images/export_move_to_list.png
deleted file mode 100644
index 5c0005856..000000000
Binary files a/resources/images/export_move_to_list.png and /dev/null differ
diff --git a/resources/images/export_remove.png b/resources/images/export_remove.png
deleted file mode 100644
index ef8e685e2..000000000
Binary files a/resources/images/export_remove.png and /dev/null differ
diff --git a/resources/images/export_selectall.png b/resources/images/export_selectall.png
deleted file mode 100644
index 0f0d9f152..000000000
Binary files a/resources/images/export_selectall.png and /dev/null differ
diff --git a/resources/images/openlp-2.qrc b/resources/images/openlp-2.qrc
index 2db924363..dd5abd861 100644
--- a/resources/images/openlp-2.qrc
+++ b/resources/images/openlp-2.qrc
@@ -80,12 +80,10 @@
import_load.png
- export_selectall.png
- export_remove.png
export_load.png
- export_move_to_list.png
+ wizard_exportsong.bmp
wizard_importsong.bmp
wizard_importbible.bmp
wizard_createtheme.bmp
diff --git a/resources/images/wizard_exportsong.bmp b/resources/images/wizard_exportsong.bmp
new file mode 100644
index 000000000..948422dcc
Binary files /dev/null and b/resources/images/wizard_exportsong.bmp differ