forked from openlp/openlp
r1161
This commit is contained in:
commit
ab4d7e7294
@ -113,6 +113,14 @@ class ImageManager(QtCore.QObject):
|
|||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
return self._cache[name].image_bytes
|
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):
|
def add_image(self, name, path):
|
||||||
"""
|
"""
|
||||||
Add image to cache if it is not already there
|
Add image to cache if it is not already there
|
||||||
@ -125,6 +133,8 @@ class ImageManager(QtCore.QObject):
|
|||||||
image.image = resize_image(path,
|
image.image = resize_image(path,
|
||||||
self.width, self.height)
|
self.width, self.height)
|
||||||
self._cache[name] = image
|
self._cache[name] = image
|
||||||
|
else:
|
||||||
|
log.debug(u'Image in cache %s:%s' % (name, path))
|
||||||
self._cache_dirty = True
|
self._cache_dirty = True
|
||||||
# only one thread please
|
# only one thread please
|
||||||
if not self._thread_running:
|
if not self._thread_running:
|
||||||
|
38
openlp/core/lib/mailto/LICENSE
Normal file
38
openlp/core/lib/mailto/LICENSE
Normal 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.
|
||||||
|
|
321
openlp/core/lib/mailto/__init__.py
Normal file
321
openlp/core/lib/mailto/__init__.py
Normal 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)
|
||||||
|
|
@ -108,7 +108,7 @@ class Plugin(QtCore.QObject):
|
|||||||
"""
|
"""
|
||||||
log.info(u'loaded')
|
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
|
This is the constructor for the plugin object. This provides an easy
|
||||||
way for descendent plugins to populate common data. This method *must*
|
way for descendent plugins to populate common data. This method *must*
|
||||||
@ -124,7 +124,7 @@ class Plugin(QtCore.QObject):
|
|||||||
``version``
|
``version``
|
||||||
Defaults to *None*. The version of the plugin.
|
Defaults to *None*. The version of the plugin.
|
||||||
|
|
||||||
``plugin_helpers``
|
``pluginHelpers``
|
||||||
Defaults to *None*. A list of helper objects.
|
Defaults to *None*. A list of helper objects.
|
||||||
"""
|
"""
|
||||||
QtCore.QObject.__init__(self)
|
QtCore.QObject.__init__(self)
|
||||||
@ -139,14 +139,14 @@ class Plugin(QtCore.QObject):
|
|||||||
self.status = PluginStatus.Inactive
|
self.status = PluginStatus.Inactive
|
||||||
# Set up logging
|
# Set up logging
|
||||||
self.log = logging.getLogger(self.name)
|
self.log = logging.getLogger(self.name)
|
||||||
self.previewController = plugin_helpers[u'preview']
|
self.previewController = pluginHelpers[u'preview']
|
||||||
self.liveController = plugin_helpers[u'live']
|
self.liveController = pluginHelpers[u'live']
|
||||||
self.renderManager = plugin_helpers[u'render']
|
self.renderManager = pluginHelpers[u'render']
|
||||||
self.serviceManager = plugin_helpers[u'service']
|
self.serviceManager = pluginHelpers[u'service']
|
||||||
self.settingsForm = plugin_helpers[u'settings form']
|
self.settingsForm = pluginHelpers[u'settings form']
|
||||||
self.mediadock = plugin_helpers[u'toolbox']
|
self.mediadock = pluginHelpers[u'toolbox']
|
||||||
self.pluginManager = plugin_helpers[u'pluginmanager']
|
self.pluginManager = pluginHelpers[u'pluginmanager']
|
||||||
self.formparent = plugin_helpers[u'formparent']
|
self.formparent = pluginHelpers[u'formparent']
|
||||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||||
QtCore.SIGNAL(u'%s_add_service_item' % self.name),
|
QtCore.SIGNAL(u'%s_add_service_item' % self.name),
|
||||||
self.processAddServiceEvent)
|
self.processAddServiceEvent)
|
||||||
|
@ -213,6 +213,8 @@ class RenderManager(object):
|
|||||||
# make big page for theme edit dialog to get line count
|
# make big page for theme edit dialog to get line count
|
||||||
if self.force_page:
|
if self.force_page:
|
||||||
verse = verse + verse + verse
|
verse = verse + verse + verse
|
||||||
|
else:
|
||||||
|
self.image_manager.del_image(self.theme_data.theme_name)
|
||||||
footer = []
|
footer = []
|
||||||
footer.append(u'Arky Arky (Unknown)' )
|
footer.append(u'Arky Arky (Unknown)' )
|
||||||
footer.append(u'Public Domain')
|
footer.append(u'Public Domain')
|
||||||
|
@ -44,6 +44,7 @@ class ServiceItemType(object):
|
|||||||
Image = 2
|
Image = 2
|
||||||
Command = 3
|
Command = 3
|
||||||
|
|
||||||
|
|
||||||
class ItemCapabilities(object):
|
class ItemCapabilities(object):
|
||||||
"""
|
"""
|
||||||
Provides an enumeration of a serviceitem's capabilities
|
Provides an enumeration of a serviceitem's capabilities
|
||||||
|
@ -166,6 +166,17 @@ class Ui_AboutDialog(object):
|
|||||||
' PyQt4: http://www.riverbankcomputing.co.uk/software/pyqt/'
|
' PyQt4: http://www.riverbankcomputing.co.uk/software/pyqt/'
|
||||||
'intro\n'
|
'intro\n'
|
||||||
' Oxygen Icons: http://oxygen-icons.org/\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.setTabText(
|
||||||
self.aboutNotebook.indexOf(self.creditsTab),
|
self.aboutNotebook.indexOf(self.creditsTab),
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
from PyQt4 import QtCore, QtGui
|
from PyQt4 import QtCore, QtGui
|
||||||
|
|
||||||
from openlp.core.lib import translate
|
from openlp.core.lib import translate, build_icon
|
||||||
|
|
||||||
class Ui_ExceptionDialog(object):
|
class Ui_ExceptionDialog(object):
|
||||||
def setupUi(self, exceptionDialog):
|
def setupUi(self, exceptionDialog):
|
||||||
@ -63,12 +63,27 @@ class Ui_ExceptionDialog(object):
|
|||||||
self.exceptionButtonBox.setStandardButtons(QtGui.QDialogButtonBox.Close)
|
self.exceptionButtonBox.setStandardButtons(QtGui.QDialogButtonBox.Close)
|
||||||
self.exceptionButtonBox.setObjectName(u'exceptionButtonBox')
|
self.exceptionButtonBox.setObjectName(u'exceptionButtonBox')
|
||||||
self.exceptionLayout.addWidget(self.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)
|
self.retranslateUi(exceptionDialog)
|
||||||
QtCore.QObject.connect(self.exceptionButtonBox,
|
QtCore.QObject.connect(self.exceptionButtonBox,
|
||||||
QtCore.SIGNAL(u'accepted()'), exceptionDialog.accept)
|
QtCore.SIGNAL(u'accepted()'), exceptionDialog.accept)
|
||||||
QtCore.QObject.connect(self.exceptionButtonBox,
|
QtCore.QObject.connect(self.exceptionButtonBox,
|
||||||
QtCore.SIGNAL(u'rejected()'), exceptionDialog.reject)
|
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)
|
QtCore.QMetaObject.connectSlotsByName(exceptionDialog)
|
||||||
|
|
||||||
def retranslateUi(self, 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 '
|
'developers, so please e-mail it to bugs@openlp.org, along with a '
|
||||||
'detailed description of what you were doing when the problem '
|
'detailed description of what you were doing when the problem '
|
||||||
'occurred.'))
|
'occurred.'))
|
||||||
|
self.sendReportButton.setText(translate('OpenLP.ExceptionDialog',
|
||||||
|
'Send E-Mail'))
|
||||||
|
self.saveReportButton.setText(translate('OpenLP.ExceptionDialog',
|
||||||
|
'Save to File'))
|
||||||
|
@ -23,11 +23,44 @@
|
|||||||
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
|
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
|
||||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
# 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
|
from exceptiondialog import Ui_ExceptionDialog
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
class ExceptionForm(QtGui.QDialog, Ui_ExceptionDialog):
|
class ExceptionForm(QtGui.QDialog, Ui_ExceptionDialog):
|
||||||
"""
|
"""
|
||||||
The exception dialog
|
The exception dialog
|
||||||
@ -35,3 +68,80 @@ class ExceptionForm(QtGui.QDialog, Ui_ExceptionDialog):
|
|||||||
def __init__(self, parent):
|
def __init__(self, parent):
|
||||||
QtGui.QDialog.__init__(self, parent)
|
QtGui.QDialog.__init__(self, parent)
|
||||||
self.setupUi(self)
|
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)
|
||||||
|
@ -30,24 +30,24 @@ from openlp.core.lib import translate
|
|||||||
|
|
||||||
class Ui_FileRenameDialog(object):
|
class Ui_FileRenameDialog(object):
|
||||||
def setupUi(self, FileRenameDialog):
|
def setupUi(self, FileRenameDialog):
|
||||||
FileRenameDialog.setObjectName("FileRenameDialog")
|
FileRenameDialog.setObjectName(u'FileRenameDialog')
|
||||||
FileRenameDialog.resize(400, 87)
|
FileRenameDialog.resize(400, 87)
|
||||||
self.buttonBox = QtGui.QDialogButtonBox(FileRenameDialog)
|
self.buttonBox = QtGui.QDialogButtonBox(FileRenameDialog)
|
||||||
self.buttonBox.setGeometry(QtCore.QRect(210, 50, 171, 25))
|
self.buttonBox.setGeometry(QtCore.QRect(210, 50, 171, 25))
|
||||||
self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel |
|
self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel |
|
||||||
QtGui.QDialogButtonBox.Ok)
|
QtGui.QDialogButtonBox.Ok)
|
||||||
self.buttonBox.setObjectName("buttonBox")
|
self.buttonBox.setObjectName(u'buttonBox')
|
||||||
self.widget = QtGui.QWidget(FileRenameDialog)
|
self.widget = QtGui.QWidget(FileRenameDialog)
|
||||||
self.widget.setGeometry(QtCore.QRect(10, 10, 381, 35))
|
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 = QtGui.QHBoxLayout(self.widget)
|
||||||
self.horizontalLayout.setObjectName("horizontalLayout")
|
self.horizontalLayout.setObjectName(u'horizontalLayout')
|
||||||
self.FileRenameLabel = QtGui.QLabel(self.widget)
|
self.fileRenameLabel = QtGui.QLabel(self.widget)
|
||||||
self.FileRenameLabel.setObjectName("FileRenameLabel")
|
self.fileRenameLabel.setObjectName(u'fileRenameLabel')
|
||||||
self.horizontalLayout.addWidget(self.FileRenameLabel)
|
self.horizontalLayout.addWidget(self.fileRenameLabel)
|
||||||
self.FileNameEdit = QtGui.QLineEdit(self.widget)
|
self.fileNameEdit = QtGui.QLineEdit(self.widget)
|
||||||
self.FileNameEdit.setObjectName("FileNameEdit")
|
self.fileNameEdit.setObjectName(u'fileNameEdit')
|
||||||
self.horizontalLayout.addWidget(self.FileNameEdit)
|
self.horizontalLayout.addWidget(self.fileNameEdit)
|
||||||
|
|
||||||
self.retranslateUi(FileRenameDialog)
|
self.retranslateUi(FileRenameDialog)
|
||||||
QtCore.QMetaObject.connectSlotsByName(FileRenameDialog)
|
QtCore.QMetaObject.connectSlotsByName(FileRenameDialog)
|
||||||
@ -55,6 +55,5 @@ class Ui_FileRenameDialog(object):
|
|||||||
def retranslateUi(self, FileRenameDialog):
|
def retranslateUi(self, FileRenameDialog):
|
||||||
FileRenameDialog.setWindowTitle(translate('OpenLP.FileRenameForm',
|
FileRenameDialog.setWindowTitle(translate('OpenLP.FileRenameForm',
|
||||||
'File Rename'))
|
'File Rename'))
|
||||||
self.FileRenameLabel.setText(translate('OpenLP.FileRenameForm',
|
self.fileRenameLabel.setText(translate('OpenLP.FileRenameForm',
|
||||||
'New File Name:'))
|
'New File Name:'))
|
||||||
|
|
||||||
|
@ -97,16 +97,16 @@ class Ui_MainWindow(object):
|
|||||||
self.ControlSplitter.setObjectName(u'ControlSplitter')
|
self.ControlSplitter.setObjectName(u'ControlSplitter')
|
||||||
self.MainContentLayout.addWidget(self.ControlSplitter)
|
self.MainContentLayout.addWidget(self.ControlSplitter)
|
||||||
# Create slide controllers
|
# Create slide controllers
|
||||||
self.PreviewController = SlideController(self, self.settingsmanager,
|
self.previewController = SlideController(self, self.settingsmanager,
|
||||||
self.screens)
|
self.screens)
|
||||||
self.LiveController = SlideController(self, self.settingsmanager,
|
self.liveController = SlideController(self, self.settingsmanager,
|
||||||
self.screens, True)
|
self.screens, True)
|
||||||
previewVisible = QtCore.QSettings().value(
|
previewVisible = QtCore.QSettings().value(
|
||||||
u'user interface/preview panel', QtCore.QVariant(True)).toBool()
|
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',
|
liveVisible = QtCore.QSettings().value(u'user interface/live panel',
|
||||||
QtCore.QVariant(True)).toBool()
|
QtCore.QVariant(True)).toBool()
|
||||||
self.LiveController.Panel.setVisible(liveVisible)
|
self.liveController.Panel.setVisible(liveVisible)
|
||||||
# Create menu
|
# Create menu
|
||||||
self.MenuBar = QtGui.QMenuBar(MainWindow)
|
self.MenuBar = QtGui.QMenuBar(MainWindow)
|
||||||
self.MenuBar.setGeometry(QtCore.QRect(0, 0, 1087, 27))
|
self.MenuBar.setGeometry(QtCore.QRect(0, 0, 1087, 27))
|
||||||
@ -362,8 +362,8 @@ class Ui_MainWindow(object):
|
|||||||
"""
|
"""
|
||||||
Splitter between the Preview and Live Controllers.
|
Splitter between the Preview and Live Controllers.
|
||||||
"""
|
"""
|
||||||
self.LiveController.widthChanged()
|
self.liveController.widthChanged()
|
||||||
self.PreviewController.widthChanged()
|
self.previewController.widthChanged()
|
||||||
|
|
||||||
def retranslateUi(self, MainWindow):
|
def retranslateUi(self, MainWindow):
|
||||||
"""
|
"""
|
||||||
@ -548,8 +548,8 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
|
|||||||
self.recentFiles = QtCore.QStringList()
|
self.recentFiles = QtCore.QStringList()
|
||||||
# Set up the path with plugins
|
# Set up the path with plugins
|
||||||
pluginpath = AppLocation.get_directory(AppLocation.PluginsDir)
|
pluginpath = AppLocation.get_directory(AppLocation.PluginsDir)
|
||||||
self.plugin_manager = PluginManager(pluginpath)
|
self.pluginManager = PluginManager(pluginpath)
|
||||||
self.plugin_helpers = {}
|
self.pluginHelpers = {}
|
||||||
# Set up the interface
|
# Set up the interface
|
||||||
self.setupUi(self)
|
self.setupUi(self)
|
||||||
# Load settings after setupUi so default UI sizes are overwritten
|
# 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)
|
self.mediaDockManager = MediaDockManager(self.MediaToolBox)
|
||||||
log.info(u'Load Plugins')
|
log.info(u'Load Plugins')
|
||||||
# make the controllers available to the plugins
|
# make the controllers available to the plugins
|
||||||
self.plugin_helpers[u'preview'] = self.PreviewController
|
self.pluginHelpers[u'preview'] = self.previewController
|
||||||
self.plugin_helpers[u'live'] = self.LiveController
|
self.pluginHelpers[u'live'] = self.liveController
|
||||||
self.plugin_helpers[u'render'] = self.renderManager
|
self.pluginHelpers[u'render'] = self.renderManager
|
||||||
self.plugin_helpers[u'service'] = self.ServiceManagerContents
|
self.pluginHelpers[u'service'] = self.ServiceManagerContents
|
||||||
self.plugin_helpers[u'settings form'] = self.settingsForm
|
self.pluginHelpers[u'settings form'] = self.settingsForm
|
||||||
self.plugin_helpers[u'toolbox'] = self.mediaDockManager
|
self.pluginHelpers[u'toolbox'] = self.mediaDockManager
|
||||||
self.plugin_helpers[u'pluginmanager'] = self.plugin_manager
|
self.pluginHelpers[u'pluginmanager'] = self.pluginManager
|
||||||
self.plugin_helpers[u'formparent'] = self
|
self.pluginHelpers[u'formparent'] = self
|
||||||
self.plugin_manager.find_plugins(pluginpath, self.plugin_helpers)
|
self.pluginManager.find_plugins(pluginpath, self.pluginHelpers)
|
||||||
# hook methods have to happen after find_plugins. Find plugins needs
|
# hook methods have to happen after find_plugins. Find plugins needs
|
||||||
# the controllers hence the hooks have moved from setupUI() to here
|
# the controllers hence the hooks have moved from setupUI() to here
|
||||||
# Find and insert settings tabs
|
# Find and insert settings tabs
|
||||||
log.info(u'hook settings')
|
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
|
# Find and insert media manager items
|
||||||
log.info(u'hook media')
|
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.
|
# Call the hook method to pull in import menus.
|
||||||
log.info(u'hook 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.
|
# 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.
|
# 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.
|
# Call the initialise method to setup plugins.
|
||||||
log.info(u'initialise plugins')
|
log.info(u'initialise plugins')
|
||||||
self.plugin_manager.initialise_plugins()
|
self.pluginManager.initialise_plugins()
|
||||||
# Once all components are initialised load the Themes
|
# Once all components are initialised load the Themes
|
||||||
log.info(u'Load Themes')
|
log.info(u'Load Themes')
|
||||||
self.ThemeManagerContents.loadThemes()
|
self.ThemeManagerContents.loadThemes()
|
||||||
@ -695,10 +695,10 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
|
|||||||
Show the main form, as well as the display form
|
Show the main form, as well as the display form
|
||||||
"""
|
"""
|
||||||
QtGui.QWidget.show(self)
|
QtGui.QWidget.show(self)
|
||||||
self.LiveController.display.setup()
|
self.liveController.display.setup()
|
||||||
self.PreviewController.display.setup()
|
self.previewController.display.setup()
|
||||||
if self.LiveController.display.isVisible():
|
if self.liveController.display.isVisible():
|
||||||
self.LiveController.display.setFocus()
|
self.liveController.display.setFocus()
|
||||||
self.activateWindow()
|
self.activateWindow()
|
||||||
if QtCore.QSettings().value(
|
if QtCore.QSettings().value(
|
||||||
self.generalSettingsSection + u'/auto open',
|
self.generalSettingsSection + u'/auto open',
|
||||||
@ -723,7 +723,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
|
|||||||
settings = QtCore.QSettings()
|
settings = QtCore.QSettings()
|
||||||
if settings.value(u'%s/screen blank' % self.generalSettingsSection,
|
if settings.value(u'%s/screen blank' % self.generalSettingsSection,
|
||||||
QtCore.QVariant(False)).toBool():
|
QtCore.QVariant(False)).toBool():
|
||||||
self.LiveController.mainDisplaySetBackground()
|
self.liveController.mainDisplaySetBackground()
|
||||||
if settings.value(u'blank warning',
|
if settings.value(u'blank warning',
|
||||||
QtCore.QVariant(False)).toBool():
|
QtCore.QVariant(False)).toBool():
|
||||||
QtGui.QMessageBox.question(self,
|
QtGui.QMessageBox.question(self,
|
||||||
@ -852,11 +852,11 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
|
|||||||
QtCore.QVariant(self.MediaToolBox.currentIndex()))
|
QtCore.QVariant(self.MediaToolBox.currentIndex()))
|
||||||
# Call the cleanup method to shutdown plugins.
|
# Call the cleanup method to shutdown plugins.
|
||||||
log.info(u'cleanup plugins')
|
log.info(u'cleanup plugins')
|
||||||
self.plugin_manager.finalise_plugins()
|
self.pluginManager.finalise_plugins()
|
||||||
# Save settings
|
# Save settings
|
||||||
self.saveSettings()
|
self.saveSettings()
|
||||||
# Close down the display
|
# Close down the display
|
||||||
self.LiveController.display.close()
|
self.liveController.display.close()
|
||||||
|
|
||||||
def serviceChanged(self, reset=False, serviceName=None):
|
def serviceChanged(self, reset=False, serviceName=None):
|
||||||
"""
|
"""
|
||||||
@ -910,7 +910,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
|
|||||||
True - Visible
|
True - Visible
|
||||||
False - Hidden
|
False - Hidden
|
||||||
"""
|
"""
|
||||||
self.PreviewController.Panel.setVisible(visible)
|
self.previewController.Panel.setVisible(visible)
|
||||||
QtCore.QSettings().setValue(u'user interface/preview panel',
|
QtCore.QSettings().setValue(u'user interface/preview panel',
|
||||||
QtCore.QVariant(visible))
|
QtCore.QVariant(visible))
|
||||||
self.ViewPreviewPanel.setChecked(visible)
|
self.ViewPreviewPanel.setChecked(visible)
|
||||||
@ -925,7 +925,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
|
|||||||
True - Visible
|
True - Visible
|
||||||
False - Hidden
|
False - Hidden
|
||||||
"""
|
"""
|
||||||
self.LiveController.Panel.setVisible(visible)
|
self.liveController.Panel.setVisible(visible)
|
||||||
QtCore.QSettings().setValue(u'user interface/live panel',
|
QtCore.QSettings().setValue(u'user interface/live panel',
|
||||||
QtCore.QVariant(visible))
|
QtCore.QVariant(visible))
|
||||||
self.ViewLivePanel.setChecked(visible)
|
self.ViewLivePanel.setChecked(visible)
|
||||||
|
@ -61,7 +61,7 @@ class PluginForm(QtGui.QDialog, Ui_PluginViewDialog):
|
|||||||
self.programaticChange = True
|
self.programaticChange = True
|
||||||
self._clearDetails()
|
self._clearDetails()
|
||||||
self.programaticChange = True
|
self.programaticChange = True
|
||||||
for plugin in self.parent.plugin_manager.plugins:
|
for plugin in self.parent.pluginManager.plugins:
|
||||||
item = QtGui.QListWidgetItem(self.pluginListWidget)
|
item = QtGui.QListWidgetItem(self.pluginListWidget)
|
||||||
# We do this just to make 100% sure the status is an integer as
|
# 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.
|
# 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 = \
|
plugin_name_plural = \
|
||||||
self.pluginListWidget.currentItem().text().split(u' ')[0]
|
self.pluginListWidget.currentItem().text().split(u' ')[0]
|
||||||
self.activePlugin = None
|
self.activePlugin = None
|
||||||
for plugin in self.parent.plugin_manager.plugins:
|
for plugin in self.parent.pluginManager.plugins:
|
||||||
name_string = plugin.getString(StringContent.Name)
|
name_string = plugin.getString(StringContent.Name)
|
||||||
if name_string[u'plural'] == plugin_name_plural:
|
if name_string[u'plural'] == plugin_name_plural:
|
||||||
self.activePlugin = plugin
|
self.activePlugin = plugin
|
||||||
|
@ -64,8 +64,7 @@ class ServiceItemEditForm(QtGui.QDialog, Ui_ServiceItemEditDialog):
|
|||||||
self.item._raw_frames = []
|
self.item._raw_frames = []
|
||||||
if self.item.is_image():
|
if self.item.is_image():
|
||||||
for item in self.itemList:
|
for item in self.itemList:
|
||||||
self.item.add_from_image(item[u'path'], item[u'title'],
|
self.item.add_from_image(item[u'path'], item[u'title'])
|
||||||
item[u'image'])
|
|
||||||
self.item.render()
|
self.item.render()
|
||||||
return self.item
|
return self.item
|
||||||
|
|
||||||
|
@ -880,7 +880,7 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
newItem.merge(item[u'service_item'])
|
newItem.merge(item[u'service_item'])
|
||||||
item[u'service_item'] = newItem
|
item[u'service_item'] = newItem
|
||||||
self.repaintServiceList(itemcount + 1, 0)
|
self.repaintServiceList(itemcount + 1, 0)
|
||||||
self.parent.LiveController.replaceServiceManagerItem(newItem)
|
self.parent.liveController.replaceServiceManagerItem(newItem)
|
||||||
self.parent.serviceChanged(False, self.serviceName)
|
self.parent.serviceChanged(False, self.serviceName)
|
||||||
|
|
||||||
def addServiceItem(self, item, rebuild=False, expand=None, replace=False):
|
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'])
|
item.merge(self.serviceItems[sitem][u'service_item'])
|
||||||
self.serviceItems[sitem][u'service_item'] = item
|
self.serviceItems[sitem][u'service_item'] = item
|
||||||
self.repaintServiceList(sitem + 1, 0)
|
self.repaintServiceList(sitem + 1, 0)
|
||||||
self.parent.LiveController.replaceServiceManagerItem(item)
|
self.parent.liveController.replaceServiceManagerItem(item)
|
||||||
else:
|
else:
|
||||||
# nothing selected for dnd
|
# nothing selected for dnd
|
||||||
if self.droppos == 0:
|
if self.droppos == 0:
|
||||||
@ -923,7 +923,7 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
self.repaintServiceList(self.droppos, 0)
|
self.repaintServiceList(self.droppos, 0)
|
||||||
# if rebuilding list make sure live is fixed.
|
# if rebuilding list make sure live is fixed.
|
||||||
if rebuild:
|
if rebuild:
|
||||||
self.parent.LiveController.replaceServiceManagerItem(item)
|
self.parent.liveController.replaceServiceManagerItem(item)
|
||||||
self.droppos = 0
|
self.droppos = 0
|
||||||
self.parent.serviceChanged(False, self.serviceName)
|
self.parent.serviceChanged(False, self.serviceName)
|
||||||
|
|
||||||
@ -933,7 +933,7 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
"""
|
"""
|
||||||
item, count = self.findServiceItem()
|
item, count = self.findServiceItem()
|
||||||
if self.serviceItems[item][u'service_item'].is_valid:
|
if self.serviceItems[item][u'service_item'].is_valid:
|
||||||
self.parent.PreviewController.addServiceManagerItem(
|
self.parent.previewController.addServiceManagerItem(
|
||||||
self.serviceItems[item][u'service_item'], count)
|
self.serviceItems[item][u'service_item'], count)
|
||||||
else:
|
else:
|
||||||
QtGui.QMessageBox.critical(self,
|
QtGui.QMessageBox.critical(self,
|
||||||
@ -957,7 +957,7 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
"""
|
"""
|
||||||
item, count = self.findServiceItem()
|
item, count = self.findServiceItem()
|
||||||
if self.serviceItems[item][u'service_item'].is_valid:
|
if self.serviceItems[item][u'service_item'].is_valid:
|
||||||
self.parent.LiveController.addServiceManagerItem(
|
self.parent.liveController.addServiceManagerItem(
|
||||||
self.serviceItems[item][u'service_item'], count)
|
self.serviceItems[item][u'service_item'], count)
|
||||||
if QtCore.QSettings().value(
|
if QtCore.QSettings().value(
|
||||||
self.parent.generalSettingsSection + u'/auto preview',
|
self.parent.generalSettingsSection + u'/auto preview',
|
||||||
@ -966,9 +966,9 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
if self.serviceItems and item < len(self.serviceItems) and \
|
if self.serviceItems and item < len(self.serviceItems) and \
|
||||||
self.serviceItems[item][u'service_item'].is_capable(
|
self.serviceItems[item][u'service_item'].is_capable(
|
||||||
ItemCapabilities.AllowsPreview):
|
ItemCapabilities.AllowsPreview):
|
||||||
self.parent.PreviewController.addServiceManagerItem(
|
self.parent.previewController.addServiceManagerItem(
|
||||||
self.serviceItems[item][u'service_item'], 0)
|
self.serviceItems[item][u'service_item'], 0)
|
||||||
self.parent.LiveController.PreviewListWidget.setFocus()
|
self.parent.liveController.PreviewListWidget.setFocus()
|
||||||
else:
|
else:
|
||||||
QtGui.QMessageBox.critical(self,
|
QtGui.QMessageBox.critical(self,
|
||||||
translate('OpenLP.ServiceManager', 'Missing Display Handler'),
|
translate('OpenLP.ServiceManager', 'Missing Display Handler'),
|
||||||
|
@ -332,11 +332,12 @@ class SlideController(QtGui.QWidget):
|
|||||||
QtCore.SIGNAL(u'clicked(QModelIndex)'), self.onSlideSelected)
|
QtCore.SIGNAL(u'clicked(QModelIndex)'), self.onSlideSelected)
|
||||||
if not self.isLive:
|
if not self.isLive:
|
||||||
QtCore.QObject.connect(self.PreviewListWidget,
|
QtCore.QObject.connect(self.PreviewListWidget,
|
||||||
QtCore.SIGNAL(u'doubleClicked(QModelIndex)'), self.onGoLiveClick)
|
QtCore.SIGNAL(u'doubleClicked(QModelIndex)'),
|
||||||
|
self.onGoLiveClick)
|
||||||
if isLive:
|
if isLive:
|
||||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||||
QtCore.SIGNAL(u'slidecontroller_live_spin_delay'),
|
QtCore.SIGNAL(u'slidecontroller_live_spin_delay'),
|
||||||
self.receiveSpinDelay)
|
self.receiveSpinDelay)
|
||||||
if isLive:
|
if isLive:
|
||||||
self.Toolbar.makeWidgetsInvisible(self.loopList)
|
self.Toolbar.makeWidgetsInvisible(self.loopList)
|
||||||
self.Toolbar.actions[u'Stop Loop'].setVisible(False)
|
self.Toolbar.actions[u'Stop Loop'].setVisible(False)
|
||||||
@ -466,7 +467,7 @@ class SlideController(QtGui.QWidget):
|
|||||||
self.Toolbar.actions[u'Stop Loop'].setVisible(False)
|
self.Toolbar.actions[u'Stop Loop'].setVisible(False)
|
||||||
if item.is_text():
|
if item.is_text():
|
||||||
if QtCore.QSettings().value(
|
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:
|
QtCore.QVariant(True)).toBool() and len(self.slideList) > 0:
|
||||||
self.Toolbar.makeWidgetsVisible([u'Song Menu'])
|
self.Toolbar.makeWidgetsVisible([u'Song Menu'])
|
||||||
if item.is_capable(ItemCapabilities.AllowsLoop) and \
|
if item.is_capable(ItemCapabilities.AllowsLoop) and \
|
||||||
@ -560,7 +561,7 @@ class SlideController(QtGui.QWidget):
|
|||||||
[serviceItem, self.isLive, blanked, slideno])
|
[serviceItem, self.isLive, blanked, slideno])
|
||||||
self.slideList = {}
|
self.slideList = {}
|
||||||
width = self.parent.ControlSplitter.sizes()[self.split]
|
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.PreviewListWidget.setCursor(QtCore.Qt.PointingHandCursor)
|
||||||
self.serviceItem = serviceItem
|
self.serviceItem = serviceItem
|
||||||
self.PreviewListWidget.clear()
|
self.PreviewListWidget.clear()
|
||||||
@ -957,7 +958,7 @@ class SlideController(QtGui.QWidget):
|
|||||||
"""
|
"""
|
||||||
row = self.PreviewListWidget.currentRow()
|
row = self.PreviewListWidget.currentRow()
|
||||||
if row > -1 and row < self.PreviewListWidget.rowCount():
|
if row > -1 and row < self.PreviewListWidget.rowCount():
|
||||||
self.parent.LiveController.addServiceManagerItem(
|
self.parent.liveController.addServiceManagerItem(
|
||||||
self.serviceItem, row)
|
self.serviceItem, row)
|
||||||
|
|
||||||
def onMediaStart(self, item):
|
def onMediaStart(self, item):
|
||||||
|
@ -289,6 +289,7 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard):
|
|||||||
"""
|
"""
|
||||||
Run the wizard.
|
Run the wizard.
|
||||||
"""
|
"""
|
||||||
|
log.debug(u'Editing theme %s' % self.theme.theme_name)
|
||||||
self.updateThemeAllowed = False
|
self.updateThemeAllowed = False
|
||||||
self.setDefaults()
|
self.setDefaults()
|
||||||
self.updateThemeAllowed = True
|
self.updateThemeAllowed = True
|
||||||
@ -444,7 +445,7 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard):
|
|||||||
|
|
||||||
def setPreviewTabValues(self):
|
def setPreviewTabValues(self):
|
||||||
self.setField(u'name', QtCore.QVariant(self.theme.theme_name))
|
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)
|
self.themeNameEdit.setEnabled(False)
|
||||||
else:
|
else:
|
||||||
self.themeNameEdit.setEnabled(True)
|
self.themeNameEdit.setEnabled(True)
|
||||||
|
@ -225,10 +225,10 @@ class ThemeManager(QtGui.QWidget):
|
|||||||
"""
|
"""
|
||||||
item = self.themeListWidget.currentItem()
|
item = self.themeListWidget.currentItem()
|
||||||
oldThemeName = unicode(item.data(QtCore.Qt.UserRole).toString())
|
oldThemeName = unicode(item.data(QtCore.Qt.UserRole).toString())
|
||||||
self.fileRenameForm.FileNameEdit.setText(oldThemeName)
|
self.fileRenameForm.fileNameEdit.setText(oldThemeName)
|
||||||
self.saveThemeName = u''
|
self.saveThemeName = u''
|
||||||
if self.fileRenameForm.exec_():
|
if self.fileRenameForm.exec_():
|
||||||
newThemeName = unicode(self.fileRenameForm.FileNameEdit.text())
|
newThemeName = unicode(self.fileRenameForm.fileNameEdit.text())
|
||||||
oldThemeData = self.getThemeData(oldThemeName)
|
oldThemeData = self.getThemeData(oldThemeName)
|
||||||
self.deleteTheme(oldThemeName)
|
self.deleteTheme(oldThemeName)
|
||||||
self.cloneThemeData(oldThemeData, newThemeName)
|
self.cloneThemeData(oldThemeData, newThemeName)
|
||||||
@ -239,10 +239,10 @@ class ThemeManager(QtGui.QWidget):
|
|||||||
"""
|
"""
|
||||||
item = self.themeListWidget.currentItem()
|
item = self.themeListWidget.currentItem()
|
||||||
oldThemeName = unicode(item.data(QtCore.Qt.UserRole).toString())
|
oldThemeName = unicode(item.data(QtCore.Qt.UserRole).toString())
|
||||||
self.fileRenameForm.FileNameEdit.setText(oldThemeName)
|
self.fileRenameForm.fileNameEdit.setText(oldThemeName)
|
||||||
self.saveThemeName = u''
|
self.saveThemeName = u''
|
||||||
if self.fileRenameForm.exec_():
|
if self.fileRenameForm.exec_():
|
||||||
newThemeName = unicode(self.fileRenameForm.FileNameEdit.text())
|
newThemeName = unicode(self.fileRenameForm.fileNameEdit.text())
|
||||||
themeData = self.getThemeData(oldThemeName)
|
themeData = self.getThemeData(oldThemeName)
|
||||||
self.cloneThemeData(themeData, newThemeName)
|
self.cloneThemeData(themeData, newThemeName)
|
||||||
self.loadThemes()
|
self.loadThemes()
|
||||||
@ -310,7 +310,7 @@ class ThemeManager(QtGui.QWidget):
|
|||||||
translate('OpenLP.ThemeManager',
|
translate('OpenLP.ThemeManager',
|
||||||
'You are unable to delete the default theme.'))
|
'You are unable to delete the default theme.'))
|
||||||
else:
|
else:
|
||||||
for plugin in self.parent.plugin_manager.plugins:
|
for plugin in self.parent.pluginManager.plugins:
|
||||||
if plugin.usesTheme(theme):
|
if plugin.usesTheme(theme):
|
||||||
QtGui.QMessageBox.critical(self,
|
QtGui.QMessageBox.critical(self,
|
||||||
translate('OpenLP.ThemeManager', 'Error'),
|
translate('OpenLP.ThemeManager', 'Error'),
|
||||||
@ -663,7 +663,7 @@ class ThemeManager(QtGui.QWidget):
|
|||||||
(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No),
|
(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No),
|
||||||
QtGui.QMessageBox.No)
|
QtGui.QMessageBox.No)
|
||||||
if self.saveThemeName != u'':
|
if self.saveThemeName != u'':
|
||||||
for plugin in self.parent.plugin_manager.plugins:
|
for plugin in self.parent.pluginManager.plugins:
|
||||||
if plugin.usesTheme(self.saveThemeName):
|
if plugin.usesTheme(self.saveThemeName):
|
||||||
plugin.renameTheme(self.saveThemeName, name)
|
plugin.renameTheme(self.saveThemeName, name)
|
||||||
if unicode(self.serviceComboBox.currentText()) == name:
|
if unicode(self.serviceComboBox.currentText()) == name:
|
||||||
|
@ -555,7 +555,8 @@ class Ui_ThemeWizard(object):
|
|||||||
u'footerDefaultPositionCheckBox')
|
u'footerDefaultPositionCheckBox')
|
||||||
self.footerPositionLayout.setWidget(0, QtGui.QFormLayout.FieldRole,
|
self.footerPositionLayout.setWidget(0, QtGui.QFormLayout.FieldRole,
|
||||||
self.footerDefaultPositionCheckBox)
|
self.footerDefaultPositionCheckBox)
|
||||||
self.areaPositionLayout.addWidget(self.footerPositionGroupBox, 1, 1, 1, 1)
|
self.areaPositionLayout.addWidget(
|
||||||
|
self.footerPositionGroupBox, 1, 1, 1, 1)
|
||||||
ThemeWizard.addPage(self.areaPositionPage)
|
ThemeWizard.addPage(self.areaPositionPage)
|
||||||
self.previewPage = QtGui.QWizardPage()
|
self.previewPage = QtGui.QWizardPage()
|
||||||
self.previewPage.setObjectName(u'previewPage')
|
self.previewPage.setObjectName(u'previewPage')
|
||||||
@ -720,8 +721,8 @@ class Ui_ThemeWizard(object):
|
|||||||
self.areaPositionPage.setTitle(
|
self.areaPositionPage.setTitle(
|
||||||
translate('OpenLP.ThemeWizard', 'Output Area Locations'))
|
translate('OpenLP.ThemeWizard', 'Output Area Locations'))
|
||||||
self.areaPositionPage.setSubTitle(
|
self.areaPositionPage.setSubTitle(
|
||||||
translate('OpenLP.ThemeWizard', 'Allows you to change and move the '
|
translate('OpenLP.ThemeWizard', 'Allows you to change and move the'
|
||||||
'main and footer areas.'))
|
' main and footer areas.'))
|
||||||
self.mainPositionGroupBox.setTitle(
|
self.mainPositionGroupBox.setTitle(
|
||||||
translate('OpenLP.ThemeWizard', '&Main Area'))
|
translate('OpenLP.ThemeWizard', '&Main Area'))
|
||||||
self.mainDefaultPositionCheckBox.setText(
|
self.mainDefaultPositionCheckBox.setText(
|
||||||
@ -733,18 +734,24 @@ class Ui_ThemeWizard(object):
|
|||||||
self.mainWidthSpinBox.setSuffix(translate('OpenLP.ThemeWizard', 'px'))
|
self.mainWidthSpinBox.setSuffix(translate('OpenLP.ThemeWizard', 'px'))
|
||||||
self.mainWidthLabel.setText(translate('OpenLP.ThemeWizard', 'Width:'))
|
self.mainWidthLabel.setText(translate('OpenLP.ThemeWizard', 'Width:'))
|
||||||
self.mainHeightSpinBox.setSuffix(translate('OpenLP.ThemeWizard', 'px'))
|
self.mainHeightSpinBox.setSuffix(translate('OpenLP.ThemeWizard', 'px'))
|
||||||
self.mainHeightLabel.setText(translate('OpenLP.ThemeWizard', 'Height:'))
|
self.mainHeightLabel.setText(
|
||||||
|
translate('OpenLP.ThemeWizard', 'Height:'))
|
||||||
self.footerPositionGroupBox.setTitle(
|
self.footerPositionGroupBox.setTitle(
|
||||||
translate('OpenLP.ThemeWizard', 'Footer Area'))
|
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.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.footerYSpinBox.setSuffix(translate('OpenLP.ThemeWizard', 'px'))
|
||||||
self.footerWidthLabel.setText(translate('OpenLP.ThemeWizard', 'Width:'))
|
self.footerWidthLabel.setText(
|
||||||
self.footerWidthSpinBox.setSuffix(translate('OpenLP.ThemeWizard', 'px'))
|
translate('OpenLP.ThemeWizard', 'Width:'))
|
||||||
|
self.footerWidthSpinBox.setSuffix(
|
||||||
|
translate('OpenLP.ThemeWizard', 'px'))
|
||||||
self.footerHeightLabel.setText(
|
self.footerHeightLabel.setText(
|
||||||
translate('OpenLP.ThemeWizard', 'Height:'))
|
translate('OpenLP.ThemeWizard', 'Height:'))
|
||||||
self.footerHeightSpinBox.setSuffix(translate('OpenLP.ThemeWizard', 'px'))
|
self.footerHeightSpinBox.setSuffix(
|
||||||
|
translate('OpenLP.ThemeWizard', 'px'))
|
||||||
self.footerDefaultPositionCheckBox.setText(
|
self.footerDefaultPositionCheckBox.setText(
|
||||||
translate('OpenLP.ThemeWizard', 'Use default location'))
|
translate('OpenLP.ThemeWizard', 'Use default location'))
|
||||||
self.previewPage.setTitle(
|
self.previewPage.setTitle(
|
||||||
|
@ -171,24 +171,23 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog):
|
|||||||
# We found '<>' in the alert text, but the ParameterEdit field is
|
# We found '<>' in the alert text, but the ParameterEdit field is
|
||||||
# empty.
|
# empty.
|
||||||
if text.find(u'<>') != -1 and not self.ParameterEdit.text() and \
|
if text.find(u'<>') != -1 and not self.ParameterEdit.text() and \
|
||||||
QtGui.QMessageBox.question(self, translate(
|
QtGui.QMessageBox.question(self,
|
||||||
'AlertPlugin.AlertForm', 'No Parameter found'),
|
translate('AlertPlugin.AlertForm', 'No Parameter found'),
|
||||||
translate('AlertPlugin.AlertForm', 'You have not entered a '
|
translate('AlertPlugin.AlertForm', 'You have not entered a '
|
||||||
'parameter to be replaced.\nDo you want to continue '
|
'parameter to be replaced.\nDo you want to continue anyway?'),
|
||||||
'anyway?'),
|
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.No |
|
||||||
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.No |
|
QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.No:
|
||||||
QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.No:
|
|
||||||
self.ParameterEdit.setFocus()
|
self.ParameterEdit.setFocus()
|
||||||
return False
|
return False
|
||||||
# The ParameterEdit field is not empty, but we have not found '<>'
|
# The ParameterEdit field is not empty, but we have not found '<>'
|
||||||
# in the alert text.
|
# in the alert text.
|
||||||
elif text.find(u'<>') == -1 and self.ParameterEdit.text() and \
|
elif text.find(u'<>') == -1 and self.ParameterEdit.text() and \
|
||||||
QtGui.QMessageBox.question(self, translate(
|
QtGui.QMessageBox.question(self,
|
||||||
'AlertPlugin.AlertForm', 'No Placeholder found'),
|
translate('AlertPlugin.AlertForm', 'No Placeholder found'),
|
||||||
translate('AlertPlugin.AlertForm', 'The alert text does not'
|
translate('AlertPlugin.AlertForm', 'The alert text does not'
|
||||||
' contain \'<>\'.\nDo want to continue anyway?'),
|
' contain \'<>\'.\nDo want to continue anyway?'),
|
||||||
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.No |
|
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.No |
|
||||||
QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.No:
|
QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.No:
|
||||||
self.ParameterEdit.setFocus()
|
self.ParameterEdit.setFocus()
|
||||||
return False
|
return False
|
||||||
text = text.replace(u'<>', unicode(self.ParameterEdit.text()))
|
text = text.replace(u'<>', unicode(self.ParameterEdit.text()))
|
||||||
|
@ -43,10 +43,12 @@ class WebDownload(object):
|
|||||||
Unknown = -1
|
Unknown = -1
|
||||||
Crosswalk = 0
|
Crosswalk = 0
|
||||||
BibleGateway = 1
|
BibleGateway = 1
|
||||||
|
Bibleserver = 2
|
||||||
|
|
||||||
Names = {
|
Names = {
|
||||||
0: u'Crosswalk',
|
0: u'Crosswalk',
|
||||||
1: u'BibleGateway'
|
1: u'BibleGateway',
|
||||||
|
2: u'Bibleserver'
|
||||||
}
|
}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -232,8 +234,7 @@ class BibleImportForm(QtGui.QWizard, Ui_BibleImportWizard):
|
|||||||
The index of the combo box.
|
The index of the combo box.
|
||||||
"""
|
"""
|
||||||
self.bibleComboBox.clear()
|
self.bibleComboBox.clear()
|
||||||
bibles = [unicode(translate('BiblesPlugin.ImportWizardForm', bible)) for
|
bibles = self.web_bible_list[index].keys()
|
||||||
bible in self.web_bible_list[index].keys()]
|
|
||||||
bibles.sort()
|
bibles.sort()
|
||||||
for bible in bibles:
|
for bible in bibles:
|
||||||
self.bibleComboBox.addItem(bible)
|
self.bibleComboBox.addItem(bible)
|
||||||
@ -252,14 +253,16 @@ class BibleImportForm(QtGui.QWizard, Ui_BibleImportWizard):
|
|||||||
"""
|
"""
|
||||||
self.getFileName(
|
self.getFileName(
|
||||||
translate('BiblesPlugin.ImportWizardForm', 'Open Books CSV File'),
|
translate('BiblesPlugin.ImportWizardForm', 'Open Books CSV File'),
|
||||||
self.booksLocationEdit)
|
self.booksLocationEdit, u'%s (*.csv)'
|
||||||
|
% translate('BiblesPlugin.ImportWizardForm', 'CSV File'))
|
||||||
|
|
||||||
def onCsvVersesFileButtonClicked(self):
|
def onCsvVersesFileButtonClicked(self):
|
||||||
"""
|
"""
|
||||||
Show the file open dialog for the verses CSV file.
|
Show the file open dialog for the verses CSV file.
|
||||||
"""
|
"""
|
||||||
self.getFileName(translate('BiblesPlugin.ImportWizardForm',
|
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):
|
def onOpenSongBrowseButtonClicked(self):
|
||||||
"""
|
"""
|
||||||
@ -275,7 +278,9 @@ class BibleImportForm(QtGui.QWizard, Ui_BibleImportWizard):
|
|||||||
"""
|
"""
|
||||||
self.getFileName(
|
self.getFileName(
|
||||||
translate('BiblesPlugin.ImportWizardForm',
|
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):
|
def onCurrentIdChanged(self, pageId):
|
||||||
if pageId == 3:
|
if pageId == 3:
|
||||||
@ -338,31 +343,27 @@ class BibleImportForm(QtGui.QWizard, Ui_BibleImportWizard):
|
|||||||
"""
|
"""
|
||||||
Load the list of Crosswalk and BibleGateway bibles.
|
Load the list of Crosswalk and BibleGateway bibles.
|
||||||
"""
|
"""
|
||||||
# Load and store Crosswalk Bibles.
|
# Load Crosswalk Bibles.
|
||||||
filepath = AppLocation.get_directory(AppLocation.PluginsDir)
|
filepath = AppLocation.get_directory(AppLocation.PluginsDir)
|
||||||
filepath = os.path.join(filepath, u'bibles', u'resources')
|
filepath = os.path.join(filepath, u'bibles', u'resources')
|
||||||
books_file = None
|
books_file = None
|
||||||
try:
|
try:
|
||||||
self.web_bible_list[WebDownload.Crosswalk] = {}
|
self.web_bible_list[WebDownload.Crosswalk] = {}
|
||||||
books_file = open(
|
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))
|
dialect = csv.Sniffer().sniff(books_file.read(1024))
|
||||||
books_file.seek(0)
|
books_file.seek(0)
|
||||||
books_reader = csv.reader(books_file, dialect)
|
books_reader = csv.reader(books_file, dialect)
|
||||||
for line in books_reader:
|
for line in books_reader:
|
||||||
ver = line[0]
|
ver = unicode(line[0], u'utf-8')
|
||||||
name = line[1]
|
name = unicode(line[1], u'utf-8')
|
||||||
if not isinstance(ver, unicode):
|
|
||||||
ver = unicode(ver, u'utf8')
|
|
||||||
if not isinstance(name, unicode):
|
|
||||||
name = unicode(name, u'utf8')
|
|
||||||
self.web_bible_list[WebDownload.Crosswalk][ver] = name.strip()
|
self.web_bible_list[WebDownload.Crosswalk][ver] = name.strip()
|
||||||
except IOError:
|
except IOError:
|
||||||
log.exception(u'Crosswalk resources missing')
|
log.exception(u'Crosswalk resources missing')
|
||||||
finally:
|
finally:
|
||||||
if books_file:
|
if books_file:
|
||||||
books_file.close()
|
books_file.close()
|
||||||
# Load and store BibleGateway Bibles.
|
# Load BibleGateway Bibles.
|
||||||
books_file = None
|
books_file = None
|
||||||
try:
|
try:
|
||||||
self.web_bible_list[WebDownload.BibleGateway] = {}
|
self.web_bible_list[WebDownload.BibleGateway] = {}
|
||||||
@ -384,10 +385,50 @@ class BibleImportForm(QtGui.QWizard, Ui_BibleImportWizard):
|
|||||||
finally:
|
finally:
|
||||||
if books_file:
|
if books_file:
|
||||||
books_file.close()
|
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,
|
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:
|
if filename:
|
||||||
editbox.setText(filename)
|
editbox.setText(filename)
|
||||||
SettingsManager.set_last_dir(
|
SettingsManager.set_last_dir(
|
||||||
@ -457,6 +498,9 @@ class BibleImportForm(QtGui.QWizard, Ui_BibleImportWizard):
|
|||||||
elif download_location == WebDownload.BibleGateway:
|
elif download_location == WebDownload.BibleGateway:
|
||||||
bible = \
|
bible = \
|
||||||
self.web_bible_list[WebDownload.BibleGateway][bible_version]
|
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(
|
importer = self.manager.import_bible(
|
||||||
BibleFormat.WebDownload,
|
BibleFormat.WebDownload,
|
||||||
name=license_version,
|
name=license_version,
|
||||||
|
@ -208,6 +208,7 @@ class Ui_BibleImportWizard(object):
|
|||||||
self.locationComboBox.setObjectName(u'LocationComboBox')
|
self.locationComboBox.setObjectName(u'LocationComboBox')
|
||||||
self.locationComboBox.addItem(u'')
|
self.locationComboBox.addItem(u'')
|
||||||
self.locationComboBox.addItem(u'')
|
self.locationComboBox.addItem(u'')
|
||||||
|
self.locationComboBox.addItem(u'')
|
||||||
self.downloadOptionsLayout.setWidget(0, QtGui.QFormLayout.FieldRole,
|
self.downloadOptionsLayout.setWidget(0, QtGui.QFormLayout.FieldRole,
|
||||||
self.locationComboBox)
|
self.locationComboBox)
|
||||||
self.bibleLabel = QtGui.QLabel(self.downloadOptionsTab)
|
self.bibleLabel = QtGui.QLabel(self.downloadOptionsTab)
|
||||||
@ -388,6 +389,8 @@ class Ui_BibleImportWizard(object):
|
|||||||
translate('BiblesPlugin.ImportWizardForm', 'Crosswalk'))
|
translate('BiblesPlugin.ImportWizardForm', 'Crosswalk'))
|
||||||
self.locationComboBox.setItemText(1,
|
self.locationComboBox.setItemText(1,
|
||||||
translate('BiblesPlugin.ImportWizardForm', 'BibleGateway'))
|
translate('BiblesPlugin.ImportWizardForm', 'BibleGateway'))
|
||||||
|
self.locationComboBox.setItemText(2,
|
||||||
|
translate('BiblesPlugin.ImportWizardForm', 'Bibleserver'))
|
||||||
self.bibleLabel.setText(
|
self.bibleLabel.setText(
|
||||||
translate('BiblesPlugin.ImportWizardForm', 'Bible:'))
|
translate('BiblesPlugin.ImportWizardForm', 'Bible:'))
|
||||||
self.webDownloadTabWidget.setTabText(
|
self.webDownloadTabWidget.setTabText(
|
||||||
|
@ -32,134 +32,164 @@ import re
|
|||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
BIBLE_REFERENCE = re.compile(
|
def get_reference_match(match_type):
|
||||||
r'^([\w ]+?) *([0-9]+)' # Initial book and chapter
|
local_separator = unicode(u':;;\s*[:vV]\s*;;-;;\s*-\s*;;,;;\s*,\s*;;end'
|
||||||
r'(?: *[:|v|V] *([0-9]+))?' # Verse for first chapter
|
).split(u';;') # English
|
||||||
r'(?: *- *([0-9]+|end$))?' # Range for verses or chapters
|
# local_separator = unicode(u',;;\s*,\s*;;-;;\s*-\s*;;.;;\.;;[Ee]nde'
|
||||||
r'(?:(?:,([0-9]+))?' # Second chapter
|
# ).split(u';;') # German
|
||||||
r' *[,|:|v|V] *([0-9]+|end$)' # More range for verses or chapters
|
separators = {
|
||||||
r'(?: *- *([0-9]+|end$))?)?$', # End of second verse range
|
u'sep_v_display': local_separator[0], u'sep_v': local_separator[1],
|
||||||
re.UNICODE)
|
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):
|
# verse range match: (<chapter>:)?<verse>(-((<chapter>:)?<verse>|end)?)?
|
||||||
"""
|
range_string = str(r'(?:(?P<from_chapter>[0-9]+)%(sep_v)s)?(?P<from_verse>'
|
||||||
Check if a regular expression match group contains the text u'end' or
|
r'[0-9]+)(?P<range_to>%(sep_r)s(?:(?:(?P<to_chapter>[0-9]+)%(sep_v)s)?'
|
||||||
should be converted to an int.
|
r'(?P<to_verse>[0-9]+)|%(sep_e)s)?)?') % separators
|
||||||
|
if match_type == u'range':
|
||||||
``match_group``
|
return re.compile(r'^\s*' + range_string + r'\s*$', re.UNICODE)
|
||||||
The match group to check.
|
elif match_type == u'range_separator':
|
||||||
"""
|
return re.compile(separators[u'sep_l'])
|
||||||
if match_group == u'end':
|
elif match_type == u'full':
|
||||||
return -1
|
# 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:
|
else:
|
||||||
return int(match_group)
|
return separators[match_type]
|
||||||
|
|
||||||
def parse_reference(reference):
|
def parse_reference(reference):
|
||||||
"""
|
"""
|
||||||
This is the über-awesome function that takes a person's typed in string
|
This is the next generation über-awesome function that takes a person's
|
||||||
and converts it to a reference list, a list of references to be queried
|
typed in string and converts it to a reference list, a list of references to
|
||||||
from the Bible database files.
|
be queried from the Bible database files.
|
||||||
|
|
||||||
The ``BIBLE_REFERENCE`` constant regular expression produces the following
|
This is a user manual like description, how the references are working.
|
||||||
match groups:
|
|
||||||
|
|
||||||
0. (match string)
|
- Each reference starts with the book name. A chapter name is manditory.
|
||||||
This is a special group consisting of the whole string that matched.
|
``John 3`` refers to Gospel of John chapter 3
|
||||||
1. ``[\w ]+``
|
- A reference range can be given after a range separator.
|
||||||
The book the reference is from.
|
``John 3-5`` refers to John chapters 3 to 5
|
||||||
2. ``[0-9]+``
|
- Single verses can be addressed after a verse separator
|
||||||
The first (or only) chapter in the reference.
|
``John 3:16`` refers to John chapter 3 verse 16
|
||||||
3. ``None`` or ``[0-9]+``
|
``John 3:16-4:3`` refers to John chapter 3 verse 16 to chapter 4 verse 3
|
||||||
``None``, or the only verse, or the first verse in a verse range or,
|
- After a verse reference all further single values are treat as verse in
|
||||||
the start verse in a chapter range.
|
the last selected chapter.
|
||||||
4. ``None`` or ``[0-9]+`` or ``end``
|
``John 3:16-18`` refers to John chapter 3 verses 16 to 18
|
||||||
``None``, or the end verse of the first verse range, or the end chapter
|
- After a list separator it is possible to refer to additional verses. They
|
||||||
of a chapter range.
|
are build analog to the first ones. This way it is possible to define each
|
||||||
5. ``None`` or ``[0-9]+``
|
number of verse references. It is not possible to refer to verses in
|
||||||
``None``, or the second chapter in multiple (non-ranged) chapters.
|
additional books.
|
||||||
6. ``None`` or ``[0-9]+`` or ``end``
|
``John 3:16,18`` refers to John chapter 3 verses 16 and 18
|
||||||
``None``, the start of the second verse range. or the end of a chapter
|
``John 3:16-18,20`` refers to John chapter 3 verses 16 to 18 and 20
|
||||||
range.
|
``John 3:16-18,4:1`` refers to John chapter 3 verses 16 to 18 and
|
||||||
7. ``None`` or ``[0-9]+`` or ``end``
|
chapter 3 verse 1
|
||||||
``None``, or the end of the second verse range.
|
- 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
|
The reference list is a list of tuples, with each tuple structured like
|
||||||
this::
|
this::
|
||||||
|
|
||||||
(book, chapter, start_verse, end_verse)
|
(book, chapter, from_verse, to_verse)
|
||||||
|
|
||||||
``reference``
|
``reference``
|
||||||
The bible reference to parse.
|
The bible reference to parse.
|
||||||
|
|
||||||
Returns None or a reference list.
|
Returns None or a reference list.
|
||||||
"""
|
"""
|
||||||
reference = reference.strip()
|
|
||||||
log.debug('parse_reference("%s")', reference)
|
log.debug('parse_reference("%s")', reference)
|
||||||
unified_ref_list = []
|
match = get_reference_match(u'full').match(reference)
|
||||||
match = BIBLE_REFERENCE.match(reference)
|
|
||||||
if match:
|
if match:
|
||||||
log.debug(u'Matched reference %s' % reference)
|
log.debug(u'Matched reference %s' % reference)
|
||||||
book = match.group(1)
|
book = match.group(u'book')
|
||||||
chapter = int(match.group(2))
|
ranges = match.group(u'ranges')
|
||||||
if match.group(7):
|
range_list = get_reference_match(u'range_separator').split(ranges)
|
||||||
# Two verse ranges
|
ref_list = []
|
||||||
vr1_start = int(match.group(3))
|
chapter = None
|
||||||
vr1_end = int(match.group(4))
|
for this_range in range_list:
|
||||||
unified_ref_list.append((book, chapter, vr1_start, vr1_end))
|
range_match = get_reference_match(u'range').match(this_range)
|
||||||
vr2_start = int(match.group(6))
|
from_chapter = range_match.group(u'from_chapter')
|
||||||
vr2_end = check_end(match.group(7))
|
from_verse = range_match.group(u'from_verse')
|
||||||
if match.group(5):
|
has_range = range_match.group(u'range_to')
|
||||||
# One verse range per chapter
|
to_chapter = range_match.group(u'to_chapter')
|
||||||
chapter2 = int(match.group(5))
|
to_verse = range_match.group(u'to_verse')
|
||||||
unified_ref_list.append((book, chapter2, vr2_start, vr2_end))
|
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:
|
else:
|
||||||
unified_ref_list.append((book, chapter, vr2_start, vr2_end))
|
from_chapter = from_verse
|
||||||
elif match.group(6):
|
from_verse = None
|
||||||
# Chapter range with verses
|
if to_chapter:
|
||||||
if match.group(3):
|
if to_chapter < from_chapter:
|
||||||
vr1_start = int(match.group(3))
|
continue
|
||||||
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))
|
|
||||||
else:
|
else:
|
||||||
log.debug(u'Ambiguous reference: %s' % reference)
|
chapter = to_chapter
|
||||||
return None
|
elif to_verse:
|
||||||
elif match.group(4) != u'end':
|
if chapter:
|
||||||
for i in range(chapter, int(match.group(4)) + 1):
|
to_chapter = chapter
|
||||||
unified_ref_list.append((book, i, 1, -1))
|
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:
|
else:
|
||||||
log.debug(u'Unsupported reference: %s' % reference)
|
ref_list.append((book, from_chapter, 1, -1))
|
||||||
return None
|
return ref_list
|
||||||
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))
|
|
||||||
else:
|
else:
|
||||||
log.debug(u'Invalid reference: %s' % reference)
|
log.debug(u'Invalid reference: %s' % reference)
|
||||||
return None
|
return None
|
||||||
return unified_ref_list
|
|
||||||
|
|
||||||
|
|
||||||
class SearchResults(object):
|
class SearchResults(object):
|
||||||
|
@ -240,6 +240,66 @@ class BGExtract(object):
|
|||||||
return SearchResults(bookname, chapter, verse_list)
|
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):
|
class CWExtract(object):
|
||||||
"""
|
"""
|
||||||
Extract verses from CrossWalk/BibleStudyTools
|
Extract verses from CrossWalk/BibleStudyTools
|
||||||
@ -350,7 +410,7 @@ class HTTPBible(BibleDB):
|
|||||||
Run the import. This method overrides the parent class method. Returns
|
Run the import. This method overrides the parent class method. Returns
|
||||||
``True`` on success, ``False`` on failure.
|
``True`` on success, ``False`` on failure.
|
||||||
"""
|
"""
|
||||||
self.wizard.ImportProgressBar.setMaximum(2)
|
self.wizard.importProgressBar.setMaximum(2)
|
||||||
self.wizard.incrementProgressBar('Registering bible...')
|
self.wizard.incrementProgressBar('Registering bible...')
|
||||||
self.create_meta(u'download source', self.download_source)
|
self.create_meta(u'download source', self.download_source)
|
||||||
self.create_meta(u'download name', self.download_name)
|
self.create_meta(u'download name', self.download_name)
|
||||||
@ -426,8 +486,10 @@ class HTTPBible(BibleDB):
|
|||||||
log.debug(u'source = %s', self.download_source)
|
log.debug(u'source = %s', self.download_source)
|
||||||
if self.download_source.lower() == u'crosswalk':
|
if self.download_source.lower() == u'crosswalk':
|
||||||
ev = CWExtract(self.proxy_server)
|
ev = CWExtract(self.proxy_server)
|
||||||
else:
|
elif self.download_source.lower() == u'biblegateway':
|
||||||
ev = BGExtract(self.proxy_server)
|
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)
|
return ev.get_bible_chapter(self.download_name, book, chapter)
|
||||||
|
|
||||||
def get_books(self):
|
def get_books(self):
|
||||||
|
@ -112,6 +112,7 @@ class BibleFormat(object):
|
|||||||
def get_availability(format):
|
def get_availability(format):
|
||||||
return BibleFormat._format_availability.get(format, True)
|
return BibleFormat._format_availability.get(format, True)
|
||||||
|
|
||||||
|
|
||||||
class BibleManager(object):
|
class BibleManager(object):
|
||||||
"""
|
"""
|
||||||
The Bible manager which holds and manages all the Bibles.
|
The Bible manager which holds and manages all the Bibles.
|
||||||
@ -311,7 +312,7 @@ class BibleManager(object):
|
|||||||
'Scripture Reference Error'),
|
'Scripture Reference Error'),
|
||||||
translate('BiblesPlugin.BibleManager', 'You did not enter a '
|
translate('BiblesPlugin.BibleManager', 'You did not enter a '
|
||||||
'search keyword.\nYou can separate different keywords by 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.'))
|
'them by a comma to search for one of them.'))
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@ -356,3 +357,4 @@ class BibleManager(object):
|
|||||||
BibleFormat.set_availability(BibleFormat.OpenLP1, has_openlp1)
|
BibleFormat.set_availability(BibleFormat.OpenLP1, has_openlp1)
|
||||||
|
|
||||||
__all__ = [u'BibleFormat']
|
__all__ = [u'BibleFormat']
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@ from PyQt4 import QtCore, QtGui
|
|||||||
from openlp.core.lib import MediaManagerItem, Receiver, BaseListWithDnD, \
|
from openlp.core.lib import MediaManagerItem, Receiver, BaseListWithDnD, \
|
||||||
ItemCapabilities, translate
|
ItemCapabilities, translate
|
||||||
from openlp.plugins.bibles.forms import BibleImportForm
|
from openlp.plugins.bibles.forms import BibleImportForm
|
||||||
|
from openlp.plugins.bibles.lib import get_reference_match
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -72,7 +73,7 @@ class BibleMediaItem(MediaManagerItem):
|
|||||||
self.hasNewIcon = False
|
self.hasNewIcon = False
|
||||||
self.hasEditIcon = False
|
self.hasEditIcon = False
|
||||||
self.hasDeleteIcon = False
|
self.hasDeleteIcon = False
|
||||||
self.addToServiceItem = True
|
self.addToServiceItem = False
|
||||||
|
|
||||||
def addEndHeaderBar(self):
|
def addEndHeaderBar(self):
|
||||||
self.SearchTabWidget = QtGui.QTabWidget(self)
|
self.SearchTabWidget = QtGui.QTabWidget(self)
|
||||||
@ -553,12 +554,15 @@ class BibleMediaItem(MediaManagerItem):
|
|||||||
bible = unicode(self.AdvancedVersionComboBox.currentText())
|
bible = unicode(self.AdvancedVersionComboBox.currentText())
|
||||||
second_bible = unicode(self.AdvancedSecondBibleComboBox.currentText())
|
second_bible = unicode(self.AdvancedSecondBibleComboBox.currentText())
|
||||||
book = unicode(self.AdvancedBookComboBox.currentText())
|
book = unicode(self.AdvancedBookComboBox.currentText())
|
||||||
chapter_from = int(self.AdvancedFromChapter.currentText())
|
chapter_from = self.AdvancedFromChapter.currentText()
|
||||||
chapter_to = int(self.AdvancedToChapter.currentText())
|
chapter_to = self.AdvancedToChapter.currentText()
|
||||||
verse_from = int(self.AdvancedFromVerse.currentText())
|
verse_from = self.AdvancedFromVerse.currentText()
|
||||||
verse_to = int(self.AdvancedToVerse.currentText())
|
verse_to = self.AdvancedToVerse.currentText()
|
||||||
versetext = u'%s %s:%s-%s:%s' % (book, chapter_from, verse_from,
|
verse_separator = get_reference_match(u'sep_v_display')
|
||||||
chapter_to, verse_to)
|
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)
|
self.search_results = self.parent.manager.get_verses(bible, versetext)
|
||||||
if second_bible:
|
if second_bible:
|
||||||
self.second_search_results = self.parent.manager.get_verses(
|
self.second_search_results = self.parent.manager.get_verses(
|
||||||
@ -709,7 +713,7 @@ class BibleMediaItem(MediaManagerItem):
|
|||||||
obj = reference[QtCore.QString(key)]
|
obj = reference[QtCore.QString(key)]
|
||||||
if isinstance(obj, QtCore.QVariant):
|
if isinstance(obj, QtCore.QVariant):
|
||||||
obj = obj.toPyObject()
|
obj = obj.toPyObject()
|
||||||
return unicode(obj)
|
return unicode(obj).strip()
|
||||||
|
|
||||||
def generateSlideData(self, service_item, item=None, xmlVersion=False):
|
def generateSlideData(self, service_item, item=None, xmlVersion=False):
|
||||||
"""
|
"""
|
||||||
@ -739,7 +743,8 @@ class BibleMediaItem(MediaManagerItem):
|
|||||||
second_bible = self._decodeQtObject(bitem, 'second_bible')
|
second_bible = self._decodeQtObject(bitem, 'second_bible')
|
||||||
second_version = self._decodeQtObject(bitem, 'second_version')
|
second_version = self._decodeQtObject(bitem, 'second_version')
|
||||||
second_copyright = self._decodeQtObject(bitem, 'second_copyright')
|
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')
|
second_text = self._decodeQtObject(bitem, 'second_text')
|
||||||
verse_text = self.formatVerse(old_chapter, chapter, verse)
|
verse_text = self.formatVerse(old_chapter, chapter, verse)
|
||||||
footer = u'%s (%s %s %s)' % (book, version, copyright, permissions)
|
footer = u'%s (%s %s %s)' % (book, version, copyright, permissions)
|
||||||
@ -750,21 +755,21 @@ class BibleMediaItem(MediaManagerItem):
|
|||||||
second_copyright, second_permissions)
|
second_copyright, second_permissions)
|
||||||
if footer not in raw_footer:
|
if footer not in raw_footer:
|
||||||
raw_footer.append(footer)
|
raw_footer.append(footer)
|
||||||
bible_text = u'%s %s\n\n%s %s' % (verse_text, text, verse_text,
|
bible_text = u'%s\u00a0%s\n\n%s\u00a0%s' % (verse_text, text,
|
||||||
second_text)
|
verse_text, second_text)
|
||||||
raw_slides.append(bible_text)
|
raw_slides.append(bible_text)
|
||||||
bible_text = u''
|
bible_text = u''
|
||||||
# If we are 'Verse Per Slide' then create a new slide.
|
# If we are 'Verse Per Slide' then create a new slide.
|
||||||
elif self.parent.settings_tab.layout_style == 0:
|
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)
|
raw_slides.append(bible_text)
|
||||||
bible_text = u''
|
bible_text = u''
|
||||||
# If we are 'Verse Per Line' then force a new line.
|
# If we are 'Verse Per Line' then force a new line.
|
||||||
elif self.parent.settings_tab.layout_style == 1:
|
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'.
|
# We have to be 'Continuous'.
|
||||||
else:
|
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:
|
if first_item:
|
||||||
start_item = item
|
start_item = item
|
||||||
first_item = False
|
first_item = False
|
||||||
@ -816,36 +821,31 @@ class BibleMediaItem(MediaManagerItem):
|
|||||||
``old_item``
|
``old_item``
|
||||||
The last item of a range.
|
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_bitem = self.listView.item(old_item.row())
|
||||||
old_chapter = int(self._decodeQtObject(old_bitem, 'chapter'))
|
old_chapter = self._decodeQtObject(old_bitem, 'chapter')
|
||||||
old_verse = int(self._decodeQtObject(old_bitem, 'verse'))
|
old_verse = self._decodeQtObject(old_bitem, 'verse')
|
||||||
start_bitem = self.listView.item(start_item.row())
|
start_bitem = self.listView.item(start_item.row())
|
||||||
start_book = self._decodeQtObject(start_bitem, 'book')
|
start_book = self._decodeQtObject(start_bitem, 'book')
|
||||||
start_chapter = int(self._decodeQtObject(start_bitem, 'chapter'))
|
start_chapter = self._decodeQtObject(start_bitem, 'chapter')
|
||||||
start_verse = int(self._decodeQtObject(start_bitem, 'verse'))
|
start_verse = self._decodeQtObject(start_bitem, 'verse')
|
||||||
start_bible = self._decodeQtObject(start_bitem, 'bible')
|
start_bible = self._decodeQtObject(start_bitem, 'bible')
|
||||||
start_second_bible = self._decodeQtObject(start_bitem, 'second_bible')
|
start_second_bible = self._decodeQtObject(start_bitem, 'second_bible')
|
||||||
if start_second_bible:
|
if start_second_bible:
|
||||||
if start_verse == old_verse and start_chapter == old_chapter:
|
bibles = u'%s, %s' % (start_bible, start_second_bible)
|
||||||
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)
|
|
||||||
else:
|
else:
|
||||||
if start_verse == old_verse and start_chapter == old_chapter:
|
bibles = start_bible
|
||||||
title = u'%s %s:%s (%s)' % (start_book, start_chapter,
|
if start_chapter == old_chapter:
|
||||||
start_verse, start_bible)
|
if start_verse == old_verse:
|
||||||
elif start_chapter == old_chapter:
|
verse_range = start_chapter + verse_separator + start_verse
|
||||||
title = u'%s %s:%s-%s (%s)' % (start_book, start_chapter,
|
|
||||||
start_verse, old_verse, start_bible)
|
|
||||||
else:
|
else:
|
||||||
title = u'%s %s:%s-%s:%s (%s)' % (start_book, start_chapter,
|
verse_range = start_chapter + verse_separator + start_verse + \
|
||||||
start_verse, old_chapter, old_verse, start_bible)
|
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
|
return title
|
||||||
|
|
||||||
def checkTitle(self, item, old_item):
|
def checkTitle(self, item, old_item):
|
||||||
@ -875,7 +875,7 @@ class BibleMediaItem(MediaManagerItem):
|
|||||||
old_second_bible = self._decodeQtObject(old_bitem, 'second_bible')
|
old_second_bible = self._decodeQtObject(old_bitem, 'second_bible')
|
||||||
if old_bible != bible or old_second_bible != second_bible or \
|
if old_bible != bible or old_second_bible != second_bible or \
|
||||||
old_book != book:
|
old_book != book:
|
||||||
# The bible, second bible or book has changed.
|
# The bible, second bible or book has changed.
|
||||||
return True
|
return True
|
||||||
elif old_verse + 1 != verse and old_chapter == chapter:
|
elif old_verse + 1 != verse and old_chapter == chapter:
|
||||||
# We are still in the same chapter, but a verse has been skipped.
|
# We are still in the same chapter, but a verse has been skipped.
|
||||||
@ -907,9 +907,10 @@ class BibleMediaItem(MediaManagerItem):
|
|||||||
``verse``
|
``verse``
|
||||||
The verse number (int).
|
The verse number (int).
|
||||||
"""
|
"""
|
||||||
|
verse_separator = get_reference_match(u'sep_v_display')
|
||||||
if not self.parent.settings_tab.show_new_chapters or \
|
if not self.parent.settings_tab.show_new_chapters or \
|
||||||
old_chapter != chapter:
|
old_chapter != chapter:
|
||||||
verse_text = u'%s:%s' % (chapter, verse)
|
verse_text = unicode(chapter) + verse_separator + unicode(verse)
|
||||||
else:
|
else:
|
||||||
verse_text = u'%s' % verse
|
verse_text = u'%s' % verse
|
||||||
if self.parent.settings_tab.display_style == 1:
|
if self.parent.settings_tab.display_style == 1:
|
||||||
|
0
openlp/plugins/bibles/lib/openlp1.py
Executable file → Normal file
0
openlp/plugins/bibles/lib/openlp1.py
Executable file → Normal file
@ -134,9 +134,9 @@ class OSISBible(BibleDB):
|
|||||||
testament)
|
testament)
|
||||||
if last_chapter == 0:
|
if last_chapter == 0:
|
||||||
if book == u'Gen':
|
if book == u'Gen':
|
||||||
self.wizard.ImportProgressBar.setMaximum(1188)
|
self.wizard.importProgressBar.setMaximum(1188)
|
||||||
else:
|
else:
|
||||||
self.wizard.ImportProgressBar.setMaximum(260)
|
self.wizard.importProgressBar.setMaximum(260)
|
||||||
if last_chapter != chapter:
|
if last_chapter != chapter:
|
||||||
if last_chapter != 0:
|
if last_chapter != 0:
|
||||||
self.session.commit()
|
self.session.commit()
|
||||||
|
@ -1,80 +1,81 @@
|
|||||||
|
João Ferreira de Almeida Atualizada,AA
|
||||||
|
التفسير التطبيقى للكتاب المقدس,ALAB
|
||||||
|
Shqip,ALB
|
||||||
|
Amplified Bible,AMP
|
||||||
Amuzgo de Guerrero,AMU
|
Amuzgo de Guerrero,AMU
|
||||||
Arabic Life Application Bible,ALAB
|
American Standard Version,ASV
|
||||||
Bulgarian Bible,BULG
|
La Bible du Semeur,BDS
|
||||||
1940 Bulgarian Bible,BG1940
|
Български 1940,BG1940
|
||||||
Chinanteco de Comaltepec,CCO
|
Български,BULG
|
||||||
Cakchiquel Occidental,CKW
|
Chinanteco de Comaltepec,CCO
|
||||||
Haitian Creole Version,HCV
|
Contemporary English Version,CEV
|
||||||
Slovo na cestu,SNC
|
Cakchiquel Occidental,CKW
|
||||||
Dette er Biblen på dansk,DN1933
|
Hrvatski,CRO
|
||||||
Hoffnung für Alle,HOF
|
Castilian,CST
|
||||||
Luther Bibel 1545,LUTH1545
|
聖經和合本 (简体中文),CUVS
|
||||||
New International Version,NIV
|
聖經和合本 (繁体中文),CUV
|
||||||
New American Standard Bible,NASB
|
Darby Translation,DARBY
|
||||||
The Message,MSG
|
Dette er Biblen på dansk,DN1933
|
||||||
Amplified Bible,AMP
|
Det Norsk Bibelselskap 1930,DNB1930
|
||||||
New Living Translation,NLT
|
English Standard Version,ESV
|
||||||
King James Version,KJV
|
GOD’S WORD Translation,GW
|
||||||
English Standard Version,ESV
|
Holman Christian Standard Bible,HCSB
|
||||||
Contemporary English Version,CEV
|
Kreyòl ayisyen bib,HCV
|
||||||
New King James Version,NKJV
|
Hiligaynon Bible,HLGN
|
||||||
New Century Version,NCV
|
Hoffnung für Alle,HOF
|
||||||
21st Century King James Version,KJ21
|
Het Boek,HTB
|
||||||
American Standard Version,ASV
|
Icelandic Bible,ICELAND
|
||||||
Young's Literal Translation,YLT
|
Jacalteco – Oriental,JAC
|
||||||
Darby Translation,DARBY
|
Károlyi-biblia,KAR
|
||||||
Holman Christian Standard Bible,HCSB
|
Kekchi,KEK
|
||||||
New International Reader's Version,NIRV
|
21st Century King James Version,KJ21
|
||||||
Wycliffe New Testament,WYC
|
King James Version,KJV
|
||||||
Worldwide English (New Testament),WE
|
La Biblia de las Américas,LBLA
|
||||||
New International Version - UK,NIVUK
|
Levande Bibeln,LB
|
||||||
Today's New International Version,TNIV
|
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
|
Reina-Valera 1960,RVR1960
|
||||||
Nueva Versión Internacional,NVI
|
Reina-Valera 1995,RVR1995
|
||||||
Reina-Valera 1995,RVR1995
|
Slovo na cestu,SNC
|
||||||
Castilian,CST
|
Ang Salita ng Diyos,SND
|
||||||
Reina-Valera Antigua,RVA
|
Swahili New Testament,SNT
|
||||||
Biblia en Lenguaje Sencillo,BLS
|
Svenska 1917,SV1917
|
||||||
La Biblia de las Américas,LBLA
|
Levande Bibeln,SVL
|
||||||
Louis Segond,LSG
|
Создать страницу,SZ
|
||||||
La Bible du Semeur,BDS
|
Traducción en lenguaje actual,TLA
|
||||||
1881 Westcott-Hort New Testament,WHNU
|
New Romanian Translation,TLCR
|
||||||
1550 Stephanus New Testament,TR1550
|
Today’s New International Version 2005,TNIV
|
||||||
1894 Scrivener New Testament,TR1894
|
Textus Receptus Stephanus 1550,TR1550
|
||||||
The Westminster Leningrad Codex,WLC
|
Textus Receptus Scrivener 1894,TR1894
|
||||||
Hiligaynon Bible,HLGN
|
Українська Біблія. Переклад Івана Огієнка,UKR
|
||||||
Croatian Bible,CRO
|
Uspanteco,USP
|
||||||
Hungarian Károli,KAR
|
Kinh Thánh tiếng Việt 1934,VIET
|
||||||
Icelandic Bible,ICELAND
|
Worldwide English (New Testament),WE
|
||||||
La Nuova Diodati,LND
|
Codex Vaticanus Westcott-Hort 1881,WHNU
|
||||||
La Parola è Vita,LM
|
Westminster Leningrad Codex,WLC
|
||||||
Jacalteco, Oriental,JAC
|
Wycliffe New Testament,WYC
|
||||||
Kekchi,KEK
|
Young's Literal Translation,YLT
|
||||||
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
|
|
||||||
|
Can't render this file because it has a wrong number of fields in line 51.
|
39
openlp/plugins/bibles/resources/bibleserver.csv
Normal file
39
openlp/plugins/bibles/resources/bibleserver.csv
Normal 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
|
|
@ -24,4 +24,4 @@ New International Reader's Version,nrv
|
|||||||
The Darby Translation,dby
|
The Darby Translation,dby
|
||||||
The Webster Bible,wbt
|
The Webster Bible,wbt
|
||||||
The Latin Vulgate,vul
|
The Latin Vulgate,vul
|
||||||
Weymouth New Testament,wnt
|
Weymouth New Testament,wnt
|
||||||
|
|
@ -109,7 +109,7 @@ class CustomPlugin(Plugin):
|
|||||||
}
|
}
|
||||||
## Name for MediaDockManager, SettingsManager ##
|
## Name for MediaDockManager, SettingsManager ##
|
||||||
self.textStrings[StringContent.VisibleName] = {
|
self.textStrings[StringContent.VisibleName] = {
|
||||||
u'title': translate('CustomsPlugin', 'Customs')
|
u'title': translate('CustomsPlugin', 'Custom')
|
||||||
}
|
}
|
||||||
# Middle Header Bar
|
# Middle Header Bar
|
||||||
## Import Button ##
|
## Import Button ##
|
||||||
|
@ -224,27 +224,24 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
|
|||||||
``edit_all``
|
``edit_all``
|
||||||
Indicates if all slides or only one slide has been edited.
|
Indicates if all slides or only one slide has been edited.
|
||||||
"""
|
"""
|
||||||
if len(slides) == 1:
|
if edit_all:
|
||||||
self.slideListView.currentItem().setText(slides[0])
|
self.slideListView.clear()
|
||||||
|
for slide in slides:
|
||||||
|
self.slideListView.addItem(slide)
|
||||||
else:
|
else:
|
||||||
if edit_all:
|
old_slides = []
|
||||||
self.slideListView.clear()
|
old_row = self.slideListView.currentRow()
|
||||||
for slide in slides:
|
# Create a list with all (old/unedited) slides.
|
||||||
self.slideListView.addItem(slide)
|
old_slides = [self.slideListView.item(row).text() for row in \
|
||||||
else:
|
range(0, self.slideListView.count())]
|
||||||
old_slides = []
|
self.slideListView.clear()
|
||||||
old_row = self.slideListView.currentRow()
|
old_slides.pop(old_row)
|
||||||
# Create a list with all (old/unedited) slides.
|
# Insert all slides to make the old_slides list complete.
|
||||||
old_slides = [self.slideListView.item(row).text() for row in \
|
for slide in slides:
|
||||||
range(0, self.slideListView.count())]
|
old_slides.insert(old_row, slide)
|
||||||
self.slideListView.clear()
|
for slide in old_slides:
|
||||||
old_slides.pop(old_row)
|
self.slideListView.addItem(slide)
|
||||||
# Insert all slides to make the old_slides list complete.
|
self.slideListView.repaint()
|
||||||
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):
|
def onDeleteButtonPressed(self):
|
||||||
self.slideListView.takeItem(self.slideListView.currentRow())
|
self.slideListView.takeItem(self.slideListView.currentRow())
|
||||||
|
@ -75,42 +75,42 @@ class ImagePlugin(Plugin):
|
|||||||
## Load Button ##
|
## Load Button ##
|
||||||
self.textStrings[StringContent.Load] = {
|
self.textStrings[StringContent.Load] = {
|
||||||
u'title': translate('ImagePlugin', 'Load'),
|
u'title': translate('ImagePlugin', 'Load'),
|
||||||
u'tooltip': translate('ImagePlugin',
|
u'tooltip': translate('ImagePlugin',
|
||||||
'Load a new Image')
|
'Load a new Image')
|
||||||
}
|
}
|
||||||
## New Button ##
|
## New Button ##
|
||||||
self.textStrings[StringContent.New] = {
|
self.textStrings[StringContent.New] = {
|
||||||
u'title': translate('ImagePlugin', 'Add'),
|
u'title': translate('ImagePlugin', 'Add'),
|
||||||
u'tooltip': translate('ImagePlugin',
|
u'tooltip': translate('ImagePlugin',
|
||||||
'Add a new Image')
|
'Add a new Image')
|
||||||
}
|
}
|
||||||
## Edit Button ##
|
## Edit Button ##
|
||||||
self.textStrings[StringContent.Edit] = {
|
self.textStrings[StringContent.Edit] = {
|
||||||
u'title': translate('ImagePlugin', 'Edit'),
|
u'title': translate('ImagePlugin', 'Edit'),
|
||||||
u'tooltip': translate('ImagePlugin',
|
u'tooltip': translate('ImagePlugin',
|
||||||
'Edit the selected Image')
|
'Edit the selected Image')
|
||||||
}
|
}
|
||||||
## Delete Button ##
|
## Delete Button ##
|
||||||
self.textStrings[StringContent.Delete] = {
|
self.textStrings[StringContent.Delete] = {
|
||||||
u'title': translate('ImagePlugin', 'Delete'),
|
u'title': translate('ImagePlugin', 'Delete'),
|
||||||
u'tooltip': translate('ImagePlugin',
|
u'tooltip': translate('ImagePlugin',
|
||||||
'Delete the selected Image')
|
'Delete the selected Image')
|
||||||
}
|
}
|
||||||
## Preview ##
|
## Preview ##
|
||||||
self.textStrings[StringContent.Preview] = {
|
self.textStrings[StringContent.Preview] = {
|
||||||
u'title': translate('ImagePlugin', 'Preview'),
|
u'title': translate('ImagePlugin', 'Preview'),
|
||||||
u'tooltip': translate('ImagePlugin',
|
u'tooltip': translate('ImagePlugin',
|
||||||
'Preview the selected Image')
|
'Preview the selected Image')
|
||||||
}
|
}
|
||||||
## Live Button ##
|
## Live Button ##
|
||||||
self.textStrings[StringContent.Live] = {
|
self.textStrings[StringContent.Live] = {
|
||||||
u'title': translate('ImagePlugin', 'Live'),
|
u'title': translate('ImagePlugin', 'Live'),
|
||||||
u'tooltip': translate('ImagePlugin',
|
u'tooltip': translate('ImagePlugin',
|
||||||
'Send the selected Image live')
|
'Send the selected Image live')
|
||||||
}
|
}
|
||||||
## Add to service Button ##
|
## Add to service Button ##
|
||||||
self.textStrings[StringContent.Service] = {
|
self.textStrings[StringContent.Service] = {
|
||||||
u'title': translate('ImagePlugin', 'Service'),
|
u'title': translate('ImagePlugin', 'Service'),
|
||||||
u'tooltip': translate('ImagePlugin',
|
u'tooltip': translate('ImagePlugin',
|
||||||
'Add the selected Image to the service')
|
'Add the selected Image to the service')
|
||||||
}
|
}
|
@ -31,7 +31,7 @@ from PyQt4 import QtCore, QtGui
|
|||||||
|
|
||||||
from openlp.core.lib import MediaManagerItem, BaseListWithDnD, build_icon, \
|
from openlp.core.lib import MediaManagerItem, BaseListWithDnD, build_icon, \
|
||||||
context_menu_action, ItemCapabilities, SettingsManager, translate, \
|
context_menu_action, ItemCapabilities, SettingsManager, translate, \
|
||||||
check_item_selected
|
check_item_selected, Receiver
|
||||||
from openlp.core.utils import AppLocation, get_images_filter
|
from openlp.core.utils import AppLocation, get_images_filter
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
@ -139,6 +139,8 @@ class ImageMediaItem(MediaManagerItem):
|
|||||||
self.settingsSection, self.getFileList())
|
self.settingsSection, self.getFileList())
|
||||||
|
|
||||||
def loadList(self, list):
|
def loadList(self, list):
|
||||||
|
self.listView.setCursor(QtCore.Qt.BusyCursor)
|
||||||
|
Receiver.send_message(u'openlp_process_events')
|
||||||
for file in list:
|
for file in list:
|
||||||
filename = os.path.split(unicode(file))[1]
|
filename = os.path.split(unicode(file))[1]
|
||||||
thumb = os.path.join(self.servicePath, filename)
|
thumb = os.path.join(self.servicePath, filename)
|
||||||
@ -153,6 +155,8 @@ class ImageMediaItem(MediaManagerItem):
|
|||||||
item_name.setIcon(icon)
|
item_name.setIcon(icon)
|
||||||
item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(file))
|
item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(file))
|
||||||
self.listView.addItem(item_name)
|
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):
|
def generateSlideData(self, service_item, item=None, xmlVersion=False):
|
||||||
items = self.listView.selectedIndexes()
|
items = self.listView.selectedIndexes()
|
||||||
|
@ -48,7 +48,7 @@ else:
|
|||||||
uno_available = True
|
uno_available = True
|
||||||
except ImportError:
|
except ImportError:
|
||||||
uno_available = False
|
uno_available = False
|
||||||
|
|
||||||
from PyQt4 import QtCore
|
from PyQt4 import QtCore
|
||||||
|
|
||||||
from presentationcontroller import PresentationController, PresentationDocument
|
from presentationcontroller import PresentationController, PresentationDocument
|
||||||
@ -210,12 +210,12 @@ class ImpressController(PresentationController):
|
|||||||
class ImpressDocument(PresentationDocument):
|
class ImpressDocument(PresentationDocument):
|
||||||
"""
|
"""
|
||||||
Class which holds information and controls a single presentation
|
Class which holds information and controls a single presentation
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, controller, 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')
|
log.debug(u'Init Presentation OpenOffice')
|
||||||
PresentationDocument.__init__(self, controller, presentation)
|
PresentationDocument.__init__(self, controller, presentation)
|
||||||
self.document = None
|
self.document = None
|
||||||
@ -287,7 +287,7 @@ class ImpressDocument(PresentationDocument):
|
|||||||
page = pages.getByIndex(idx)
|
page = pages.getByIndex(idx)
|
||||||
doc.getCurrentController().setCurrentPage(page)
|
doc.getCurrentController().setCurrentPage(page)
|
||||||
urlpath = u'%s/%s.png' % (thumbdirurl, unicode(idx + 1))
|
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')
|
unicode(idx + 1) + u'.png')
|
||||||
try:
|
try:
|
||||||
doc.storeToURL(urlpath, props)
|
doc.storeToURL(urlpath, props)
|
||||||
|
@ -51,7 +51,7 @@ class Controller(object):
|
|||||||
|
|
||||||
def add_handler(self, controller, file, is_blank):
|
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
|
slidecontroller combination. If the slidecontroller has a display
|
||||||
then load the presentation.
|
then load the presentation.
|
||||||
"""
|
"""
|
||||||
@ -362,7 +362,7 @@ class MessageListener(object):
|
|||||||
|
|
||||||
def timeout(self):
|
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
|
application directly, rather than through OpenLP. Poll occassionally
|
||||||
to check which slide is currently displayed so the slidecontroller
|
to check which slide is currently displayed so the slidecontroller
|
||||||
view can be updated
|
view can be updated
|
||||||
|
@ -108,7 +108,7 @@ class PptviewDocument(PresentationDocument):
|
|||||||
"""
|
"""
|
||||||
def __init__(self, controller, 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 PowerPoint')
|
log.debug(u'Init Presentation PowerPoint')
|
||||||
PresentationDocument.__init__(self, controller, presentation)
|
PresentationDocument.__init__(self, controller, presentation)
|
||||||
|
@ -133,7 +133,7 @@ class PresentationTab(SettingsTab):
|
|||||||
self.settingsSection + u'/' + controller.name,
|
self.settingsSection + u'/' + controller.name,
|
||||||
QtCore.QVariant(QtCore.Qt.Checked)).toInt()[0])
|
QtCore.QVariant(QtCore.Qt.Checked)).toInt()[0])
|
||||||
self.OverrideAppCheckBox.setChecked(QtCore.QSettings().value(
|
self.OverrideAppCheckBox.setChecked(QtCore.QSettings().value(
|
||||||
self.settingsSection + u'/override app',
|
self.settingsSection + u'/override app',
|
||||||
QtCore.QVariant(QtCore.Qt.Unchecked)).toInt()[0])
|
QtCore.QVariant(QtCore.Qt.Unchecked)).toInt()[0])
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
|
@ -163,30 +163,30 @@ class PresentationPlugin(Plugin):
|
|||||||
## Load Button ##
|
## Load Button ##
|
||||||
self.textStrings[StringContent.Load] = {
|
self.textStrings[StringContent.Load] = {
|
||||||
u'title': translate('PresentationPlugin', 'Load'),
|
u'title': translate('PresentationPlugin', 'Load'),
|
||||||
u'tooltip': translate('PresentationPlugin',
|
u'tooltip': translate('PresentationPlugin',
|
||||||
'Load a new Presentation')
|
'Load a new Presentation')
|
||||||
}
|
}
|
||||||
## Delete Button ##
|
## Delete Button ##
|
||||||
self.textStrings[StringContent.Delete] = {
|
self.textStrings[StringContent.Delete] = {
|
||||||
u'title': translate('PresentationPlugin', 'Delete'),
|
u'title': translate('PresentationPlugin', 'Delete'),
|
||||||
u'tooltip': translate('PresentationPlugin',
|
u'tooltip': translate('PresentationPlugin',
|
||||||
'Delete the selected Presentation')
|
'Delete the selected Presentation')
|
||||||
}
|
}
|
||||||
## Preview ##
|
## Preview ##
|
||||||
self.textStrings[StringContent.Preview] = {
|
self.textStrings[StringContent.Preview] = {
|
||||||
u'title': translate('PresentationPlugin', 'Preview'),
|
u'title': translate('PresentationPlugin', 'Preview'),
|
||||||
u'tooltip': translate('PresentationPlugin',
|
u'tooltip': translate('PresentationPlugin',
|
||||||
'Preview the selected Presentation')
|
'Preview the selected Presentation')
|
||||||
}
|
}
|
||||||
## Live Button ##
|
## Live Button ##
|
||||||
self.textStrings[StringContent.Live] = {
|
self.textStrings[StringContent.Live] = {
|
||||||
u'title': translate('PresentationPlugin', 'Live'),
|
u'title': translate('PresentationPlugin', 'Live'),
|
||||||
u'tooltip': translate('PresentationPlugin',
|
u'tooltip': translate('PresentationPlugin',
|
||||||
'Send the selected Presentation live')
|
'Send the selected Presentation live')
|
||||||
}
|
}
|
||||||
## Add to service Button ##
|
## Add to service Button ##
|
||||||
self.textStrings[StringContent.Service] = {
|
self.textStrings[StringContent.Service] = {
|
||||||
u'title': translate('PresentationPlugin', 'Service'),
|
u'title': translate('PresentationPlugin', 'Service'),
|
||||||
u'tooltip': translate('PresentationPlugin',
|
u'tooltip': translate('PresentationPlugin',
|
||||||
'Add the selected Presentation to the service')
|
'Add the selected Presentation to the service')
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,7 @@ class RemotesPlugin(Plugin):
|
|||||||
'a running version of OpenLP on a different computer via a web '
|
'a running version of OpenLP on a different computer via a web '
|
||||||
'browser or through the remote API.')
|
'browser or through the remote API.')
|
||||||
return about_text
|
return about_text
|
||||||
|
|
||||||
def setPluginTextStrings(self):
|
def setPluginTextStrings(self):
|
||||||
"""
|
"""
|
||||||
Called to define all translatable texts of the plugin
|
Called to define all translatable texts of the plugin
|
||||||
|
@ -108,6 +108,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
|||||||
self.TopicsListView.setSortingEnabled(False)
|
self.TopicsListView.setSortingEnabled(False)
|
||||||
self.TopicsListView.setAlternatingRowColors(True)
|
self.TopicsListView.setAlternatingRowColors(True)
|
||||||
self.findVerseSplit = re.compile(u'---\[\]---\n', re.UNICODE)
|
self.findVerseSplit = re.compile(u'---\[\]---\n', re.UNICODE)
|
||||||
|
self.whitespace = re.compile(r'\W+', re.UNICODE)
|
||||||
|
|
||||||
def initialise(self):
|
def initialise(self):
|
||||||
self.VerseEditButton.setEnabled(False)
|
self.VerseEditButton.setEnabled(False)
|
||||||
@ -120,35 +121,55 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
|||||||
order_by_ref=Author.display_name)
|
order_by_ref=Author.display_name)
|
||||||
self.AuthorsSelectionComboItem.clear()
|
self.AuthorsSelectionComboItem.clear()
|
||||||
self.AuthorsSelectionComboItem.addItem(u'')
|
self.AuthorsSelectionComboItem.addItem(u'')
|
||||||
|
self.authors = []
|
||||||
for author in authors:
|
for author in authors:
|
||||||
row = self.AuthorsSelectionComboItem.count()
|
row = self.AuthorsSelectionComboItem.count()
|
||||||
self.AuthorsSelectionComboItem.addItem(author.display_name)
|
self.AuthorsSelectionComboItem.addItem(author.display_name)
|
||||||
self.AuthorsSelectionComboItem.setItemData(
|
self.AuthorsSelectionComboItem.setItemData(
|
||||||
row, QtCore.QVariant(author.id))
|
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):
|
def loadTopics(self):
|
||||||
topics = self.manager.get_all_objects(Topic, order_by_ref=Topic.name)
|
topics = self.manager.get_all_objects(Topic, order_by_ref=Topic.name)
|
||||||
self.SongTopicCombo.clear()
|
self.SongTopicCombo.clear()
|
||||||
self.SongTopicCombo.addItem(u'')
|
self.SongTopicCombo.addItem(u'')
|
||||||
|
self.topics = []
|
||||||
for topic in topics:
|
for topic in topics:
|
||||||
row = self.SongTopicCombo.count()
|
row = self.SongTopicCombo.count()
|
||||||
self.SongTopicCombo.addItem(topic.name)
|
self.SongTopicCombo.addItem(topic.name)
|
||||||
|
self.topics.append(topic.name)
|
||||||
self.SongTopicCombo.setItemData(row, QtCore.QVariant(topic.id))
|
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):
|
def loadBooks(self):
|
||||||
books = self.manager.get_all_objects(Book, order_by_ref=Book.name)
|
books = self.manager.get_all_objects(Book, order_by_ref=Book.name)
|
||||||
self.SongbookCombo.clear()
|
self.SongbookCombo.clear()
|
||||||
self.SongbookCombo.addItem(u'')
|
self.SongbookCombo.addItem(u'')
|
||||||
|
self.books = []
|
||||||
for book in books:
|
for book in books:
|
||||||
row = self.SongbookCombo.count()
|
row = self.SongbookCombo.count()
|
||||||
self.SongbookCombo.addItem(book.name)
|
self.SongbookCombo.addItem(book.name)
|
||||||
|
self.books.append(book.name)
|
||||||
self.SongbookCombo.setItemData(row, QtCore.QVariant(book.id))
|
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):
|
def loadThemes(self, theme_list):
|
||||||
self.ThemeSelectionComboItem.clear()
|
self.ThemeSelectionComboItem.clear()
|
||||||
self.ThemeSelectionComboItem.addItem(u'')
|
self.ThemeSelectionComboItem.addItem(u'')
|
||||||
|
self.themes = []
|
||||||
for theme in theme_list:
|
for theme in theme_list:
|
||||||
self.ThemeSelectionComboItem.addItem(theme)
|
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):
|
def newSong(self):
|
||||||
log.debug(u'New Song')
|
log.debug(u'New Song')
|
||||||
@ -526,14 +547,11 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
|||||||
if self.AuthorsListView.count() == 0:
|
if self.AuthorsListView.count() == 0:
|
||||||
self.SongTabWidget.setCurrentIndex(1)
|
self.SongTabWidget.setCurrentIndex(1)
|
||||||
self.AuthorsListView.setFocus()
|
self.AuthorsListView.setFocus()
|
||||||
answer = QtGui.QMessageBox.warning(self,
|
QtGui.QMessageBox.critical(self,
|
||||||
translate('SongsPlugin.EditSongForm', 'Warning'),
|
translate('SongsPlugin.EditSongForm', 'Warning'),
|
||||||
translate('SongsPlugin.EditSongForm',
|
translate('SongsPlugin.EditSongForm',
|
||||||
'You have not added any authors for this song. Do you '
|
'You need to have an author for this song.'))
|
||||||
'want to add an author now?'),
|
return False
|
||||||
QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)
|
|
||||||
if answer == QtGui.QMessageBox.Yes:
|
|
||||||
return False
|
|
||||||
if self.song.verse_order:
|
if self.song.verse_order:
|
||||||
order = []
|
order = []
|
||||||
order_names = self.song.verse_order.split()
|
order_names = self.song.verse_order.split()
|
||||||
@ -614,12 +632,29 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
|||||||
self.saveSong(True):
|
self.saveSong(True):
|
||||||
Receiver.send_message(u'songs_preview')
|
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):
|
def closePressed(self):
|
||||||
|
"""
|
||||||
|
Exit Dialog and do not save
|
||||||
|
"""
|
||||||
Receiver.send_message(u'songs_edit_clear')
|
Receiver.send_message(u'songs_edit_clear')
|
||||||
|
self.clearCaches()
|
||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
def accept(self):
|
def accept(self):
|
||||||
|
"""
|
||||||
|
Exit Dialog and save soong if valid
|
||||||
|
"""
|
||||||
log.debug(u'accept')
|
log.debug(u'accept')
|
||||||
|
self.clearCaches()
|
||||||
if not self.song:
|
if not self.song:
|
||||||
self.song = Song()
|
self.song = Song()
|
||||||
item = int(self.SongbookCombo.currentIndex())
|
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
|
Get all the data from the widgets on the form, and then save it to the
|
||||||
database.
|
database.
|
||||||
|
|
||||||
``preview``
|
``preview``
|
||||||
Should be ``True`` if the song is also previewed (boolean).
|
Should be ``True`` if the song is also previewed (boolean).
|
||||||
"""
|
"""
|
||||||
self.song.title = unicode(self.TitleEditItem.text())
|
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())
|
verseId = unicode(item.data(QtCore.Qt.UserRole).toString())
|
||||||
bits = verseId.split(u':')
|
bits = verseId.split(u':')
|
||||||
sxml.add_verse_to_lyrics(bits[0], bits[1], unicode(item.text()))
|
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' '
|
unicode(self.VerseListWidget.item(i, 0).text())) + u' '
|
||||||
if (bits[1] > u'1') and (bits[0][0] not in multiple):
|
if (bits[1] > u'1') and (bits[0][0] not in multiple):
|
||||||
multiple.append(bits[0][0])
|
multiple.append(bits[0][0])
|
||||||
|
@ -29,7 +29,7 @@ import logging
|
|||||||
|
|
||||||
from PyQt4 import QtCore, QtGui
|
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
|
from editversedialog import Ui_EditVerseDialog
|
||||||
|
|
||||||
@ -131,6 +131,7 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog):
|
|||||||
|
|
||||||
def setVerse(self, text, single=False,
|
def setVerse(self, text, single=False,
|
||||||
tag=u'%s:1' % VerseType.to_string(VerseType.Verse)):
|
tag=u'%s:1' % VerseType.to_string(VerseType.Verse)):
|
||||||
|
self.hasSingleVerse = single
|
||||||
if single:
|
if single:
|
||||||
verse_type, verse_number = tag.split(u':')
|
verse_type, verse_number = tag.split(u':')
|
||||||
verse_type_index = VerseType.from_string(verse_type)
|
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 = u'---[%s:1]---\n%s' % (VerseType.to_string(VerseType.Verse),
|
||||||
text)
|
text)
|
||||||
return 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)
|
||||||
|
@ -152,101 +152,101 @@ class SongImportForm(QtGui.QWizard, Ui_SongImportWizard):
|
|||||||
if self.openLP2FilenameEdit.text().isEmpty():
|
if self.openLP2FilenameEdit.text().isEmpty():
|
||||||
QtGui.QMessageBox.critical(self,
|
QtGui.QMessageBox.critical(self,
|
||||||
translate('SongsPlugin.ImportWizardForm',
|
translate('SongsPlugin.ImportWizardForm',
|
||||||
'No OpenLP 2.0 Song Database Selected'),
|
'No OpenLP 2.0 Song Database Selected'),
|
||||||
translate('SongsPlugin.ImportWizardForm',
|
translate('SongsPlugin.ImportWizardForm',
|
||||||
'You need to select an OpenLP 2.0 song database '
|
'You need to select an OpenLP 2.0 song database '
|
||||||
'file to import from.'))
|
'file to import from.'))
|
||||||
self.openLP2BrowseButton.setFocus()
|
self.openLP2BrowseButton.setFocus()
|
||||||
return False
|
return False
|
||||||
elif source_format == SongFormat.OpenLP1:
|
elif source_format == SongFormat.OpenLP1:
|
||||||
if self.openLP1FilenameEdit.text().isEmpty():
|
if self.openLP1FilenameEdit.text().isEmpty():
|
||||||
QtGui.QMessageBox.critical(self,
|
QtGui.QMessageBox.critical(self,
|
||||||
translate('SongsPlugin.ImportWizardForm',
|
translate('SongsPlugin.ImportWizardForm',
|
||||||
'No openlp.org 1.x Song Database Selected'),
|
'No openlp.org 1.x Song Database Selected'),
|
||||||
translate('SongsPlugin.ImportWizardForm',
|
translate('SongsPlugin.ImportWizardForm',
|
||||||
'You need to select an openlp.org 1.x song '
|
'You need to select an openlp.org 1.x song '
|
||||||
'database file to import from.'))
|
'database file to import from.'))
|
||||||
self.openLP1BrowseButton.setFocus()
|
self.openLP1BrowseButton.setFocus()
|
||||||
return False
|
return False
|
||||||
elif source_format == SongFormat.OpenLyrics:
|
elif source_format == SongFormat.OpenLyrics:
|
||||||
#if self.openLyricsFileListWidget.count() == 0:
|
# if self.openLyricsFileListWidget.count() == 0:
|
||||||
# QtGui.QMessageBox.critical(self,
|
# QtGui.QMessageBox.critical(self,
|
||||||
# translate('SongsPlugin.ImportWizardForm',
|
# translate('SongsPlugin.ImportWizardForm',
|
||||||
# 'No OpenLyrics Files Selected'),
|
# 'No OpenLyrics Files Selected'),
|
||||||
# translate('SongsPlugin.ImportWizardForm',
|
# translate('SongsPlugin.ImportWizardForm',
|
||||||
# 'You need to add at least one OpenLyrics '
|
# 'You need to add at least one OpenLyrics '
|
||||||
# 'song file to import from.'))
|
# 'song file to import from.'))
|
||||||
# self.openLyricsAddButton.setFocus()
|
# self.openLyricsAddButton.setFocus()
|
||||||
# return False
|
# return False
|
||||||
return False
|
return False
|
||||||
elif source_format == SongFormat.OpenSong:
|
elif source_format == SongFormat.OpenSong:
|
||||||
if self.openSongFileListWidget.count() == 0:
|
if self.openSongFileListWidget.count() == 0:
|
||||||
QtGui.QMessageBox.critical(self,
|
QtGui.QMessageBox.critical(self,
|
||||||
translate('SongsPlugin.ImportWizardForm',
|
translate('SongsPlugin.ImportWizardForm',
|
||||||
'No OpenSong Files Selected'),
|
'No OpenSong Files Selected'),
|
||||||
translate('SongsPlugin.ImportWizardForm',
|
translate('SongsPlugin.ImportWizardForm',
|
||||||
'You need to add at least one OpenSong '
|
'You need to add at least one OpenSong '
|
||||||
'song file to import from.'))
|
'song file to import from.'))
|
||||||
self.openSongAddButton.setFocus()
|
self.openSongAddButton.setFocus()
|
||||||
return False
|
return False
|
||||||
elif source_format == SongFormat.WordsOfWorship:
|
elif source_format == SongFormat.WordsOfWorship:
|
||||||
if self.wordsOfWorshipFileListWidget.count() == 0:
|
if self.wordsOfWorshipFileListWidget.count() == 0:
|
||||||
QtGui.QMessageBox.critical(self,
|
QtGui.QMessageBox.critical(self,
|
||||||
translate('SongsPlugin.ImportWizardForm',
|
translate('SongsPlugin.ImportWizardForm',
|
||||||
'No Words of Worship Files Selected'),
|
'No Words of Worship Files Selected'),
|
||||||
translate('SongsPlugin.ImportWizardForm',
|
translate('SongsPlugin.ImportWizardForm',
|
||||||
'You need to add at least one Words of Worship '
|
'You need to add at least one Words of Worship '
|
||||||
'file to import from.'))
|
'file to import from.'))
|
||||||
self.wordsOfWorshipAddButton.setFocus()
|
self.wordsOfWorshipAddButton.setFocus()
|
||||||
return False
|
return False
|
||||||
elif source_format == SongFormat.CCLI:
|
elif source_format == SongFormat.CCLI:
|
||||||
if self.ccliFileListWidget.count() == 0:
|
if self.ccliFileListWidget.count() == 0:
|
||||||
QtGui.QMessageBox.critical(self,
|
QtGui.QMessageBox.critical(self,
|
||||||
translate('SongsPlugin.ImportWizardForm',
|
translate('SongsPlugin.ImportWizardForm',
|
||||||
'No CCLI Files Selected'),
|
'No CCLI Files Selected'),
|
||||||
translate('SongsPlugin.ImportWizardForm',
|
translate('SongsPlugin.ImportWizardForm',
|
||||||
'You need to add at least one CCLI file '
|
'You need to add at least one CCLI file '
|
||||||
'to import from.'))
|
'to import from.'))
|
||||||
self.ccliAddButton.setFocus()
|
self.ccliAddButton.setFocus()
|
||||||
return False
|
return False
|
||||||
elif source_format == SongFormat.SongsOfFellowship:
|
elif source_format == SongFormat.SongsOfFellowship:
|
||||||
if self.songsOfFellowshipFileListWidget.count() == 0:
|
if self.songsOfFellowshipFileListWidget.count() == 0:
|
||||||
QtGui.QMessageBox.critical(self,
|
QtGui.QMessageBox.critical(self,
|
||||||
translate('SongsPlugin.ImportWizardForm',
|
translate('SongsPlugin.ImportWizardForm',
|
||||||
'No Songs of Fellowship File Selected'),
|
'No Songs of Fellowship File Selected'),
|
||||||
translate('SongsPlugin.ImportWizardForm',
|
translate('SongsPlugin.ImportWizardForm',
|
||||||
'You need to add at least one Songs of Fellowship '
|
'You need to add at least one Songs of Fellowship '
|
||||||
'file to import from.'))
|
'file to import from.'))
|
||||||
self.songsOfFellowshipAddButton.setFocus()
|
self.songsOfFellowshipAddButton.setFocus()
|
||||||
return False
|
return False
|
||||||
elif source_format == SongFormat.Generic:
|
elif source_format == SongFormat.Generic:
|
||||||
if self.genericFileListWidget.count() == 0:
|
if self.genericFileListWidget.count() == 0:
|
||||||
QtGui.QMessageBox.critical(self,
|
QtGui.QMessageBox.critical(self,
|
||||||
translate('SongsPlugin.ImportWizardForm',
|
translate('SongsPlugin.ImportWizardForm',
|
||||||
'No Document/Presentation Selected'),
|
'No Document/Presentation Selected'),
|
||||||
translate('SongsPlugin.ImportWizardForm',
|
translate('SongsPlugin.ImportWizardForm',
|
||||||
'You need to add at least one document or '
|
'You need to add at least one document or '
|
||||||
'presentation file to import from.'))
|
'presentation file to import from.'))
|
||||||
self.genericAddButton.setFocus()
|
self.genericAddButton.setFocus()
|
||||||
return False
|
return False
|
||||||
elif source_format == SongFormat.EasyWorship:
|
elif source_format == SongFormat.EasyWorship:
|
||||||
if self.ewFilenameEdit.text().isEmpty():
|
if self.ewFilenameEdit.text().isEmpty():
|
||||||
QtGui.QMessageBox.critical(self,
|
QtGui.QMessageBox.critical(self,
|
||||||
translate('SongsPlugin.ImportWizardForm',
|
translate('SongsPlugin.ImportWizardForm',
|
||||||
'No EasyWorship Song Database Selected'),
|
'No EasyWorship Song Database Selected'),
|
||||||
translate('SongsPlugin.ImportWizardForm',
|
translate('SongsPlugin.ImportWizardForm',
|
||||||
'You need to select an EasyWorship song database '
|
'You need to select an EasyWorship song database '
|
||||||
'file to import from.'))
|
'file to import from.'))
|
||||||
self.ewBrowseButton.setFocus()
|
self.ewBrowseButton.setFocus()
|
||||||
return False
|
return False
|
||||||
elif source_format == SongFormat.SongBeamer:
|
elif source_format == SongFormat.SongBeamer:
|
||||||
if self.songBeamerFileListWidget.count() == 0:
|
if self.songBeamerFileListWidget.count() == 0:
|
||||||
QtGui.QMessageBox.critical(self,
|
QtGui.QMessageBox.critical(self,
|
||||||
translate('SongsPlugin.ImportWizardForm',
|
translate('SongsPlugin.ImportWizardForm',
|
||||||
'No SongBeamer File Selected'),
|
'No SongBeamer File Selected'),
|
||||||
translate('SongsPlugin.ImportWizardForm',
|
translate('SongsPlugin.ImportWizardForm',
|
||||||
'You need to add at least one SongBeamer '
|
'You need to add at least one SongBeamer '
|
||||||
'file to import from.'))
|
'file to import from.'))
|
||||||
self.songBeamerAddButton.setFocus()
|
self.songBeamerAddButton.setFocus()
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
@ -254,24 +254,57 @@ class SongImportForm(QtGui.QWizard, Ui_SongImportWizard):
|
|||||||
# Progress page
|
# Progress page
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def getFileName(self, title, editbox,
|
def getFileName(self, title, editbox, filters=u''):
|
||||||
filters = '%s (*)' % translate('SongsPlugin.ImportWizardForm',
|
"""
|
||||||
'All Files')):
|
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,
|
filename = QtGui.QFileDialog.getOpenFileName(self, title,
|
||||||
SettingsManager.get_last_dir(self.plugin.settingsSection, 1),
|
os.path.dirname(SettingsManager.get_last_dir(
|
||||||
filters)
|
self.plugin.settingsSection, 1)), filters)
|
||||||
if filename:
|
if filename:
|
||||||
editbox.setText(filename)
|
editbox.setText(filename)
|
||||||
SettingsManager.set_last_dir(
|
SettingsManager.set_last_dir(self.plugin.settingsSection,
|
||||||
self.plugin.settingsSection,
|
|
||||||
os.path.split(unicode(filename))[0], 1)
|
os.path.split(unicode(filename))[0], 1)
|
||||||
|
|
||||||
def getFiles(self, title, listbox,
|
def getFiles(self, title, listbox, filters=u''):
|
||||||
filters = u'%s (*)' % translate('SongsPlugin.ImportWizardForm',
|
"""
|
||||||
'All Files')):
|
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,
|
filenames = QtGui.QFileDialog.getOpenFileNames(self, title,
|
||||||
SettingsManager.get_last_dir(self.plugin.settingsSection, 1),
|
os.path.dirname(SettingsManager.get_last_dir(
|
||||||
filters)
|
self.plugin.settingsSection, 1)), filters)
|
||||||
if filenames:
|
if filenames:
|
||||||
listbox.addItems(filenames)
|
listbox.addItems(filenames)
|
||||||
SettingsManager.set_last_dir(
|
SettingsManager.set_last_dir(
|
||||||
@ -293,24 +326,18 @@ class SongImportForm(QtGui.QWizard, Ui_SongImportWizard):
|
|||||||
self.getFileName(
|
self.getFileName(
|
||||||
translate('SongsPlugin.ImportWizardForm',
|
translate('SongsPlugin.ImportWizardForm',
|
||||||
'Select OpenLP 2.0 Database File'),
|
'Select OpenLP 2.0 Database File'),
|
||||||
self.openLP2FilenameEdit,
|
self.openLP2FilenameEdit, u'%s (*.sqlite)'
|
||||||
u'%s (*.sqlite);;%s (*)'
|
|
||||||
% (translate('SongsPlugin.ImportWizardForm',
|
% (translate('SongsPlugin.ImportWizardForm',
|
||||||
'OpenLP 2.0 Databases'),
|
'OpenLP 2.0 Databases'))
|
||||||
translate('SongsPlugin.ImportWizardForm',
|
|
||||||
'All Files'))
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def onOpenLP1BrowseButtonClicked(self):
|
def onOpenLP1BrowseButtonClicked(self):
|
||||||
self.getFileName(
|
self.getFileName(
|
||||||
translate('SongsPlugin.ImportWizardForm',
|
translate('SongsPlugin.ImportWizardForm',
|
||||||
'Select openlp.org 1.x Database File'),
|
'Select openlp.org 1.x Database File'),
|
||||||
self.openLP1FilenameEdit,
|
self.openLP1FilenameEdit, u'%s (*.olp)'
|
||||||
u'%s (*.olp);;%s (*)'
|
% translate('SongsPlugin.ImportWizardForm',
|
||||||
% (translate('SongsPlugin.ImportWizardForm',
|
'openlp.org v1.x Databases')
|
||||||
'openlp.org v1.x Databases'),
|
|
||||||
translate('SongsPlugin.ImportWizardForm',
|
|
||||||
'All Files'))
|
|
||||||
)
|
)
|
||||||
|
|
||||||
#def onOpenLyricsAddButtonClicked(self):
|
#def onOpenLyricsAddButtonClicked(self):
|
||||||
@ -337,12 +364,9 @@ class SongImportForm(QtGui.QWizard, Ui_SongImportWizard):
|
|||||||
self.getFiles(
|
self.getFiles(
|
||||||
translate('SongsPlugin.ImportWizardForm',
|
translate('SongsPlugin.ImportWizardForm',
|
||||||
'Select Words of Worship Files'),
|
'Select Words of Worship Files'),
|
||||||
self.wordsOfWorshipFileListWidget,
|
self.wordsOfWorshipFileListWidget, u'%s (*.wsg *.wow-song)'
|
||||||
u'%s (*.wsg *.wow-song);;%s (*)'
|
% translate('SongsPlugin.ImportWizardForm',
|
||||||
% (translate('SongsPlugin.ImportWizardForm',
|
'Words Of Worship Song Files')
|
||||||
'Words Of Worship Song Files'),
|
|
||||||
translate('SongsPlugin.ImportWizardForm',
|
|
||||||
'All Files'))
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def onWordsOfWorshipRemoveButtonClicked(self):
|
def onWordsOfWorshipRemoveButtonClicked(self):
|
||||||
@ -362,12 +386,9 @@ class SongImportForm(QtGui.QWizard, Ui_SongImportWizard):
|
|||||||
self.getFiles(
|
self.getFiles(
|
||||||
translate('SongsPlugin.ImportWizardForm',
|
translate('SongsPlugin.ImportWizardForm',
|
||||||
'Select Songs of Fellowship Files'),
|
'Select Songs of Fellowship Files'),
|
||||||
self.songsOfFellowshipFileListWidget,
|
self.songsOfFellowshipFileListWidget, u'%s (*.rtf)'
|
||||||
u'%s (*.rtf);;%s (*)'
|
% translate('SongsPlugin.ImportWizardForm',
|
||||||
% (translate('SongsPlugin.ImportWizardForm',
|
'Songs Of Felloship Song Files')
|
||||||
'Songs Of Felloship Song Files'),
|
|
||||||
translate('SongsPlugin.ImportWizardForm',
|
|
||||||
'All Files'))
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def onSongsOfFellowshipRemoveButtonClicked(self):
|
def onSongsOfFellowshipRemoveButtonClicked(self):
|
||||||
@ -394,7 +415,8 @@ class SongImportForm(QtGui.QWizard, Ui_SongImportWizard):
|
|||||||
self.getFiles(
|
self.getFiles(
|
||||||
translate('SongsPlugin.ImportWizardForm',
|
translate('SongsPlugin.ImportWizardForm',
|
||||||
'Select SongBeamer Files'),
|
'Select SongBeamer Files'),
|
||||||
self.songBeamerFileListWidget
|
self.songBeamerFileListWidget, u'%s (*.sng)' %
|
||||||
|
translate('SongsPlugin.ImportWizardForm', 'SongBeamer files')
|
||||||
)
|
)
|
||||||
|
|
||||||
def onSongBeamerRemoveButtonClicked(self):
|
def onSongBeamerRemoveButtonClicked(self):
|
||||||
|
@ -411,7 +411,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
|
|||||||
"""
|
"""
|
||||||
existing_author = self.manager.get_object_filtered(Author,
|
existing_author = self.manager.get_object_filtered(Author,
|
||||||
and_(Author.first_name == old_author.first_name,
|
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))
|
Author.display_name == old_author.display_name))
|
||||||
songs = self.manager.get_all_objects(Song,
|
songs = self.manager.get_all_objects(Song,
|
||||||
Song.authors.contains(old_author))
|
Song.authors.contains(old_author))
|
||||||
|
@ -71,7 +71,8 @@ class VerseType(object):
|
|||||||
The string to return a VerseType for
|
The string to return a VerseType for
|
||||||
"""
|
"""
|
||||||
verse_type = verse_type.lower()
|
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')
|
return translate('SongsPlugin.VerseType', 'Verse')
|
||||||
elif verse_type == \
|
elif verse_type == \
|
||||||
unicode(VerseType.to_string(VerseType.Chorus)).lower()[0]:
|
unicode(VerseType.to_string(VerseType.Chorus)).lower()[0]:
|
||||||
|
@ -197,7 +197,7 @@ class CCLIFileImport(SongImport):
|
|||||||
verse_text = verse_lines[1]
|
verse_text = verse_lines[1]
|
||||||
elif verse_lines[0].startswith(u'('):
|
elif verse_lines[0].startswith(u'('):
|
||||||
verse_type = u'O'
|
verse_type = u'O'
|
||||||
verse_text = verse_lines[1]
|
verse_text = verse_lines[1]
|
||||||
if len(verse_text) > 0:
|
if len(verse_text) > 0:
|
||||||
self.add_verse(verse_text, verse_type)
|
self.add_verse(verse_text, verse_type)
|
||||||
check_first_verse_line = False
|
check_first_verse_line = False
|
||||||
@ -303,13 +303,13 @@ class CCLIFileImport(SongImport):
|
|||||||
verse_type = u'P'
|
verse_type = u'P'
|
||||||
elif line.startswith(u'(BRIDGE'):
|
elif line.startswith(u'(BRIDGE'):
|
||||||
verse_type = u'B'
|
verse_type = u'B'
|
||||||
# Handle all other misc types
|
# Handle all other misc types
|
||||||
elif line.startswith(u'('):
|
elif line.startswith(u'('):
|
||||||
verse_type = u'O'
|
verse_type = u'O'
|
||||||
else:
|
else:
|
||||||
verse_text = verse_text + line
|
verse_text = verse_text + line
|
||||||
check_first_verse_line = False
|
check_first_verse_line = False
|
||||||
else:
|
else:
|
||||||
# We have verse content or the start of the
|
# We have verse content or the start of the
|
||||||
# last part. Add l so as to keep the CRLF
|
# last part. Add l so as to keep the CRLF
|
||||||
verse_text = verse_text + line
|
verse_text = verse_text + line
|
||||||
|
@ -41,7 +41,7 @@ def strip_rtf(blob, encoding):
|
|||||||
control_word = []
|
control_word = []
|
||||||
for c in blob:
|
for c in blob:
|
||||||
if control:
|
if control:
|
||||||
# for delimiters, set control to False
|
# for delimiters, set control to False
|
||||||
if c == '{':
|
if c == '{':
|
||||||
if len(control_word) > 0:
|
if len(control_word) > 0:
|
||||||
depth += 1
|
depth += 1
|
||||||
|
@ -44,6 +44,7 @@ class SongListView(BaseListWithDnD):
|
|||||||
self.PluginName = u'Songs'
|
self.PluginName = u'Songs'
|
||||||
BaseListWithDnD.__init__(self, parent)
|
BaseListWithDnD.__init__(self, parent)
|
||||||
|
|
||||||
|
|
||||||
class SongMediaItem(MediaManagerItem):
|
class SongMediaItem(MediaManagerItem):
|
||||||
"""
|
"""
|
||||||
This is the custom media manager item for Songs.
|
This is the custom media manager item for Songs.
|
||||||
@ -392,7 +393,7 @@ class SongMediaItem(MediaManagerItem):
|
|||||||
author_audit.append(unicode(author.display_name))
|
author_audit.append(unicode(author.display_name))
|
||||||
raw_footer.append(song.title)
|
raw_footer.append(song.title)
|
||||||
raw_footer.append(author_list)
|
raw_footer.append(author_list)
|
||||||
raw_footer.append(song.copyright )
|
raw_footer.append(song.copyright)
|
||||||
raw_footer.append(unicode(
|
raw_footer.append(unicode(
|
||||||
translate('SongsPlugin.MediaItem', 'CCLI License: ') +
|
translate('SongsPlugin.MediaItem', 'CCLI License: ') +
|
||||||
QtCore.QSettings().value(u'general/ccli number',
|
QtCore.QSettings().value(u'general/ccli number',
|
||||||
@ -417,27 +418,37 @@ class SongMediaItem(MediaManagerItem):
|
|||||||
item.data_string[u'title'].split(u'@')[0].lower() ,
|
item.data_string[u'title'].split(u'@')[0].lower() ,
|
||||||
Song.search_title.asc())
|
Song.search_title.asc())
|
||||||
author_list = item.data_string[u'authors'].split(u', ')
|
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
|
editId = 0
|
||||||
uuid = item._uuid
|
uuid = item._uuid
|
||||||
|
add_song = True
|
||||||
if search_results:
|
if search_results:
|
||||||
for song in search_results:
|
for song in search_results:
|
||||||
count = 0
|
same_authors = True
|
||||||
for author in song.authors:
|
# If the author counts are different, we do not have to do
|
||||||
if author.display_name in author_list:
|
# any further checking. This is also important when a song
|
||||||
count += 1
|
# does not have any author (because we can not loop over an
|
||||||
# All Authors the same
|
# empty list).
|
||||||
if count == len(author_list):
|
if len(song.authors) == len(author_list):
|
||||||
editId = song.id
|
for author in song.authors:
|
||||||
|
if author.display_name not in author_list:
|
||||||
|
same_authors = False
|
||||||
else:
|
else:
|
||||||
# Authors different
|
same_authors = False
|
||||||
if self.addSongFromService:
|
# All authors are the same, so we can stop here and the song
|
||||||
editId = self.openLyrics. \
|
# does not have to be saved.
|
||||||
xml_to_song(item.xml_version)
|
if same_authors:
|
||||||
else:
|
add_song = False
|
||||||
# Title does not match
|
editId = song.id
|
||||||
|
break
|
||||||
|
if add_song:
|
||||||
if self.addSongFromService:
|
if self.addSongFromService:
|
||||||
editId = self.openLyrics.xml_to_song(item.xml_version)
|
editId = self.openLyrics.xml_to_song(item.xml_version)
|
||||||
# Update service with correct song id
|
# Update service with correct song id.
|
||||||
if editId != 0:
|
if editId != 0:
|
||||||
Receiver.send_message(u'service_item_update',
|
Receiver.send_message(u'service_item_update',
|
||||||
u'%s:%s' %(editId, uuid))
|
u'%s:%s' %(editId, uuid))
|
||||||
|
@ -46,7 +46,7 @@ else:
|
|||||||
|
|
||||||
class OooImport(SongImport):
|
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):
|
def __init__(self, master_manager, **kwargs):
|
||||||
"""
|
"""
|
||||||
@ -122,7 +122,7 @@ class OooImport(SongImport):
|
|||||||
manager = ctx.ServiceManager
|
manager = ctx.ServiceManager
|
||||||
self.desktop = manager.createInstanceWithContext(
|
self.desktop = manager.createInstanceWithContext(
|
||||||
"com.sun.star.frame.Desktop", ctx)
|
"com.sun.star.frame.Desktop", ctx)
|
||||||
|
|
||||||
def start_ooo_process(self):
|
def start_ooo_process(self):
|
||||||
try:
|
try:
|
||||||
if os.name == u'nt':
|
if os.name == u'nt':
|
||||||
@ -168,11 +168,11 @@ class OooImport(SongImport):
|
|||||||
u'Processing file ' + filepath, 0)
|
u'Processing file ' + filepath, 0)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
return
|
return
|
||||||
|
|
||||||
def close_ooo_file(self):
|
def close_ooo_file(self):
|
||||||
"""
|
"""
|
||||||
Close file.
|
Close file.
|
||||||
"""
|
"""
|
||||||
self.document.close(True)
|
self.document.close(True)
|
||||||
self.document = None
|
self.document = None
|
||||||
@ -187,7 +187,7 @@ class OooImport(SongImport):
|
|||||||
def process_pres(self):
|
def process_pres(self):
|
||||||
"""
|
"""
|
||||||
Process the file
|
Process the file
|
||||||
"""
|
"""
|
||||||
doc = self.document
|
doc = self.document
|
||||||
slides = doc.getDrawPages()
|
slides = doc.getDrawPages()
|
||||||
text = u''
|
text = u''
|
||||||
@ -195,7 +195,7 @@ class OooImport(SongImport):
|
|||||||
if self.abort:
|
if self.abort:
|
||||||
self.import_wizard.incrementProgressBar(u'Import cancelled', 0)
|
self.import_wizard.incrementProgressBar(u'Import cancelled', 0)
|
||||||
return
|
return
|
||||||
slide = slides.getByIndex(slide_no)
|
slide = slides.getByIndex(slide_no)
|
||||||
slidetext = u''
|
slidetext = u''
|
||||||
for idx in range(slide.getCount()):
|
for idx in range(slide.getCount()):
|
||||||
shape = slide.getByIndex(idx)
|
shape = slide.getByIndex(idx)
|
||||||
@ -209,12 +209,12 @@ class OooImport(SongImport):
|
|||||||
songs = SongImport.process_songs_text(self.manager, text)
|
songs = SongImport.process_songs_text(self.manager, text)
|
||||||
for song in songs:
|
for song in songs:
|
||||||
song.finish()
|
song.finish()
|
||||||
return
|
return
|
||||||
|
|
||||||
def process_doc(self):
|
def process_doc(self):
|
||||||
"""
|
"""
|
||||||
Process the doc file, a paragraph at a time
|
Process the doc file, a paragraph at a time
|
||||||
"""
|
"""
|
||||||
text = u''
|
text = u''
|
||||||
paragraphs = self.document.getText().createEnumeration()
|
paragraphs = self.document.getText().createEnumeration()
|
||||||
while paragraphs.hasMoreElements():
|
while paragraphs.hasMoreElements():
|
||||||
|
@ -249,7 +249,7 @@ class OpenSongImport(SongImport):
|
|||||||
words = thisline[1:].strip()
|
words = thisline[1:].strip()
|
||||||
if words is None:
|
if words is None:
|
||||||
words = thisline
|
words = thisline
|
||||||
if not versenum:
|
if not versenum:
|
||||||
versenum = u'1'
|
versenum = u'1'
|
||||||
if versenum is not None:
|
if versenum is not None:
|
||||||
versetag = u'%s%s' % (versetype, versenum)
|
versetag = u'%s%s' % (versetype, versenum)
|
||||||
@ -298,7 +298,7 @@ class OpenSongImport(SongImport):
|
|||||||
for tag in order:
|
for tag in order:
|
||||||
if tag[0].isdigit():
|
if tag[0].isdigit():
|
||||||
# Assume it's a verse if it has no prefix
|
# Assume it's a verse if it has no prefix
|
||||||
tag = u'V' + tag
|
tag = u'V' + tag
|
||||||
elif not re.search('\d+', tag):
|
elif not re.search('\d+', tag):
|
||||||
# Assume it's no.1 if there's no digits
|
# Assume it's no.1 if there's no digits
|
||||||
tag = tag + u'1'
|
tag = tag + u'1'
|
||||||
|
@ -56,13 +56,13 @@ class SofImport(OooImport):
|
|||||||
"""
|
"""
|
||||||
Import songs provided on disks with the Songs of Fellowship music books
|
Import songs provided on disks with the Songs of Fellowship music books
|
||||||
VOLS1_2.RTF, sof3words.rtf and sof4words.rtf
|
VOLS1_2.RTF, sof3words.rtf and sof4words.rtf
|
||||||
|
|
||||||
Use OpenOffice.org Writer for processing the rtf file
|
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
|
inconsistant in themselves too with their formatting. Not only this, but
|
||||||
the 1+2 book does not space out verses correctly. This script attempts
|
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!
|
type them all out!
|
||||||
|
|
||||||
It attempts to detect italiced verses, and treats these as choruses in
|
It attempts to detect italiced verses, and treats these as choruses in
|
||||||
@ -96,7 +96,7 @@ class SofImport(OooImport):
|
|||||||
def process_sof_file(self):
|
def process_sof_file(self):
|
||||||
"""
|
"""
|
||||||
Process the RTF file, a paragraph at a time
|
Process the RTF file, a paragraph at a time
|
||||||
"""
|
"""
|
||||||
self.blanklines = 0
|
self.blanklines = 0
|
||||||
self.new_song()
|
self.new_song()
|
||||||
paragraphs = self.document.getText().createEnumeration()
|
paragraphs = self.document.getText().createEnumeration()
|
||||||
@ -113,11 +113,11 @@ class SofImport(OooImport):
|
|||||||
|
|
||||||
def process_paragraph(self, paragraph):
|
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
|
In the first book, a paragraph is a single line. In the latter ones
|
||||||
they may contain multiple lines.
|
they may contain multiple lines.
|
||||||
Each paragraph contains textportions. Each textportion has it's own
|
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.
|
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
|
In later books, there may not be line breaks, so check for 3 or more
|
||||||
newlines
|
newlines
|
||||||
@ -136,7 +136,7 @@ class SofImport(OooImport):
|
|||||||
self.new_song()
|
self.new_song()
|
||||||
text = u''
|
text = u''
|
||||||
self.process_paragraph_text(text)
|
self.process_paragraph_text(text)
|
||||||
|
|
||||||
def process_paragraph_text(self, text):
|
def process_paragraph_text(self, text):
|
||||||
"""
|
"""
|
||||||
Split the paragraph text into multiple lines and process
|
Split the paragraph text into multiple lines and process
|
||||||
@ -147,12 +147,12 @@ class SofImport(OooImport):
|
|||||||
self.new_song()
|
self.new_song()
|
||||||
|
|
||||||
def process_paragraph_line(self, text):
|
def process_paragraph_line(self, text):
|
||||||
"""
|
"""
|
||||||
Process a single line. Throw away that text which isn't relevant, i.e.
|
Process a single line. Throw away that text which isn't relevant, i.e.
|
||||||
stuff that appears at the end of the song.
|
stuff that appears at the end of the song.
|
||||||
Anything that is OK, append to the current verse
|
Anything that is OK, append to the current verse
|
||||||
"""
|
"""
|
||||||
text = text.strip()
|
text = text.strip()
|
||||||
if text == u'':
|
if text == u'':
|
||||||
self.blanklines += 1
|
self.blanklines += 1
|
||||||
if self.blanklines > 1:
|
if self.blanklines > 1:
|
||||||
@ -164,7 +164,7 @@ class SofImport(OooImport):
|
|||||||
if self.skip_to_close_bracket:
|
if self.skip_to_close_bracket:
|
||||||
if text.endswith(u')'):
|
if text.endswith(u')'):
|
||||||
self.skip_to_close_bracket = False
|
self.skip_to_close_bracket = False
|
||||||
return
|
return
|
||||||
if text.startswith(u'CCL Licence'):
|
if text.startswith(u'CCL Licence'):
|
||||||
self.italics = False
|
self.italics = False
|
||||||
return
|
return
|
||||||
@ -264,7 +264,7 @@ class SofImport(OooImport):
|
|||||||
"""
|
"""
|
||||||
Add the author. OpenLP stores them individually so split by 'and', '&'
|
Add the author. OpenLP stores them individually so split by 'and', '&'
|
||||||
and comma.
|
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".
|
"Mr Smith" and "Mrs Smith".
|
||||||
"""
|
"""
|
||||||
text = text.replace(u' and ', u' & ')
|
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
|
we're beyond the second line of first verse, then this indicates
|
||||||
a change of verse. Italics are a chorus
|
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.currentverse.count(u'\n') > 1)):
|
||||||
self.finish_verse()
|
self.finish_verse()
|
||||||
if self.italics:
|
if self.italics:
|
||||||
@ -307,7 +307,7 @@ class SofImport(OooImport):
|
|||||||
ln = 0
|
ln = 0
|
||||||
if line:
|
if line:
|
||||||
verse = line + u'\n'
|
verse = line + u'\n'
|
||||||
else:
|
else:
|
||||||
verse = u''
|
verse = u''
|
||||||
else:
|
else:
|
||||||
verse += line + u'\n'
|
verse += line + u'\n'
|
||||||
@ -320,34 +320,34 @@ class SofImport(OooImport):
|
|||||||
|
|
||||||
|
|
||||||
def uncap_text(self, text):
|
def uncap_text(self, text):
|
||||||
"""
|
"""
|
||||||
Words in the title are in all capitals, so we lowercase them.
|
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.
|
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.
|
sometimes upper depending on context. Never mind, keep it lower.
|
||||||
"""
|
"""
|
||||||
textarr = re.split(u'(\W+)', text)
|
textarr = re.split(u'(\W+)', text)
|
||||||
textarr[0] = textarr[0].capitalize()
|
textarr[0] = textarr[0].capitalize()
|
||||||
for i in range(1, len(textarr)):
|
for i in range(1, len(textarr)):
|
||||||
# Do not translate these. Fixed strings in SOF song file
|
# Do not translate these. Fixed strings in SOF song file
|
||||||
if textarr[i] in (u'JESUS', u'CHRIST', u'KING', u'ALMIGHTY',
|
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'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'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'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'HIM', u'ZION', u'EMMANUEL', u'MAJESTY', u'JESUS\'', u'JIREH',
|
||||||
u'JUDAH', u'LION', u'LORD\'S', u'ABRAHAM', u'GOD\'S',
|
u'JUDAH', u'LION', u'LORD\'S', u'ABRAHAM', u'GOD\'S',
|
||||||
u'FATHER\'S', u'ELIJAH'):
|
u'FATHER\'S', u'ELIJAH'):
|
||||||
textarr[i] = textarr[i].capitalize()
|
textarr[i] = textarr[i].capitalize()
|
||||||
else:
|
else:
|
||||||
textarr[i] = textarr[i].lower()
|
textarr[i] = textarr[i].lower()
|
||||||
text = u''.join(textarr)
|
text = u''.join(textarr)
|
||||||
return text
|
return text
|
||||||
|
|
||||||
def verse_splits(self, song_number):
|
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.
|
some verses were not formatted correctly.
|
||||||
"""
|
"""
|
||||||
if song_number == 11:
|
if song_number == 11:
|
||||||
@ -369,7 +369,7 @@ class SofImport(OooImport):
|
|||||||
if song_number == 50:
|
if song_number == 50:
|
||||||
return 8
|
return 8
|
||||||
if song_number == 70:
|
if song_number == 70:
|
||||||
return 4
|
return 4
|
||||||
if song_number == 75:
|
if song_number == 75:
|
||||||
return 8
|
return 8
|
||||||
if song_number == 79:
|
if song_number == 79:
|
||||||
@ -529,7 +529,7 @@ class SofImport(OooImport):
|
|||||||
if song_number == 955:
|
if song_number == 955:
|
||||||
return 9
|
return 9
|
||||||
if song_number == 968:
|
if song_number == 968:
|
||||||
return 8
|
return 8
|
||||||
if song_number == 972:
|
if song_number == 972:
|
||||||
return 7
|
return 7
|
||||||
if song_number == 974:
|
if song_number == 974:
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
# 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.
|
SongBeamer songs into the OpenLP database.
|
||||||
"""
|
"""
|
||||||
import logging
|
import logging
|
||||||
@ -90,7 +90,7 @@ class SongBeamerImport(SongImport):
|
|||||||
len(self.import_source))
|
len(self.import_source))
|
||||||
for file in self.import_source:
|
for file in self.import_source:
|
||||||
# TODO: check that it is a valid SongBeamer file
|
# TODO: check that it is a valid SongBeamer file
|
||||||
self.current_verse = u''
|
self.current_verse = u''
|
||||||
self.current_verse_type = u'V'
|
self.current_verse_type = u'V'
|
||||||
read_verses = False
|
read_verses = False
|
||||||
self.file_name = os.path.split(file)[1]
|
self.file_name = os.path.split(file)[1]
|
||||||
@ -115,7 +115,7 @@ class SongBeamerImport(SongImport):
|
|||||||
self.replace_html_tags()
|
self.replace_html_tags()
|
||||||
self.add_verse(self.current_verse,
|
self.add_verse(self.current_verse,
|
||||||
self.current_verse_type)
|
self.current_verse_type)
|
||||||
self.current_verse = u''
|
self.current_verse = u''
|
||||||
self.current_verse_type = u'V'
|
self.current_verse_type = u'V'
|
||||||
read_verses = True
|
read_verses = True
|
||||||
verse_start = True
|
verse_start = True
|
||||||
|
@ -247,7 +247,7 @@ class SongImport(QtCore.QObject):
|
|||||||
"""
|
"""
|
||||||
Extracts alphanumeric words for searchable fields
|
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):
|
def finish(self):
|
||||||
"""
|
"""
|
||||||
|
@ -56,11 +56,11 @@ def test():
|
|||||||
assert o.title == u'Martins Test'
|
assert o.title == u'Martins Test'
|
||||||
assert o.alternate_title == u''
|
assert o.alternate_title == u''
|
||||||
assert o.song_number == u'1'
|
assert o.song_number == u'1'
|
||||||
assert [u'C1', u'Chorus 1'] in o.verses
|
assert [u'C1', u'Chorus 1'] in o.verses
|
||||||
assert [u'C2', u'Chorus 2'] in o.verses
|
assert [u'C2', u'Chorus 2'] in o.verses
|
||||||
assert not [u'C3', u'Chorus 3'] 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'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'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'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'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
|
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.title == u'Martins Test'
|
||||||
assert o.alternate_title == u''
|
assert o.alternate_title == u''
|
||||||
assert o.song_number == u'1'
|
assert o.song_number == u'1'
|
||||||
assert [u'B1', u'Bridge 1\nBridge 1 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'C1', u'Chorus 1'] in o.verses
|
||||||
assert [u'C2', u'Chorus 2'] in o.verses
|
assert [u'C2', u'Chorus 2'] in o.verses
|
||||||
assert not [u'C3', u'Chorus 3'] 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'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'V2', u'v2 Line 1\nV2 Line 2'] in o.verses
|
||||||
print o.verse_order_list
|
print o.verse_order_list
|
||||||
assert o.verse_order_list == [u'V1', u'C1', u'V2', u'C2', u'V3', u'B1', u'V1']
|
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.alternate_title == u''
|
||||||
assert o.song_number == u'2'
|
assert o.song_number == u'2'
|
||||||
print o.verses
|
print o.verses
|
||||||
assert [u'B1', u'Bridge 1\nBridge 1 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'C1', u'Chorus 1'] in o.verses
|
||||||
assert [u'C2', u'Chorus 2'] in o.verses
|
assert [u'C2', u'Chorus 2'] in o.verses
|
||||||
assert not [u'C3', u'Chorus 3'] 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'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'V2', u'v2 Line 1\nV2 Line 2'] in o.verses
|
||||||
print o.verse_order_list
|
print o.verse_order_list
|
||||||
assert o.verse_order_list == [u'V1', u'V2', u'B1', u'C1', u'C2']
|
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.verse_order_list == [u'V1']
|
||||||
assert o.topics == [u'Worship: Declaration']
|
assert o.topics == [u'Worship: Declaration']
|
||||||
print o.verses[0]
|
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"
|
print "Tests passed"
|
||||||
|
|
||||||
|
@ -297,6 +297,8 @@ class OpenLyricsParser(object):
|
|||||||
song_xml = objectify.fromstring(xml)
|
song_xml = objectify.fromstring(xml)
|
||||||
properties = song_xml.properties
|
properties = song_xml.properties
|
||||||
song.copyright = unicode(properties.copyright.text)
|
song.copyright = unicode(properties.copyright.text)
|
||||||
|
if song.copyright == u'None':
|
||||||
|
song.copyright = u''
|
||||||
song.verse_order = unicode(properties.verseOrder.text)
|
song.verse_order = unicode(properties.verseOrder.text)
|
||||||
if song.verse_order == u'None':
|
if song.verse_order == u'None':
|
||||||
song.verse_order = u''
|
song.verse_order = u''
|
||||||
@ -357,7 +359,7 @@ class OpenLyricsParser(object):
|
|||||||
|
|
||||||
def _add_text_to_element(self, tag, parent, text=None, label=None):
|
def _add_text_to_element(self, tag, parent, text=None, label=None):
|
||||||
if label:
|
if label:
|
||||||
element = etree.Element(tag, name = unicode(label))
|
element = etree.Element(tag, name=unicode(label))
|
||||||
else:
|
else:
|
||||||
element = etree.Element(tag)
|
element = etree.Element(tag)
|
||||||
if text:
|
if text:
|
||||||
|
@ -31,7 +31,7 @@ from PyQt4 import QtCore, QtGui
|
|||||||
|
|
||||||
from openlp.core.lib import Plugin, StringContent, build_icon, translate
|
from openlp.core.lib import Plugin, StringContent, build_icon, translate
|
||||||
from openlp.core.lib.db import Manager
|
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.db import init_schema, Song
|
||||||
from openlp.plugins.songs.lib.importer import SongFormat
|
from openlp.plugins.songs.lib.importer import SongFormat
|
||||||
|
|
||||||
@ -150,9 +150,13 @@ class SongsPlugin(Plugin):
|
|||||||
song.title = u''
|
song.title = u''
|
||||||
if song.alternate_title is None:
|
if song.alternate_title is None:
|
||||||
song.alternate_title = u''
|
song.alternate_title = u''
|
||||||
song.search_title = self.whitespace.sub(u' ', \
|
song.search_title = self.whitespace.sub(u' ', song.title.lower() + \
|
||||||
song.title.lower()) + u' ' + \
|
u' ' + song.alternate_title.lower())
|
||||||
self.whitespace.sub(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)
|
progressDialog.setValue(counter)
|
||||||
self.manager.save_objects(songs)
|
self.manager.save_objects(songs)
|
||||||
counter += 1
|
counter += 1
|
||||||
|
3047
resources/i18n/af.ts
3047
resources/i18n/af.ts
File diff suppressed because it is too large
Load Diff
3194
resources/i18n/de.ts
3194
resources/i18n/de.ts
File diff suppressed because it is too large
Load Diff
2973
resources/i18n/en.ts
2973
resources/i18n/en.ts
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
2977
resources/i18n/es.ts
2977
resources/i18n/es.ts
File diff suppressed because it is too large
Load Diff
3046
resources/i18n/et.ts
3046
resources/i18n/et.ts
File diff suppressed because it is too large
Load Diff
3228
resources/i18n/hu.ts
3228
resources/i18n/hu.ts
File diff suppressed because it is too large
Load Diff
2977
resources/i18n/ja.ts
2977
resources/i18n/ja.ts
File diff suppressed because it is too large
Load Diff
3154
resources/i18n/ko.ts
3154
resources/i18n/ko.ts
File diff suppressed because it is too large
Load Diff
3013
resources/i18n/nb.ts
3013
resources/i18n/nb.ts
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
3308
resources/i18n/sv.ts
3308
resources/i18n/sv.ts
File diff suppressed because it is too large
Load Diff
BIN
resources/images/general_email.png
Normal file
BIN
resources/images/general_email.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 833 B |
@ -39,6 +39,7 @@
|
|||||||
<file>general_new.png</file>
|
<file>general_new.png</file>
|
||||||
<file>general_open.png</file>
|
<file>general_open.png</file>
|
||||||
<file>general_save.png</file>
|
<file>general_save.png</file>
|
||||||
|
<file>general_email.png</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
<qresource prefix="slides">
|
<qresource prefix="slides">
|
||||||
<file>slide_close.png</file>
|
<file>slide_close.png</file>
|
||||||
|
2
scripts/openlp-remoteclient.py
Executable file → Normal file
2
scripts/openlp-remoteclient.py
Executable file → Normal file
@ -47,7 +47,7 @@ def main():
|
|||||||
help="Recipient address ",
|
help="Recipient address ",
|
||||||
default="localhost")
|
default="localhost")
|
||||||
parser.add_option("-e", "--event",
|
parser.add_option("-e", "--event",
|
||||||
help="Action to be performed",
|
help="Action to be performed",
|
||||||
default="alerts_text")
|
default="alerts_text")
|
||||||
parser.add_option("-m", "--message",
|
parser.add_option("-m", "--message",
|
||||||
help="Message to be passed for the action",
|
help="Message to be passed for the action",
|
||||||
|
Loading…
Reference in New Issue
Block a user