This commit is contained in:
Andreas Preikschat 2010-12-23 06:51:09 +01:00
commit ab4d7e7294
72 changed files with 26625 additions and 15344 deletions

View File

@ -113,6 +113,14 @@ class ImageManager(QtCore.QObject):
time.sleep(0.1)
return self._cache[name].image_bytes
def del_image(self, name):
"""
Delete the Image from the Cache
"""
log.debug(u'del_image %s' % name)
if name in self._cache:
del self._cache[name]
def add_image(self, name, path):
"""
Add image to cache if it is not already there
@ -125,6 +133,8 @@ class ImageManager(QtCore.QObject):
image.image = resize_image(path,
self.width, self.height)
self._cache[name] = image
else:
log.debug(u'Image in cache %s:%s' % (name, path))
self._cache_dirty = True
# only one thread please
if not self._thread_running:

View File

@ -0,0 +1,38 @@
PSF LICENSE AGREEMENT FOR PYTHON 2.7.1
1. This LICENSE AGREEMENT is between the Python Software Foundation ("PSF"),
and the Individual or Organization ("Licensee") accessing and otherwise
using Python 2.7.1 software in source or binary form and its associated
documentation.
2. Subject to the terms and conditions of this License Agreement, PSF hereby
grants Licensee a nonexclusive, royalty-free, world-wide license to
reproduce, analyze, test, perform and/or display publicly, prepare
derivative works, distribute, and otherwise use Python 2.7.1 alone or in any
derivative version, provided, however, that PSF's License Agreement and
PSF's notice of copyright, i.e., "Copyright (c) 2001-2010 Python Software
Foundation; All Rights Reserved" are retained in Python 2.7.1 alone or in
any derivative version prepared by Licensee.
3. In the event Licensee prepares a derivative work that is based on or
incorporates Python 2.7.1 or any part thereof, and wants to make the
derivative work available to others as provided herein, then Licensee hereby
agrees to include in any such work a brief summary of the changes made to
Python 2.7.1.
4. PSF is making Python 2.7.1 available to Licensee on an "AS IS" basis. PSF
MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF
EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION
OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT
THE USE OF PYTHON 2.7.1 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS.
5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 2.7.1 FOR
ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF
MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 2.7.1, OR ANY DERIVATIVE
THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
6. This License Agreement will automatically terminate upon a material breach
of its terms and conditions.
7. Nothing in this License Agreement shall be deemed to create any relationship
of agency, partnership, or joint venture between PSF and Licensee. This
License Agreement does not grant permission to use PSF trademarks or trade
name in a trademark sense to endorse or promote products or services of
Licensee, or any third party.
8. By copying, installing or otherwise using Python 2.7.1, Licensee agrees to
be bound by the terms and conditions of this License Agreement.

View File

@ -0,0 +1,321 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
###############################################################################
# Utilities for opening files or URLs in the registered default application #
# and for sending e-mail using the user's preferred composer. #
# --------------------------------------------------------------------------- #
# Copyright (c) 2007 Antonio Valentino #
# All rights reserved. #
# --------------------------------------------------------------------------- #
# This program offered under the PSF License as published by the Python #
# Software Foundation. #
# #
# The license text can be found at http://docs.python.org/license.html #
# #
# This code is taken from: http://code.activestate.com/recipes/511443 #
# Modified for use in OpenLP #
###############################################################################
__version__ = u'1.1'
__all__ = [u'open', u'mailto']
import os
import sys
import webbrowser
import subprocess
from email.Utils import encode_rfc2231
_controllers = {}
_open = None
class BaseController(object):
"""
Base class for open program controllers.
"""
def __init__(self, name):
self.name = name
def open(self, filename):
raise NotImplementedError
class Controller(BaseController):
"""
Controller for a generic open program.
"""
def __init__(self, *args):
super(Controller, self).__init__(os.path.basename(args[0]))
self.args = list(args)
def _invoke(self, cmdline):
if sys.platform[:3] == u'win':
closefds = False
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
else:
closefds = True
startupinfo = None
if (os.environ.get(u'DISPLAY') or sys.platform[:3] == u'win' or \
sys.platform == u'darwin'):
inout = file(os.devnull, u'r+')
else:
# for TTY programs, we need stdin/out
inout = None
# if possible, put the child precess in separate process group,
# so keyboard interrupts don't affect child precess as well as
# Python
setsid = getattr(os, u'setsid', None)
if not setsid:
setsid = getattr(os, u'setpgrp', None)
pipe = subprocess.Popen(cmdline, stdin=inout, stdout=inout,
stderr=inout, close_fds=closefds, preexec_fn=setsid,
startupinfo=startupinfo)
# It is assumed that this kind of tools (gnome-open, kfmclient,
# exo-open, xdg-open and open for OSX) immediately exit after lauching
# the specific application
returncode = pipe.wait()
if hasattr(self, u'fixreturncode'):
returncode = self.fixreturncode(returncode)
return not returncode
def open(self, filename):
if isinstance(filename, basestring):
cmdline = self.args + [filename]
else:
# assume it is a sequence
cmdline = self.args + filename
try:
return self._invoke(cmdline)
except OSError:
return False
# Platform support for Windows
if sys.platform[:3] == u'win':
class Start(BaseController):
"""
Controller for the win32 start progam through os.startfile.
"""
def open(self, filename):
try:
os.startfile(filename)
except WindowsError:
# [Error 22] No application is associated with the specified
# file for this operation: '<URL>'
return False
else:
return True
_controllers[u'windows-default'] = Start(u'start')
_open = _controllers[u'windows-default'].open
# Platform support for MacOS
elif sys.platform == u'darwin':
_controllers[u'open'] = Controller(u'open')
_open = _controllers[u'open'].open
# Platform support for Unix
else:
import commands
# @WARNING: use the private API of the webbrowser module
from webbrowser import _iscommand
class KfmClient(Controller):
"""
Controller for the KDE kfmclient program.
"""
def __init__(self, kfmclient=u'kfmclient'):
super(KfmClient, self).__init__(kfmclient, u'exec')
self.kde_version = self.detect_kde_version()
def detect_kde_version(self):
kde_version = None
try:
info = commands.getoutput(u'kfmclient --version')
for line in info.splitlines():
if line.startswith(u'KDE'):
kde_version = line.split(u':')[-1].strip()
break
except (OSError, RuntimeError):
pass
return kde_version
def fixreturncode(self, returncode):
if returncode is not None and self.kde_version > u'3.5.4':
return returncode
else:
return os.EX_OK
def detect_desktop_environment():
"""
Checks for known desktop environments
Return the desktop environments name, lowercase (kde, gnome, xfce)
or "generic"
"""
desktop_environment = u'generic'
if os.environ.get(u'KDE_FULL_SESSION') == u'true':
desktop_environment = u'kde'
elif os.environ.get(u'GNOME_DESKTOP_SESSION_ID'):
desktop_environment = u'gnome'
else:
try:
info = commands.getoutput(u'xprop -root _DT_SAVE_MODE')
if u' = "xfce4"' in info:
desktop_environment = u'xfce'
except (OSError, RuntimeError):
pass
return desktop_environment
def register_X_controllers():
if _iscommand(u'kfmclient'):
_controllers[u'kde-open'] = KfmClient()
for command in (u'gnome-open', u'exo-open', u'xdg-open'):
if _iscommand(command):
_controllers[command] = Controller(command)
def get():
controllers_map = {
u'gnome': u'gnome-open',
u'kde': u'kde-open',
u'xfce': u'exo-open',
}
desktop_environment = detect_desktop_environment()
try:
controller_name = controllers_map[desktop_environment]
return _controllers[controller_name].open
except KeyError:
if _controllers.has_key(u'xdg-open'):
return _controllers[u'xdg-open'].open
else:
return webbrowser.open
if os.environ.get(u'DISPLAY'):
register_X_controllers()
_open = get()
def open(filename):
"""
Open a file or an URL in the registered default application.
"""
return _open(filename)
def _fix_addersses(**kwargs):
for headername in (u'address', u'to', u'cc', u'bcc'):
try:
headervalue = kwargs[headername]
if not headervalue:
del kwargs[headername]
continue
elif not isinstance(headervalue, basestring):
# assume it is a sequence
headervalue = u','.join(headervalue)
except KeyError:
pass
except TypeError:
raise TypeError(u'string or sequence expected for "%s", %s '
u'found' % (headername, type(headervalue).__name__))
else:
translation_map = {u'%': u'%25', u'&': u'%26', u'?': u'%3F'}
for char, replacement in translation_map.items():
headervalue = headervalue.replace(char, replacement)
kwargs[headername] = headervalue
return kwargs
def mailto_format(**kwargs):
"""
Compile mailto string from call parameters
"""
# @TODO: implement utf8 option
kwargs = _fix_addersses(**kwargs)
parts = []
for headername in (u'to', u'cc', u'bcc', u'subject', u'body', u'attach'):
if kwargs.has_key(headername):
headervalue = kwargs[headername]
if not headervalue:
continue
if headername in (u'address', u'to', u'cc', u'bcc'):
parts.append(u'%s=%s' % (headername, headervalue))
else:
headervalue = encode_rfc2231(headervalue) # @TODO: check
parts.append(u'%s=%s' % (headername, headervalue))
mailto_string = u'mailto:%s' % kwargs.get(u'address', '')
if parts:
mailto_string = u'%s?%s' % (mailto_string, u'&'.join(parts))
return mailto_string
def mailto(address, to=None, cc=None, bcc=None, subject=None, body=None,
attach=None):
"""
Send an e-mail using the user's preferred composer.
Open the user's preferred e-mail composer in order to send a mail to
address(es) that must follow the syntax of RFC822. Multiple addresses
may be provided (for address, cc and bcc parameters) as separate
arguments.
All parameters provided are used to prefill corresponding fields in
the user's e-mail composer. The user will have the opportunity to
change any of this information before actually sending the e-mail.
``address``
specify the destination recipient
``cc``
specify a recipient to be copied on the e-mail
``bcc``
specify a recipient to be blindly copied on the e-mail
``subject``
specify a subject for the e-mail
``body``
specify a body for the e-mail. Since the user will be able to make
changes before actually sending the e-mail, this can be used to provide
the user with a template for the e-mail text may contain linebreaks
``attach``
specify an attachment for the e-mail. file must point to an existing
file
"""
mailto_string = mailto_format(**locals())
return open(mailto_string)

View File

@ -108,7 +108,7 @@ class Plugin(QtCore.QObject):
"""
log.info(u'loaded')
def __init__(self, name, version=None, plugin_helpers=None):
def __init__(self, name, version=None, pluginHelpers=None):
"""
This is the constructor for the plugin object. This provides an easy
way for descendent plugins to populate common data. This method *must*
@ -124,7 +124,7 @@ class Plugin(QtCore.QObject):
``version``
Defaults to *None*. The version of the plugin.
``plugin_helpers``
``pluginHelpers``
Defaults to *None*. A list of helper objects.
"""
QtCore.QObject.__init__(self)
@ -139,14 +139,14 @@ class Plugin(QtCore.QObject):
self.status = PluginStatus.Inactive
# Set up logging
self.log = logging.getLogger(self.name)
self.previewController = plugin_helpers[u'preview']
self.liveController = plugin_helpers[u'live']
self.renderManager = plugin_helpers[u'render']
self.serviceManager = plugin_helpers[u'service']
self.settingsForm = plugin_helpers[u'settings form']
self.mediadock = plugin_helpers[u'toolbox']
self.pluginManager = plugin_helpers[u'pluginmanager']
self.formparent = plugin_helpers[u'formparent']
self.previewController = pluginHelpers[u'preview']
self.liveController = pluginHelpers[u'live']
self.renderManager = pluginHelpers[u'render']
self.serviceManager = pluginHelpers[u'service']
self.settingsForm = pluginHelpers[u'settings form']
self.mediadock = pluginHelpers[u'toolbox']
self.pluginManager = pluginHelpers[u'pluginmanager']
self.formparent = pluginHelpers[u'formparent']
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'%s_add_service_item' % self.name),
self.processAddServiceEvent)

View File

@ -213,6 +213,8 @@ class RenderManager(object):
# make big page for theme edit dialog to get line count
if self.force_page:
verse = verse + verse + verse
else:
self.image_manager.del_image(self.theme_data.theme_name)
footer = []
footer.append(u'Arky Arky (Unknown)' )
footer.append(u'Public Domain')

View File

@ -44,6 +44,7 @@ class ServiceItemType(object):
Image = 2
Command = 3
class ItemCapabilities(object):
"""
Provides an enumeration of a serviceitem's capabilities

View File

@ -166,6 +166,17 @@ class Ui_AboutDialog(object):
' PyQt4: http://www.riverbankcomputing.co.uk/software/pyqt/'
'intro\n'
' Oxygen Icons: http://oxygen-icons.org/\n'
'\n'
'Final Credit\n'
' "For God so loved the world that He gave\n'
' His one and only Son, so that whoever\n'
' believes in Him will not perish but inherit\n'
' eternal life." -- John 3:16\n\n'
' And last but not least, final credit goes to\n'
' God our Father, for sending His Son to die\n'
' on the cross, setting us free from sin. We\n'
' bring this software to you for free because\n'
' He has set us free.'
))
self.aboutNotebook.setTabText(
self.aboutNotebook.indexOf(self.creditsTab),

View File

@ -26,7 +26,7 @@
from PyQt4 import QtCore, QtGui
from openlp.core.lib import translate
from openlp.core.lib import translate, build_icon
class Ui_ExceptionDialog(object):
def setupUi(self, exceptionDialog):
@ -63,12 +63,27 @@ class Ui_ExceptionDialog(object):
self.exceptionButtonBox.setStandardButtons(QtGui.QDialogButtonBox.Close)
self.exceptionButtonBox.setObjectName(u'exceptionButtonBox')
self.exceptionLayout.addWidget(self.exceptionButtonBox)
self.sendReportButton = QtGui.QPushButton(exceptionDialog)
self.sendReportButton.setIcon(build_icon(
u':/general/general_email.png'))
self.sendReportButton.setObjectName(u'sendReportButton')
self.exceptionButtonBox.addButton(self.sendReportButton,
QtGui.QDialogButtonBox.ActionRole)
self.saveReportButton = QtGui.QPushButton(exceptionDialog)
self.saveReportButton.setIcon(build_icon(u':/general/general_save.png'))
self.saveReportButton.setObjectName(u'saveReportButton')
self.exceptionButtonBox.addButton(self.saveReportButton,
QtGui.QDialogButtonBox.ActionRole)
self.retranslateUi(exceptionDialog)
QtCore.QObject.connect(self.exceptionButtonBox,
QtCore.SIGNAL(u'accepted()'), exceptionDialog.accept)
QtCore.QObject.connect(self.exceptionButtonBox,
QtCore.SIGNAL(u'rejected()'), exceptionDialog.reject)
QtCore.QObject.connect(self.sendReportButton,
QtCore.SIGNAL(u'pressed()'), self.onSendReportButtonPressed)
QtCore.QObject.connect(self.saveReportButton,
QtCore.SIGNAL(u'pressed()'), self.onSaveReportButtonPressed)
QtCore.QMetaObject.connectSlotsByName(exceptionDialog)
def retranslateUi(self, exceptionDialog):
@ -80,3 +95,7 @@ class Ui_ExceptionDialog(object):
'developers, so please e-mail it to bugs@openlp.org, along with a '
'detailed description of what you were doing when the problem '
'occurred.'))
self.sendReportButton.setText(translate('OpenLP.ExceptionDialog',
'Send E-Mail'))
self.saveReportButton.setText(translate('OpenLP.ExceptionDialog',
'Save to File'))

View File

@ -23,11 +23,44 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
import logging
import re
import os
import platform
from PyQt4 import QtGui
import sqlalchemy
import BeautifulSoup
from lxml import etree
from PyQt4 import Qt, QtCore, QtGui
try:
from PyQt4.phonon import Phonon
phonon_version = Phonon.phononVersion()
except ImportError:
phonon_version = u'-'
try:
import chardet
chardet_version = chardet.__version__
except ImportError:
chardet_version = u'-'
try:
import enchant
enchant_version = enchant.__version__
except ImportError:
enchant_version = u'-'
try:
import sqlite
sqlite_version = sqlite.version
except ImportError:
sqlite_version = u'-'
from openlp.core.lib import translate, SettingsManager
from openlp.core.lib.mailto import mailto
from exceptiondialog import Ui_ExceptionDialog
log = logging.getLogger(__name__)
class ExceptionForm(QtGui.QDialog, Ui_ExceptionDialog):
"""
The exception dialog
@ -35,3 +68,80 @@ class ExceptionForm(QtGui.QDialog, Ui_ExceptionDialog):
def __init__(self, parent):
QtGui.QDialog.__init__(self, parent)
self.setupUi(self)
self.settingsSection = u'crashreport'
def _createReport(self):
openlp_version = self.parent().applicationVersion[u'full']
traceback = unicode(self.exceptionTextEdit.toPlainText())
system = unicode(translate('OpenLP.ExceptionForm',
'Platform: %s\n')) % platform.platform()
libraries = u'Python: %s\n' % platform.python_version() + \
u'Qt4: %s\n' % Qt.qVersion() + \
u'Phonon: %s\n' % phonon_version + \
u'PyQt4: %s\n' % Qt.PYQT_VERSION_STR + \
u'SQLAlchemy: %s\n' % sqlalchemy.__version__ + \
u'BeautifulSoup: %s\n' % BeautifulSoup.__version__ + \
u'lxml: %s\n' % etree.__version__ + \
u'Chardet: %s\n' % chardet_version + \
u'PyEnchant: %s\n' % enchant_version + \
u'PySQLite: %s\n' % sqlite_version
if platform.system() == u'Linux':
if os.environ.get(u'KDE_FULL_SESSION') == u'true':
system = system + u'Desktop: KDE SC\n'
elif os.environ.get(u'GNOME_DESKTOP_SESSION_ID'):
system = system + u'Desktop: GNOME\n'
return (openlp_version, traceback, system, libraries)
def onSaveReportButtonPressed(self):
"""
Saving exception log and system informations to a file.
"""
report = unicode(translate('OpenLP.ExceptionForm',
'**OpenLP Bug Report**\n'
'Version: %s\n\n'
'--- Exception Traceback ---\n%s\n'
'--- System information ---\n%s\n'
'--- Library Versions ---\n%s\n'))
filename = QtGui.QFileDialog.getSaveFileName(self,
translate('OpenLP.ExceptionForm', 'Save Crash Report'),
SettingsManager.get_last_dir(self.settingsSection),
translate('OpenLP.ExceptionForm',
'Text files (*.txt *.log *.text)'))
if filename:
filename = unicode(QtCore.QDir.toNativeSeparators(filename))
SettingsManager.set_last_dir(self.settingsSection, os.path.dirname(
filename))
report = report % self._createReport()
try:
file = open(filename, u'w')
try:
file.write(report)
except UnicodeError:
file.close()
file = open(filename, u'wb')
file.write(report.encode(u'utf-8'))
file.close()
except IOError:
log.exception(u'Failed to write crash report')
def onSendReportButtonPressed(self):
"""
Opening systems default email client and inserting exception log and
system informations.
"""
body = unicode(translate('OpenLP.ExceptionForm',
'*OpenLP Bug Report*\n'
'Version: %s\n\n'
'--- Please enter the report below this line. ---\n\n\n'
'--- Exception Traceback ---\n%s\n'
'--- System information ---\n%s\n'
'--- Library Versions ---\n%s\n'))
content = self._createReport()
for line in content[1].split(u'\n'):
if re.search(r'[/\\]openlp[/\\]', line):
source = re.sub(r'.*[/\\]openlp[/\\](.*)".*', r'\1', line)
if u':' in line:
exception = line.split(u'\n')[-1].split(u':')[0]
subject = u'Bug report: %s in %s' % (exception, source)
mailto(address=u'bugs@openlp.org', subject=subject,
body=body % content)

View File

@ -30,24 +30,24 @@ from openlp.core.lib import translate
class Ui_FileRenameDialog(object):
def setupUi(self, FileRenameDialog):
FileRenameDialog.setObjectName("FileRenameDialog")
FileRenameDialog.setObjectName(u'FileRenameDialog')
FileRenameDialog.resize(400, 87)
self.buttonBox = QtGui.QDialogButtonBox(FileRenameDialog)
self.buttonBox.setGeometry(QtCore.QRect(210, 50, 171, 25))
self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel |
QtGui.QDialogButtonBox.Ok)
self.buttonBox.setObjectName("buttonBox")
self.buttonBox.setObjectName(u'buttonBox')
self.widget = QtGui.QWidget(FileRenameDialog)
self.widget.setGeometry(QtCore.QRect(10, 10, 381, 35))
self.widget.setObjectName("widget")
self.widget.setObjectName(u'widget')
self.horizontalLayout = QtGui.QHBoxLayout(self.widget)
self.horizontalLayout.setObjectName("horizontalLayout")
self.FileRenameLabel = QtGui.QLabel(self.widget)
self.FileRenameLabel.setObjectName("FileRenameLabel")
self.horizontalLayout.addWidget(self.FileRenameLabel)
self.FileNameEdit = QtGui.QLineEdit(self.widget)
self.FileNameEdit.setObjectName("FileNameEdit")
self.horizontalLayout.addWidget(self.FileNameEdit)
self.horizontalLayout.setObjectName(u'horizontalLayout')
self.fileRenameLabel = QtGui.QLabel(self.widget)
self.fileRenameLabel.setObjectName(u'fileRenameLabel')
self.horizontalLayout.addWidget(self.fileRenameLabel)
self.fileNameEdit = QtGui.QLineEdit(self.widget)
self.fileNameEdit.setObjectName(u'fileNameEdit')
self.horizontalLayout.addWidget(self.fileNameEdit)
self.retranslateUi(FileRenameDialog)
QtCore.QMetaObject.connectSlotsByName(FileRenameDialog)
@ -55,6 +55,5 @@ class Ui_FileRenameDialog(object):
def retranslateUi(self, FileRenameDialog):
FileRenameDialog.setWindowTitle(translate('OpenLP.FileRenameForm',
'File Rename'))
self.FileRenameLabel.setText(translate('OpenLP.FileRenameForm',
self.fileRenameLabel.setText(translate('OpenLP.FileRenameForm',
'New File Name:'))

View File

@ -97,16 +97,16 @@ class Ui_MainWindow(object):
self.ControlSplitter.setObjectName(u'ControlSplitter')
self.MainContentLayout.addWidget(self.ControlSplitter)
# Create slide controllers
self.PreviewController = SlideController(self, self.settingsmanager,
self.previewController = SlideController(self, self.settingsmanager,
self.screens)
self.LiveController = SlideController(self, self.settingsmanager,
self.liveController = SlideController(self, self.settingsmanager,
self.screens, True)
previewVisible = QtCore.QSettings().value(
u'user interface/preview panel', QtCore.QVariant(True)).toBool()
self.PreviewController.Panel.setVisible(previewVisible)
self.previewController.Panel.setVisible(previewVisible)
liveVisible = QtCore.QSettings().value(u'user interface/live panel',
QtCore.QVariant(True)).toBool()
self.LiveController.Panel.setVisible(liveVisible)
self.liveController.Panel.setVisible(liveVisible)
# Create menu
self.MenuBar = QtGui.QMenuBar(MainWindow)
self.MenuBar.setGeometry(QtCore.QRect(0, 0, 1087, 27))
@ -362,8 +362,8 @@ class Ui_MainWindow(object):
"""
Splitter between the Preview and Live Controllers.
"""
self.LiveController.widthChanged()
self.PreviewController.widthChanged()
self.liveController.widthChanged()
self.previewController.widthChanged()
def retranslateUi(self, MainWindow):
"""
@ -548,8 +548,8 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.recentFiles = QtCore.QStringList()
# Set up the path with plugins
pluginpath = AppLocation.get_directory(AppLocation.PluginsDir)
self.plugin_manager = PluginManager(pluginpath)
self.plugin_helpers = {}
self.pluginManager = PluginManager(pluginpath)
self.pluginHelpers = {}
# Set up the interface
self.setupUi(self)
# Load settings after setupUi so default UI sizes are overwritten
@ -633,33 +633,33 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.mediaDockManager = MediaDockManager(self.MediaToolBox)
log.info(u'Load Plugins')
# make the controllers available to the plugins
self.plugin_helpers[u'preview'] = self.PreviewController
self.plugin_helpers[u'live'] = self.LiveController
self.plugin_helpers[u'render'] = self.renderManager
self.plugin_helpers[u'service'] = self.ServiceManagerContents
self.plugin_helpers[u'settings form'] = self.settingsForm
self.plugin_helpers[u'toolbox'] = self.mediaDockManager
self.plugin_helpers[u'pluginmanager'] = self.plugin_manager
self.plugin_helpers[u'formparent'] = self
self.plugin_manager.find_plugins(pluginpath, self.plugin_helpers)
self.pluginHelpers[u'preview'] = self.previewController
self.pluginHelpers[u'live'] = self.liveController
self.pluginHelpers[u'render'] = self.renderManager
self.pluginHelpers[u'service'] = self.ServiceManagerContents
self.pluginHelpers[u'settings form'] = self.settingsForm
self.pluginHelpers[u'toolbox'] = self.mediaDockManager
self.pluginHelpers[u'pluginmanager'] = self.pluginManager
self.pluginHelpers[u'formparent'] = self
self.pluginManager.find_plugins(pluginpath, self.pluginHelpers)
# hook methods have to happen after find_plugins. Find plugins needs
# the controllers hence the hooks have moved from setupUI() to here
# Find and insert settings tabs
log.info(u'hook settings')
self.plugin_manager.hook_settings_tabs(self.settingsForm)
self.pluginManager.hook_settings_tabs(self.settingsForm)
# Find and insert media manager items
log.info(u'hook media')
self.plugin_manager.hook_media_manager(self.mediaDockManager)
self.pluginManager.hook_media_manager(self.mediaDockManager)
# Call the hook method to pull in import menus.
log.info(u'hook menus')
self.plugin_manager.hook_import_menu(self.FileImportMenu)
self.pluginManager.hook_import_menu(self.FileImportMenu)
# Call the hook method to pull in export menus.
self.plugin_manager.hook_export_menu(self.FileExportMenu)
self.pluginManager.hook_export_menu(self.FileExportMenu)
# Call the hook method to pull in tools menus.
self.plugin_manager.hook_tools_menu(self.ToolsMenu)
self.pluginManager.hook_tools_menu(self.ToolsMenu)
# Call the initialise method to setup plugins.
log.info(u'initialise plugins')
self.plugin_manager.initialise_plugins()
self.pluginManager.initialise_plugins()
# Once all components are initialised load the Themes
log.info(u'Load Themes')
self.ThemeManagerContents.loadThemes()
@ -695,10 +695,10 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
Show the main form, as well as the display form
"""
QtGui.QWidget.show(self)
self.LiveController.display.setup()
self.PreviewController.display.setup()
if self.LiveController.display.isVisible():
self.LiveController.display.setFocus()
self.liveController.display.setup()
self.previewController.display.setup()
if self.liveController.display.isVisible():
self.liveController.display.setFocus()
self.activateWindow()
if QtCore.QSettings().value(
self.generalSettingsSection + u'/auto open',
@ -723,7 +723,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
settings = QtCore.QSettings()
if settings.value(u'%s/screen blank' % self.generalSettingsSection,
QtCore.QVariant(False)).toBool():
self.LiveController.mainDisplaySetBackground()
self.liveController.mainDisplaySetBackground()
if settings.value(u'blank warning',
QtCore.QVariant(False)).toBool():
QtGui.QMessageBox.question(self,
@ -852,11 +852,11 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
QtCore.QVariant(self.MediaToolBox.currentIndex()))
# Call the cleanup method to shutdown plugins.
log.info(u'cleanup plugins')
self.plugin_manager.finalise_plugins()
self.pluginManager.finalise_plugins()
# Save settings
self.saveSettings()
# Close down the display
self.LiveController.display.close()
self.liveController.display.close()
def serviceChanged(self, reset=False, serviceName=None):
"""
@ -910,7 +910,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
True - Visible
False - Hidden
"""
self.PreviewController.Panel.setVisible(visible)
self.previewController.Panel.setVisible(visible)
QtCore.QSettings().setValue(u'user interface/preview panel',
QtCore.QVariant(visible))
self.ViewPreviewPanel.setChecked(visible)
@ -925,7 +925,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
True - Visible
False - Hidden
"""
self.LiveController.Panel.setVisible(visible)
self.liveController.Panel.setVisible(visible)
QtCore.QSettings().setValue(u'user interface/live panel',
QtCore.QVariant(visible))
self.ViewLivePanel.setChecked(visible)

View File

@ -61,7 +61,7 @@ class PluginForm(QtGui.QDialog, Ui_PluginViewDialog):
self.programaticChange = True
self._clearDetails()
self.programaticChange = True
for plugin in self.parent.plugin_manager.plugins:
for plugin in self.parent.pluginManager.plugins:
item = QtGui.QListWidgetItem(self.pluginListWidget)
# We do this just to make 100% sure the status is an integer as
# sometimes when it's loaded from the config, it isn't cast to int.
@ -110,7 +110,7 @@ class PluginForm(QtGui.QDialog, Ui_PluginViewDialog):
plugin_name_plural = \
self.pluginListWidget.currentItem().text().split(u' ')[0]
self.activePlugin = None
for plugin in self.parent.plugin_manager.plugins:
for plugin in self.parent.pluginManager.plugins:
name_string = plugin.getString(StringContent.Name)
if name_string[u'plural'] == plugin_name_plural:
self.activePlugin = plugin

View File

@ -64,8 +64,7 @@ class ServiceItemEditForm(QtGui.QDialog, Ui_ServiceItemEditDialog):
self.item._raw_frames = []
if self.item.is_image():
for item in self.itemList:
self.item.add_from_image(item[u'path'], item[u'title'],
item[u'image'])
self.item.add_from_image(item[u'path'], item[u'title'])
self.item.render()
return self.item

View File

@ -880,7 +880,7 @@ class ServiceManager(QtGui.QWidget):
newItem.merge(item[u'service_item'])
item[u'service_item'] = newItem
self.repaintServiceList(itemcount + 1, 0)
self.parent.LiveController.replaceServiceManagerItem(newItem)
self.parent.liveController.replaceServiceManagerItem(newItem)
self.parent.serviceChanged(False, self.serviceName)
def addServiceItem(self, item, rebuild=False, expand=None, replace=False):
@ -902,7 +902,7 @@ class ServiceManager(QtGui.QWidget):
item.merge(self.serviceItems[sitem][u'service_item'])
self.serviceItems[sitem][u'service_item'] = item
self.repaintServiceList(sitem + 1, 0)
self.parent.LiveController.replaceServiceManagerItem(item)
self.parent.liveController.replaceServiceManagerItem(item)
else:
# nothing selected for dnd
if self.droppos == 0:
@ -923,7 +923,7 @@ class ServiceManager(QtGui.QWidget):
self.repaintServiceList(self.droppos, 0)
# if rebuilding list make sure live is fixed.
if rebuild:
self.parent.LiveController.replaceServiceManagerItem(item)
self.parent.liveController.replaceServiceManagerItem(item)
self.droppos = 0
self.parent.serviceChanged(False, self.serviceName)
@ -933,7 +933,7 @@ class ServiceManager(QtGui.QWidget):
"""
item, count = self.findServiceItem()
if self.serviceItems[item][u'service_item'].is_valid:
self.parent.PreviewController.addServiceManagerItem(
self.parent.previewController.addServiceManagerItem(
self.serviceItems[item][u'service_item'], count)
else:
QtGui.QMessageBox.critical(self,
@ -957,7 +957,7 @@ class ServiceManager(QtGui.QWidget):
"""
item, count = self.findServiceItem()
if self.serviceItems[item][u'service_item'].is_valid:
self.parent.LiveController.addServiceManagerItem(
self.parent.liveController.addServiceManagerItem(
self.serviceItems[item][u'service_item'], count)
if QtCore.QSettings().value(
self.parent.generalSettingsSection + u'/auto preview',
@ -966,9 +966,9 @@ class ServiceManager(QtGui.QWidget):
if self.serviceItems and item < len(self.serviceItems) and \
self.serviceItems[item][u'service_item'].is_capable(
ItemCapabilities.AllowsPreview):
self.parent.PreviewController.addServiceManagerItem(
self.parent.previewController.addServiceManagerItem(
self.serviceItems[item][u'service_item'], 0)
self.parent.LiveController.PreviewListWidget.setFocus()
self.parent.liveController.PreviewListWidget.setFocus()
else:
QtGui.QMessageBox.critical(self,
translate('OpenLP.ServiceManager', 'Missing Display Handler'),

View File

@ -332,11 +332,12 @@ class SlideController(QtGui.QWidget):
QtCore.SIGNAL(u'clicked(QModelIndex)'), self.onSlideSelected)
if not self.isLive:
QtCore.QObject.connect(self.PreviewListWidget,
QtCore.SIGNAL(u'doubleClicked(QModelIndex)'), self.onGoLiveClick)
QtCore.SIGNAL(u'doubleClicked(QModelIndex)'),
self.onGoLiveClick)
if isLive:
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'slidecontroller_live_spin_delay'),
self.receiveSpinDelay)
self.receiveSpinDelay)
if isLive:
self.Toolbar.makeWidgetsInvisible(self.loopList)
self.Toolbar.actions[u'Stop Loop'].setVisible(False)
@ -466,7 +467,7 @@ class SlideController(QtGui.QWidget):
self.Toolbar.actions[u'Stop Loop'].setVisible(False)
if item.is_text():
if QtCore.QSettings().value(
self.parent.songsSettingsSection + u'/show songbar',
self.parent.songsSettingsSection + u'/display songbar',
QtCore.QVariant(True)).toBool() and len(self.slideList) > 0:
self.Toolbar.makeWidgetsVisible([u'Song Menu'])
if item.is_capable(ItemCapabilities.AllowsLoop) and \
@ -560,7 +561,7 @@ class SlideController(QtGui.QWidget):
[serviceItem, self.isLive, blanked, slideno])
self.slideList = {}
width = self.parent.ControlSplitter.sizes()[self.split]
# Set pointing cursor when we have somthing to point at
# Set pointing cursor when we have something to point at
self.PreviewListWidget.setCursor(QtCore.Qt.PointingHandCursor)
self.serviceItem = serviceItem
self.PreviewListWidget.clear()
@ -957,7 +958,7 @@ class SlideController(QtGui.QWidget):
"""
row = self.PreviewListWidget.currentRow()
if row > -1 and row < self.PreviewListWidget.rowCount():
self.parent.LiveController.addServiceManagerItem(
self.parent.liveController.addServiceManagerItem(
self.serviceItem, row)
def onMediaStart(self, item):

View File

@ -289,6 +289,7 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard):
"""
Run the wizard.
"""
log.debug(u'Editing theme %s' % self.theme.theme_name)
self.updateThemeAllowed = False
self.setDefaults()
self.updateThemeAllowed = True
@ -444,7 +445,7 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard):
def setPreviewTabValues(self):
self.setField(u'name', QtCore.QVariant(self.theme.theme_name))
if len(self.theme.theme_name) > 1:
if len(self.theme.theme_name) > 0:
self.themeNameEdit.setEnabled(False)
else:
self.themeNameEdit.setEnabled(True)

View File

@ -225,10 +225,10 @@ class ThemeManager(QtGui.QWidget):
"""
item = self.themeListWidget.currentItem()
oldThemeName = unicode(item.data(QtCore.Qt.UserRole).toString())
self.fileRenameForm.FileNameEdit.setText(oldThemeName)
self.fileRenameForm.fileNameEdit.setText(oldThemeName)
self.saveThemeName = u''
if self.fileRenameForm.exec_():
newThemeName = unicode(self.fileRenameForm.FileNameEdit.text())
newThemeName = unicode(self.fileRenameForm.fileNameEdit.text())
oldThemeData = self.getThemeData(oldThemeName)
self.deleteTheme(oldThemeName)
self.cloneThemeData(oldThemeData, newThemeName)
@ -239,10 +239,10 @@ class ThemeManager(QtGui.QWidget):
"""
item = self.themeListWidget.currentItem()
oldThemeName = unicode(item.data(QtCore.Qt.UserRole).toString())
self.fileRenameForm.FileNameEdit.setText(oldThemeName)
self.fileRenameForm.fileNameEdit.setText(oldThemeName)
self.saveThemeName = u''
if self.fileRenameForm.exec_():
newThemeName = unicode(self.fileRenameForm.FileNameEdit.text())
newThemeName = unicode(self.fileRenameForm.fileNameEdit.text())
themeData = self.getThemeData(oldThemeName)
self.cloneThemeData(themeData, newThemeName)
self.loadThemes()
@ -310,7 +310,7 @@ class ThemeManager(QtGui.QWidget):
translate('OpenLP.ThemeManager',
'You are unable to delete the default theme.'))
else:
for plugin in self.parent.plugin_manager.plugins:
for plugin in self.parent.pluginManager.plugins:
if plugin.usesTheme(theme):
QtGui.QMessageBox.critical(self,
translate('OpenLP.ThemeManager', 'Error'),
@ -663,7 +663,7 @@ class ThemeManager(QtGui.QWidget):
(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No),
QtGui.QMessageBox.No)
if self.saveThemeName != u'':
for plugin in self.parent.plugin_manager.plugins:
for plugin in self.parent.pluginManager.plugins:
if plugin.usesTheme(self.saveThemeName):
plugin.renameTheme(self.saveThemeName, name)
if unicode(self.serviceComboBox.currentText()) == name:

View File

@ -555,7 +555,8 @@ class Ui_ThemeWizard(object):
u'footerDefaultPositionCheckBox')
self.footerPositionLayout.setWidget(0, QtGui.QFormLayout.FieldRole,
self.footerDefaultPositionCheckBox)
self.areaPositionLayout.addWidget(self.footerPositionGroupBox, 1, 1, 1, 1)
self.areaPositionLayout.addWidget(
self.footerPositionGroupBox, 1, 1, 1, 1)
ThemeWizard.addPage(self.areaPositionPage)
self.previewPage = QtGui.QWizardPage()
self.previewPage.setObjectName(u'previewPage')
@ -720,8 +721,8 @@ class Ui_ThemeWizard(object):
self.areaPositionPage.setTitle(
translate('OpenLP.ThemeWizard', 'Output Area Locations'))
self.areaPositionPage.setSubTitle(
translate('OpenLP.ThemeWizard', 'Allows you to change and move the '
'main and footer areas.'))
translate('OpenLP.ThemeWizard', 'Allows you to change and move the'
' main and footer areas.'))
self.mainPositionGroupBox.setTitle(
translate('OpenLP.ThemeWizard', '&Main Area'))
self.mainDefaultPositionCheckBox.setText(
@ -733,18 +734,24 @@ class Ui_ThemeWizard(object):
self.mainWidthSpinBox.setSuffix(translate('OpenLP.ThemeWizard', 'px'))
self.mainWidthLabel.setText(translate('OpenLP.ThemeWizard', 'Width:'))
self.mainHeightSpinBox.setSuffix(translate('OpenLP.ThemeWizard', 'px'))
self.mainHeightLabel.setText(translate('OpenLP.ThemeWizard', 'Height:'))
self.mainHeightLabel.setText(
translate('OpenLP.ThemeWizard', 'Height:'))
self.footerPositionGroupBox.setTitle(
translate('OpenLP.ThemeWizard', 'Footer Area'))
self.footerXLabel.setText(translate('OpenLP.ThemeWizard', 'X position:'))
self.footerXLabel.setText(
translate('OpenLP.ThemeWizard', 'X position:'))
self.footerXSpinBox.setSuffix(translate('OpenLP.ThemeWizard', 'px'))
self.footerYLabel.setText(translate('OpenLP.ThemeWizard', 'Y position:'))
self.footerYLabel.setText(
translate('OpenLP.ThemeWizard', 'Y position:'))
self.footerYSpinBox.setSuffix(translate('OpenLP.ThemeWizard', 'px'))
self.footerWidthLabel.setText(translate('OpenLP.ThemeWizard', 'Width:'))
self.footerWidthSpinBox.setSuffix(translate('OpenLP.ThemeWizard', 'px'))
self.footerWidthLabel.setText(
translate('OpenLP.ThemeWizard', 'Width:'))
self.footerWidthSpinBox.setSuffix(
translate('OpenLP.ThemeWizard', 'px'))
self.footerHeightLabel.setText(
translate('OpenLP.ThemeWizard', 'Height:'))
self.footerHeightSpinBox.setSuffix(translate('OpenLP.ThemeWizard', 'px'))
self.footerHeightSpinBox.setSuffix(
translate('OpenLP.ThemeWizard', 'px'))
self.footerDefaultPositionCheckBox.setText(
translate('OpenLP.ThemeWizard', 'Use default location'))
self.previewPage.setTitle(

View File

@ -171,24 +171,23 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog):
# We found '<>' in the alert text, but the ParameterEdit field is
# empty.
if text.find(u'<>') != -1 and not self.ParameterEdit.text() and \
QtGui.QMessageBox.question(self, translate(
'AlertPlugin.AlertForm', 'No Parameter found'),
translate('AlertPlugin.AlertForm', 'You have not entered a '
'parameter to be replaced.\nDo you want to continue '
'anyway?'),
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.No |
QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.No:
QtGui.QMessageBox.question(self,
translate('AlertPlugin.AlertForm', 'No Parameter found'),
translate('AlertPlugin.AlertForm', 'You have not entered a '
'parameter to be replaced.\nDo you want to continue anyway?'),
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.No |
QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.No:
self.ParameterEdit.setFocus()
return False
# The ParameterEdit field is not empty, but we have not found '<>'
# in the alert text.
elif text.find(u'<>') == -1 and self.ParameterEdit.text() and \
QtGui.QMessageBox.question(self, translate(
'AlertPlugin.AlertForm', 'No Placeholder found'),
translate('AlertPlugin.AlertForm', 'The alert text does not'
' contain \'<>\'.\nDo want to continue anyway?'),
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.No |
QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.No:
QtGui.QMessageBox.question(self,
translate('AlertPlugin.AlertForm', 'No Placeholder found'),
translate('AlertPlugin.AlertForm', 'The alert text does not'
' contain \'<>\'.\nDo want to continue anyway?'),
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.No |
QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.No:
self.ParameterEdit.setFocus()
return False
text = text.replace(u'<>', unicode(self.ParameterEdit.text()))

View File

@ -43,10 +43,12 @@ class WebDownload(object):
Unknown = -1
Crosswalk = 0
BibleGateway = 1
Bibleserver = 2
Names = {
0: u'Crosswalk',
1: u'BibleGateway'
1: u'BibleGateway',
2: u'Bibleserver'
}
@classmethod
@ -232,8 +234,7 @@ class BibleImportForm(QtGui.QWizard, Ui_BibleImportWizard):
The index of the combo box.
"""
self.bibleComboBox.clear()
bibles = [unicode(translate('BiblesPlugin.ImportWizardForm', bible)) for
bible in self.web_bible_list[index].keys()]
bibles = self.web_bible_list[index].keys()
bibles.sort()
for bible in bibles:
self.bibleComboBox.addItem(bible)
@ -252,14 +253,16 @@ class BibleImportForm(QtGui.QWizard, Ui_BibleImportWizard):
"""
self.getFileName(
translate('BiblesPlugin.ImportWizardForm', 'Open Books CSV File'),
self.booksLocationEdit)
self.booksLocationEdit, u'%s (*.csv)'
% translate('BiblesPlugin.ImportWizardForm', 'CSV File'))
def onCsvVersesFileButtonClicked(self):
"""
Show the file open dialog for the verses CSV file.
"""
self.getFileName(translate('BiblesPlugin.ImportWizardForm',
'Open Verses CSV File'), self.csvVerseLocationEdit)
'Open Verses CSV File'), self.csvVerseLocationEdit, u'%s (*.csv)'
% translate('BiblesPlugin.ImportWizardForm', 'CSV File'))
def onOpenSongBrowseButtonClicked(self):
"""
@ -275,7 +278,9 @@ class BibleImportForm(QtGui.QWizard, Ui_BibleImportWizard):
"""
self.getFileName(
translate('BiblesPlugin.ImportWizardForm',
'Open openlp.org 1.x Bible'), self.openlp1LocationEdit)
'Open openlp.org 1.x Bible'), self.openlp1LocationEdit,
u'%s (*.bible)' % translate('BiblesPlugin.ImportWizardForm',
'openlp.org 1.x bible'))
def onCurrentIdChanged(self, pageId):
if pageId == 3:
@ -338,31 +343,27 @@ class BibleImportForm(QtGui.QWizard, Ui_BibleImportWizard):
"""
Load the list of Crosswalk and BibleGateway bibles.
"""
# Load and store Crosswalk Bibles.
# Load Crosswalk Bibles.
filepath = AppLocation.get_directory(AppLocation.PluginsDir)
filepath = os.path.join(filepath, u'bibles', u'resources')
books_file = None
try:
self.web_bible_list[WebDownload.Crosswalk] = {}
books_file = open(
os.path.join(filepath, u'crosswalkbooks.csv'), 'r')
os.path.join(filepath, u'crosswalkbooks.csv'), 'rb')
dialect = csv.Sniffer().sniff(books_file.read(1024))
books_file.seek(0)
books_reader = csv.reader(books_file, dialect)
for line in books_reader:
ver = line[0]
name = line[1]
if not isinstance(ver, unicode):
ver = unicode(ver, u'utf8')
if not isinstance(name, unicode):
name = unicode(name, u'utf8')
ver = unicode(line[0], u'utf-8')
name = unicode(line[1], u'utf-8')
self.web_bible_list[WebDownload.Crosswalk][ver] = name.strip()
except IOError:
log.exception(u'Crosswalk resources missing')
finally:
if books_file:
books_file.close()
# Load and store BibleGateway Bibles.
# Load BibleGateway Bibles.
books_file = None
try:
self.web_bible_list[WebDownload.BibleGateway] = {}
@ -384,10 +385,50 @@ class BibleImportForm(QtGui.QWizard, Ui_BibleImportWizard):
finally:
if books_file:
books_file.close()
# Load and Bibleserver Bibles.
filepath = AppLocation.get_directory(AppLocation.PluginsDir)
filepath = os.path.join(filepath, u'bibles', u'resources')
books_file = None
try:
self.web_bible_list[WebDownload.Bibleserver] = {}
books_file = open(
os.path.join(filepath, u'bibleserver.csv'), 'rb')
dialect = csv.Sniffer().sniff(books_file.read(1024))
books_file.seek(0)
books_reader = csv.reader(books_file, dialect)
for line in books_reader:
ver = unicode(line[0], u'utf-8')
name = unicode(line[1], u'utf-8')
self.web_bible_list[WebDownload.Bibleserver][ver] = name.strip()
except IOError, UnicodeError:
log.exception(u'Bibleserver resources missing')
finally:
if books_file:
books_file.close()
def getFileName(self, title, editbox):
def getFileName(self, title, editbox, filters=u''):
"""
Opens a QFileDialog and saves the filename to the given editbox.
``title``
The title of the dialog (unicode).
``editbox``
A editbox (QLineEdit).
``filters``
The file extension filters. It should contain the file description as
well as the file extension. For example::
u'openlp.org 1.x bible (*.bible)'
"""
if filters:
filters += u';;'
filters += u'%s (*)' % translate('BiblesPlugin.ImportWizardForm',
'All Files')
filename = QtGui.QFileDialog.getOpenFileName(self, title,
SettingsManager.get_last_dir(self.bibleplugin.settingsSection, 1))
os.path.dirname(SettingsManager.get_last_dir(
self.bibleplugin.settingsSection, 1)), filters)
if filename:
editbox.setText(filename)
SettingsManager.set_last_dir(
@ -457,6 +498,9 @@ class BibleImportForm(QtGui.QWizard, Ui_BibleImportWizard):
elif download_location == WebDownload.BibleGateway:
bible = \
self.web_bible_list[WebDownload.BibleGateway][bible_version]
elif download_location == WebDownload.Bibleserver:
bible = \
self.web_bible_list[WebDownload.Bibleserver][bible_version]
importer = self.manager.import_bible(
BibleFormat.WebDownload,
name=license_version,

View File

@ -208,6 +208,7 @@ class Ui_BibleImportWizard(object):
self.locationComboBox.setObjectName(u'LocationComboBox')
self.locationComboBox.addItem(u'')
self.locationComboBox.addItem(u'')
self.locationComboBox.addItem(u'')
self.downloadOptionsLayout.setWidget(0, QtGui.QFormLayout.FieldRole,
self.locationComboBox)
self.bibleLabel = QtGui.QLabel(self.downloadOptionsTab)
@ -388,6 +389,8 @@ class Ui_BibleImportWizard(object):
translate('BiblesPlugin.ImportWizardForm', 'Crosswalk'))
self.locationComboBox.setItemText(1,
translate('BiblesPlugin.ImportWizardForm', 'BibleGateway'))
self.locationComboBox.setItemText(2,
translate('BiblesPlugin.ImportWizardForm', 'Bibleserver'))
self.bibleLabel.setText(
translate('BiblesPlugin.ImportWizardForm', 'Bible:'))
self.webDownloadTabWidget.setTabText(

View File

@ -32,134 +32,164 @@ import re
log = logging.getLogger(__name__)
BIBLE_REFERENCE = re.compile(
r'^([\w ]+?) *([0-9]+)' # Initial book and chapter
r'(?: *[:|v|V] *([0-9]+))?' # Verse for first chapter
r'(?: *- *([0-9]+|end$))?' # Range for verses or chapters
r'(?:(?:,([0-9]+))?' # Second chapter
r' *[,|:|v|V] *([0-9]+|end$)' # More range for verses or chapters
r'(?: *- *([0-9]+|end$))?)?$', # End of second verse range
re.UNICODE)
def get_reference_match(match_type):
local_separator = unicode(u':;;\s*[:vV]\s*;;-;;\s*-\s*;;,;;\s*,\s*;;end'
).split(u';;') # English
# local_separator = unicode(u',;;\s*,\s*;;-;;\s*-\s*;;.;;\.;;[Ee]nde'
# ).split(u';;') # German
separators = {
u'sep_v_display': local_separator[0], u'sep_v': local_separator[1],
u'sep_r_display': local_separator[2], u'sep_r': local_separator[3],
u'sep_l_display': local_separator[4], u'sep_l': local_separator[5],
u'sep_e': local_separator[6]}
def check_end(match_group):
"""
Check if a regular expression match group contains the text u'end' or
should be converted to an int.
``match_group``
The match group to check.
"""
if match_group == u'end':
return -1
# verse range match: (<chapter>:)?<verse>(-((<chapter>:)?<verse>|end)?)?
range_string = str(r'(?:(?P<from_chapter>[0-9]+)%(sep_v)s)?(?P<from_verse>'
r'[0-9]+)(?P<range_to>%(sep_r)s(?:(?:(?P<to_chapter>[0-9]+)%(sep_v)s)?'
r'(?P<to_verse>[0-9]+)|%(sep_e)s)?)?') % separators
if match_type == u'range':
return re.compile(r'^\s*' + range_string + r'\s*$', re.UNICODE)
elif match_type == u'range_separator':
return re.compile(separators[u'sep_l'])
elif match_type == u'full':
# full reference match: <book>(<range>(,|(?=$)))+
return re.compile(str(r'^\s*(?!\s)(?P<book>[\d]*[^\d]+)(?<!\s)\s*'
r'(?P<ranges>(?:' + range_string + r'(?:%(sep_l)s|(?=\s*$)))+)\s*$')
% separators, re.UNICODE)
else:
return int(match_group)
return separators[match_type]
def parse_reference(reference):
"""
This is the über-awesome function that takes a person's typed in string
and converts it to a reference list, a list of references to be queried
from the Bible database files.
This is the next generation über-awesome function that takes a person's
typed in string and converts it to a reference list, a list of references to
be queried from the Bible database files.
The ``BIBLE_REFERENCE`` constant regular expression produces the following
match groups:
This is a user manual like description, how the references are working.
0. (match string)
This is a special group consisting of the whole string that matched.
1. ``[\w ]+``
The book the reference is from.
2. ``[0-9]+``
The first (or only) chapter in the reference.
3. ``None`` or ``[0-9]+``
``None``, or the only verse, or the first verse in a verse range or,
the start verse in a chapter range.
4. ``None`` or ``[0-9]+`` or ``end``
``None``, or the end verse of the first verse range, or the end chapter
of a chapter range.
5. ``None`` or ``[0-9]+``
``None``, or the second chapter in multiple (non-ranged) chapters.
6. ``None`` or ``[0-9]+`` or ``end``
``None``, the start of the second verse range. or the end of a chapter
range.
7. ``None`` or ``[0-9]+`` or ``end``
``None``, or the end of the second verse range.
- Each reference starts with the book name. A chapter name is manditory.
``John 3`` refers to Gospel of John chapter 3
- A reference range can be given after a range separator.
``John 3-5`` refers to John chapters 3 to 5
- Single verses can be addressed after a verse separator
``John 3:16`` refers to John chapter 3 verse 16
``John 3:16-4:3`` refers to John chapter 3 verse 16 to chapter 4 verse 3
- After a verse reference all further single values are treat as verse in
the last selected chapter.
``John 3:16-18`` refers to John chapter 3 verses 16 to 18
- After a list separator it is possible to refer to additional verses. They
are build analog to the first ones. This way it is possible to define each
number of verse references. It is not possible to refer to verses in
additional books.
``John 3:16,18`` refers to John chapter 3 verses 16 and 18
``John 3:16-18,20`` refers to John chapter 3 verses 16 to 18 and 20
``John 3:16-18,4:1`` refers to John chapter 3 verses 16 to 18 and
chapter 3 verse 1
- If there is a range separator without further verse declaration the last
refered chapter is addressed until the end.
``range_string`` is a regular expression which matches for verse range
declarations:
1. ``(?:(?P<from_chapter>[0-9]+)%(sep_v)s)?'
It starts with a optional chapter reference ``from_chapter`` followed by
a verse separator.
2. ``(?P<from_verse>[0-9]+)``
The verse reference ``from_verse`` is manditory
3. ``(?P<range_to>%(sep_r)s(?:`` ... ``|%(sep_e)s)?)?``
A ``range_to`` declaration is optional. It starts with a range separator
and contains optional a chapter and verse declaration or a end
separator.
4. ``(?:(?P<to_chapter>[0-9]+)%(sep_v)s)?``
The ``to_chapter`` reference with separator is equivalent to group 1.
5. ``(?P<to_verse>[0-9]+)``
The ``to_verse`` reference is equivalent to group 2.
The full reference is matched against get_reference_match(u'full'). This
regular expression looks like this:
1. ``^\s*(?!\s)(?P<book>[\d]*[^\d]+)(?<!\s)\s*``
The ``book`` group starts with the first non-whitespace character. There
are optional leading digits followed by non-digits. The group ends
before the whitspace in front of the next digit.
2. ``(?P<ranges>(?:`` + range_string + ``(?:%(sep_l)s|(?=\s*$)))+)\s*$``
The second group contains all ``ranges``. This can be multiple
declarations of a range_string separated by a list separator.
The reference list is a list of tuples, with each tuple structured like
this::
(book, chapter, start_verse, end_verse)
(book, chapter, from_verse, to_verse)
``reference``
The bible reference to parse.
Returns None or a reference list.
"""
reference = reference.strip()
log.debug('parse_reference("%s")', reference)
unified_ref_list = []
match = BIBLE_REFERENCE.match(reference)
match = get_reference_match(u'full').match(reference)
if match:
log.debug(u'Matched reference %s' % reference)
book = match.group(1)
chapter = int(match.group(2))
if match.group(7):
# Two verse ranges
vr1_start = int(match.group(3))
vr1_end = int(match.group(4))
unified_ref_list.append((book, chapter, vr1_start, vr1_end))
vr2_start = int(match.group(6))
vr2_end = check_end(match.group(7))
if match.group(5):
# One verse range per chapter
chapter2 = int(match.group(5))
unified_ref_list.append((book, chapter2, vr2_start, vr2_end))
book = match.group(u'book')
ranges = match.group(u'ranges')
range_list = get_reference_match(u'range_separator').split(ranges)
ref_list = []
chapter = None
for this_range in range_list:
range_match = get_reference_match(u'range').match(this_range)
from_chapter = range_match.group(u'from_chapter')
from_verse = range_match.group(u'from_verse')
has_range = range_match.group(u'range_to')
to_chapter = range_match.group(u'to_chapter')
to_verse = range_match.group(u'to_verse')
if from_chapter:
from_chapter = int(from_chapter)
if from_verse:
from_verse = int(from_verse)
if to_chapter:
to_chapter = int(to_chapter)
if to_verse:
to_verse = int(to_verse)
# Fill chapter fields with reasonable values.
if from_chapter:
chapter = from_chapter
elif chapter:
from_chapter = chapter
else:
unified_ref_list.append((book, chapter, vr2_start, vr2_end))
elif match.group(6):
# Chapter range with verses
if match.group(3):
vr1_start = int(match.group(3))
else:
vr1_start = 1
if match.group(2) == match.group(4):
vr1_end = int(match.group(6))
unified_ref_list.append((book, chapter, vr1_start, vr1_end))
else:
vr1_end = -1
unified_ref_list.append((book, chapter, vr1_start, vr1_end))
vr2_end = check_end(match.group(6))
if int(match.group(4)) > chapter:
for i in range(chapter + 1, int(match.group(4)) + 1):
if i == int(match.group(4)):
unified_ref_list.append((book, i, 1, vr2_end))
else:
unified_ref_list.append((book, i, 1, -1))
elif match.group(4):
# Chapter range or chapter and verse range
if match.group(3):
vr1_start = int(match.group(3))
vr1_end = check_end(match.group(4))
if vr1_end == -1 or vr1_end > vr1_start:
unified_ref_list.append((book, chapter, vr1_start, vr1_end))
from_chapter = from_verse
from_verse = None
if to_chapter:
if to_chapter < from_chapter:
continue
else:
log.debug(u'Ambiguous reference: %s' % reference)
return None
elif match.group(4) != u'end':
for i in range(chapter, int(match.group(4)) + 1):
unified_ref_list.append((book, i, 1, -1))
chapter = to_chapter
elif to_verse:
if chapter:
to_chapter = chapter
else:
to_chapter = to_verse
to_verse = None
# Append references to the list
if has_range:
if not from_verse:
from_verse = 1
if not to_verse:
to_verse = -1
if to_chapter > from_chapter:
ref_list.append((book, from_chapter, from_verse, -1))
for i in range(from_chapter + 1, to_chapter - 1):
ref_list.append((book, i, 1, -1))
ref_list.append((book, to_chapter, 1, to_verse))
elif to_verse >= from_verse or to_verse == -1:
ref_list.append((book, from_chapter, from_verse, to_verse))
elif from_verse:
ref_list.append((book, from_chapter, from_verse, from_verse))
else:
log.debug(u'Unsupported reference: %s' % reference)
return None
elif match.group(3):
# Single chapter and verse
verse = int(match.group(3))
unified_ref_list.append((book, chapter, verse, verse))
else:
# Single chapter
unified_ref_list.append((book, chapter, -1, -1))
ref_list.append((book, from_chapter, 1, -1))
return ref_list
else:
log.debug(u'Invalid reference: %s' % reference)
return None
return unified_ref_list
class SearchResults(object):

View File

@ -240,6 +240,66 @@ class BGExtract(object):
return SearchResults(bookname, chapter, verse_list)
class BSExtract(object):
"""
Extract verses from Bibleserver.com
"""
def __init__(self, proxyurl=None):
log.debug(u'init %s', proxyurl)
self.proxyurl = proxyurl
def get_bible_chapter(self, version, bookname, chapter):
"""
Access and decode bibles via Bibleserver mobile website
``version``
The version of the bible like NIV for New International Version
``bookname``
Text name of bible book e.g. Genesis, 1. John, 1John or Offenbarung
``chapter``
Chapter number
"""
log.debug(u'get_bible_chapter %s,%s,%s', version, bookname, chapter)
chapter_url = u'http://m.bibleserver.com/text/%s/%s%s' % \
(version, bookname, chapter)
log.debug(u'URL: %s', chapter_url)
page = None
try:
page = urllib2.urlopen(chapter_url)
Receiver.send_message(u'openlp_process_events')
except urllib2.URLError:
log.exception(u'The web bible page could not be downloaded.')
finally:
if not page:
return None
soup = None
try:
soup = BeautifulSoup(page)
except HTMLParseError:
log.exception(u'BeautifulSoup could not parse the bible page.')
finally:
if not soup:
return None
Receiver.send_message(u'openlp_process_events')
try:
content = soup.find(u'div', u'content').find(u'div').findAll(u'div')
except:
log.exception(u'No verses found.')
finally:
if not content:
return None
verse_number = re.compile(r'v(\d{2})(\d{3})(\d{3}) verse')
verses = {}
for verse in content:
Receiver.send_message(u'openlp_process_events')
versenumber = int(verse_number.sub(r'\3', verse[u'class']))
verses[versenumber] = verse.contents[1].rstrip(u'\n')
return SearchResults(bookname, chapter, verses)
class CWExtract(object):
"""
Extract verses from CrossWalk/BibleStudyTools
@ -350,7 +410,7 @@ class HTTPBible(BibleDB):
Run the import. This method overrides the parent class method. Returns
``True`` on success, ``False`` on failure.
"""
self.wizard.ImportProgressBar.setMaximum(2)
self.wizard.importProgressBar.setMaximum(2)
self.wizard.incrementProgressBar('Registering bible...')
self.create_meta(u'download source', self.download_source)
self.create_meta(u'download name', self.download_name)
@ -426,8 +486,10 @@ class HTTPBible(BibleDB):
log.debug(u'source = %s', self.download_source)
if self.download_source.lower() == u'crosswalk':
ev = CWExtract(self.proxy_server)
else:
elif self.download_source.lower() == u'biblegateway':
ev = BGExtract(self.proxy_server)
elif self.download_source.lower() == u'bibleserver':
ev = BSExtract(self.proxy_server)
return ev.get_bible_chapter(self.download_name, book, chapter)
def get_books(self):

View File

@ -112,6 +112,7 @@ class BibleFormat(object):
def get_availability(format):
return BibleFormat._format_availability.get(format, True)
class BibleManager(object):
"""
The Bible manager which holds and manages all the Bibles.
@ -311,7 +312,7 @@ class BibleManager(object):
'Scripture Reference Error'),
translate('BiblesPlugin.BibleManager', 'You did not enter a '
'search keyword.\nYou can separate different keywords by a '
'space to search for all of your keywords and you can seperate '
'space to search for all of your keywords and you can separate '
'them by a comma to search for one of them.'))
return None
@ -356,3 +357,4 @@ class BibleManager(object):
BibleFormat.set_availability(BibleFormat.OpenLP1, has_openlp1)
__all__ = [u'BibleFormat']

View File

@ -32,6 +32,7 @@ from PyQt4 import QtCore, QtGui
from openlp.core.lib import MediaManagerItem, Receiver, BaseListWithDnD, \
ItemCapabilities, translate
from openlp.plugins.bibles.forms import BibleImportForm
from openlp.plugins.bibles.lib import get_reference_match
log = logging.getLogger(__name__)
@ -72,7 +73,7 @@ class BibleMediaItem(MediaManagerItem):
self.hasNewIcon = False
self.hasEditIcon = False
self.hasDeleteIcon = False
self.addToServiceItem = True
self.addToServiceItem = False
def addEndHeaderBar(self):
self.SearchTabWidget = QtGui.QTabWidget(self)
@ -553,12 +554,15 @@ class BibleMediaItem(MediaManagerItem):
bible = unicode(self.AdvancedVersionComboBox.currentText())
second_bible = unicode(self.AdvancedSecondBibleComboBox.currentText())
book = unicode(self.AdvancedBookComboBox.currentText())
chapter_from = int(self.AdvancedFromChapter.currentText())
chapter_to = int(self.AdvancedToChapter.currentText())
verse_from = int(self.AdvancedFromVerse.currentText())
verse_to = int(self.AdvancedToVerse.currentText())
versetext = u'%s %s:%s-%s:%s' % (book, chapter_from, verse_from,
chapter_to, verse_to)
chapter_from = self.AdvancedFromChapter.currentText()
chapter_to = self.AdvancedToChapter.currentText()
verse_from = self.AdvancedFromVerse.currentText()
verse_to = self.AdvancedToVerse.currentText()
verse_separator = get_reference_match(u'sep_v_display')
range_separator = get_reference_match(u'sep_r_display')
verse_range = chapter_from + verse_separator + verse_from + \
range_separator + chapter_to + verse_separator + verse_to
versetext = u'%s %s' % (book, verse_range)
self.search_results = self.parent.manager.get_verses(bible, versetext)
if second_bible:
self.second_search_results = self.parent.manager.get_verses(
@ -709,7 +713,7 @@ class BibleMediaItem(MediaManagerItem):
obj = reference[QtCore.QString(key)]
if isinstance(obj, QtCore.QVariant):
obj = obj.toPyObject()
return unicode(obj)
return unicode(obj).strip()
def generateSlideData(self, service_item, item=None, xmlVersion=False):
"""
@ -739,7 +743,8 @@ class BibleMediaItem(MediaManagerItem):
second_bible = self._decodeQtObject(bitem, 'second_bible')
second_version = self._decodeQtObject(bitem, 'second_version')
second_copyright = self._decodeQtObject(bitem, 'second_copyright')
second_permissions = self._decodeQtObject(bitem, 'second_permissions')
second_permissions = \
self._decodeQtObject(bitem, 'second_permissions')
second_text = self._decodeQtObject(bitem, 'second_text')
verse_text = self.formatVerse(old_chapter, chapter, verse)
footer = u'%s (%s %s %s)' % (book, version, copyright, permissions)
@ -750,21 +755,21 @@ class BibleMediaItem(MediaManagerItem):
second_copyright, second_permissions)
if footer not in raw_footer:
raw_footer.append(footer)
bible_text = u'%s %s\n\n%s %s' % (verse_text, text, verse_text,
second_text)
bible_text = u'%s\u00a0%s\n\n%s\u00a0%s' % (verse_text, text,
verse_text, second_text)
raw_slides.append(bible_text)
bible_text = u''
# If we are 'Verse Per Slide' then create a new slide.
elif self.parent.settings_tab.layout_style == 0:
bible_text = u'%s %s' % (verse_text, text)
bible_text = u'%s\u00a0%s' % (verse_text, text)
raw_slides.append(bible_text)
bible_text = u''
# If we are 'Verse Per Line' then force a new line.
elif self.parent.settings_tab.layout_style == 1:
bible_text = u'%s %s %s\n' % (bible_text, verse_text, text)
bible_text = u'%s %s\u00a0%s\n' % (bible_text, verse_text, text)
# We have to be 'Continuous'.
else:
bible_text = u'%s %s %s\n' % (bible_text, verse_text, text)
bible_text = u'%s %s\u00a0%s\n' % (bible_text, verse_text, text)
if first_item:
start_item = item
first_item = False
@ -816,36 +821,31 @@ class BibleMediaItem(MediaManagerItem):
``old_item``
The last item of a range.
"""
verse_separator = get_reference_match(u'sep_v_display')
range_separator = get_reference_match(u'sep_r_display')
old_bitem = self.listView.item(old_item.row())
old_chapter = int(self._decodeQtObject(old_bitem, 'chapter'))
old_verse = int(self._decodeQtObject(old_bitem, 'verse'))
old_chapter = self._decodeQtObject(old_bitem, 'chapter')
old_verse = self._decodeQtObject(old_bitem, 'verse')
start_bitem = self.listView.item(start_item.row())
start_book = self._decodeQtObject(start_bitem, 'book')
start_chapter = int(self._decodeQtObject(start_bitem, 'chapter'))
start_verse = int(self._decodeQtObject(start_bitem, 'verse'))
start_chapter = self._decodeQtObject(start_bitem, 'chapter')
start_verse = self._decodeQtObject(start_bitem, 'verse')
start_bible = self._decodeQtObject(start_bitem, 'bible')
start_second_bible = self._decodeQtObject(start_bitem, 'second_bible')
if start_second_bible:
if start_verse == old_verse and start_chapter == old_chapter:
title = u'%s %s:%s (%s, %s)' % (start_book, start_chapter,
start_verse, start_bible, start_second_bible)
elif start_chapter == old_chapter:
title = u'%s %s:%s-%s (%s, %s)' % (start_book, start_chapter,
start_verse, old_verse, start_bible, start_second_bible)
else:
title = u'%s %s:%s-%s:%s (%s, %s)' % (start_book, start_chapter,
start_verse, old_chapter, old_verse, start_bible,
start_second_bible)
bibles = u'%s, %s' % (start_bible, start_second_bible)
else:
if start_verse == old_verse and start_chapter == old_chapter:
title = u'%s %s:%s (%s)' % (start_book, start_chapter,
start_verse, start_bible)
elif start_chapter == old_chapter:
title = u'%s %s:%s-%s (%s)' % (start_book, start_chapter,
start_verse, old_verse, start_bible)
bibles = start_bible
if start_chapter == old_chapter:
if start_verse == old_verse:
verse_range = start_chapter + verse_separator + start_verse
else:
title = u'%s %s:%s-%s:%s (%s)' % (start_book, start_chapter,
start_verse, old_chapter, old_verse, start_bible)
verse_range = start_chapter + verse_separator + start_verse + \
range_separator + old_verse
else:
verse_range = start_chapter + verse_separator + start_verse + \
range_separator + old_chapter + verse_separator + old_verse
title = u'%s %s (%s)' % (start_book, verse_range, bibles)
return title
def checkTitle(self, item, old_item):
@ -875,7 +875,7 @@ class BibleMediaItem(MediaManagerItem):
old_second_bible = self._decodeQtObject(old_bitem, 'second_bible')
if old_bible != bible or old_second_bible != second_bible or \
old_book != book:
# The bible, second bible or book has changed.
# The bible, second bible or book has changed.
return True
elif old_verse + 1 != verse and old_chapter == chapter:
# We are still in the same chapter, but a verse has been skipped.
@ -907,9 +907,10 @@ class BibleMediaItem(MediaManagerItem):
``verse``
The verse number (int).
"""
verse_separator = get_reference_match(u'sep_v_display')
if not self.parent.settings_tab.show_new_chapters or \
old_chapter != chapter:
verse_text = u'%s:%s' % (chapter, verse)
verse_text = unicode(chapter) + verse_separator + unicode(verse)
else:
verse_text = u'%s' % verse
if self.parent.settings_tab.display_style == 1:

0
openlp/plugins/bibles/lib/openlp1.py Executable file → Normal file
View File

View File

@ -134,9 +134,9 @@ class OSISBible(BibleDB):
testament)
if last_chapter == 0:
if book == u'Gen':
self.wizard.ImportProgressBar.setMaximum(1188)
self.wizard.importProgressBar.setMaximum(1188)
else:
self.wizard.ImportProgressBar.setMaximum(260)
self.wizard.importProgressBar.setMaximum(260)
if last_chapter != chapter:
if last_chapter != 0:
self.session.commit()

View File

@ -1,80 +1,81 @@
João Ferreira de Almeida Atualizada,AA
التفسير التطبيقى للكتاب المقدس,ALAB
Shqip,ALB
Amplified Bible,AMP
Amuzgo de Guerrero,AMU
Arabic Life Application Bible,ALAB
Bulgarian Bible,BULG
1940 Bulgarian Bible,BG1940
Chinanteco de Comaltepec,CCO
Cakchiquel Occidental,CKW
Haitian Creole Version,HCV
Slovo na cestu,SNC
Dette er Biblen på dansk,DN1933
Hoffnung für Alle,HOF
Luther Bibel 1545,LUTH1545
New International Version,NIV
New American Standard Bible,NASB
The Message,MSG
Amplified Bible,AMP
New Living Translation,NLT
King James Version,KJV
English Standard Version,ESV
Contemporary English Version,CEV
New King James Version,NKJV
New Century Version,NCV
21st Century King James Version,KJ21
American Standard Version,ASV
Young's Literal Translation,YLT
Darby Translation,DARBY
Holman Christian Standard Bible,HCSB
New International Reader's Version,NIRV
Wycliffe New Testament,WYC
Worldwide English (New Testament),WE
New International Version - UK,NIVUK
Today's New International Version,TNIV
American Standard Version,ASV
La Bible du Semeur,BDS
Български 1940,BG1940
Български,BULG
Chinanteco de Comaltepec,CCO
Contemporary English Version,CEV
Cakchiquel Occidental,CKW
Hrvatski,CRO
Castilian,CST
聖經和合本 (简体中文),CUVS
聖經和合本 (繁体中文),CUV
Darby Translation,DARBY
Dette er Biblen på dansk,DN1933
Det Norsk Bibelselskap 1930,DNB1930
English Standard Version,ESV
GODS WORD Translation,GW
Holman Christian Standard Bible,HCSB
Kreyòl ayisyen bib,HCV
Hiligaynon Bible,HLGN
Hoffnung für Alle,HOF
Het Boek,HTB
Icelandic Bible,ICELAND
Jacalteco Oriental,JAC
Károlyi-biblia,KAR
Kekchi,KEK
21st Century King James Version,KJ21
King James Version,KJV
La Biblia de las Américas,LBLA
Levande Bibeln,LB
La Parola è Vita,LM
La Nuova Diodati,LND
Louis Segond,LSG
Luther Bibel 1545,LUTH1545
Māori Bible,MAORI
Македонски Новиот Завет,MNT
The Message,MSG
Mam de Comitancillo Central,MVC
Mam de Todos Santos Cuchumatán,MVJ
New American Standard Bible,NASB
New Century Version,NCV
Náhuatl de Guerrero,NGU
New International Reader's Version,NIRV
New International Version 1984,NIV1984
New International Version 2010,NIV
New International Version - UK,NIVUK
New King James Version,NKJV
New Living Translation,NLT
Nádej pre kazdého,NPK
Nueva Versión Internacional,NVI
O Livro,OL
Quiché Centro Occidental,QUT
Reimer 2001,REIMER
Română Cornilescu,RMNN
Новый перевод на русский язык,RUSV
Reina-Valera Antigua,RVA
Reina-Valera 1960,RVR1960
Nueva Versión Internacional,NVI
Reina-Valera 1995,RVR1995
Castilian,CST
Reina-Valera Antigua,RVA
Biblia en Lenguaje Sencillo,BLS
La Biblia de las Américas,LBLA
Louis Segond,LSG
La Bible du Semeur,BDS
1881 Westcott-Hort New Testament,WHNU
1550 Stephanus New Testament,TR1550
1894 Scrivener New Testament,TR1894
The Westminster Leningrad Codex,WLC
Hiligaynon Bible,HLGN
Croatian Bible,CRO
Hungarian Károli,KAR
Icelandic Bible,ICELAND
La Nuova Diodati,LND
La Parola è Vita,LM
Jacalteco, Oriental,JAC
Kekchi,KEK
Korean Bible,KOREAN
Maori Bible,MAORI
Macedonian New Testament,MNT
Mam, Central,MVC
Mam de Todos Santos Chuchumatán,MVJ
Reimer 2001,REIMER
Náhuatl de Guerrero,NGU
Het Boek,HTB
Det Norsk Bibelselskap 1930,DNB1930
Levande Bibeln,LB
O Livro,OL
João Ferreira de Almeida Atualizada,AA
Quiché, Centro Occidental,QUT
Romanian,RMNN
Romanian,TLCR
Russian Synodal Version,RUSV
Slovo Zhizny,SZ
Nádej pre kazdého,NPK
Albanian Bible,ALB
Levande Bibeln,SVL
Svenska 1917,SV1917
Swahili New Testament,SNT
Ang Salita ng Diyos,SND
Ukrainian Bible,UKR
Uspanteco,USP
1934 Vietnamese Bible,VIET
Chinese Union Version (Simplified),CUVS
Chinese Union Version (Traditional),CUV
Reina-Valera 1995,RVR1995
Slovo na cestu,SNC
Ang Salita ng Diyos,SND
Swahili New Testament,SNT
Svenska 1917,SV1917
Levande Bibeln,SVL
Создать страницу,SZ
Traducción en lenguaje actual,TLA
New Romanian Translation,TLCR
Todays New International Version 2005,TNIV
Textus Receptus Stephanus 1550,TR1550
Textus Receptus Scrivener 1894,TR1894
Українська Біблія. Переклад Івана Огієнка,UKR
Uspanteco,USP
Kinh Thánh tiếng Việt 1934,VIET
Worldwide English (New Testament),WE
Codex Vaticanus Westcott-Hort 1881,WHNU
Westminster Leningrad Codex,WLC
Wycliffe New Testament,WYC
Young's Literal Translation,YLT

Can't render this file because it has a wrong number of fields in line 51.

View File

@ -0,0 +1,39 @@
عربي, ARA
Bible překlad 21. století, B21
Bible du Semeur, BDS
Българската Библия, BLG
Český ekumenický překlad, CEP
Hrvatski, CRO
Священное Писание, CRS
Version La Biblia al Dia, CST
中文和合本(简体), CUVS
Bibelen på hverdagsdansk, DK
Revidierte Elberfelder, ELB
Einheitsübersetzung, EU
Gute Nachricht Bibel, GNB
Hoffnung für alle, HFA
Hungarian, HUN
Het Boek, HTB
La Parola è Vita, ITA
IBS-fordítás (Új Károli), KAR
King James Version, KJV
Luther 1984, LUT
Septuaginta, LXX
Neue Genfer Übersetzung, NGÜ
New International Readers Version, NIRV
New International Version, NIV
Neues Leben, NL
En Levende Bok (NOR), NOR
Nádej pre kazdého, NPK
Noua traducere în limba românã, NTR
Nueva Versión Internacional, NVI
הברית הישנה, OT
Słowo Życia, POL
O Livro, PRT
Новый перевод на русский язык, RUS
Slovo na cestu, SNC
Schlachter 2000, SLT
En Levande Bok (SWE), SVL
Today's New International Version, TNIV
Türkçe, TR
Biblia Vulgata, VUL
1 عربي ARA
2 Bible – překlad 21. století B21
3 Bible du Semeur BDS
4 Българската Библия BLG
5 Český ekumenický překlad CEP
6 Hrvatski CRO
7 Священное Писание CRS
8 Version La Biblia al Dia CST
9 中文和合本(简体) CUVS
10 Bibelen på hverdagsdansk DK
11 Revidierte Elberfelder ELB
12 Einheitsübersetzung EU
13 Gute Nachricht Bibel GNB
14 Hoffnung für alle HFA
15 Hungarian HUN
16 Het Boek HTB
17 La Parola è Vita ITA
18 IBS-fordítás (Új Károli) KAR
19 King James Version KJV
20 Luther 1984 LUT
21 Septuaginta LXX
22 Neue Genfer Übersetzung NGÜ
23 New International Readers Version NIRV
24 New International Version NIV
25 Neues Leben NL
26 En Levende Bok (NOR) NOR
27 Nádej pre kazdého NPK
28 Noua traducere în limba românã NTR
29 Nueva Versión Internacional NVI
30 הברית הישנה OT
31 Słowo Życia POL
32 O Livro PRT
33 Новый перевод на русский язык RUS
34 Slovo na cestu SNC
35 Schlachter 2000 SLT
36 En Levande Bok (SWE) SVL
37 Today's New International Version TNIV
38 Türkçe TR
39 Biblia Vulgata VUL

View File

@ -24,4 +24,4 @@ New International Reader's Version,nrv
The Darby Translation,dby
The Webster Bible,wbt
The Latin Vulgate,vul
Weymouth New Testament,wnt
Weymouth New Testament,wnt

1 New American Standard nas
24 The Darby Translation dby
25 The Webster Bible wbt
26 The Latin Vulgate vul
27 Weymouth New Testament wnt

View File

@ -109,7 +109,7 @@ class CustomPlugin(Plugin):
}
## Name for MediaDockManager, SettingsManager ##
self.textStrings[StringContent.VisibleName] = {
u'title': translate('CustomsPlugin', 'Customs')
u'title': translate('CustomsPlugin', 'Custom')
}
# Middle Header Bar
## Import Button ##

View File

@ -224,27 +224,24 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
``edit_all``
Indicates if all slides or only one slide has been edited.
"""
if len(slides) == 1:
self.slideListView.currentItem().setText(slides[0])
if edit_all:
self.slideListView.clear()
for slide in slides:
self.slideListView.addItem(slide)
else:
if edit_all:
self.slideListView.clear()
for slide in slides:
self.slideListView.addItem(slide)
else:
old_slides = []
old_row = self.slideListView.currentRow()
# Create a list with all (old/unedited) slides.
old_slides = [self.slideListView.item(row).text() for row in \
range(0, self.slideListView.count())]
self.slideListView.clear()
old_slides.pop(old_row)
# Insert all slides to make the old_slides list complete.
for slide in slides:
old_slides.insert(old_row, slide)
for slide in old_slides:
self.slideListView.addItem(slide)
self.slideListView.repaint()
old_slides = []
old_row = self.slideListView.currentRow()
# Create a list with all (old/unedited) slides.
old_slides = [self.slideListView.item(row).text() for row in \
range(0, self.slideListView.count())]
self.slideListView.clear()
old_slides.pop(old_row)
# Insert all slides to make the old_slides list complete.
for slide in slides:
old_slides.insert(old_row, slide)
for slide in old_slides:
self.slideListView.addItem(slide)
self.slideListView.repaint()
def onDeleteButtonPressed(self):
self.slideListView.takeItem(self.slideListView.currentRow())

View File

@ -75,42 +75,42 @@ class ImagePlugin(Plugin):
## Load Button ##
self.textStrings[StringContent.Load] = {
u'title': translate('ImagePlugin', 'Load'),
u'tooltip': translate('ImagePlugin',
u'tooltip': translate('ImagePlugin',
'Load a new Image')
}
## New Button ##
self.textStrings[StringContent.New] = {
u'title': translate('ImagePlugin', 'Add'),
u'tooltip': translate('ImagePlugin',
u'tooltip': translate('ImagePlugin',
'Add a new Image')
}
## Edit Button ##
self.textStrings[StringContent.Edit] = {
u'title': translate('ImagePlugin', 'Edit'),
u'tooltip': translate('ImagePlugin',
u'tooltip': translate('ImagePlugin',
'Edit the selected Image')
}
## Delete Button ##
self.textStrings[StringContent.Delete] = {
u'title': translate('ImagePlugin', 'Delete'),
u'tooltip': translate('ImagePlugin',
u'tooltip': translate('ImagePlugin',
'Delete the selected Image')
}
## Preview ##
self.textStrings[StringContent.Preview] = {
u'title': translate('ImagePlugin', 'Preview'),
u'tooltip': translate('ImagePlugin',
u'tooltip': translate('ImagePlugin',
'Preview the selected Image')
}
## Live Button ##
self.textStrings[StringContent.Live] = {
u'title': translate('ImagePlugin', 'Live'),
u'tooltip': translate('ImagePlugin',
u'tooltip': translate('ImagePlugin',
'Send the selected Image live')
}
## Add to service Button ##
self.textStrings[StringContent.Service] = {
u'title': translate('ImagePlugin', 'Service'),
u'tooltip': translate('ImagePlugin',
u'tooltip': translate('ImagePlugin',
'Add the selected Image to the service')
}

View File

@ -31,7 +31,7 @@ from PyQt4 import QtCore, QtGui
from openlp.core.lib import MediaManagerItem, BaseListWithDnD, build_icon, \
context_menu_action, ItemCapabilities, SettingsManager, translate, \
check_item_selected
check_item_selected, Receiver
from openlp.core.utils import AppLocation, get_images_filter
log = logging.getLogger(__name__)
@ -139,6 +139,8 @@ class ImageMediaItem(MediaManagerItem):
self.settingsSection, self.getFileList())
def loadList(self, list):
self.listView.setCursor(QtCore.Qt.BusyCursor)
Receiver.send_message(u'openlp_process_events')
for file in list:
filename = os.path.split(unicode(file))[1]
thumb = os.path.join(self.servicePath, filename)
@ -153,6 +155,8 @@ class ImageMediaItem(MediaManagerItem):
item_name.setIcon(icon)
item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(file))
self.listView.addItem(item_name)
self.listView.setCursor(QtCore.Qt.ArrowCursor)
Receiver.send_message(u'openlp_process_events')
def generateSlideData(self, service_item, item=None, xmlVersion=False):
items = self.listView.selectedIndexes()

View File

@ -48,7 +48,7 @@ else:
uno_available = True
except ImportError:
uno_available = False
from PyQt4 import QtCore
from presentationcontroller import PresentationController, PresentationDocument
@ -210,12 +210,12 @@ class ImpressController(PresentationController):
class ImpressDocument(PresentationDocument):
"""
Class which holds information and controls a single presentation
"""
"""
def __init__(self, controller, presentation):
"""
Constructor, store information about the file and initialise
"""
Constructor, store information about the file and initialise
"""
log.debug(u'Init Presentation OpenOffice')
PresentationDocument.__init__(self, controller, presentation)
self.document = None
@ -287,7 +287,7 @@ class ImpressDocument(PresentationDocument):
page = pages.getByIndex(idx)
doc.getCurrentController().setCurrentPage(page)
urlpath = u'%s/%s.png' % (thumbdirurl, unicode(idx + 1))
path = os.path.join(self.get_temp_folder(),
path = os.path.join(self.get_temp_folder(),
unicode(idx + 1) + u'.png')
try:
doc.storeToURL(urlpath, props)

View File

@ -51,7 +51,7 @@ class Controller(object):
def add_handler(self, controller, file, is_blank):
"""
Add a handler, which is an instance of a presentation and
Add a handler, which is an instance of a presentation and
slidecontroller combination. If the slidecontroller has a display
then load the presentation.
"""
@ -362,7 +362,7 @@ class MessageListener(object):
def timeout(self):
"""
The presentation may be timed or might be controlled by the
The presentation may be timed or might be controlled by the
application directly, rather than through OpenLP. Poll occassionally
to check which slide is currently displayed so the slidecontroller
view can be updated

View File

@ -108,7 +108,7 @@ class PptviewDocument(PresentationDocument):
"""
def __init__(self, controller, presentation):
"""
Constructor, store information about the file and initialise
Constructor, store information about the file and initialise
"""
log.debug(u'Init Presentation PowerPoint')
PresentationDocument.__init__(self, controller, presentation)

View File

@ -133,7 +133,7 @@ class PresentationTab(SettingsTab):
self.settingsSection + u'/' + controller.name,
QtCore.QVariant(QtCore.Qt.Checked)).toInt()[0])
self.OverrideAppCheckBox.setChecked(QtCore.QSettings().value(
self.settingsSection + u'/override app',
self.settingsSection + u'/override app',
QtCore.QVariant(QtCore.Qt.Unchecked)).toInt()[0])
def save(self):

View File

@ -163,30 +163,30 @@ class PresentationPlugin(Plugin):
## Load Button ##
self.textStrings[StringContent.Load] = {
u'title': translate('PresentationPlugin', 'Load'),
u'tooltip': translate('PresentationPlugin',
u'tooltip': translate('PresentationPlugin',
'Load a new Presentation')
}
## Delete Button ##
self.textStrings[StringContent.Delete] = {
u'title': translate('PresentationPlugin', 'Delete'),
u'tooltip': translate('PresentationPlugin',
u'tooltip': translate('PresentationPlugin',
'Delete the selected Presentation')
}
## Preview ##
self.textStrings[StringContent.Preview] = {
u'title': translate('PresentationPlugin', 'Preview'),
u'tooltip': translate('PresentationPlugin',
u'tooltip': translate('PresentationPlugin',
'Preview the selected Presentation')
}
## Live Button ##
self.textStrings[StringContent.Live] = {
u'title': translate('PresentationPlugin', 'Live'),
u'tooltip': translate('PresentationPlugin',
u'tooltip': translate('PresentationPlugin',
'Send the selected Presentation live')
}
## Add to service Button ##
self.textStrings[StringContent.Service] = {
u'title': translate('PresentationPlugin', 'Service'),
u'tooltip': translate('PresentationPlugin',
u'tooltip': translate('PresentationPlugin',
'Add the selected Presentation to the service')
}

View File

@ -77,7 +77,7 @@ class RemotesPlugin(Plugin):
'a running version of OpenLP on a different computer via a web '
'browser or through the remote API.')
return about_text
def setPluginTextStrings(self):
"""
Called to define all translatable texts of the plugin

View File

@ -108,6 +108,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
self.TopicsListView.setSortingEnabled(False)
self.TopicsListView.setAlternatingRowColors(True)
self.findVerseSplit = re.compile(u'---\[\]---\n', re.UNICODE)
self.whitespace = re.compile(r'\W+', re.UNICODE)
def initialise(self):
self.VerseEditButton.setEnabled(False)
@ -120,35 +121,55 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
order_by_ref=Author.display_name)
self.AuthorsSelectionComboItem.clear()
self.AuthorsSelectionComboItem.addItem(u'')
self.authors = []
for author in authors:
row = self.AuthorsSelectionComboItem.count()
self.AuthorsSelectionComboItem.addItem(author.display_name)
self.AuthorsSelectionComboItem.setItemData(
row, QtCore.QVariant(author.id))
self.authors.append(author.display_name)
completer = QtGui.QCompleter(self.authors)
completer.setCaseSensitivity(QtCore.Qt.CaseInsensitive)
self.AuthorsSelectionComboItem.setCompleter(completer)
def loadTopics(self):
topics = self.manager.get_all_objects(Topic, order_by_ref=Topic.name)
self.SongTopicCombo.clear()
self.SongTopicCombo.addItem(u'')
self.topics = []
for topic in topics:
row = self.SongTopicCombo.count()
self.SongTopicCombo.addItem(topic.name)
self.topics.append(topic.name)
self.SongTopicCombo.setItemData(row, QtCore.QVariant(topic.id))
completer = QtGui.QCompleter(self.topics)
completer.setCaseSensitivity(QtCore.Qt.CaseInsensitive)
self.SongTopicCombo.setCompleter(completer)
def loadBooks(self):
books = self.manager.get_all_objects(Book, order_by_ref=Book.name)
self.SongbookCombo.clear()
self.SongbookCombo.addItem(u'')
self.books = []
for book in books:
row = self.SongbookCombo.count()
self.SongbookCombo.addItem(book.name)
self.books.append(book.name)
self.SongbookCombo.setItemData(row, QtCore.QVariant(book.id))
completer = QtGui.QCompleter(self.books)
completer.setCaseSensitivity(QtCore.Qt.CaseInsensitive)
self.SongbookCombo.setCompleter(completer)
def loadThemes(self, theme_list):
self.ThemeSelectionComboItem.clear()
self.ThemeSelectionComboItem.addItem(u'')
self.themes = []
for theme in theme_list:
self.ThemeSelectionComboItem.addItem(theme)
self.themes.append(theme)
completer = QtGui.QCompleter(self.themes)
completer.setCaseSensitivity(QtCore.Qt.CaseInsensitive)
self.ThemeSelectionComboItem.setCompleter(completer)
def newSong(self):
log.debug(u'New Song')
@ -526,14 +547,11 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
if self.AuthorsListView.count() == 0:
self.SongTabWidget.setCurrentIndex(1)
self.AuthorsListView.setFocus()
answer = QtGui.QMessageBox.warning(self,
QtGui.QMessageBox.critical(self,
translate('SongsPlugin.EditSongForm', 'Warning'),
translate('SongsPlugin.EditSongForm',
'You have not added any authors for this song. Do you '
'want to add an author now?'),
QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)
if answer == QtGui.QMessageBox.Yes:
return False
'You need to have an author for this song.'))
return False
if self.song.verse_order:
order = []
order_names = self.song.verse_order.split()
@ -614,12 +632,29 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
self.saveSong(True):
Receiver.send_message(u'songs_preview')
def clearCaches(self):
"""
Free up autocompletion memory on dialog exit
"""
self.authors = []
self.themes = []
self.books = []
self.topics = []
def closePressed(self):
"""
Exit Dialog and do not save
"""
Receiver.send_message(u'songs_edit_clear')
self.clearCaches()
self.close()
def accept(self):
"""
Exit Dialog and save soong if valid
"""
log.debug(u'accept')
self.clearCaches()
if not self.song:
self.song = Song()
item = int(self.SongbookCombo.currentIndex())
@ -644,7 +679,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
Get all the data from the widgets on the form, and then save it to the
database.
``preview``
``preview``
Should be ``True`` if the song is also previewed (boolean).
"""
self.song.title = unicode(self.TitleEditItem.text())
@ -701,7 +736,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
verseId = unicode(item.data(QtCore.Qt.UserRole).toString())
bits = verseId.split(u':')
sxml.add_verse_to_lyrics(bits[0], bits[1], unicode(item.text()))
text = text + re.sub(r'\W+', u' ',
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])

View File

@ -29,7 +29,7 @@ import logging
from PyQt4 import QtCore, QtGui
from openlp.plugins.songs.lib import VerseType
from openlp.plugins.songs.lib import VerseType, translate
from editversedialog import Ui_EditVerseDialog
@ -131,6 +131,7 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog):
def setVerse(self, text, single=False,
tag=u'%s:1' % VerseType.to_string(VerseType.Verse)):
self.hasSingleVerse = single
if single:
verse_type, verse_number = tag.split(u':')
verse_type_index = VerseType.from_string(verse_type)
@ -159,3 +160,16 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog):
text = u'---[%s:1]---\n%s' % (VerseType.to_string(VerseType.Verse),
text)
return text
def accept(self):
if self.hasSingleVerse:
value = unicode(self.getVerse()[0])
else:
value = self.getVerse()[0].split(u'\n')[1]
if len(value) == 0:
QtGui.QMessageBox.critical(self,
translate('SongsPlugin.EditSongForm', 'Error'),
translate('SongsPlugin.EditSongForm',
'You need to type some text in to the verse.'))
return False
QtGui.QDialog.accept(self)

View File

@ -152,101 +152,101 @@ class SongImportForm(QtGui.QWizard, Ui_SongImportWizard):
if self.openLP2FilenameEdit.text().isEmpty():
QtGui.QMessageBox.critical(self,
translate('SongsPlugin.ImportWizardForm',
'No OpenLP 2.0 Song Database Selected'),
'No OpenLP 2.0 Song Database Selected'),
translate('SongsPlugin.ImportWizardForm',
'You need to select an OpenLP 2.0 song database '
'file to import from.'))
'You need to select an OpenLP 2.0 song database '
'file to import from.'))
self.openLP2BrowseButton.setFocus()
return False
elif source_format == SongFormat.OpenLP1:
if self.openLP1FilenameEdit.text().isEmpty():
QtGui.QMessageBox.critical(self,
translate('SongsPlugin.ImportWizardForm',
'No openlp.org 1.x Song Database Selected'),
'No openlp.org 1.x Song Database Selected'),
translate('SongsPlugin.ImportWizardForm',
'You need to select an openlp.org 1.x song '
'database file to import from.'))
'You need to select an openlp.org 1.x song '
'database file to import from.'))
self.openLP1BrowseButton.setFocus()
return False
elif source_format == SongFormat.OpenLyrics:
#if self.openLyricsFileListWidget.count() == 0:
# QtGui.QMessageBox.critical(self,
# translate('SongsPlugin.ImportWizardForm',
# 'No OpenLyrics Files Selected'),
# translate('SongsPlugin.ImportWizardForm',
# 'You need to add at least one OpenLyrics '
# 'song file to import from.'))
# self.openLyricsAddButton.setFocus()
# return False
# if self.openLyricsFileListWidget.count() == 0:
# QtGui.QMessageBox.critical(self,
# translate('SongsPlugin.ImportWizardForm',
# 'No OpenLyrics Files Selected'),
# translate('SongsPlugin.ImportWizardForm',
# 'You need to add at least one OpenLyrics '
# 'song file to import from.'))
# self.openLyricsAddButton.setFocus()
# return False
return False
elif source_format == SongFormat.OpenSong:
if self.openSongFileListWidget.count() == 0:
QtGui.QMessageBox.critical(self,
translate('SongsPlugin.ImportWizardForm',
'No OpenSong Files Selected'),
'No OpenSong Files Selected'),
translate('SongsPlugin.ImportWizardForm',
'You need to add at least one OpenSong '
'song file to import from.'))
'You need to add at least one OpenSong '
'song file to import from.'))
self.openSongAddButton.setFocus()
return False
elif source_format == SongFormat.WordsOfWorship:
if self.wordsOfWorshipFileListWidget.count() == 0:
QtGui.QMessageBox.critical(self,
translate('SongsPlugin.ImportWizardForm',
'No Words of Worship Files Selected'),
'No Words of Worship Files Selected'),
translate('SongsPlugin.ImportWizardForm',
'You need to add at least one Words of Worship '
'file to import from.'))
'You need to add at least one Words of Worship '
'file to import from.'))
self.wordsOfWorshipAddButton.setFocus()
return False
elif source_format == SongFormat.CCLI:
if self.ccliFileListWidget.count() == 0:
QtGui.QMessageBox.critical(self,
translate('SongsPlugin.ImportWizardForm',
'No CCLI Files Selected'),
'No CCLI Files Selected'),
translate('SongsPlugin.ImportWizardForm',
'You need to add at least one CCLI file '
'to import from.'))
'You need to add at least one CCLI file '
'to import from.'))
self.ccliAddButton.setFocus()
return False
elif source_format == SongFormat.SongsOfFellowship:
if self.songsOfFellowshipFileListWidget.count() == 0:
QtGui.QMessageBox.critical(self,
translate('SongsPlugin.ImportWizardForm',
'No Songs of Fellowship File Selected'),
'No Songs of Fellowship File Selected'),
translate('SongsPlugin.ImportWizardForm',
'You need to add at least one Songs of Fellowship '
'file to import from.'))
'You need to add at least one Songs of Fellowship '
'file to import from.'))
self.songsOfFellowshipAddButton.setFocus()
return False
elif source_format == SongFormat.Generic:
if self.genericFileListWidget.count() == 0:
QtGui.QMessageBox.critical(self,
translate('SongsPlugin.ImportWizardForm',
'No Document/Presentation Selected'),
'No Document/Presentation Selected'),
translate('SongsPlugin.ImportWizardForm',
'You need to add at least one document or '
'presentation file to import from.'))
'You need to add at least one document or '
'presentation file to import from.'))
self.genericAddButton.setFocus()
return False
elif source_format == SongFormat.EasyWorship:
if self.ewFilenameEdit.text().isEmpty():
QtGui.QMessageBox.critical(self,
translate('SongsPlugin.ImportWizardForm',
'No EasyWorship Song Database Selected'),
'No EasyWorship Song Database Selected'),
translate('SongsPlugin.ImportWizardForm',
'You need to select an EasyWorship song database '
'file to import from.'))
'You need to select an EasyWorship song database '
'file to import from.'))
self.ewBrowseButton.setFocus()
return False
elif source_format == SongFormat.SongBeamer:
if self.songBeamerFileListWidget.count() == 0:
QtGui.QMessageBox.critical(self,
translate('SongsPlugin.ImportWizardForm',
'No SongBeamer File Selected'),
'No SongBeamer File Selected'),
translate('SongsPlugin.ImportWizardForm',
'You need to add at least one SongBeamer '
'file to import from.'))
'You need to add at least one SongBeamer '
'file to import from.'))
self.songBeamerAddButton.setFocus()
return False
return True
@ -254,24 +254,57 @@ class SongImportForm(QtGui.QWizard, Ui_SongImportWizard):
# Progress page
return True
def getFileName(self, title, editbox,
filters = '%s (*)' % translate('SongsPlugin.ImportWizardForm',
'All Files')):
def getFileName(self, title, editbox, filters=u''):
"""
Opens a QFileDialog and writes the filename to the given editbox.
``title``
The title of the dialog (unicode).
``editbox``
A editbox (QLineEdit).
``filters``
The file extension filters. It should contain the file descriptions
as well as the file extensions. For example::
u'OpenLP 2.0 Databases (*.sqlite)'
"""
if filters:
filters += u';;'
filters += u'%s (*)' % translate('SongsPlugin.ImportWizardForm',
'All Files')
filename = QtGui.QFileDialog.getOpenFileName(self, title,
SettingsManager.get_last_dir(self.plugin.settingsSection, 1),
filters)
os.path.dirname(SettingsManager.get_last_dir(
self.plugin.settingsSection, 1)), filters)
if filename:
editbox.setText(filename)
SettingsManager.set_last_dir(
self.plugin.settingsSection,
SettingsManager.set_last_dir(self.plugin.settingsSection,
os.path.split(unicode(filename))[0], 1)
def getFiles(self, title, listbox,
filters = u'%s (*)' % translate('SongsPlugin.ImportWizardForm',
'All Files')):
def getFiles(self, title, listbox, filters=u''):
"""
Opens a QFileDialog and writes the filenames to the given listbox.
``title``
The title of the dialog (unicode).
``listbox``
A listbox (QListWidget).
``filters``
The file extension filters. It should contain the file descriptions
as well as the file extensions. For example::
u'SongBeamer files (*.sng)'
"""
if filters:
filters += u';;'
filters += u'%s (*)' % translate('SongsPlugin.ImportWizardForm',
'All Files')
filenames = QtGui.QFileDialog.getOpenFileNames(self, title,
SettingsManager.get_last_dir(self.plugin.settingsSection, 1),
filters)
os.path.dirname(SettingsManager.get_last_dir(
self.plugin.settingsSection, 1)), filters)
if filenames:
listbox.addItems(filenames)
SettingsManager.set_last_dir(
@ -293,24 +326,18 @@ class SongImportForm(QtGui.QWizard, Ui_SongImportWizard):
self.getFileName(
translate('SongsPlugin.ImportWizardForm',
'Select OpenLP 2.0 Database File'),
self.openLP2FilenameEdit,
u'%s (*.sqlite);;%s (*)'
self.openLP2FilenameEdit, u'%s (*.sqlite)'
% (translate('SongsPlugin.ImportWizardForm',
'OpenLP 2.0 Databases'),
translate('SongsPlugin.ImportWizardForm',
'All Files'))
'OpenLP 2.0 Databases'))
)
def onOpenLP1BrowseButtonClicked(self):
self.getFileName(
translate('SongsPlugin.ImportWizardForm',
'Select openlp.org 1.x Database File'),
self.openLP1FilenameEdit,
u'%s (*.olp);;%s (*)'
% (translate('SongsPlugin.ImportWizardForm',
'openlp.org v1.x Databases'),
translate('SongsPlugin.ImportWizardForm',
'All Files'))
self.openLP1FilenameEdit, u'%s (*.olp)'
% translate('SongsPlugin.ImportWizardForm',
'openlp.org v1.x Databases')
)
#def onOpenLyricsAddButtonClicked(self):
@ -337,12 +364,9 @@ class SongImportForm(QtGui.QWizard, Ui_SongImportWizard):
self.getFiles(
translate('SongsPlugin.ImportWizardForm',
'Select Words of Worship Files'),
self.wordsOfWorshipFileListWidget,
u'%s (*.wsg *.wow-song);;%s (*)'
% (translate('SongsPlugin.ImportWizardForm',
'Words Of Worship Song Files'),
translate('SongsPlugin.ImportWizardForm',
'All Files'))
self.wordsOfWorshipFileListWidget, u'%s (*.wsg *.wow-song)'
% translate('SongsPlugin.ImportWizardForm',
'Words Of Worship Song Files')
)
def onWordsOfWorshipRemoveButtonClicked(self):
@ -362,12 +386,9 @@ class SongImportForm(QtGui.QWizard, Ui_SongImportWizard):
self.getFiles(
translate('SongsPlugin.ImportWizardForm',
'Select Songs of Fellowship Files'),
self.songsOfFellowshipFileListWidget,
u'%s (*.rtf);;%s (*)'
% (translate('SongsPlugin.ImportWizardForm',
'Songs Of Felloship Song Files'),
translate('SongsPlugin.ImportWizardForm',
'All Files'))
self.songsOfFellowshipFileListWidget, u'%s (*.rtf)'
% translate('SongsPlugin.ImportWizardForm',
'Songs Of Felloship Song Files')
)
def onSongsOfFellowshipRemoveButtonClicked(self):
@ -394,7 +415,8 @@ class SongImportForm(QtGui.QWizard, Ui_SongImportWizard):
self.getFiles(
translate('SongsPlugin.ImportWizardForm',
'Select SongBeamer Files'),
self.songBeamerFileListWidget
self.songBeamerFileListWidget, u'%s (*.sng)' %
translate('SongsPlugin.ImportWizardForm', 'SongBeamer files')
)
def onSongBeamerRemoveButtonClicked(self):

View File

@ -411,7 +411,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
"""
existing_author = self.manager.get_object_filtered(Author,
and_(Author.first_name == old_author.first_name,
Author.last_name == old_author.last_name,
Author.last_name == old_author.last_name,
Author.display_name == old_author.display_name))
songs = self.manager.get_all_objects(Song,
Song.authors.contains(old_author))

View File

@ -71,7 +71,8 @@ class VerseType(object):
The string to return a VerseType for
"""
verse_type = verse_type.lower()
if verse_type == unicode(VerseType.to_string(VerseType.Verse)).lower()[0]:
if verse_type == \
unicode(VerseType.to_string(VerseType.Verse)).lower()[0]:
return translate('SongsPlugin.VerseType', 'Verse')
elif verse_type == \
unicode(VerseType.to_string(VerseType.Chorus)).lower()[0]:

View File

@ -197,7 +197,7 @@ class CCLIFileImport(SongImport):
verse_text = verse_lines[1]
elif verse_lines[0].startswith(u'('):
verse_type = u'O'
verse_text = verse_lines[1]
verse_text = verse_lines[1]
if len(verse_text) > 0:
self.add_verse(verse_text, verse_type)
check_first_verse_line = False
@ -303,13 +303,13 @@ class CCLIFileImport(SongImport):
verse_type = u'P'
elif line.startswith(u'(BRIDGE'):
verse_type = u'B'
# Handle all other misc types
# Handle all other misc types
elif line.startswith(u'('):
verse_type = u'O'
else:
verse_text = verse_text + line
verse_text = verse_text + line
check_first_verse_line = False
else:
else:
# We have verse content or the start of the
# last part. Add l so as to keep the CRLF
verse_text = verse_text + line

View File

@ -41,7 +41,7 @@ def strip_rtf(blob, encoding):
control_word = []
for c in blob:
if control:
# for delimiters, set control to False
# for delimiters, set control to False
if c == '{':
if len(control_word) > 0:
depth += 1

View File

@ -44,6 +44,7 @@ class SongListView(BaseListWithDnD):
self.PluginName = u'Songs'
BaseListWithDnD.__init__(self, parent)
class SongMediaItem(MediaManagerItem):
"""
This is the custom media manager item for Songs.
@ -392,7 +393,7 @@ class SongMediaItem(MediaManagerItem):
author_audit.append(unicode(author.display_name))
raw_footer.append(song.title)
raw_footer.append(author_list)
raw_footer.append(song.copyright )
raw_footer.append(song.copyright)
raw_footer.append(unicode(
translate('SongsPlugin.MediaItem', 'CCLI License: ') +
QtCore.QSettings().value(u'general/ccli number',
@ -417,27 +418,37 @@ class SongMediaItem(MediaManagerItem):
item.data_string[u'title'].split(u'@')[0].lower() ,
Song.search_title.asc())
author_list = item.data_string[u'authors'].split(u', ')
# The service item always has an author (at least it has u'' as
# author). However, songs saved in the database do not have to have
# an author.
if u'' in author_list:
author_list.remove(u'')
editId = 0
uuid = item._uuid
add_song = True
if search_results:
for song in search_results:
count = 0
for author in song.authors:
if author.display_name in author_list:
count += 1
# All Authors the same
if count == len(author_list):
editId = song.id
same_authors = True
# If the author counts are different, we do not have to do
# any further checking. This is also important when a song
# does not have any author (because we can not loop over an
# empty list).
if len(song.authors) == len(author_list):
for author in song.authors:
if author.display_name not in author_list:
same_authors = False
else:
# Authors different
if self.addSongFromService:
editId = self.openLyrics. \
xml_to_song(item.xml_version)
else:
# Title does not match
same_authors = False
# All authors are the same, so we can stop here and the song
# does not have to be saved.
if same_authors:
add_song = False
editId = song.id
break
if add_song:
if self.addSongFromService:
editId = self.openLyrics.xml_to_song(item.xml_version)
# Update service with correct song id
# Update service with correct song id.
if editId != 0:
Receiver.send_message(u'service_item_update',
u'%s:%s' %(editId, uuid))

View File

@ -46,7 +46,7 @@ else:
class OooImport(SongImport):
"""
Import songs from Impress/Powerpoint docs using Impress
Import songs from Impress/Powerpoint docs using Impress
"""
def __init__(self, master_manager, **kwargs):
"""
@ -122,7 +122,7 @@ class OooImport(SongImport):
manager = ctx.ServiceManager
self.desktop = manager.createInstanceWithContext(
"com.sun.star.frame.Desktop", ctx)
def start_ooo_process(self):
try:
if os.name == u'nt':
@ -168,11 +168,11 @@ class OooImport(SongImport):
u'Processing file ' + filepath, 0)
except:
pass
return
return
def close_ooo_file(self):
"""
Close file.
Close file.
"""
self.document.close(True)
self.document = None
@ -187,7 +187,7 @@ class OooImport(SongImport):
def process_pres(self):
"""
Process the file
"""
"""
doc = self.document
slides = doc.getDrawPages()
text = u''
@ -195,7 +195,7 @@ class OooImport(SongImport):
if self.abort:
self.import_wizard.incrementProgressBar(u'Import cancelled', 0)
return
slide = slides.getByIndex(slide_no)
slide = slides.getByIndex(slide_no)
slidetext = u''
for idx in range(slide.getCount()):
shape = slide.getByIndex(idx)
@ -209,12 +209,12 @@ class OooImport(SongImport):
songs = SongImport.process_songs_text(self.manager, text)
for song in songs:
song.finish()
return
return
def process_doc(self):
"""
Process the doc file, a paragraph at a time
"""
"""
text = u''
paragraphs = self.document.getText().createEnumeration()
while paragraphs.hasMoreElements():

View File

@ -249,7 +249,7 @@ class OpenSongImport(SongImport):
words = thisline[1:].strip()
if words is None:
words = thisline
if not versenum:
if not versenum:
versenum = u'1'
if versenum is not None:
versetag = u'%s%s' % (versetype, versenum)
@ -298,7 +298,7 @@ class OpenSongImport(SongImport):
for tag in order:
if tag[0].isdigit():
# Assume it's a verse if it has no prefix
tag = u'V' + tag
tag = u'V' + tag
elif not re.search('\d+', tag):
# Assume it's no.1 if there's no digits
tag = tag + u'1'

View File

@ -56,13 +56,13 @@ class SofImport(OooImport):
"""
Import songs provided on disks with the Songs of Fellowship music books
VOLS1_2.RTF, sof3words.rtf and sof4words.rtf
Use OpenOffice.org Writer for processing the rtf file
The three books are not only inconsistant with each other, they are
The three books are not only inconsistant with each other, they are
inconsistant in themselves too with their formatting. Not only this, but
the 1+2 book does not space out verses correctly. This script attempts
to sort it out, but doesn't get it 100% right. But better than having to
to sort it out, but doesn't get it 100% right. But better than having to
type them all out!
It attempts to detect italiced verses, and treats these as choruses in
@ -96,7 +96,7 @@ class SofImport(OooImport):
def process_sof_file(self):
"""
Process the RTF file, a paragraph at a time
"""
"""
self.blanklines = 0
self.new_song()
paragraphs = self.document.getText().createEnumeration()
@ -113,11 +113,11 @@ class SofImport(OooImport):
def process_paragraph(self, paragraph):
"""
Process a paragraph.
Process a paragraph.
In the first book, a paragraph is a single line. In the latter ones
they may contain multiple lines.
Each paragraph contains textportions. Each textportion has it's own
styling, e.g. italics, bold etc.
styling, e.g. italics, bold etc.
Also check for page breaks, which indicates a new song in books 1+2.
In later books, there may not be line breaks, so check for 3 or more
newlines
@ -136,7 +136,7 @@ class SofImport(OooImport):
self.new_song()
text = u''
self.process_paragraph_text(text)
def process_paragraph_text(self, text):
"""
Split the paragraph text into multiple lines and process
@ -147,12 +147,12 @@ class SofImport(OooImport):
self.new_song()
def process_paragraph_line(self, text):
"""
"""
Process a single line. Throw away that text which isn't relevant, i.e.
stuff that appears at the end of the song.
Anything that is OK, append to the current verse
"""
text = text.strip()
text = text.strip()
if text == u'':
self.blanklines += 1
if self.blanklines > 1:
@ -164,7 +164,7 @@ class SofImport(OooImport):
if self.skip_to_close_bracket:
if text.endswith(u')'):
self.skip_to_close_bracket = False
return
return
if text.startswith(u'CCL Licence'):
self.italics = False
return
@ -264,7 +264,7 @@ class SofImport(OooImport):
"""
Add the author. OpenLP stores them individually so split by 'and', '&'
and comma.
However need to check for "Mr and Mrs Smith" and turn it to
However need to check for "Mr and Mrs Smith" and turn it to
"Mr Smith" and "Mrs Smith".
"""
text = text.replace(u' and ', u' & ')
@ -276,7 +276,7 @@ class SofImport(OooImport):
we're beyond the second line of first verse, then this indicates
a change of verse. Italics are a chorus
"""
if self.italics != self.is_chorus and ((len(self.song.verses) > 0) or
if self.italics != self.is_chorus and ((len(self.song.verses) > 0) or
(self.currentverse.count(u'\n') > 1)):
self.finish_verse()
if self.italics:
@ -307,7 +307,7 @@ class SofImport(OooImport):
ln = 0
if line:
verse = line + u'\n'
else:
else:
verse = u''
else:
verse += line + u'\n'
@ -320,34 +320,34 @@ class SofImport(OooImport):
def uncap_text(self, text):
"""
"""
Words in the title are in all capitals, so we lowercase them.
However some of these words, e.g. referring to God need a leading
However some of these words, e.g. referring to God need a leading
capital letter.
There is a complicated word "One", which is sometimes lower and
There is a complicated word "One", which is sometimes lower and
sometimes upper depending on context. Never mind, keep it lower.
"""
textarr = re.split(u'(\W+)', text)
textarr[0] = textarr[0].capitalize()
for i in range(1, len(textarr)):
# Do not translate these. Fixed strings in SOF song file
if textarr[i] in (u'JESUS', u'CHRIST', u'KING', u'ALMIGHTY',
u'REDEEMER', u'SHEPHERD', u'SON', u'GOD', u'LORD', u'FATHER',
u'HOLY', u'SPIRIT', u'LAMB', u'YOU', u'YOUR', u'I', u'I\'VE',
u'I\'M', u'I\'LL', u'SAVIOUR', u'O', u'YOU\'RE', u'HE', u'HIS',
u'HIM', u'ZION', u'EMMANUEL', u'MAJESTY', u'JESUS\'', u'JIREH',
u'JUDAH', u'LION', u'LORD\'S', u'ABRAHAM', u'GOD\'S',
if textarr[i] in (u'JESUS', u'CHRIST', u'KING', u'ALMIGHTY',
u'REDEEMER', u'SHEPHERD', u'SON', u'GOD', u'LORD', u'FATHER',
u'HOLY', u'SPIRIT', u'LAMB', u'YOU', u'YOUR', u'I', u'I\'VE',
u'I\'M', u'I\'LL', u'SAVIOUR', u'O', u'YOU\'RE', u'HE', u'HIS',
u'HIM', u'ZION', u'EMMANUEL', u'MAJESTY', u'JESUS\'', u'JIREH',
u'JUDAH', u'LION', u'LORD\'S', u'ABRAHAM', u'GOD\'S',
u'FATHER\'S', u'ELIJAH'):
textarr[i] = textarr[i].capitalize()
else:
textarr[i] = textarr[i].lower()
text = u''.join(textarr)
return text
def verse_splits(self, song_number):
"""
Because someone at Kingsway forgot to check the 1+2 RTF file,
Because someone at Kingsway forgot to check the 1+2 RTF file,
some verses were not formatted correctly.
"""
if song_number == 11:
@ -369,7 +369,7 @@ class SofImport(OooImport):
if song_number == 50:
return 8
if song_number == 70:
return 4
return 4
if song_number == 75:
return 8
if song_number == 79:
@ -529,7 +529,7 @@ class SofImport(OooImport):
if song_number == 955:
return 9
if song_number == 968:
return 8
return 8
if song_number == 972:
return 7
if song_number == 974:

View File

@ -24,7 +24,7 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`songbeamerimport` module provides the functionality for importing
The :mod:`songbeamerimport` module provides the functionality for importing
SongBeamer songs into the OpenLP database.
"""
import logging
@ -90,7 +90,7 @@ class SongBeamerImport(SongImport):
len(self.import_source))
for file in self.import_source:
# TODO: check that it is a valid SongBeamer file
self.current_verse = u''
self.current_verse = u''
self.current_verse_type = u'V'
read_verses = False
self.file_name = os.path.split(file)[1]
@ -115,7 +115,7 @@ class SongBeamerImport(SongImport):
self.replace_html_tags()
self.add_verse(self.current_verse,
self.current_verse_type)
self.current_verse = u''
self.current_verse = u''
self.current_verse_type = u'V'
read_verses = True
verse_start = True

View File

@ -247,7 +247,7 @@ class SongImport(QtCore.QObject):
"""
Extracts alphanumeric words for searchable fields
"""
return re.sub(r'\W+', u' ', text)
return re.sub(r'\W+', u' ', text, re.UNICODE)
def finish(self):
"""

View File

@ -56,11 +56,11 @@ def test():
assert o.title == u'Martins Test'
assert o.alternate_title == u''
assert o.song_number == u'1'
assert [u'C1', u'Chorus 1'] in o.verses
assert [u'C2', u'Chorus 2'] in o.verses
assert not [u'C3', u'Chorus 3'] in o.verses
assert [u'B1', u'Bridge 1\nBridge 1 line 2'] in o.verses
assert [u'V1', u'v1 Line 1\nV1 Line 2'] in o.verses
assert [u'C1', u'Chorus 1'] in o.verses
assert [u'C2', u'Chorus 2'] in o.verses
assert not [u'C3', u'Chorus 3'] in o.verses
assert [u'B1', u'Bridge 1\nBridge 1 line 2'] in o.verses
assert [u'V1', u'v1 Line 1\nV1 Line 2'] in o.verses
assert [u'V2', u'v2 Line 1\nV2 Line 2'] in o.verses
assert [u'V3A', u'V3 Line 1\nV3 Line 2'] in o.verses
assert [u'RAP1', u'Rap 1 Line 1\nRap 1 Line 2'] in o.verses
@ -80,11 +80,11 @@ def test():
assert o.title == u'Martins Test'
assert o.alternate_title == u''
assert o.song_number == u'1'
assert [u'B1', u'Bridge 1\nBridge 1 line 2'] in o.verses
assert [u'C1', u'Chorus 1'] in o.verses
assert [u'C2', u'Chorus 2'] in o.verses
assert not [u'C3', u'Chorus 3'] in o.verses
assert [u'V1', u'v1 Line 1\nV1 Line 2'] in o.verses
assert [u'B1', u'Bridge 1\nBridge 1 line 2'] in o.verses
assert [u'C1', u'Chorus 1'] in o.verses
assert [u'C2', u'Chorus 2'] in o.verses
assert not [u'C3', u'Chorus 3'] in o.verses
assert [u'V1', u'v1 Line 1\nV1 Line 2'] in o.verses
assert [u'V2', u'v2 Line 1\nV2 Line 2'] in o.verses
print o.verse_order_list
assert o.verse_order_list == [u'V1', u'C1', u'V2', u'C2', u'V3', u'B1', u'V1']
@ -99,11 +99,11 @@ def test():
assert o.alternate_title == u''
assert o.song_number == u'2'
print o.verses
assert [u'B1', u'Bridge 1\nBridge 1 line 2'] in o.verses
assert [u'C1', u'Chorus 1'] in o.verses
assert [u'C2', u'Chorus 2'] in o.verses
assert not [u'C3', u'Chorus 3'] in o.verses
assert [u'V1', u'v1 Line 1\nV1 Line 2'] in o.verses
assert [u'B1', u'Bridge 1\nBridge 1 line 2'] in o.verses
assert [u'C1', u'Chorus 1'] in o.verses
assert [u'C2', u'Chorus 2'] in o.verses
assert not [u'C3', u'Chorus 3'] in o.verses
assert [u'V1', u'v1 Line 1\nV1 Line 2'] in o.verses
assert [u'V2', u'v2 Line 1\nV2 Line 2'] in o.verses
print o.verse_order_list
assert o.verse_order_list == [u'V1', u'V2', u'B1', u'C1', u'C2']
@ -120,7 +120,7 @@ def test():
assert o.verse_order_list == [u'V1']
assert o.topics == [u'Worship: Declaration']
print o.verses[0]
assert [u'V1', u'Line 1\nLine 2'] in o.verses
assert [u'V1', u'Line 1\nLine 2'] in o.verses
print "Tests passed"

View File

@ -297,6 +297,8 @@ class OpenLyricsParser(object):
song_xml = objectify.fromstring(xml)
properties = song_xml.properties
song.copyright = unicode(properties.copyright.text)
if song.copyright == u'None':
song.copyright = u''
song.verse_order = unicode(properties.verseOrder.text)
if song.verse_order == u'None':
song.verse_order = u''
@ -357,7 +359,7 @@ class OpenLyricsParser(object):
def _add_text_to_element(self, tag, parent, text=None, label=None):
if label:
element = etree.Element(tag, name = unicode(label))
element = etree.Element(tag, name=unicode(label))
else:
element = etree.Element(tag)
if text:

View File

@ -31,7 +31,7 @@ from PyQt4 import QtCore, QtGui
from openlp.core.lib import Plugin, StringContent, build_icon, translate
from openlp.core.lib.db import Manager
from openlp.plugins.songs.lib import SongMediaItem, SongsTab
from openlp.plugins.songs.lib import SongMediaItem, SongsTab, SongXMLParser
from openlp.plugins.songs.lib.db import init_schema, Song
from openlp.plugins.songs.lib.importer import SongFormat
@ -150,9 +150,13 @@ class SongsPlugin(Plugin):
song.title = u''
if song.alternate_title is None:
song.alternate_title = u''
song.search_title = self.whitespace.sub(u' ', \
song.title.lower()) + u' ' + \
self.whitespace.sub(u' ', song.alternate_title.lower())
song.search_title = self.whitespace.sub(u' ', song.title.lower() + \
u' ' + song.alternate_title.lower())
lyrics = u''
verses = SongXMLParser(song.lyrics).get_verses()
for verse in verses:
lyrics = lyrics + self.whitespace.sub(u' ', verse[1]) + u' '
song.search_lyrics = lyrics.lower()
progressDialog.setValue(counter)
self.manager.save_objects(songs)
counter += 1

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 833 B

View File

@ -39,6 +39,7 @@
<file>general_new.png</file>
<file>general_open.png</file>
<file>general_save.png</file>
<file>general_email.png</file>
</qresource>
<qresource prefix="slides">
<file>slide_close.png</file>

2
scripts/openlp-remoteclient.py Executable file → Normal file
View File

@ -47,7 +47,7 @@ def main():
help="Recipient address ",
default="localhost")
parser.add_option("-e", "--event",
help="Action to be performed",
help="Action to be performed",
default="alerts_text")
parser.add_option("-m", "--message",
help="Message to be passed for the action",