Fix code so values saved

This commit is contained in:
Tim Bentley 2013-08-23 19:37:36 +01:00
commit 9648e0c81b
26 changed files with 276 additions and 85 deletions

View File

@ -384,6 +384,7 @@ def create_separated_list(stringlist):
from eventreceiver import Receiver
from filedialog import FileDialog
from listwidgetwithdnd import ListWidgetWithDnD
from formattingtags import FormattingTags
from spelltextedit import SpellTextEdit

View File

@ -0,0 +1,63 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2013 Raoul Snyman #
# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan #
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
# 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, Martin Zibricky #
# --------------------------------------------------------------------------- #
# 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 #
###############################################################################
"""
Provide a work around for a bug in QFileDialog
<https://bugs.launchpad.net/openlp/+bug/1209515>
"""
import os
import urllib
from PyQt4 import QtCore, QtGui
from openlp.core.lib.ui import UiStrings
class FileDialog(QtGui.QFileDialog):
"""
Subclass QFileDialog to work round a bug
"""
@staticmethod
def getOpenFileNames(parent, title, path, filters):
"""
Reimplement getOpenFileNames to fix the way it returns some file
names that url encoded when selecting multiple files/
"""
files = QtGui.QFileDialog.getOpenFileNames(parent, title, path, filters)
file_list = QtCore.QStringList()
for file in files:
file = unicode(file)
if not os.path.exists(file):
file = urllib.unquote(file)
if not os.path.exists(file):
QtGui.QMessageBox.information(parent,
UiStrings().FileNotFound,
UiStrings().FileNotFoundMessage % file)
continue
file_list.append(QtCore.QString(file))
return file_list

View File

@ -35,7 +35,7 @@ import re
from PyQt4 import QtCore, QtGui
from openlp.core.lib import SettingsManager, OpenLPToolbar, ServiceItem, \
from openlp.core.lib import FileDialog, SettingsManager, OpenLPToolbar, ServiceItem, \
StringContent, build_icon, translate, Receiver, ListWidgetWithDnD
from openlp.core.lib.searchedit import SearchEdit
from openlp.core.lib.ui import UiStrings, create_widget_action, \
@ -337,7 +337,7 @@ class MediaManagerItem(QtGui.QWidget):
"""
Add a file to the list widget to make it available for showing
"""
files = QtGui.QFileDialog.getOpenFileNames(
files = FileDialog.getOpenFileNames(
self, self.onNewPrompt,
SettingsManager.get_last_dir(self.settingsSection),
self.onNewFileMasks)

View File

@ -77,6 +77,10 @@ class UiStrings(object):
self.Error = translate('OpenLP.Ui', 'Error')
self.Export = translate('OpenLP.Ui', 'Export')
self.File = translate('OpenLP.Ui', 'File')
self.FileNotFound = unicode(translate('OpenLP.Ui',
'File Not Found'))
self.FileNotFoundMessage = unicode(translate('OpenLP.Ui',
'File %s not found.\nPlease try selecting it individually.'))
self.FontSizePtUnit = translate('OpenLP.Ui', 'pt',
'Abbreviated font pointsize unit')
self.Help = translate('OpenLP.Ui', 'Help')

View File

@ -26,7 +26,9 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The First Time Wizard
"""
import io
import logging
import os
@ -48,6 +50,7 @@ from firsttimewizard import Ui_FirstTimeWizard, FirstTimePage
log = logging.getLogger(__name__)
class ThemeScreenshotThread(QtCore.QThread):
"""
This thread downloads the theme screenshots.
@ -56,6 +59,9 @@ class ThemeScreenshotThread(QtCore.QThread):
QtCore.QThread.__init__(self, parent)
def run(self):
"""
Run the thread.
"""
themes = self.parent().config.get(u'themes', u'files')
themes = themes.split(u',')
themes_dir = self.parent().config.get(u'themes', u'directory')
@ -180,15 +186,28 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
Determine the next page in the Wizard to go to.
"""
Receiver.send_message(u'openlp_process_events')
# If we are currently on the plugins page
if self.currentId() == FirstTimePage.Plugins:
# But we don't have Internet access
if not self.webAccess:
return FirstTimePage.NoInternet
else:
# The songs plugin is enabled
elif self.songsCheckBox.isChecked():
return FirstTimePage.Songs
# The Bibles plugin is enabled
elif self.bibleCheckBox.isChecked():
return FirstTimePage.Bibles
else:
return FirstTimePage.Themes
elif self.currentId() == FirstTimePage.Progress:
return -1
elif self.currentId() == FirstTimePage.NoInternet:
return FirstTimePage.Progress
elif self.currentId() == FirstTimePage.Songs:
if self.bibleCheckBox.isChecked():
return FirstTimePage.Bibles
else:
return FirstTimePage.Themes
elif self.currentId() == FirstTimePage.Themes:
Receiver.send_message(u'cursor_busy')
Receiver.send_message(u'openlp_process_events')
@ -395,7 +414,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
self.max_progress += size
if self.max_progress:
# Add on 2 for plugins status setting plus a "finished" point.
self.max_progress = self.max_progress + 2
self.max_progress += 2
self.progressBar.setValue(0)
self.progressBar.setMinimum(0)
self.progressBar.setMaximum(self.max_progress)

View File

@ -34,7 +34,11 @@ import sys
from openlp.core.lib import translate
from openlp.core.lib.ui import add_welcome_page
class FirstTimePage(object):
"""
An enumeration object to make it easy for a developer to determine which page is which by index
"""
Welcome = 0
Plugins = 1
NoInternet = 2

View File

@ -109,6 +109,7 @@ class FormattingTagForm(QtGui.QDialog, Ui_FormattingTagDialog):
has been changed.
"""
self.savePushButton.setEnabled(True)
self.savePushButton.setDefault(True)
def onNewClicked(self):
"""

View File

@ -89,7 +89,8 @@ VIDEO_EXT = [
u'*.xa',
u'*.iso',
u'*.vob',
u'*.webm'
u'*.webm',
u'*.divx'
]

View File

@ -229,32 +229,32 @@ FLASH_HTML = u"""
"""
VIDEO_EXT = [
u'*.3gp'
, u'*.3gpp'
, u'*.3g2'
, u'*.3gpp2'
, u'*.aac'
, u'*.flv'
, u'*.f4a'
, u'*.f4b'
, u'*.f4p'
, u'*.f4v'
, u'*.mov'
, u'*.m4a'
, u'*.m4b'
, u'*.m4p'
, u'*.m4v'
, u'*.mkv'
, u'*.mp4'
, u'*.ogv'
, u'*.webm'
, u'*.mpg', u'*.wmv', u'*.mpeg', u'*.avi'
, u'*.swf'
u'*.3gp',
u'*.3gpp',
u'*.3g2',
u'*.3gpp2',
u'*.aac',
u'*.flv',
u'*.f4a',
u'*.f4b',
u'*.f4p',
u'*.f4v',
u'*.mov',
u'*.m4a',
u'*.m4b',
u'*.m4p',
u'*.m4v',
u'*.mkv',
u'*.mp4',
u'*.ogv',
u'*.webm',
u'*.mpg', u'*.wmv', u'*.mpeg', u'*.avi',
u'*.swf'
]
AUDIO_EXT = [
u'*.mp3'
, u'*.ogg'
u'*.mp3',
u'*.ogg'
]

View File

@ -78,6 +78,8 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard):
QtCore.SIGNAL(u'clicked()'), self.onGradientEndButtonClicked)
QtCore.QObject.connect(self.imageBrowseButton,
QtCore.SIGNAL(u'clicked()'), self.onImageBrowseButtonClicked)
QtCore.QObject.connect(self.imageFileEdit,
QtCore.SIGNAL(u'editingFinished()'), self.onImageFileEditEditingFinished)
QtCore.QObject.connect(self.mainColorButton,
QtCore.SIGNAL(u'clicked()'), self.onMainColorButtonClicked)
QtCore.QObject.connect(self.outlineColorButton,
@ -233,7 +235,7 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard):
background_image = BackgroundType.to_string(BackgroundType.Image)
if self.page(self.currentId()) == self.backgroundPage and \
self.theme.background_type == background_image and \
is_not_image_file(self.imageFileEdit.text()):
is_not_image_file(self.theme.background_filename):
QtGui.QMessageBox.critical(self,
translate('OpenLP.ThemeWizard', 'Background Image Empty'),
translate('OpenLP.ThemeWizard', 'You have not selected a '
@ -545,6 +547,12 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard):
self.theme.background_filename = unicode(filename)
self.setBackgroundPageValues()
def onImageFileEditEditingFinished(self):
"""
Background image path edited
"""
self.theme.background_filename = unicode(self.imageFileEdit.text())
def onMainColorButtonClicked(self):
self.theme.font_main_color = \
self._colorButton(self.theme.font_main_color)

View File

@ -36,7 +36,7 @@ import re
from xml.etree.ElementTree import ElementTree, XML
from PyQt4 import QtCore, QtGui
from openlp.core.lib import OpenLPToolbar, get_text_file_string, build_icon, \
from openlp.core.lib import FileDialog, OpenLPToolbar, get_text_file_string, build_icon, \
Receiver, SettingsManager, translate, check_item_selected, \
check_directory_exists, create_thumb, validate_thumb, ImageSource
from openlp.core.lib.theme import ThemeXML, BackgroundType, VerticalType, \
@ -420,7 +420,7 @@ class ThemeManager(QtGui.QWidget):
attempting to extract OpenLP themes from those files. This process
will load both OpenLP version 1 and version 2 themes.
"""
files = QtGui.QFileDialog.getOpenFileNames(self,
files = FileDialog.getOpenFileNames(self,
translate('OpenLP.ThemeManager', 'Select Theme Import File'),
SettingsManager.get_last_dir(self.settingsSection),
unicode(translate('OpenLP.ThemeManager',

View File

@ -371,15 +371,14 @@ def is_not_image_file(file_name):
``file_name``
File name to be checked.
"""
if file_name.isEmpty():
return True
else:
formats = [unicode(fmt).lower()
for fmt in QtGui.QImageReader.supportedImageFormats()]
file_part, file_extension = os.path.splitext(unicode(file_name))
if file_extension[1:].lower() in formats and os.path.exists(file_name):
return False
if not file_name:
return True
formats = [unicode(fmt).lower()
for fmt in QtGui.QImageReader.supportedImageFormats()]
file_part, file_extension = os.path.splitext(unicode(file_name))
if file_extension[1:].lower() in formats and os.path.exists(file_name):
return False
return True
def join_url(base, *args):
"""

View File

@ -862,6 +862,26 @@ class BiblesResourcesDB(QtCore.QObject, Manager):
return book[0]
return None
@staticmethod
def get_language_by_id(language_id):
"""
Return a dict containing the language id, name and code by id.
``id``
The id of the language in the database.
"""
log.debug(u'BiblesResourcesDB.get_language_by_id(%d)', language_id)
language = BiblesResourcesDB.run_sql(u'SELECT id, name, code FROM '
u'language WHERE id = ?', (language_id,))
if language:
return {
u'id': language[0][0],
u'name': unicode(language[0][1]),
u'code': unicode(language[0][2])
}
else:
return None
@staticmethod
def get_language(name):
"""

View File

@ -245,6 +245,8 @@ class BGExtract(object):
return None
Receiver.send_message(u'openlp_process_events')
div = soup.find('div', 'result-text-style-normal')
if not div:
return None
self._clean_soup(div)
span_list = div.findAll('span', 'text')
log.debug('Span list: %s', span_list)
@ -375,6 +377,7 @@ class BSExtract(object):
content = content.findAll(u'li')
return [
book.contents[0].contents[0] for book in content
if len(book.contents[0].contents)
]

View File

@ -34,7 +34,7 @@ import codecs
import re
from openlp.core.lib import Receiver, translate
from openlp.core.utils import AppLocation
from openlp.core.utils import AppLocation, LanguageManager
from openlp.plugins.bibles.lib.db import BibleDB, BiblesResourcesDB
log = logging.getLogger(__name__)
@ -148,10 +148,22 @@ class OSISBible(BibleDB):
self.filename)
return False
book_details = BiblesResourcesDB.get_book_by_id(book_ref_id)
if not db_book or db_book.name != book_details[u'name']:
log.debug(u'New book: "%s"' % book_details[u'name'])
bible_language = BiblesResourcesDB.get_language_by_id(language_id)
if bible_language is not None:
# The language of this bible was found, so we can
# translate the name of this book
custom_translator = LanguageManager.get_translator(
bible_language['code'])[0]
book_name_localized = unicode(custom_translator.translate(
'BiblesPlugin', book_details[u'name']))
else:
# The language of this bible was not found, so we just
# use the English name for this book
book_name_localized = book_details[u'name']
if not db_book or db_book.name != book_name_localized:
log.debug(u'New book: "%s"' % book_name_localized)
db_book = self.create_book(
book_details[u'name'],
book_name_localized,
book_ref_id,
book_details[u'testament_id'])
if last_chapter == 0:
@ -162,7 +174,7 @@ class OSISBible(BibleDB):
self.wizard.incrementProgressBar(unicode(translate(
'BiblesPlugin.OsisImport', 'Importing %s %s...',
'Importing <book name> <chapter>...')) %
(book_details[u'name'], chapter))
(book_name_localized, chapter))
last_chapter = chapter
# All of this rigmarol below is because the mod2osis
# tool from the Sword library embeds XML in the OSIS

View File

@ -44,6 +44,7 @@ import time
if os.name == u'nt':
from win32com.client import Dispatch
import pywintypes
# Declare an empty exception to match the exception imported from UNO
class ErrorCodeIOException(Exception):
pass
@ -63,6 +64,7 @@ from presentationcontroller import PresentationController, PresentationDocument
log = logging.getLogger(__name__)
class ImpressController(PresentationController):
"""
Class to control interactions with Impress presentations.
@ -79,7 +81,7 @@ class ImpressController(PresentationController):
PresentationController.__init__(self, plugin, u'Impress',
ImpressDocument)
self.supports = [u'odp']
self.alsosupports = [u'ppt', u'pps', u'pptx', u'ppsx']
self.alsosupports = [u'ppt', u'pps', u'pptx', u'ppsx', u'pptm']
self.process = None
self.desktop = None
self.manager = None

View File

@ -45,6 +45,7 @@ log = logging.getLogger(__name__)
ERROR = QtGui.QImage(u':/general/general_delete.png')
class PresentationMediaItem(MediaManagerItem):
"""
This is the Presentation media manager item for Presentation Items.
@ -88,10 +89,10 @@ class PresentationMediaItem(MediaManagerItem):
if self.controllers[controller].enabled():
types = self.controllers[controller].supports + \
self.controllers[controller].alsosupports
for type in types:
if fileType.find(type) == -1:
fileType += u'*.%s ' % type
self.plugin.serviceManager.supportedSuffixes(type)
for type_ in types:
if fileType.find(type_) == -1:
fileType += u'*.%s ' % type_
self.plugin.serviceManager.supportedSuffixes(type_)
self.onNewFileMasks = unicode(translate('PresentationPlugin.MediaItem',
'Presentations (%s)')) % fileType

View File

@ -43,6 +43,7 @@ log = logging.getLogger(__name__)
# PPT API documentation:
# http://msdn.microsoft.com/en-us/library/aa269321(office.10).aspx
class PowerpointController(PresentationController):
"""
Class to control interactions with PowerPoint Presentations
@ -58,7 +59,7 @@ class PowerpointController(PresentationController):
log.debug(u'Initialising')
PresentationController.__init__(self, plugin, u'Powerpoint',
PowerpointDocument)
self.supports = [u'ppt', u'pps', u'pptx', u'ppsx']
self.supports = [u'ppt', u'pps', u'pptx', u'ppsx', u'pptm']
self.process = None
def check_available(self):

View File

@ -38,6 +38,7 @@ from presentationcontroller import PresentationController, PresentationDocument
log = logging.getLogger(__name__)
class PptviewController(PresentationController):
"""
Class to control interactions with PowerPOint Viewer Presentations
@ -54,7 +55,7 @@ class PptviewController(PresentationController):
self.process = None
PresentationController.__init__(self, plugin, u'Powerpoint Viewer',
PptviewDocument)
self.supports = [u'ppt', u'pps', u'pptx', u'ppsx']
self.supports = [u'ppt', u'pps', u'pptx', u'ppsx', u'pptm']
def check_available(self):
"""

View File

@ -34,7 +34,7 @@ import shutil
from PyQt4 import QtCore, QtGui
from openlp.core.lib import PluginStatus, Receiver, MediaType, translate, \
from openlp.core.lib import FileDialog, PluginStatus, Receiver, MediaType, translate, \
create_separated_list, check_directory_exists
from openlp.core.lib.ui import UiStrings, set_case_insensitive_completer, \
critical_error_message_box, find_and_set_in_combo_box
@ -47,6 +47,7 @@ from editsongdialog import Ui_EditSongDialog
log = logging.getLogger(__name__)
class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
"""
Class to manage the editing of a song
@ -229,6 +230,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
self.loadTopics()
self.loadBooks()
self.loadMediaFiles()
self.themeComboBox.setEditText(u'')
self.themeComboBox.setCurrentIndex(0)
# it's a new song to preview is not possible
self.previewButton.setVisible(False)
@ -261,6 +263,9 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
if self.song.theme_name:
find_and_set_in_combo_box(
self.themeComboBox, unicode(self.song.theme_name))
else:
self.themeComboBox.setEditText(u'')
self.themeComboBox.setCurrentIndex(0)
self.copyrightEdit.setText(
self.song.copyright if self.song.copyright else u'')
self.commentsEdit.setPlainText(
@ -757,7 +762,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
Loads file(s) from the filesystem.
"""
filters = u'%s (*)' % UiStrings().AllFiles
filenames = QtGui.QFileDialog.getOpenFileNames(self,
filenames = FileDialog.getOpenFileNames(self,
translate('SongsPlugin.EditSongForm', 'Open File(s)'),
QtCore.QString(), filters)
for filename in filenames:

View File

@ -35,7 +35,7 @@ import os
from PyQt4 import QtCore, QtGui
from openlp.core.lib import Receiver, SettingsManager, translate
from openlp.core.lib import FileDialog, Receiver, SettingsManager, translate
from openlp.core.lib.ui import UiStrings, critical_error_message_box
from openlp.core.lib.settings import Settings
from openlp.core.ui.wizard import OpenLPWizard, WizardStrings
@ -281,7 +281,7 @@ class SongImportForm(OpenLPWizard):
if filters:
filters += u';;'
filters += u'%s (*)' % UiStrings().AllFiles
filenames = QtGui.QFileDialog.getOpenFileNames(self, title,
filenames = FileDialog.getOpenFileNames(self, title,
SettingsManager.get_last_dir(self.plugin.settingsSection, 1),
filters)
if filenames:

View File

@ -96,6 +96,7 @@ import os
from lxml import etree, objectify
from openlp.core.lib import translate
from openlp.core.ui.wizard import WizardStrings
from openlp.plugins.songs.lib import clean_song, VerseType
from openlp.plugins.songs.lib.songimport import SongImport
@ -115,7 +116,7 @@ class FoilPresenterImport(SongImport):
"""
log.debug(u'initialise FoilPresenterImport')
SongImport.__init__(self, manager, **kwargs)
self.FoilPresenter = FoilPresenter(self.manager)
self.FoilPresenter = FoilPresenter(self.manager, self)
def doImport(self):
"""
@ -202,8 +203,9 @@ class FoilPresenter(object):
<copyright> tag.
"""
def __init__(self, manager):
def __init__(self, manager, importer):
self.manager = manager
self.importer = importer
def xml_to_song(self, xml):
"""
@ -222,6 +224,7 @@ class FoilPresenter(object):
song.search_lyrics = u''
song.verse_order = u''
song.search_title = u''
self.save_song = True
# Because "text" seems to be an reserverd word, we have to recompile it.
xml = re.compile(u'<text>').sub(u'<text_>', xml)
xml = re.compile(u'</text>').sub(u'</text_>', xml)
@ -236,8 +239,9 @@ class FoilPresenter(object):
self._process_authors(foilpresenterfolie, song)
self._process_songbooks(foilpresenterfolie, song)
self._process_topics(foilpresenterfolie, song)
clean_song(self.manager, song)
self.manager.save_object(song)
if self.save_song:
clean_song(self.manager, song)
self.manager.save_object(song)
def _child(self, element):
"""
@ -424,6 +428,12 @@ class FoilPresenter(object):
VerseType.Tags[VerseType.Intro]: 1,
VerseType.Tags[VerseType.PreChorus]: 1
}
if not hasattr(foilpresenterfolie.strophen, u'strophe'):
self.importer.logError(self._child(foilpresenterfolie.titel),
unicode(translate('SongsPlugin.FoilPresenterSongImport',
'Invalid Foilpresenter song file. No verses found.')))
self.save_song = False
return
for strophe in foilpresenterfolie.strophen.strophe:
text = self._child(strophe.text_) if hasattr(strophe, u'text_') \
else u''

View File

@ -49,6 +49,9 @@ class OpenSongImport(SongImport):
the OpenSong web site. However, it doesn't describe the <lyrics> section,
so here's an attempt:
If the first charachter of a line is a space, then the rest of that line
is lyrics. If it is not a space the following applies.
Verses can be expressed in one of 2 ways, either in complete verses, or by
line grouping, i.e. grouping all line 1's of a verse together, all line 2's
of a verse together, and so on.
@ -171,13 +174,11 @@ class OpenSongImport(SongImport):
else:
lyrics = u''
for this_line in lyrics.split(u'\n'):
# remove comments
semicolon = this_line.find(u';')
if semicolon >= 0:
this_line = this_line[:semicolon]
this_line = this_line.strip()
if not this_line:
continue
# skip this line if it is a comment
if this_line.startswith(u';'):
continue
# skip guitar chords and page and column breaks
if this_line.startswith(u'.') or this_line.startswith(u'---') \
or this_line.startswith(u'-!!'):
@ -212,7 +213,6 @@ class OpenSongImport(SongImport):
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])
verses.setdefault(verse_tag, {})
verses[verse_tag].setdefault(verse_num, {})
if inst not in verses[verse_tag][verse_num]:
@ -222,6 +222,7 @@ class OpenSongImport(SongImport):
this_line = self.tidyText(this_line)
this_line = this_line.replace(u'_', u'')
this_line = this_line.replace(u'|', u'\n')
this_line = this_line.strip()
verses[verse_tag][verse_num][inst].append(this_line)
# done parsing
# add verses in original order

View File

@ -30,13 +30,14 @@
The :mod:`songshowplusimport` module provides the functionality for importing
SongShow Plus songs into the OpenLP database.
"""
import chardet
import os
import logging
import re
import struct
from openlp.core.ui.wizard import WizardStrings
from openlp.plugins.songs.lib import VerseType
from openlp.plugins.songs.lib import VerseType, retrieve_windows_encoding
from openlp.plugins.songs.lib.songimport import SongImport
TITLE = 1
@ -142,44 +143,44 @@ class SongShowPlusImport(SongImport):
log.debug(length_descriptor_size)
data = song_data.read(length_descriptor)
if block_key == TITLE:
self.title = unicode(data, u'cp1252')
self.title = self.decode(data)
elif block_key == AUTHOR:
authors = data.split(" / ")
for author in authors:
if author.find(",") !=-1:
authorParts = author.split(", ")
author = authorParts[1] + " " + authorParts[0]
self.parseAuthor(unicode(author, u'cp1252'))
self.parseAuthor(self.decode(author))
elif block_key == COPYRIGHT:
self.addCopyright(unicode(data, u'cp1252'))
self.addCopyright(self.decode(data))
elif block_key == CCLI_NO:
self.ccliNumber = int(data)
elif block_key == VERSE:
self.addVerse(unicode(data, u'cp1252'),
self.addVerse(self.decode(data),
"%s%s" % (VerseType.Tags[VerseType.Verse], verse_no))
elif block_key == CHORUS:
self.addVerse(unicode(data, u'cp1252'),
self.addVerse(self.decode(data),
"%s%s" % (VerseType.Tags[VerseType.Chorus], verse_no))
elif block_key == BRIDGE:
self.addVerse(unicode(data, u'cp1252'),
self.addVerse(self.decode(data),
"%s%s" % (VerseType.Tags[VerseType.Bridge], verse_no))
elif block_key == TOPIC:
self.topics.append(unicode(data, u'cp1252'))
self.topics.append(self.decode(data))
elif block_key == COMMENTS:
self.comments = unicode(data, u'cp1252')
self.comments = self.decode(data)
elif block_key == VERSE_ORDER:
verse_tag = self.toOpenLPVerseTag(data, True)
if verse_tag:
if not isinstance(verse_tag, unicode):
verse_tag = unicode(verse_tag, u'cp1252')
verse_tag = self.decode(verse_tag)
self.sspVerseOrderList.append(verse_tag)
elif block_key == SONG_BOOK:
self.songBookName = unicode(data, u'cp1252')
self.songBookName = self.decode(data)
elif block_key == SONG_NUMBER:
self.songNumber = ord(data)
elif block_key == CUSTOM_VERSE:
verse_tag = self.toOpenLPVerseTag(verse_name)
self.addVerse(unicode(data, u'cp1252'), verse_tag)
self.addVerse(self.decode(data), verse_tag)
else:
log.debug("Unrecognised blockKey: %s, data: %s"
% (block_key, data))
@ -221,3 +222,9 @@ class SongShowPlusImport(SongImport):
verse_tag = VerseType.Tags[VerseType.Other]
verse_number = self.otherList[verse_name]
return verse_tag + verse_number
def decode(self, data):
try:
return unicode(data, chardet.detect(data)['encoding'])
except:
return unicode(data, retrieve_windows_encoding())

View File

@ -68,7 +68,7 @@ class SundayPlusImport(SongImport):
for filename in self.importSource:
if self.stopImportFlag:
return
song_file = open(filename)
song_file = open(filename, 'rb')
self.doImportFile(song_file)
song_file.close()
@ -96,7 +96,7 @@ class SundayPlusImport(SongImport):
# Now we are looking for the name.
if data[i:i + 1] == '#':
name_end = data.find(':', i + 1)
name = data[i + 1:name_end]
name = data[i + 1:name_end].upper()
i = name_end + 1
while data[i:i + 1] == ' ':
i += 1
@ -122,13 +122,13 @@ class SundayPlusImport(SongImport):
value = data[i:end]
# If we are in the main group.
if cell == False:
if name == 'title':
if name == 'TITLE':
self.title = self.decode(self.unescape(value))
elif name == 'Author':
elif name == 'AUTHOR':
author = self.decode(self.unescape(value))
if len(author):
self.addAuthor(author)
elif name == 'Copyright':
elif name == 'COPYRIGHT':
self.copyright = self.decode(self.unescape(value))
elif name[0:4] == 'CELL':
self.parse(value, cell = name[4:])
@ -142,13 +142,13 @@ class SundayPlusImport(SongImport):
if len(value) >= 2 and value[-1] in ['0', '1', '2',
'3', '4', '5', '6', '7', '8', '9']:
verse_type = "%s%s" % (verse_type, value[-1])
elif name == 'Hotkey':
elif name == 'HOTKEY':
# Hotkey always appears after MARKER_NAME, so it
# effectively overrides MARKER_NAME, if present.
if len(value) and \
value in HOTKEY_TO_VERSE_TYPE.keys():
verse_type = HOTKEY_TO_VERSE_TYPE[value]
if name == 'rtf':
if name == 'RTF':
value = self.unescape(value)
result = strip_rtf(value, self.encoding)
if result is None:

View File

@ -79,6 +79,33 @@ NAMESPACE = u'http://openlyrics.info/namespace/2009/song'
NSMAP = '{' + NAMESPACE + '}' + '%s'
def clean_xml_string(xml):
"""
Filter out invalid characters in xml
Source <http://stackoverflow.com/questions/8733233/filtering-out-certain-bytes-in-python>
``xml``
The actual text to be checked.
"""
return ''.join(char for char in xml if valid_XML_char_ordinal(ord(char)))
def valid_XML_char_ordinal(char):
"""
Undertake the filter test.
``char``
The individual character to be checked.
"""
return (
0x20 <= char <= 0xD7FF
or char in (0x9, 0xA, 0xD)
or 0xE000 <= char <= 0xFFFD
or 0x10000 <= char <= 0x10FFFF
)
class SongXML(object):
"""
This class builds and parses the XML used to describe songs.
@ -112,6 +139,7 @@ class SongXML(object):
The verse's language code (ISO-639). This is not required, but
should be added if available.
"""
content = clean_xml_string(content)
verse = etree.Element(u'verse', type=unicode(type),
label=unicode(number))
if lang: