diff --git a/openlp/core/__init__.py b/openlp/core/__init__.py index 17d95547b..13c344367 100644 --- a/openlp/core/__init__.py +++ b/openlp/core/__init__.py @@ -208,6 +208,20 @@ class OpenLP(QtGui.QApplication): return QtGui.QApplication.event(self, event) +def set_up_logging(log_path): + """ + Setup our logging using log_path + """ + check_directory_exists(log_path) + filename = os.path.join(log_path, u'openlp.log') + logfile = logging.FileHandler(filename, u'w') + logfile.setFormatter(logging.Formatter( + u'%(asctime)s %(name)-55s %(levelname)-8s %(message)s')) + log.addHandler(logfile) + if log.isEnabledFor(logging.DEBUG): + print 'Logging to:', filename + + def main(args=None): """ The main function which parses command line options and then runs @@ -231,21 +245,12 @@ def main(args=None): help='Set the Qt4 style (passed directly to Qt4).') parser.add_option('--testing', dest='testing', action='store_true', help='Run by testing framework') - # Set up logging - log_path = AppLocation.get_directory(AppLocation.CacheDir) - check_directory_exists(log_path) - filename = os.path.join(log_path, u'openlp.log') - logfile = logging.FileHandler(filename, u'w') - logfile.setFormatter(logging.Formatter( - u'%(asctime)s %(name)-55s %(levelname)-8s %(message)s')) - log.addHandler(logfile) # Parse command line options and deal with them. # Use args supplied programatically if possible. (options, args) = parser.parse_args(args) if args else parser.parse_args() qt_args = [] if options.loglevel.lower() in ['d', 'debug']: log.setLevel(logging.DEBUG) - print 'Logging to:', filename elif options.loglevel.lower() in ['w', 'warning']: log.setLevel(logging.WARNING) else: @@ -261,11 +266,13 @@ def main(args=None): app.setOrganizationName(u'OpenLP') app.setOrganizationDomain(u'openlp.org') if options.portable: - log.info(u'Running portable') app.setApplicationName(u'OpenLPPortable') Settings.setDefaultFormat(Settings.IniFormat) # Get location OpenLPPortable.ini app_path = AppLocation.get_directory(AppLocation.AppDir) + set_up_logging(os.path.abspath(os.path.join(app_path, u'..', + u'..', u'Other'))) + log.info(u'Running portable') portable_settings_file = os.path.abspath(os.path.join(app_path, u'..', u'..', u'Data', u'OpenLP.ini')) # Make this our settings file @@ -282,6 +289,7 @@ def main(args=None): portable_settings.sync() else: app.setApplicationName(u'OpenLP') + set_up_logging(AppLocation.get_directory(AppLocation.CacheDir)) app.setApplicationVersion(get_application_version()[u'version']) # Instance check if not options.testing: diff --git a/openlp/core/ui/formattingtagdialog.py b/openlp/core/ui/formattingtagdialog.py index e80ed45d1..1eb03e13c 100644 --- a/openlp/core/ui/formattingtagdialog.py +++ b/openlp/core/ui/formattingtagdialog.py @@ -130,15 +130,15 @@ class Ui_FormattingTagDialog(object): translate('OpenLP.FormattingTagDialog', 'Description')) self.tagLabel.setText(translate('OpenLP.FormattingTagDialog', 'Tag')) self.startTagLabel.setText( - translate('OpenLP.FormattingTagDialog', 'Start tag')) + translate('OpenLP.FormattingTagDialog', 'Start HTML')) self.endTagLabel.setText( - translate('OpenLP.FormattingTagDialog', 'End tag')) + translate('OpenLP.FormattingTagDialog', 'End HTML')) self.deletePushButton.setText(UiStrings().Delete) self.newPushButton.setText(UiStrings().New) self.tagTableWidget.horizontalHeaderItem(0).setText( translate('OpenLP.FormattingTagDialog', 'Description')) self.tagTableWidget.horizontalHeaderItem(1).setText( - translate('OpenLP.FormattingTagDialog', 'Tag Id')) + translate('OpenLP.FormattingTagDialog', 'Tag')) self.tagTableWidget.horizontalHeaderItem(2).setText( translate('OpenLP.FormattingTagDialog', 'Start HTML')) self.tagTableWidget.horizontalHeaderItem(3).setText( diff --git a/openlp/core/ui/formattingtagform.py b/openlp/core/ui/formattingtagform.py index 9d26e6683..e7b996180 100644 --- a/openlp/core/ui/formattingtagform.py +++ b/openlp/core/ui/formattingtagform.py @@ -49,7 +49,7 @@ class FormattingTagForm(QtGui.QDialog, Ui_FormattingTagDialog): QtGui.QDialog.__init__(self, parent) self.setupUi(self) QtCore.QObject.connect(self.tagTableWidget, - QtCore.SIGNAL(u'clicked(QModelIndex)'), self.onRowSelected) + QtCore.SIGNAL(u'itemSelectionChanged()'),self.onRowSelected) QtCore.QObject.connect(self.newPushButton, QtCore.SIGNAL(u'clicked()'), self.onNewClicked) QtCore.QObject.connect(self.savePushButton, diff --git a/openlp/core/ui/themeform.py b/openlp/core/ui/themeform.py index 46ad0b773..be8f9bde1 100644 --- a/openlp/core/ui/themeform.py +++ b/openlp/core/ui/themeform.py @@ -226,7 +226,7 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard): def onCurrentIdChanged(self, pageId): """ - Detects Page changes and updates as approprate. + Detects Page changes and updates as appropriate. """ enabled = self.page(pageId) == self.areaPositionPage self.setOption(QtGui.QWizard.HaveCustomButton1, enabled) diff --git a/openlp/core/utils/__init__.py b/openlp/core/utils/__init__.py index 7f2ef08e2..224ab4344 100644 --- a/openlp/core/utils/__init__.py +++ b/openlp/core/utils/__init__.py @@ -172,6 +172,11 @@ def _get_os_dir_path(dir_type): u'Library', u'Application Support', u'openlp') else: if dir_type == AppLocation.LanguageDir: + prefixes = [u'/usr/local', u'/usr'] + for prefix in prefixes: + directory = os.path.join(prefix, u'share', u'openlp') + if os.path.exists(directory): + return directory return os.path.join(u'/usr', u'share', u'openlp') if XDG_BASE_AVAILABLE: if dir_type == AppLocation.ConfigDir: diff --git a/openlp/plugins/bibles/lib/mediaitem.py b/openlp/plugins/bibles/lib/mediaitem.py index d6607a02e..5176e7d47 100644 --- a/openlp/plugins/bibles/lib/mediaitem.py +++ b/openlp/plugins/bibles/lib/mediaitem.py @@ -569,7 +569,9 @@ class BibleMediaItem(MediaManagerItem): if bible: if QtGui.QMessageBox.question(self, UiStrings().ConfirmDelete, unicode(translate('BiblesPlugin.MediaItem', - 'Are you sure you want to delete "%s"?')) % bible, + 'Are you sure you want to completely delete "%s" Bible from ' + 'OpenLP?\n\nYou will need to re-import this Bible to use it ' + 'again.'))% bible, QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No), QtGui.QMessageBox.Yes) == QtGui.QMessageBox.No: diff --git a/openlp/plugins/songs/forms/authorsform.py b/openlp/plugins/songs/forms/authorsform.py index 0df330cd1..8dede69a7 100644 --- a/openlp/plugins/songs/forms/authorsform.py +++ b/openlp/plugins/songs/forms/authorsform.py @@ -61,14 +61,14 @@ class AuthorsForm(QtGui.QDialog, Ui_AuthorsDialog): def onFirstNameEditTextEdited(self, display_name): if not self._autoDisplayName: return - if not self.lastNameEdit.text(): + if self.lastNameEdit.text(): display_name = display_name + u' ' + self.lastNameEdit.text() self.displayEdit.setText(display_name) def onLastNameEditTextEdited(self, display_name): if not self._autoDisplayName: return - if not self.firstNameEdit.text(): + if self.firstNameEdit.text(): display_name = self.firstNameEdit.text() + u' ' + display_name self.displayEdit.setText(display_name) diff --git a/openlp/plugins/songs/lib/__init__.py b/openlp/plugins/songs/lib/__init__.py index a51f3f2fc..d984d5a8d 100644 --- a/openlp/plugins/songs/lib/__init__.py +++ b/openlp/plugins/songs/lib/__init__.py @@ -476,7 +476,7 @@ def get_encoding(font, font_table, default_encoding, failed=False): Dictionary of fonts and respective encodings. ``default_encoding`` - The defaul encoding to use when font_table is empty or no font is used. + The default encoding to use when font_table is empty or no font is used. ``failed`` A boolean indicating whether the previous encoding didn't work. diff --git a/openlp/plugins/songs/lib/easyslidesimport.py b/openlp/plugins/songs/lib/easyslidesimport.py index 6e3b937ed..c7c169a1e 100644 --- a/openlp/plugins/songs/lib/easyslidesimport.py +++ b/openlp/plugins/songs/lib/easyslidesimport.py @@ -48,15 +48,8 @@ class EasySlidesImport(SongImport): Initialise the class. """ SongImport.__init__(self, manager, **kwargs) - self.commit = True def doImport(self): - """ - Import either each of the files in self.importSources - each element of - which can be either a single opensong file, or a zipfile containing - multiple opensong files. If `self.commit` is set False, the - import will not be committed to the database (useful for test scripts). - """ log.info(u'Importing EasySlides XML file %s', self.importSource) parser = etree.XMLParser(remove_blank_text=True) parsed_file = etree.parse(self.importSource, parser) diff --git a/openlp/plugins/songs/lib/importer.py b/openlp/plugins/songs/lib/importer.py index 2b04d6859..a8de7172e 100644 --- a/openlp/plugins/songs/lib/importer.py +++ b/openlp/plugins/songs/lib/importer.py @@ -28,6 +28,7 @@ """ The :mod:`importer` modules provides the general song import functionality. """ +import os import logging from openlp.core.lib import translate @@ -44,6 +45,7 @@ from powersongimport import PowerSongImport from ewimport import EasyWorshipSongImport from songbeamerimport import SongBeamerImport from songshowplusimport import SongShowPlusImport +from songproimport import SongProImport from sundayplusimport import SundayPlusImport from foilpresenterimport import FoilPresenterImport from zionworximport import ZionWorxImport @@ -67,6 +69,13 @@ try: except ImportError: log.exception('Error importing %s', 'OooImport') HAS_OOO = False +HAS_MEDIASHOUT = False +if os.name == u'nt': + try: + from mediashoutimport import MediaShoutImport + HAS_MEDIASHOUT = True + except ImportError: + log.exception('Error importing %s', 'MediaShoutImport') class SongFormatSelect(object): @@ -100,6 +109,7 @@ class SongFormat(object): ``u'canDisable'`` Whether song format importer is disablable. + If ``True``, then ``u'disabledLabelText'`` must also be defined. ``u'availability'`` Whether song format importer is available. @@ -141,15 +151,16 @@ class SongFormat(object): EasySlides = 6 EasyWorship = 7 FoilPresenter = 8 - OpenSong = 9 - PowerSong = 10 - SongBeamer = 11 - SongShowPlus = 12 - SongsOfFellowship = 13 - SundayPlus = 14 - WordsOfWorship = 15 - ZionWorx = 16 - #CSV = 17 + MediaShout = 9 + OpenSong = 10 + PowerSong = 11 + SongBeamer = 12 + SongPro = 13 + SongShowPlus = 14 + SongsOfFellowship = 15 + SundayPlus = 16 + WordsOfWorship = 17 + ZionWorx = 18 # Set optional attribute defaults __defaults__ = { @@ -158,7 +169,8 @@ class SongFormat(object): u'selectMode': SongFormatSelect.MultipleFiles, u'filter': u'', u'comboBoxText': None, - u'disabledLabelText': u'', + u'disabledLabelText': translate('SongsPlugin.ImportWizardForm', + 'This importer has been disabled.'), u'getFilesTitle': None, u'invalidSourceMsg': None, u'descriptionText': None @@ -240,6 +252,19 @@ class SongFormat(object): u'filter': u'%s (*.foil)' % translate( 'SongsPlugin.ImportWizardForm', 'Foilpresenter Song Files') }, + MediaShout: { + u'name': u'MediaShout', + u'prefix': u'mediaShout', + u'canDisable': True, + u'selectMode': SongFormatSelect.SingleFile, + u'filter': u'%s (*.mdb)' % translate('SongsPlugin.ImportWizardForm', + 'MediaShout Database'), + u'disabledLabelText': translate('SongsPlugin.ImportWizardForm', + 'The MediaShout importer is only supported on Windows. It has ' + 'been disabled due to a missing Python module. If you want to ' + 'use this importer, you will need to install the "pyodbc" ' + 'module.') + }, OpenSong: { u'class': OpenSongImport, u'name': WizardStrings.OS, @@ -260,6 +285,18 @@ class SongFormat(object): u'filter': u'%s (*.sng)' % translate('SongsPlugin.ImportWizardForm', 'SongBeamer Files') }, + SongPro: { + u'class': SongProImport, + u'name': u'SongPro', + u'prefix': u'songPro', + u'selectMode': SongFormatSelect.SingleFile, + u'filter': u'%s (*.txt)' % translate('SongsPlugin.ImportWizardForm', + 'SongPro Text Files'), + u'comboBoxText': translate('SongsPlugin.ImportWizardForm', + 'SongPro (Export File)'), + u'descriptionText': translate('SongsPlugin.ImportWizardForm', + 'In SongPro, export your songs using the File -> Export menu') + }, SongShowPlus: { u'class': SongShowPlusImport, u'name': u'SongShow Plus', @@ -302,12 +339,6 @@ class SongFormat(object): 'First convert your ZionWorx database to a CSV text file, as ' 'explained in the User Manual.') -# }, -# CSV: { -# u'class': CSVImport, -# u'name': WizardStrings.CSV, -# u'prefix': u'csv', -# u'selectMode': SongFormatSelect.SingleFile } } @@ -326,9 +357,11 @@ class SongFormat(object): SongFormat.EasySlides, SongFormat.EasyWorship, SongFormat.FoilPresenter, + SongFormat.MediaShout, SongFormat.OpenSong, SongFormat.PowerSong, SongFormat.SongBeamer, + SongFormat.SongPro, SongFormat.SongShowPlus, SongFormat.SongsOfFellowship, SongFormat.SundayPlus, @@ -383,5 +416,8 @@ if HAS_SOF: SongFormat.set(SongFormat.Generic, u'availability', HAS_OOO) if HAS_OOO: SongFormat.set(SongFormat.Generic, u'class', OooImport) +SongFormat.set(SongFormat.MediaShout, u'availability', HAS_MEDIASHOUT) +if HAS_MEDIASHOUT: + SongFormat.set(SongFormat.MediaShout, u'class', MediaShoutImport) __all__ = [u'SongFormat', u'SongFormatSelect'] diff --git a/openlp/plugins/songs/lib/mediashoutimport.py b/openlp/plugins/songs/lib/mediashoutimport.py new file mode 100644 index 000000000..f81b208ac --- /dev/null +++ b/openlp/plugins/songs/lib/mediashoutimport.py @@ -0,0 +1,112 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2012 Raoul Snyman # +# Portions copyright (c) 2008-2012 Tim Bentley, Gerald Britton, Jonathan # +# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, # +# Meinert Jordan, Armin Köhler, Edwin Lunando, Joshua Miller, Stevan Pettit, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Simon Scudder, Jeffrey Smith, Maikel Stuivenberg, Martin Thompson, Jon # +# Tibble, Dave Warnock, 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:`mediashoutimport` module provides the functionality for importing +a MediaShout database into the OpenLP database. +""" +import re +import os +import pyodbc + +from openlp.core.lib import translate +from openlp.plugins.songs.lib.songimport import SongImport + +VERSE_TAGS = [u'V', u'C', u'B', u'O', u'P', u'I', u'E'] + +class MediaShoutImport(SongImport): + """ + The :class:`MediaShoutImport` class provides the ability to import the + MediaShout Access Database + """ + def __init__(self, manager, **kwargs): + """ + Initialise the MediaShout importer. + """ + SongImport.__init__(self, manager, **kwargs) + + def doImport(self): + """ + Receive a single file to import. + """ + try: + conn = pyodbc.connect(u'DRIVER={Microsoft Access Driver (*.mdb)};' + u'DBQ=%s;PWD=6NOZ4eHK7k' % self.importSource) + except: + # Unfortunately no specific exception type + self.logError(self.importSource, + translate('SongsPlugin.MediaShoutImport', + 'Unable to open the MediaShout database.')) + return + cursor = conn.cursor() + cursor.execute(u'SELECT Record, Title, Author, Copyright, ' + u'SongID, CCLI, Notes FROM Songs ORDER BY Title') + songs = cursor.fetchall() + self.importWizard.progressBar.setMaximum(len(songs)) + for song in songs: + if self.stopImportFlag: + break + cursor.execute(u'SELECT Type, Number, Text FROM Verses ' + u'WHERE Record = %s ORDER BY Type, Number' % song.Record) + verses = cursor.fetchall() + cursor.execute(u'SELECT Type, Number, POrder FROM PlayOrder ' + u'WHERE Record = %s ORDER BY POrder' % song.Record) + verse_order = cursor.fetchall() + cursor.execute(u'SELECT Name FROM Themes INNER JOIN SongThemes ' + u'ON SongThemes.ThemeId = Themes.ThemeId ' + u'WHERE SongThemes.Record = %s' % song.Record) + topics = cursor.fetchall() + cursor.execute(u'SELECT Name FROM Groups INNER JOIN SongGroups ' + u'ON SongGroups.GroupId = Groups.GroupId ' + u'WHERE SongGroups.Record = %s' % song.Record) + topics += cursor.fetchall() + self.processSong(song, verses, verse_order, topics) + + def processSong(self, song, verses, verse_order, topics): + """ + Create the song, i.e. title, verse etc. + """ + self.setDefaults() + self.title = song.Title + self.parseAuthor(song.Author) + self.addCopyright(song.Copyright) + self.comments = song.Notes + for topic in topics: + self.topics.append(topic.Name) + if u'-' in song.SongID: + self.songBookName, self.songNumber = song.SongID.split(u'-', 1) + else: + self.songBookName = song.SongID + for verse in verses: + tag = VERSE_TAGS[verse.Type] + unicode(verse.Number) \ + if verse.Type < len(VERSE_TAGS) else u'O' + self.addVerse(verse.Text, tag) + for order in verse_order: + if order.Type < len(VERSE_TAGS): + self.verseOrderList.append(VERSE_TAGS[order.Type] + + unicode(order.Number)) + self.finish() diff --git a/openlp/plugins/songs/lib/songproimport.py b/openlp/plugins/songs/lib/songproimport.py new file mode 100644 index 000000000..44bf0cb44 --- /dev/null +++ b/openlp/plugins/songs/lib/songproimport.py @@ -0,0 +1,143 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2012 Raoul Snyman # +# Portions copyright (c) 2008-2012 Tim Bentley, Gerald Britton, Jonathan # +# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, # +# Meinert Jordan, Armin Köhler, Edwin Lunando, Joshua Miller, Stevan Pettit, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Simon Scudder, Jeffrey Smith, Maikel Stuivenberg, Martin Thompson, Jon # +# Tibble, Dave Warnock, 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:`songproimport` module provides the functionality for importing SongPro +songs into the OpenLP database. +""" +import re +import os + +from openlp.core.lib import translate +from openlp.plugins.songs.lib import strip_rtf +from openlp.plugins.songs.lib.songimport import SongImport + +class SongProImport(SongImport): + """ + The :class:`SongProImport` class provides the ability to import song files + from SongPro export files. + + **SongPro Song File Format:** + + SongPro has the option to export under its File menu + This produces files containing single or multiple songs + The file is text with lines tagged with # followed by an identifier. + This is documented here: http://creationsoftware.com/ImportIdentifiers.php + An example here: http://creationsoftware.com/ExampleImportingManySongs.txt + + #A - next line is the Song Author + #B - the lines following until next tagged line are the "Bridge" words + (can be in rtf or plain text) which we map as B1 + #C - the lines following until next tagged line are the chorus words + (can be in rtf or plain text) + which we map as C1 + #D - the lines following until next tagged line are the "Ending" words + (can be in rtf or plain text) which we map as E1 + #E - this song ends here, so we process the song - + and start again at the next line + #G - next line is the Group + #M - next line is the Song Number + #N - next line are Notes + #R - next line is the SongCopyright + #O - next line is the Verse Sequence + #T - next line is the Song Title + #1 - #7 the lines following until next tagged line are the verse x words + (can be in rtf or plain text) + """ + def __init__(self, manager, **kwargs): + """ + Initialise the SongPro importer. + """ + SongImport.__init__(self, manager, **kwargs) + + def doImport(self): + """ + Receive a single file or a list of files to import. + """ + self.encoding = None + with open(self.importSource, 'r') as songs_file: + self.importWizard.progressBar.setMaximum(0) + tag = u'' + text = u'' + for file_line in songs_file: + if self.stopImportFlag: + break + file_line = unicode(file_line, u'cp1252') + file_text = file_line.rstrip() + if file_text and file_text[0] == u'#': + self.processSection(tag, text.rstrip()) + tag = file_text[1:] + text = u'' + else: + text += file_line + + def processSection(self, tag, text): + """ + Process a section of the song, i.e. title, verse etc. + """ + if tag == u'T': + self.setDefaults() + if text: + self.title = text + return + elif tag == u'E': + self.finish() + return + if u'rtf1' in text: + text, self.encoding = strip_rtf(text, self.encoding) + text = text.rstrip() + if not text: + return + if tag == u'A': + self.parseAuthor(text) + elif tag in [u'B', u'C']: + self.addVerse(text, tag) + elif tag == u'D': + self.addVerse(text, u'E') + elif tag == u'G': + self.topics.append(text) + elif tag == u'M': + matches = re.findall(r'\d+', text) + if matches: + self.songNumber = matches[-1] + self.songBookName = text[:text.rfind(self.songNumber)] + elif tag == u'N': + self.comments = text + elif tag == u'O': + for char in text: + if char == u'C': + self.verseOrderList.append(u'C1') + elif char == u'B': + self.verseOrderList.append(u'B1') + elif char == u'D': + self.verseOrderList.append(u'E1') + elif u'1' <= char <= u'7': + self.verseOrderList.append(u'V' + char) + elif tag == u'R': + self.addCopyright(text) + elif u'1' <= tag <= u'7': + self.addVerse(text, u'V' + tag[1:]) diff --git a/openlp/plugins/songs/lib/zionworximport.py b/openlp/plugins/songs/lib/zionworximport.py index 0e7a1b425..1a00b3a7c 100644 --- a/openlp/plugins/songs/lib/zionworximport.py +++ b/openlp/plugins/songs/lib/zionworximport.py @@ -37,6 +37,9 @@ from openlp.plugins.songs.lib.songimport import SongImport log = logging.getLogger(__name__) +# Used to strip control chars (except 10=LF, 13=CR) +CONTROL_CHARS_MAP = dict.fromkeys(range(10) + [11, 12] + range(14,32) + [127]) + class ZionWorxImport(SongImport): """ The :class:`ZionWorxImport` class provides the ability to import songs @@ -78,13 +81,10 @@ class ZionWorxImport(SongImport): """ Receive a CSV file (from a ZionWorx database dump) to import. """ - # Used to strip control chars (10=LF, 13=CR, 127=DEL) - self.control_chars_map = dict.fromkeys( - range(10) + [11, 12] + range(14,32) + [127]) with open(self.importSource, 'rb') as songs_file: - fieldnames = [u'SongNum', u'Title1', u'Title2', u'Lyrics', + field_names = [u'SongNum', u'Title1', u'Title2', u'Lyrics', u'Writer', u'Copyright', u'Keywords', u'DefaultStyle'] - songs_reader = csv.DictReader(songs_file, fieldnames) + songs_reader = csv.DictReader(songs_file, field_names) try: records = list(songs_reader) except csv.Error, e: @@ -140,4 +140,4 @@ class ZionWorxImport(SongImport): """ # This encoding choice seems OK. ZionWorx has no option for setting the # encoding for its songs, so we assume encoding is always the same. - return unicode(str, u'cp1252').translate(self.control_chars_map) + return unicode(str, u'cp1252').translate(CONTROL_CHARS_MAP) diff --git a/resources/__init__.py b/resources/__init__.py new file mode 100644 index 000000000..377413191 --- /dev/null +++ b/resources/__init__.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2012 Raoul Snyman # +# Portions copyright (c) 2008-2012 Tim Bentley, Gerald Britton, Jonathan # +# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, # +# Meinert Jordan, Armin Köhler, Edwin Lunando, Joshua Miller, Stevan Pettit, # +# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, # +# Simon Scudder, Jeffrey Smith, Maikel Stuivenberg, Martin Thompson, Jon # +# Tibble, Dave Warnock, 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:`resources` module contains a bunch of resources for OpenLP. + +DO NOT REMOVE THIS FILE, IT IS REQUIRED FOR INCLUDING THE RESOURCES ON SOME +PLATFORMS! +""" + diff --git a/setup.py b/setup.py index 2f8919f4b..b101d2907 100755 --- a/setup.py +++ b/setup.py @@ -28,10 +28,56 @@ ############################################################################### from setuptools import setup, find_packages +import re VERSION_FILE = 'openlp/.version' +SPLIT_ALPHA_DIGITS = re.compile(r'(\d+|\D+)') + +def try_int(s): + """ + Convert string s to an integer if possible. Fail silently and return + the string as-is if it isn't an integer. + + ``s`` + The string to try to convert. + """ + try: + return int(s) + except Exception: + return s + +def natural_sort_key(s): + """ + Return a tuple by which s is sorted. + + ``s`` + A string value from the list we want to sort. + """ + return map(try_int, SPLIT_ALPHA_DIGITS.findall(s)) + +def natural_compare(a, b): + """ + Compare two strings naturally and return the result. + + ``a`` + A string to compare. + + ``b`` + A string to compare. + """ + return cmp(natural_sort_key(a), natural_sort_key(b)) + +def natural_sort(seq, compare=natural_compare): + """ + Returns a copy of seq, sorted by natural string sort. + """ + import copy + temp = copy.copy(seq) + temp.sort(compare) + return temp try: + # Try to import Bazaar from bzrlib.branch import Branch b = Branch.open_containing('.')[0] b.lock_read() @@ -46,7 +92,8 @@ try: if revision_id in tags: version = u'%s' % tags[revision_id][0] else: - version = '%s-bzr%s' % (sorted(b.tags.get_tag_dict().keys())[-1], revno) + version = '%s-bzr%s' % \ + (natural_sort(b.tags.get_tag_dict().keys())[-1], revno) ver_file = open(VERSION_FILE, u'w') ver_file.write(version) ver_file.close()