This commit is contained in:
Jonathan Corwin 2010-10-14 21:39:09 +01:00
commit 3c464a4a0f
87 changed files with 3271 additions and 1025 deletions

View File

@ -1,19 +0,0 @@
# -*- mode: python -*-
a = Analysis([os.path.join(HOMEPATH,'support\\_mountzlib.py'), os.path.join(HOMEPATH,'support\\useUnicode.py'), 'openlp.pyw'],
pathex=[os.path.abspath('.')])
pyz = PYZ(a.pure)
exe = EXE(pyz,
a.scripts,
exclude_binaries=1,
name=os.path.join('build\\pyi.win32\\OpenLP', 'OpenLP.exe'),
debug=False,
strip=False,
upx=True,
console=False , icon='resources\\images\\OpenLP.ico')
coll = COLLECT( exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=True,
name=os.path.join('dist', 'OpenLP'))

View File

@ -17,7 +17,7 @@ import sys
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
sys.path.append(os.path.abspath(os.path.join('..', '..')))
sys.path.insert(0, os.path.abspath(os.path.join('..', '..')))
# -- General configuration -----------------------------------------------------

View File

@ -60,12 +60,6 @@
.. autoclass:: openlp.core.lib.settingstab.SettingsTab
:members:
:mod:`ThemeXML`
---------------
.. autoclass:: openlp.core.lib.themexmlhandler.ThemeXML
:members:
:mod:`OpenLPToolbar`
--------------------

View File

@ -0,0 +1,22 @@
.. OpenLP documentation master file, created by
sphinx-quickstart on Thu Sep 30 21:24:54 2010.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to OpenLP's documentation
==================================
Contents:
.. toctree::
:maxdepth: 2
introduction
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

View File

@ -0,0 +1,46 @@
=============
Introduction
=============
About
-----
OpenLP is an open source lyrics projection application developed specifically
for churches. It is licensed under the GNU Generic Public License, which means
that it is free to use and distribute, and it stays free.
Lyrics Projection
-----------------
OpenLP's purpose is to project the lyrics of songs and Bible verses using a
computer and a data projector. OpenLP also has the ability to project videos,
images, and also play audio. OpenLP also is highly customizable providing users
with the ability to set up a wide variety of themes, including themes with
video backgrounds.
Open Source
-----------
OpenLP is open source software. This means that the source code (the
programming instructions the developers write) is open to anyone who wants to
look at it. This gives you, the end user, a few freedoms.
From a developer's perspective, it gives you the freedom to inspect the code
and make sure that it is not malicious. Also, it gives you the freedom to
change the code and the freedom to "fork" the project and make it your own.
For end users open source software gives you the freedom to use software as
you wish. You are not required to pay for the software and you are free to
make copies and distribute it to anyone you want.
GNU General Public License
--------------------------
The GNU General Public License was specifically chosen because it ensures the
above mentioned freedoms. It specifically states that you are not allowed
to charge for the software, and that you have to distribute the source code as
well.
You can find a copy of the GNU General Public License from the Help menu
selecting about OpenLP or on-line
at: http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt

View File

@ -1,7 +1,7 @@
.. _plugins-bibles:
:mod:`bibles` Plugin
====================
Bibles Plugin
=============
.. automodule:: openlp.plugins.bibles
:members:
@ -60,8 +60,8 @@
.. autoclass:: openlp.plugins.bibles.lib.http.HTTPBible
:members:
:mod:`bibleOSISimpl`
^^^^^^^^^^^^^^^^^^^^
:mod:`osis`
^^^^^^^^^^^
.. automodule:: openlp.plugins.bibles.lib.osis
:members:
@ -69,18 +69,21 @@
.. autoclass:: openlp.plugins.bibles.lib.osis.OSISBible
:members:
:mod:`opensong`
^^^^^^^^^^^^^^^
.. automodule:: openlp.plugins.bibles.lib.opensong
:members:
.. autoclass:: openlp.plugins.bibles.lib.opensong.OpenSongBible
:members:
:mod:`biblestab`
^^^^^^^^^^^^^^^^
.. automodule:: openlp.plugins.bibles.lib.biblestab
:members:
:mod:`common`
^^^^^^^^^^^^^
.. automodule:: openlp.plugins.bibles.lib.common
:members:
:mod:`manager`
^^^^^^^^^^^^^^

View File

@ -0,0 +1,8 @@
.. _plugins-images:
Images Plugin
=============
.. automodule:: openlp.plugins.images
:members:

View File

@ -11,24 +11,9 @@
songs
bibles
:mod:`presentations` Plugin
---------------------------
.. automodule:: openlp.plugins.presentations
:members:
:mod:`media` Plugin
-------------------
.. automodule:: openlp.plugins.media
:members:
:mod:`images` Plugin
--------------------
.. automodule:: openlp.plugins.images
:members:
presentations
media
images
:mod:`custom` Plugin
--------------------

View File

@ -0,0 +1,8 @@
.. _plugins-media:
Media Plugin
============
.. automodule:: openlp.plugins.media
:members:

View File

@ -0,0 +1,40 @@
.. _plugins-presentations:
Presentations Plugin
====================
Plugin Class
------------
.. autoclass:: openlp.plugins.presentations.presentationplugin.PresentationPlugin
:members:
Helper Classes & Functions
--------------------------
.. automodule:: openlp.plugins.presentations.lib
:members:
.. automodule:: openlp.plugins.presentations.lib.mediaitem
:members:
.. automodule:: openlp.plugins.presentations.lib.presentationtab
:members:
.. automodule:: openlp.plugins.presentations.lib.messagelistener
:members:
.. automodule:: openlp.plugins.presentations.lib.presentationcontroller
:members:
Presentation Application Controllers
------------------------------------
.. automodule:: openlp.plugins.presentations.lib.impresscontroller
:members:
.. automodule:: openlp.plugins.presentations.lib.pptviewcontroller
:members:
.. automodule:: openlp.plugins.presentations.lib.powerpointcontroller
:members:

View File

@ -1,13 +1,13 @@
.. _plugins-songs:
:mod:`songs` Plugin
===================
Songs Plugin
============
.. automodule:: openlp.plugins.songs
:members:
:mod:`SongsPlugin` Class
------------------------
:class:`SongsPlugin` Class
--------------------------
.. autoclass:: openlp.plugins.songs.songsplugin.SongsPlugin
:members:
@ -18,8 +18,8 @@
.. automodule:: openlp.plugins.songs.forms
:members:
:mod:`AuthorsForm`
^^^^^^^^^^^^^^^^^^
:class:`AuthorsForm`
^^^^^^^^^^^^^^^^^^^^
.. autoclass:: openlp.plugins.songs.forms.authorsdialog.Ui_AuthorsDialog
:members:
@ -27,8 +27,8 @@
.. autoclass:: openlp.plugins.songs.forms.authorsform.AuthorsForm
:members:
:mod:`EditSongForm`
^^^^^^^^^^^^^^^^^^^
:class:`EditSongForm`
^^^^^^^^^^^^^^^^^^^^^
.. autoclass:: openlp.plugins.songs.forms.editsongdialog.Ui_EditSongDialog
:members:
@ -36,11 +36,158 @@
.. autoclass:: openlp.plugins.songs.forms.editsongform.EditSongForm
:members:
:mod:`EditVerseForm`
^^^^^^^^^^^^^^^^^^^^
:class:`EditVerseForm`
^^^^^^^^^^^^^^^^^^^^^^
.. autoclass:: openlp.plugins.songs.forms.editversedialog.Ui_EditVerseDialog
:members:
.. autoclass:: openlp.plugins.songs.forms.editverseform.EditVerseForm
:members:
:class:`SongBookForm`
^^^^^^^^^^^^^^^^^^^^^
.. autoclass:: openlp.plugins.songs.forms.songbookdialog.Ui_SongBookDialog
:members:
.. autoclass:: openlp.plugins.songs.forms.songbookform.SongBookForm
:members:
:class:`SongImportForm`
^^^^^^^^^^^^^^^^^^^^^^^
.. autoclass:: openlp.plugins.songs.forms.songimportwizard.Ui_SongImportWizard
:members:
.. autoclass:: openlp.plugins.songs.forms.songimportform.ImportWizardForm
:members:
:class:`SongMaintenanceForm`
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. autoclass:: openlp.plugins.songs.forms.songmaintenancedialog.Ui_SongMaintenanceDialog
:members:
.. autoclass:: openlp.plugins.songs.forms.songmaintenanceform.SongMaintenanceForm
:members:
:class:`TopicsForm`
^^^^^^^^^^^^^^^^^^^
.. autoclass:: openlp.plugins.songs.forms.topicsdialog.Ui_TopicsDialog
:members:
.. autoclass:: openlp.plugins.songs.forms.topicsform.TopicsForm
:members:
:mod:`lib` Submodule
--------------------
.. automodule:: openlp.plugins.songs.lib
:members:
:mod:`cclifileimport` Submodule
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. automodule:: openlp.plugins.songs.lib.cclifileimport
:members:
.. autoclass:: openlp.plugins.songs.lib.cclifileimport.CCLIFileImportError
:members:
:mod:`db` Submodule
^^^^^^^^^^^^^^^^^^^
.. automodule:: openlp.plugins.songs.lib.db
:members:
:mod:`ewimport` Submodule
^^^^^^^^^^^^^^^^^^^^^^^^^
.. automodule:: openlp.plugins.songs.lib.ewimport
:members:
.. autoclass:: openlp.plugins.songs.lib.ewimport.FieldDescEntry
:members:
:mod:`importer` Submodule
^^^^^^^^^^^^^^^^^^^^^^^^^
.. automodule:: openlp.plugins.songs.lib.importer
:members:
:mod:`mediaitem` Submodule
^^^^^^^^^^^^^^^^^^^^^^^^^^
.. automodule:: openlp.plugins.songs.lib.mediaitem
:members:
.. autoclass:: openlp.plugins.songs.lib.mediaitem.SongListView
:members:
:mod:`olp1import` Submodule
^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. automodule:: openlp.plugins.songs.lib.olp1import
:members:
:mod:`olpimport` Submodule
^^^^^^^^^^^^^^^^^^^^^^^^^^
.. automodule:: openlp.plugins.songs.lib.olpimport
:members:
:mod:`oooimport` Submodule
^^^^^^^^^^^^^^^^^^^^^^^^^^
.. automodule:: openlp.plugins.songs.lib.oooimport
:members:
:mod:`opensongimport` Submodule
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. automodule:: openlp.plugins.songs.lib.opensongimport
:members:
:mod:`sofimport` Submodule
^^^^^^^^^^^^^^^^^^^^^^^^^^
.. automodule:: openlp.plugins.songs.lib.sofimport
:members:
:mod:`songbeamerimport` Submodule
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. automodule:: openlp.plugins.songs.lib.songbeamerimport
:members:
:mod:`songimport` Submodule
^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. automodule:: openlp.plugins.songs.lib.songimport
:members:
:mod:`songstab` Submodule
^^^^^^^^^^^^^^^^^^^^^^^^^
.. automodule:: openlp.plugins.songs.lib.songstab
:members:
:mod:`wowimport` Submodule
^^^^^^^^^^^^^^^^^^^^^^^^^^
.. automodule:: openlp.plugins.songs.lib.wowimport
:members:
:mod:`songxml` Submodule
^^^^^^^^^^^^^^^^^^^^^^^^
.. automodule:: openlp.plugins.songs.lib.songxml
:members:
:mod:`xml` Submodule
^^^^^^^^^^^^^^^^^^^^
.. automodule:: openlp.plugins.songs.lib.xml
:members:

View File

@ -30,6 +30,7 @@ import sys
import logging
from optparse import OptionParser
from traceback import format_exception
from subprocess import Popen, PIPE
from PyQt4 import QtCore, QtGui
@ -71,23 +72,68 @@ class OpenLP(QtGui.QApplication):
"""
log.info(u'OpenLP Application Loaded')
def notify(self, obj, evt):
#TODO needed for presentation exceptions
return QtGui.QApplication.notify(self, obj, evt)
def run(self):
def _get_version(self):
"""
Run the OpenLP application.
Load and store current Application Version
"""
#Load and store current Application Version
if u'--dev-version' in sys.argv:
# If we're running the dev version, let's use bzr to get the version
try:
# If bzrlib is availble, use it
from bzrlib.branch import Branch
b = Branch.open_containing('.')[0]
b.lock_read()
try:
# Get the branch's latest revision number.
revno = b.revno()
# Convert said revision number into a bzr revision id.
revision_id = b.dotted_revno_to_revision_id((revno,))
# Get a dict of tags, with the revision id as the key.
tags = b.tags.get_reverse_tag_dict()
# Check if the latest
if revision_id in tags:
full_version = u'%s' % tags[revision_id][0]
else:
full_version = '%s-bzr%s' % \
(sorted(b.tags.get_tag_dict().keys())[-1], revno)
finally:
b.unlock()
except:
# Otherwise run the command line bzr client
bzr = Popen((u'bzr', u'tags', u'--sort', u'time'), stdout=PIPE)
output, error = bzr.communicate()
code = bzr.wait()
if code != 0:
raise Exception(u'Error running bzr tags')
lines = output.splitlines()
if len(lines) == 0:
tag = u'0.0.0'
revision = u'0'
else:
tag, revision = lines[-1].split()
bzr = Popen((u'bzr', u'log', u'--line', u'-r', u'-1'),
stdout=PIPE)
output, error = bzr.communicate()
code = bzr.wait()
if code != 0:
raise Exception(u'Error running bzr log')
latest = output.split(u':')[0]
full_version = latest == revision and tag or \
u'%s-bzr%s' % (tag, latest)
else:
# We're not running the development version, let's use the file
filepath = AppLocation.get_directory(AppLocation.VersionDir)
filepath = os.path.join(filepath, u'.version')
fversion = None
try:
fversion = open(filepath, u'r')
for line in fversion:
full_version = unicode(line).rstrip() #\
#.replace(u'\r', u'').replace(u'\n', u'')
full_version = unicode(fversion.read()).rstrip()
except IOError:
log.exception('Error in version file.')
full_version = u'0.0.0-bzr000'
finally:
if fversion:
fversion.close()
bits = full_version.split(u'-')
app_version = {
u'full': full_version,
@ -102,16 +148,17 @@ class OpenLP(QtGui.QApplication):
)
else:
log.info(u'Openlp version %s' % app_version[u'version'])
except IOError:
log.exception('Error in version file.')
app_version = {
u'full': u'1.9.0-bzr000',
u'version': u'1.9.0',
u'build': u'bzr000'
}
finally:
if fversion:
fversion.close()
return app_version
def notify(self, obj, evt):
#TODO needed for presentation exceptions
return QtGui.QApplication.notify(self, obj, evt)
def run(self):
"""
Run the OpenLP application.
"""
app_version = self._get_version()
#provide a listener for widgets to reqest a screen update.
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'openlp_process_events'), self.processEvents)
@ -172,6 +219,9 @@ def main():
parser.add_option('-p', '--portable', dest='portable',
action='store_true', help='Specify if this should be run as a '
'portable app, off a USB flash drive (not implemented).')
parser.add_option('-d', '--dev-version', dest='dev_version',
action='store_true', help='Ignore the version file and pull the '
'version directly from Bazaar')
parser.add_option('-s', '--style', dest='style',
help='Set the Qt4 style (passed directly to Qt4).')
# Set up logging

View File

@ -313,7 +313,7 @@ def expand_tags(text):
from spelltextedit import SpellTextEdit
from eventreceiver import Receiver
from settingsmanager import SettingsManager
from plugin import PluginStatus, Plugin
from plugin import PluginStatus, StringContent, Plugin
from pluginmanager import PluginManager
from settingstab import SettingsTab
from serviceitem import ServiceItem

View File

@ -193,6 +193,14 @@ class EventReceiver(QtCore.QObject):
``{plugin}_add_service_item``
Ask the plugin to push the selected items to the service item
``{plugin}_service_load``
Ask the plugin to process an individual service item after it has been
loaded
``service_item_update``
Passes back to the service manager the service item after it has been
processed by the plugin
``alerts_text``
Displays an alert message

View File

@ -55,14 +55,17 @@ body {
background-color: black;
display: none;
}
#image {
#bgimage {
z-index:1;
}
#video1 {
#image {
z-index:2;
}
#video1 {
z-index:3;
}
#video2 {
z-index:2;
z-index:3;
}
#alert {
position: absolute;
@ -73,7 +76,7 @@ body {
}
#footer {
position: absolute;
z-index:5;
z-index:6;
%s
}
/* lyric css */
@ -294,7 +297,8 @@ body {
</script>
</head>
<body>
<img id="image" class="size" %s />
<img id="bgimage" class="size" %s />
<img id="image" class="size" style="display:none" />
<video id="video1" class="size" style="visibility:hidden" autobuffer preload>
</video>
<video id="video2" class="size" style="visibility:hidden" autobuffer preload>
@ -397,7 +401,7 @@ def build_lyrics_css(item, webkitvers):
"""
style = """
.lyricstable {
z-index:4;
z-index:5;
position: absolute;
display: table;
%s

View File

@ -32,7 +32,8 @@ import os
from PyQt4 import QtCore, QtGui
from openlp.core.lib import context_menu_action, context_menu_separator, \
SettingsManager, OpenLPToolbar, ServiceItem, build_icon, translate
SettingsManager, OpenLPToolbar, ServiceItem, StringContent, build_icon, \
translate, Receiver
log = logging.getLogger(__name__)
@ -51,26 +52,19 @@ class MediaManagerItem(QtGui.QWidget):
The parent widget. Usually this will be the *Media Manager*
itself. This needs to be a class descended from ``QWidget``.
``plugin``
The plugin widget. Usually this will be the *Plugin*
itself. This needs to be a class descended from ``Plugin``.
``icon``
Either a ``QIcon``, a resource path, or a file name. This is
the icon which is displayed in the *Media Manager*.
``title``
The title visible on the item in the *Media Manager*.
**Member Variables**
When creating a descendant class from this class for your plugin,
the following member variables should be set.
``self.PluginNameShort``
The shortened (usually singular) name for the plugin e.g. *'Song'*
for the Songs plugin.
``self.pluginNameVisible``
The user visible name for a plugin which should use a suitable
translation function.
``self.OnNewPrompt``
Defaults to *'Select Image(s)'*.
@ -93,13 +87,17 @@ class MediaManagerItem(QtGui.QWidget):
"""
log.info(u'Media Item loaded')
def __init__(self, parent=None, icon=None, title=None):
def __init__(self, parent=None, plugin=None, icon=None):
"""
Constructor to create the media manager item.
"""
QtGui.QWidget.__init__(self)
self.parent = parent
self.settingsSection = title.lower()
#TODO: plugin should not be the parent in future
self.plugin = parent # plugin
visible_title = self.plugin.getString(StringContent.VisibleName)
self.title = unicode(visible_title[u'title'])
self.settingsSection = self.plugin.name.lower()
if isinstance(icon, QtGui.QIcon):
self.icon = icon
elif isinstance(icon, basestring):
@ -107,8 +105,6 @@ class MediaManagerItem(QtGui.QWidget):
QtGui.QIcon.Normal, QtGui.QIcon.Off)
else:
self.icon = None
if title:
self.title = title
self.toolbar = None
self.remoteTriggered = None
self.serviceItemIconName = None
@ -119,6 +115,9 @@ class MediaManagerItem(QtGui.QWidget):
self.requiredIcons()
self.setupUi()
self.retranslateUi()
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'%s_service_load' % self.parent.name.lower()),
self.serviceLoad)
def requiredIcons(self):
"""
@ -208,64 +207,58 @@ class MediaManagerItem(QtGui.QWidget):
"""
## Import Button ##
if self.hasImportIcon:
import_string = self.plugin.getString(StringContent.Import)
self.addToolbarButton(
unicode(translate('OpenLP.MediaManagerItem', 'Import %s')) %
self.PluginNameShort,
unicode(translate('OpenLP.MediaManagerItem', 'Import a %s')) %
self.pluginNameVisible,
import_string[u'title'],
import_string[u'tooltip'],
u':/general/general_import.png', self.onImportClick)
## File Button ##
## Load Button ##
if self.hasFileIcon:
load_string = self.plugin.getString(StringContent.Load)
self.addToolbarButton(
unicode(translate('OpenLP.MediaManagerItem', 'Load %s')) %
self.PluginNameShort,
unicode(translate('OpenLP.MediaManagerItem', 'Load a new %s')) %
self.pluginNameVisible,
load_string[u'title'],
load_string[u'tooltip'],
u':/general/general_open.png', self.onFileClick)
## New Button ##
if self.hasNewIcon:
new_string = self.plugin.getString(StringContent.New)
self.addToolbarButton(
unicode(translate('OpenLP.MediaManagerItem', 'New %s')) %
self.PluginNameShort,
unicode(translate('OpenLP.MediaManagerItem', 'Add a new %s')) %
self.pluginNameVisible,
new_string[u'title'],
new_string[u'tooltip'],
u':/general/general_new.png', self.onNewClick)
## Edit Button ##
if self.hasEditIcon:
edit_string = self.plugin.getString(StringContent.Edit)
self.addToolbarButton(
unicode(translate('OpenLP.MediaManagerItem', 'Edit %s')) %
self.PluginNameShort,
unicode(translate(
'OpenLP.MediaManagerItem', 'Edit the selected %s')) %
self.pluginNameVisible,
edit_string[u'title'],
edit_string[u'tooltip'],
u':/general/general_edit.png', self.onEditClick)
## Delete Button ##
if self.hasDeleteIcon:
delete_string = self.plugin.getString(StringContent.Delete)
self.addToolbarButton(
unicode(translate('OpenLP.MediaManagerItem', 'Delete %s')) %
self.PluginNameShort,
translate('OpenLP.MediaManagerItem',
'Delete the selected item'),
delete_string[u'title'],
delete_string[u'tooltip'],
u':/general/general_delete.png', self.onDeleteClick)
## Separator Line ##
self.addToolbarSeparator()
## Preview ##
preview_string = self.plugin.getString(StringContent.Preview)
self.addToolbarButton(
unicode(translate('OpenLP.MediaManagerItem', 'Preview %s')) %
self.PluginNameShort,
translate('OpenLP.MediaManagerItem', 'Preview the selected item'),
preview_string[u'title'],
preview_string[u'tooltip'],
u':/general/general_preview.png', self.onPreviewClick)
## Live Button ##
live_string = self.plugin.getString(StringContent.Live)
self.addToolbarButton(
u'Go Live',
translate('OpenLP.MediaManagerItem', 'Send the selected item live'),
live_string[u'title'],
live_string[u'tooltip'],
u':/general/general_live.png', self.onLiveClick)
## Add to service Button ##
service_string = self.plugin.getString(StringContent.Service)
self.addToolbarButton(
unicode(translate('OpenLP.MediaManagerItem', 'Add %s to Service')) %
self.PluginNameShort,
translate('OpenLP.MediaManagerItem',
'Add the selected item(s) to the service'),
service_string[u'title'],
service_string[u'tooltip'],
u':/general/general_add.png', self.onAddClick)
def addListViewToToolBar(self):
@ -281,17 +274,18 @@ class MediaManagerItem(QtGui.QWidget):
QtGui.QAbstractItemView.ExtendedSelection)
self.listView.setAlternatingRowColors(True)
self.listView.setDragEnabled(True)
self.listView.setObjectName(u'%sListView' % self.PluginNameShort)
self.listView.setObjectName(u'%sListView' % self.plugin.name)
#Add to pageLayout
self.pageLayout.addWidget(self.listView)
#define and add the context menu
self.listView.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
name_string = self.plugin.getString(StringContent.Name)
if self.hasEditIcon:
self.listView.addAction(
context_menu_action(
self.listView, u':/general/general_edit.png',
unicode(translate('OpenLP.MediaManagerItem', '&Edit %s')) %
self.pluginNameVisible,
name_string[u'singular'],
self.onEditClick))
self.listView.addAction(context_menu_separator(self.listView))
if self.hasDeleteIcon:
@ -300,14 +294,14 @@ class MediaManagerItem(QtGui.QWidget):
self.listView, u':/general/general_delete.png',
unicode(translate('OpenLP.MediaManagerItem',
'&Delete %s')) %
self.pluginNameVisible,
name_string[u'singular'],
self.onDeleteClick))
self.listView.addAction(context_menu_separator(self.listView))
self.listView.addAction(
context_menu_action(
self.listView, u':/general/general_preview.png',
unicode(translate('OpenLP.MediaManagerItem', '&Preview %s')) %
self.pluginNameVisible,
name_string[u'singular'],
self.onPreviewClick))
self.listView.addAction(
context_menu_action(
@ -447,7 +441,7 @@ class MediaManagerItem(QtGui.QWidget):
translate('OpenLP.MediaManagerItem',
'You must select one or more items to preview.'))
else:
log.debug(self.PluginNameShort + u' Preview requested')
log.debug(self.plugin.name + u' Preview requested')
service_item = self.buildServiceItem()
if service_item:
service_item.from_plugin = True
@ -464,7 +458,7 @@ class MediaManagerItem(QtGui.QWidget):
translate('OpenLP.MediaManagerItem',
'You must select one or more items to send live.'))
else:
log.debug(self.PluginNameShort + u' Live requested')
log.debug(self.plugin.name + u' Live requested')
service_item = self.buildServiceItem()
if service_item:
service_item.from_plugin = True
@ -483,7 +477,7 @@ class MediaManagerItem(QtGui.QWidget):
# Is it posssible to process multiple list items to generate multiple
# service items?
if self.singleServiceItem or self.remoteTriggered:
log.debug(self.PluginNameShort + u' Add requested')
log.debug(self.plugin.name + u' Add requested')
service_item = self.buildServiceItem()
if service_item:
service_item.from_plugin = False
@ -507,7 +501,7 @@ class MediaManagerItem(QtGui.QWidget):
translate('OpenLP.MediaManagerItem',
'You must select one or more items'))
else:
log.debug(self.PluginNameShort + u' Add requested')
log.debug(self.plugin.name + u' Add requested')
service_item = self.parent.serviceManager.getServiceItem()
if not service_item:
QtGui.QMessageBox.information(self,
@ -540,3 +534,11 @@ class MediaManagerItem(QtGui.QWidget):
return service_item
else:
return None
def serviceLoad(self, message):
"""
Method to add processing when a service has been loaded and
individual service items need to be processed by the plugins
"""
pass

View File

@ -42,6 +42,18 @@ class PluginStatus(object):
Inactive = 0
Disabled = -1
class StringContent(object):
Name = u'name'
Import = u'import'
Load = u'load'
New = u'new'
Edit = u'edit'
Delete = u'delete'
Preview = u'preview'
Live = u'live'
Service = u'service'
VisibleName = u'visible_name'
class Plugin(QtCore.QObject):
"""
Base class for openlp plugins to inherit from.
@ -117,6 +129,8 @@ class Plugin(QtCore.QObject):
"""
QtCore.QObject.__init__(self)
self.name = name
self.textStrings = {}
self.setPluginTextStrings()
if version:
self.version = version
self.settingsSection = self.name.lower()
@ -257,9 +271,9 @@ class Plugin(QtCore.QObject):
Called by the plugin to remove toolbar
"""
if self.mediaItem:
self.mediadock.remove_dock(self.name)
self.mediadock.remove_dock(self.mediaItem)
if self.settings_tab:
self.settingsForm.removeTab(self.name)
self.settingsForm.removeTab(self.settings_tab)
def insertToolboxItem(self):
"""
@ -289,3 +303,15 @@ class Plugin(QtCore.QObject):
The new name the plugin should now use.
"""
pass
def getString(self, name):
"""
encapsulate access of plugins translated text strings
"""
return self.textStrings[name]
def setPluginTextStrings(self):
"""
Called to define all translatable texts of the plugin
"""
pass

View File

@ -30,7 +30,7 @@ import os
import sys
import logging
from openlp.core.lib import Plugin, PluginStatus
from openlp.core.lib import Plugin, StringContent, PluginStatus
log = logging.getLogger(__name__)
@ -152,12 +152,13 @@ class PluginManager(object):
for plugin in self.plugins:
if plugin.status is not PluginStatus.Disabled:
plugin.settings_tab = plugin.getSettingsTab()
visible_title = plugin.getString(StringContent.VisibleName)
if plugin.settings_tab:
log.debug(u'Inserting settings tab item from %s' %
plugin.name)
settingsform.addTab(plugin.name, plugin.settings_tab)
visible_title[u'title'])
settingsform.addTab(visible_title[u'title'], plugin.settings_tab)
else:
log.debug(u'No tab settings in %s' % plugin.name)
log.debug(u'No tab settings in %s' % visible_title[u'title'])
def hook_import_menu(self, import_menu):
"""

View File

@ -58,6 +58,9 @@ class ItemCapabilities(object):
AllowsLoop = 5
AllowsAdditions = 6
NoLineBreaks = 7
OnLoadUpdate = 8
AddIfNewItem = 9
class ServiceItem(object):
"""
@ -98,6 +101,9 @@ class ServiceItem(object):
self.main = None
self.footer = None
self.bg_image_bytes = None
self.search_string = u''
self.data_string = u''
self._new_item()
def _new_item(self):
"""
@ -149,8 +155,6 @@ class ServiceItem(object):
line_break = True
if self.is_capable(ItemCapabilities.NoLineBreaks):
line_break = False
if self.service_item_type == ServiceItemType.Text:
log.debug(u'Formatting slides')
theme = None
if self.theme:
theme = self.theme
@ -158,6 +162,8 @@ class ServiceItem(object):
self.render_manager.set_override_theme(theme, useOverride)
self.bg_image_bytes = self.render_manager.renderer.bg_image_bytes
self.themedata = self.render_manager.renderer._theme
if self.service_item_type == ServiceItemType.Text:
log.debug(u'Formatting slides')
for slide in self._raw_frames:
before = time.time()
formatted = self.render_manager \
@ -170,7 +176,6 @@ class ServiceItem(object):
u'verseTag': slide[u'verseTag'] })
log.log(15, u'Formatting took %4s' % (time.time() - before))
elif self.service_item_type == ServiceItemType.Image:
self.themedata = self.render_manager.global_theme_data
for slide in self._raw_frames:
slide[u'image'] = resize_image(slide[u'image'],
self.render_manager.width, self.render_manager.height)
@ -255,7 +260,9 @@ class ServiceItem(object):
u'audit':self.audit,
u'notes':self.notes,
u'from_plugin':self.from_plugin,
u'capabilities':self.capabilities
u'capabilities':self.capabilities,
u'search':self.search_string,
u'data':self.data_string
}
service_data = []
if self.service_item_type == ServiceItemType.Text:
@ -293,6 +300,10 @@ class ServiceItem(object):
self.notes = header[u'notes']
self.from_plugin = header[u'from_plugin']
self.capabilities = header[u'capabilities']
# Added later so may not be present in older services.
if u'search' in header:
self.search_string = header[u'search']
self.data_string = header[u'data']
if self.service_item_type == ServiceItemType.Text:
for slide in serviceitem[u'serviceitem'][u'data']:
self._raw_frames.append(slide)
@ -306,6 +317,7 @@ class ServiceItem(object):
filename = os.path.join(path, text_image[u'title'])
self.add_from_command(
path, text_image[u'title'], text_image[u'image'] )
self._new_item()
def merge(self, other):
"""

View File

@ -31,16 +31,19 @@ class SettingsTab(QtGui.QWidget):
SettingsTab is a helper widget for plugins to define Tabs for the settings
dialog.
"""
def __init__(self, title):
def __init__(self, title, visible_title=None):
"""
Constructor to create the Settings tab item.
``title``
The title of the tab, which is used internally for the tab handling.
``visible_title``
The title of the tab, which is usually displayed on the tab.
"""
QtGui.QWidget.__init__(self)
self.tabTitle = title
self.tabTitleVisible = None
self.tabTitleVisible = visible_title
self.settingsSection = self.tabTitle.lower()
self.setupUi()
self.retranslateUi()

View File

@ -82,6 +82,9 @@ class AdvancedTab(SettingsTab):
self.doubleClickLiveCheckBox.setObjectName(u'doubleClickLiveCheckBox')
self.uiLayout.addWidget(self.doubleClickLiveCheckBox)
self.leftLayout.addWidget(self.uiGroupBox)
self.expandServiceItemCheckBox = QtGui.QCheckBox(self.uiGroupBox)
self.expandServiceItemCheckBox.setObjectName(u'expandServiceItemCheckBox')
self.uiLayout.addWidget(self.expandServiceItemCheckBox)
# self.sharedDirGroupBox = QtGui.QGroupBox(self.leftWidget)
# self.sharedDirGroupBox.setObjectName(u'sharedDirGroupBox')
# self.sharedDirGroupBox.setGeometry(QtCore.QRect(0, 65, 500, 85))
@ -140,6 +143,8 @@ class AdvancedTab(SettingsTab):
'Remember active media manager tab on startup'))
self.doubleClickLiveCheckBox.setText(translate('OpenLP.AdvancedTab',
'Double-click to send items straight to live (requires restart)'))
self.expandServiceItemCheckBox.setText(translate('OpenLP.AdvancedTab',
'Expand new service items on creation'))
# self.sharedDirGroupBox.setTitle(
# translate('AdvancedTab', 'Central Data Store'))
# self.sharedCheckBox.setText(
@ -167,6 +172,9 @@ class AdvancedTab(SettingsTab):
self.doubleClickLiveCheckBox.setChecked(
settings.value(u'double click live',
QtCore.QVariant(False)).toBool())
self.expandServiceItemCheckBox.setChecked(
settings.value(u'expand service item',
QtCore.QVariant(False)).toBool())
settings.endGroup()
def save(self):
@ -181,6 +189,8 @@ class AdvancedTab(SettingsTab):
QtCore.QVariant(self.mediaPluginCheckBox.isChecked()))
settings.setValue(u'double click live',
QtCore.QVariant(self.doubleClickLiveCheckBox.isChecked()))
settings.setValue(u'expand service item',
QtCore.QVariant(self.expandServiceItemCheckBox.isChecked()))
settings.endGroup()
def onSharedCheckBoxChanged(self, checked):

View File

@ -114,18 +114,20 @@ class MainDisplay(DisplayWidget):
"""
log.debug(u'Setup live = %s for %s ' % (self.isLive,
self.screens.monitor_number))
self.usePhonon = QtCore.QSettings().value(
u'media/use phonon', QtCore.QVariant(True)).toBool()
self.phononActive = False
self.screen = self.screens.current
self.setVisible(False)
self.setGeometry(self.screen[u'size'])
try:
self.webView = QtWebKit.QGraphicsWebView()
self.scene = QtGui.QGraphicsScene(self)
self.setScene(self.scene)
self.scene.addItem(self.webView)
self.webView.setGeometry(QtCore.QRectF(0, 0,
self.videoWidget = Phonon.VideoWidget(self)
self.videoWidget.setVisible(False)
self.videoWidget.setGeometry(QtCore.QRect(0, 0,
self.screen[u'size'].width(), self.screen[u'size'].height()))
except AttributeError:
# QGraphicsWebView a recent addition, so fall back to QWebView
self.mediaObject = Phonon.MediaObject(self)
self.audio = Phonon.AudioOutput(Phonon.VideoCategory, self.mediaObject)
Phonon.createPath(self.mediaObject, self.videoWidget)
Phonon.createPath(self.mediaObject, self.audio)
self.webView = QtWebKit.QWebView(self)
self.webView.setGeometry(0, 0,
self.screen[u'size'].width(), self.screen[u'size'].height())
@ -199,7 +201,7 @@ class MainDisplay(DisplayWidget):
"""
log.debug(u'alert')
if self.height() != self.screen[u'size'].height() \
or not self.isVisible():
or not self.isVisible() or self.videoWidget.isVisible():
shrink = True
else:
shrink = False
@ -208,12 +210,17 @@ class MainDisplay(DisplayWidget):
u'top' if shrink else u'')
height = self.frame.evaluateJavaScript(js)
if shrink:
if text:
self.resize(self.width(), int(height.toString()))
self.setVisible(True)
if self.phononActive:
shrinkItem = self.webView
else:
self.setGeometry(self.screen[u'size'])
self.setVisible(False)
shrinkItem = self
if text:
shrinkItem.resize(self.width(), int(height.toString()))
shrinkItem.setVisible(True)
else:
shrinkItem.setVisible(False)
shrinkItem.resize(self.screen[u'size'].width(),
self.screen[u'size'].height())
def image(self, image):
"""
@ -259,6 +266,13 @@ class MainDisplay(DisplayWidget):
Used after Video plugin has changed the background
"""
log.debug(u'resetVideo')
if self.phononActive:
self.mediaObject.stop()
self.mediaObject.clearQueue()
self.webView.setVisible(True)
self.videoWidget.setVisible(False)
self.phononActive = False
else:
self.frame.evaluateJavaScript(u'show_video("close");')
def videoPlay(self):
@ -266,6 +280,9 @@ class MainDisplay(DisplayWidget):
Responds to the request to play a loaded video
"""
log.debug(u'videoPlay')
if self.phononActive:
self.mediaObject.play()
else:
self.frame.evaluateJavaScript(u'show_video("play");')
# show screen
if self.isLive:
@ -276,6 +293,9 @@ class MainDisplay(DisplayWidget):
Responds to the request to pause a loaded video
"""
log.debug(u'videoPause')
if self.phononActive:
self.mediaObject.pause()
else:
self.frame.evaluateJavaScript(u'show_video("pause");')
def videoStop(self):
@ -283,6 +303,9 @@ class MainDisplay(DisplayWidget):
Responds to the request to stop a loaded video
"""
log.debug(u'videoStop')
if self.phononActive:
self.mediaObject.stop()
else:
self.frame.evaluateJavaScript(u'show_video("stop");')
def videoVolume(self, volume):
@ -290,18 +313,34 @@ class MainDisplay(DisplayWidget):
Changes the volume of a running video
"""
log.debug(u'videoVolume %d' % volume)
vol = float(volume)/float(10)
if self.phononActive:
self.audio.setVolume(vol)
else:
self.frame.evaluateJavaScript(u'show_video(null, null, %s);' %
str(float(volume)/float(10)))
str(vol))
def video(self, videoPath, volume):
def video(self, videoPath, volume, isBackground=False):
"""
Loads and starts a video to run with the option of sound
"""
log.debug(u'video')
self.loaded = True
vol = float(volume)/float(10)
if isBackground or not self.usePhonon:
js = u'show_video("init", "%s", %s, true); show_video("play");' % \
(videoPath.replace(u'\\', u'\\\\'), str(float(volume)/float(10)))
(videoPath.replace(u'\\', u'\\\\'), \
str(vol))
self.frame.evaluateJavaScript(js)
else:
self.phononActive = True
self.mediaObject.stop()
self.mediaObject.clearQueue()
self.mediaObject.setCurrentSource(Phonon.MediaSource(videoPath))
self.mediaObject.play()
self.webView.setVisible(False)
self.videoWidget.setVisible(True)
self.audio.setVolume(vol)
return self.preview()
def isLoaded(self):
@ -382,6 +421,8 @@ class MainDisplay(DisplayWidget):
Store the images so they can be replaced when required
"""
log.debug(u'hideDisplay mode = %d', mode)
if self.phononActive:
self.videoPause()
if mode == HideMode.Screen:
self.frame.evaluateJavaScript(u'show_blank("desktop");')
self.setVisible(False)
@ -389,8 +430,11 @@ class MainDisplay(DisplayWidget):
self.frame.evaluateJavaScript(u'show_blank("black");')
else:
self.frame.evaluateJavaScript(u'show_blank("theme");')
if mode != HideMode.Screen and self.isHidden():
if mode != HideMode.Screen:
if self.isHidden():
self.setVisible(True)
if self.phononActive:
self.webView.setVisible(True)
self.hide_mode = mode
def showDisplay(self):
@ -403,6 +447,9 @@ class MainDisplay(DisplayWidget):
self.frame.evaluateJavaScript('show_blank("show");')
if self.isHidden():
self.setVisible(True)
if self.phononActive:
self.webView.setVisible(False)
self.videoPlay()
# Trigger actions when display is active again
Receiver.send_message(u'maindisplay_active')
self.hide_mode = None
@ -484,3 +531,4 @@ class AudioPlayer(QtCore.QObject):
"""
log.debug(u'AudioPlayer Reached end of media playlist')
self.mediaObject.clearQueue()

View File

@ -175,19 +175,13 @@ class Ui_MainWindow(object):
QtCore.Qt.DockWidgetArea(2), self.ThemeManagerDock)
# Create the menu items
self.FileNewItem = QtGui.QAction(MainWindow)
self.FileNewItem.setIcon(
self.ServiceManagerContents.toolbar.getIconFromTitle(
u'New Service'))
self.FileNewItem.setIcon(build_icon(u':/general/general_new.png'))
self.FileNewItem.setObjectName(u'FileNewItem')
self.FileOpenItem = QtGui.QAction(MainWindow)
self.FileOpenItem.setIcon(
self.ServiceManagerContents.toolbar.getIconFromTitle(
u'Open Service'))
self.FileOpenItem.setIcon(build_icon(u':/general/general_open.png'))
self.FileOpenItem.setObjectName(u'FileOpenItem')
self.FileSaveItem = QtGui.QAction(MainWindow)
self.FileSaveItem.setIcon(
self.ServiceManagerContents.toolbar.getIconFromTitle(
u'Save Service'))
self.FileSaveItem.setIcon(build_icon(u':/general/general_save.png'))
self.FileSaveItem.setObjectName(u'FileSaveItem')
self.FileSaveAsItem = QtGui.QAction(MainWindow)
self.FileSaveAsItem.setObjectName(u'FileSaveAsItem')
@ -343,7 +337,6 @@ class Ui_MainWindow(object):
Set up the translation system
"""
MainWindow.mainTitle = translate('OpenLP.MainWindow', 'OpenLP 2.0')
# MainWindow.language = translate('OpenLP.MainWindow', 'English')
MainWindow.setWindowTitle(MainWindow.mainTitle)
self.FileMenu.setTitle(translate('OpenLP.MainWindow', '&File'))
self.FileImportMenu.setTitle(translate('OpenLP.MainWindow', '&Import'))

View File

@ -26,6 +26,8 @@
import logging
from openlp.core.lib import StringContent
log = logging.getLogger(__name__)
class MediaDockManager(object):
@ -48,8 +50,9 @@ class MediaDockManager(object):
``icon``
An icon for this dock item
"""
log.info(u'Adding %s dock' % media_item.title)
self.media_dock.addItem(media_item, icon, media_item.title)
visible_title = media_item.plugin.getString(StringContent.VisibleName)
log.info(u'Adding %s dock' % visible_title)
self.media_dock.addItem(media_item, icon, visible_title[u'title'])
def insert_dock(self, media_item, icon, weight):
"""
@ -57,27 +60,29 @@ class MediaDockManager(object):
This does not work as it gives a Segmentation error.
For now add at end of stack if not present
"""
log.debug(u'Inserting %s dock' % media_item.title)
visible_title = media_item.plugin.getString(StringContent.VisibleName)
log.debug(u'Inserting %s dock' % visible_title[u'title'])
match = False
for dock_index in range(0, self.media_dock.count()):
if self.media_dock.widget(dock_index).settingsSection == \
media_item.title.lower():
media_item.plugin.name.lower():
match = True
break
if not match:
self.media_dock.addItem(media_item, icon, media_item.title)
self.media_dock.addItem(media_item, icon, visible_title[u'title'])
def remove_dock(self, name):
def remove_dock(self, media_item):
"""
Removes a MediaManagerItem from the dock
``name``
The item to remove
``media_item``
The item to add to the dock
"""
log.debug(u'remove %s dock' % name)
visible_title = media_item.plugin.getString(StringContent.VisibleName)
log.debug(u'remove %s dock' % visible_title[u'title'])
for dock_index in range(0, self.media_dock.count()):
if self.media_dock.widget(dock_index):
if self.media_dock.widget(dock_index).settingsSection == \
name.lower():
media_item.plugin.name.lower():
self.media_dock.widget(dock_index).hide()
self.media_dock.removeItem(dock_index)

View File

@ -28,7 +28,7 @@ import logging
from PyQt4 import QtCore, QtGui
from openlp.core.lib import PluginStatus, translate
from openlp.core.lib import PluginStatus, StringContent, translate
from plugindialog import Ui_PluginViewDialog
log = logging.getLogger(__name__)
@ -78,7 +78,8 @@ class PluginForm(QtGui.QDialog, Ui_PluginViewDialog):
elif plugin.status == PluginStatus.Disabled:
status_text = unicode(
translate('OpenLP.PluginForm', '%s (Disabled)'))
item.setText(status_text % plugin.name)
name_string = plugin.getString(StringContent.Name)
item.setText(status_text % name_string[u'plural'])
# If the plugin has an icon, set it!
if plugin.icon:
item.setIcon(plugin.icon)
@ -106,10 +107,11 @@ class PluginForm(QtGui.QDialog, Ui_PluginViewDialog):
if self.pluginListWidget.currentItem() is None:
self._clearDetails()
return
plugin_name = self.pluginListWidget.currentItem().text().split(u' ')[0]
plugin_name_plural = self.pluginListWidget.currentItem().text().split(u' ')[0]
self.activePlugin = None
for plugin in self.parent.plugin_manager.plugins:
if plugin.name == plugin_name:
name_string = plugin.getString(StringContent.Name)
if name_string[u'plural'] == plugin_name_plural:
self.activePlugin = plugin
break
if self.activePlugin:
@ -137,5 +139,6 @@ class PluginForm(QtGui.QDialog, Ui_PluginViewDialog):
elif self.activePlugin.status == PluginStatus.Disabled:
status_text = unicode(
translate('OpenLP.PluginForm', '%s (Disabled)'))
name_string = self.activePlugin.getString(StringContent.Name)
self.pluginListWidget.currentItem().setText(
status_text % self.activePlugin.name)
status_text % name_string[u'plural'])

View File

@ -107,6 +107,7 @@ class ServiceManager(QtGui.QWidget):
self.serviceName = u''
self.suffixes = []
self.droppos = 0
self.expandTabs = False
#is a new service and has not been saved
self.isNew = True
self.serviceNoteForm = ServiceNoteForm(self.parent)
@ -199,6 +200,19 @@ class ServiceManager(QtGui.QWidget):
translate('OpenLP.ServiceManager',
'Delete the selected item from the service.'),
self.onDeleteFromService)
self.orderToolbar.addSeparator()
self.orderToolbar.addToolbarButton(
translate('OpenLP.ServiceManager', '&Expand all'),
u':/services/service_top.png',
translate('OpenLP.ServiceManager',
'Expand all the service items.'),
self.onExpandAll)
self.orderToolbar.addToolbarButton(
translate('OpenLP.ServiceManager', '&Collapse all'),
u':/services/service_bottom.png',
translate('OpenLP.ServiceManager',
'Collapse all the service items.'),
self.onCollapseAll)
self.layout.addWidget(self.orderToolbar)
# Connect up our signals and slots
QtCore.QObject.connect(self.themeComboBox,
@ -220,9 +234,11 @@ class ServiceManager(QtGui.QWidget):
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'servicemanager_list_request'), self.listRequest)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'config_updated'), self.regenerateServiceItems)
QtCore.SIGNAL(u'config_updated'), self.configUpdated)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'theme_update_global'), self.themeChange)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'service_item_update'), self.serviceItemUpdate)
# Last little bits of setting up
self.service_theme = unicode(QtCore.QSettings().value(
self.parent.serviceSettingsSection + u'/service theme',
@ -263,6 +279,17 @@ class ServiceManager(QtGui.QWidget):
self.themeMenu = QtGui.QMenu(
translate('OpenLP.ServiceManager', '&Change Item Theme'))
self.menu.addMenu(self.themeMenu)
self.configUpdated(True)
def configUpdated(self, firstTime=False):
"""
Triggered when Config dialog is updated.
"""
self.expandTabs = QtCore.QSettings().value(
u'advanced/expand service item',
QtCore.QVariant(u'False')).toBool()
if not firstTime:
self.regenerateServiceItems()
def supportedSuffixes(self, suffix):
self.suffixes.append(suffix)
@ -319,7 +346,7 @@ class ServiceManager(QtGui.QWidget):
self.serviceItems[item][u'service_item'])
if self.serviceItemEditForm.exec_():
self.addServiceItem(self.serviceItemEditForm.getServiceItem(),
replace=True)
replace=True, expand=self.serviceItems[item][u'expand'])
def nextItem(self):
"""
@ -421,6 +448,14 @@ class ServiceManager(QtGui.QWidget):
if setSelected:
firstItem.setSelected(True)
def onCollapseAll(self):
"""
Collapse all the service items
"""
for item in self.serviceItems:
item[u'expanded'] = False
self.regenerateServiceItems()
def collapsed(self, item):
"""
Record if an item is collapsed
@ -429,6 +464,14 @@ class ServiceManager(QtGui.QWidget):
pos = item.data(0, QtCore.Qt.UserRole).toInt()[0]
self.serviceItems[pos -1 ][u'expanded'] = False
def onExpandAll(self):
"""
Collapse all the service items
"""
for item in self.serviceItems:
item[u'expanded'] = True
self.regenerateServiceItems()
def expanded(self, item):
"""
Record if an item is collapsed
@ -600,6 +643,7 @@ class ServiceManager(QtGui.QWidget):
zip = None
file = None
try:
write_list = []
zip = zipfile.ZipFile(unicode(filename), 'w')
for item in self.serviceItems:
service.append({u'serviceitem':item[u'service_item']
@ -609,6 +653,9 @@ class ServiceManager(QtGui.QWidget):
path_from = unicode(os.path.join(
frame[u'path'],
frame[u'title']))
# On write a file once
if not path_from in write_list:
write_list.append(path_from)
zip.write(path_from.encode(u'utf-8'))
file = open(servicefile, u'wb')
cPickle.dump(service, file)
@ -711,6 +758,9 @@ class ServiceManager(QtGui.QWidget):
serviceitem.set_from_service(item, self.servicePath)
self.validateItem(serviceitem)
self.addServiceItem(serviceitem)
if serviceitem.is_capable(ItemCapabilities.OnLoadUpdate):
Receiver.send_message(u'%s_service_load' %
serviceitem.name.lower(), serviceitem)
try:
if os.path.isfile(p_file):
os.remove(p_file)
@ -796,19 +846,48 @@ class ServiceManager(QtGui.QWidget):
self.isNew = True
for item in tempServiceItems:
self.addServiceItem(
item[u'service_item'], False, item[u'expanded'])
item[u'service_item'], False, expand=item[u'expanded'])
# Set to False as items may have changed rendering
# does not impact the saved song so True may also be valid
self.parent.serviceChanged(False, self.serviceName)
def addServiceItem(self, item, rebuild=False, expand=True, replace=False):
def serviceItemUpdate(self, message):
"""
Triggered from plugins to update service items.
"""
editId, uuid = message.split(u':')
for item in self.serviceItems:
if item[u'service_item']._uuid == uuid:
item[u'service_item'].editId = editId
def replaceServiceItem(self, newItem):
"""
Using the service item passed replace the one with the same edit id
if found.
"""
newItem.render()
for itemcount, item in enumerate(self.serviceItems):
if item[u'service_item'].editId == newItem.editId and \
item[u'service_item'].name == newItem.name:
newItem.merge(item[u'service_item'])
item[u'service_item'] = newItem
self.repaintServiceList(itemcount + 1, 0)
self.parent.LiveController.replaceServiceManagerItem(newItem)
self.parent.serviceChanged(False, self.serviceName)
def addServiceItem(self, item, rebuild=False, expand=None, replace=False):
"""
Add a Service item to the list
``item``
Service Item to be added
``expand``
Override the default expand settings. (Tristate)
"""
log.debug(u'addServiceItem')
if expand == None:
expand = self.expandTabs
sitem = self.findServiceItem()[0]
item.render()
if replace:

View File

@ -72,14 +72,15 @@ class SettingsForm(QtGui.QDialog, Ui_SettingsDialog):
self.settingsTabWidget.insertTab(
location + 14, tab, tab.tabTitleVisible)
def removeTab(self, name):
def removeTab(self, tab):
"""
Remove a tab from the form
"""
log.debug(u'remove %s tab' % name)
log.debug(u'remove %s tab' % tab.tabTitleVisible)
for tabIndex in range(0, self.settingsTabWidget.count()):
if self.settingsTabWidget.widget(tabIndex):
if self.settingsTabWidget.widget(tabIndex).tabTitle == name:
if self.settingsTabWidget.widget(tabIndex).tabTitleVisible == \
tab.tabTitleVisible:
self.settingsTabWidget.removeTab(tabIndex)
def accept(self):

View File

@ -179,19 +179,24 @@ class SlideController(QtGui.QWidget):
self.HideMenu.setMenu(QtGui.QMenu(
translate('OpenLP.SlideController', 'Hide'), self.Toolbar))
self.BlankScreen = QtGui.QAction(QtGui.QIcon(
u':/slides/slide_blank.png'), u'Blank Screen', self.HideMenu)
u':/slides/slide_blank.png'),
translate('OpenLP.SlideController',
'Blank Screen'), self.HideMenu)
self.BlankScreen.setCheckable(True)
QtCore.QObject.connect(self.BlankScreen,
QtCore.SIGNAL("triggered(bool)"), self.onBlankDisplay)
self.ThemeScreen = QtGui.QAction(QtGui.QIcon(
u':/slides/slide_theme.png'), u'Blank to Theme', self.HideMenu)
u':/slides/slide_theme.png'),
translate('OpenLP.SlideController',
'Blank to Theme'), self.HideMenu)
self.ThemeScreen.setCheckable(True)
QtCore.QObject.connect(self.ThemeScreen,
QtCore.SIGNAL("triggered(bool)"), self.onThemeDisplay)
if self.screens.display_count > 1:
self.DesktopScreen = QtGui.QAction(QtGui.QIcon(
u':/slides/slide_desktop.png'), u'Show Desktop',
self.HideMenu)
u':/slides/slide_desktop.png'),
translate('OpenLP.SlideController',
'Show Desktop'), self.HideMenu)
self.DesktopScreen.setCheckable(True)
QtCore.QObject.connect(self.DesktopScreen,
QtCore.SIGNAL("triggered(bool)"), self.onHideDisplay)
@ -538,7 +543,7 @@ class SlideController(QtGui.QWidget):
Receiver.send_message(u'%s_stop' %
self.serviceItem.name.lower(), [serviceItem, self.isLive])
if self.serviceItem.is_media():
self.onMediaStop()
self.onMediaClose()
if self.isLive:
blanked = self.BlankScreen.isChecked()
else:
@ -926,14 +931,13 @@ class SlideController(QtGui.QWidget):
Respond to the arrival of a media service item
"""
log.debug(u'SlideController onMediaStart')
if self.isLive:
file = os.path.join(item.get_frame_path(), item.get_frame_title())
if self.isLive:
self.display.video(file, self.volume)
self.volumeSlider.setValue(self.volume)
else:
self.mediaObject.stop()
self.mediaObject.clearQueue()
file = os.path.join(item.get_frame_path(), item.get_frame_title())
self.mediaObject.setCurrentSource(Phonon.MediaSource(file))
self.seekSlider.setMediaObject(self.mediaObject)
self.seekSlider.show()
@ -981,3 +985,18 @@ class SlideController(QtGui.QWidget):
self.video.hide()
self.SlidePreview.clear()
self.SlidePreview.show()
def onMediaClose(self):
"""
Respond to a request to close the Video
"""
log.debug(u'SlideController onMediaStop')
if self.isLive:
self.display.resetVideo()
else:
self.mediaObject.stop()
self.mediaObject.clearQueue()
self.video.hide()
self.SlidePreview.clear()
self.SlidePreview.show()

View File

@ -28,7 +28,7 @@ import logging
from PyQt4 import QtCore, QtGui
from openlp.core.lib import Plugin, build_icon, translate
from openlp.core.lib import Plugin, StringContent, build_icon, translate
from openlp.core.lib.db import Manager
from openlp.plugins.alerts.lib import AlertsManager, AlertsTab
from openlp.plugins.alerts.lib.db import init_schema
@ -101,3 +101,18 @@ class AlertsPlugin(Plugin):
'<br />The alert plugin controls the displaying of nursery alerts '
'on the display screen')
return about_text
def setPluginTextStrings(self):
"""
Called to define all translatable texts of the plugin
"""
## Name PluginList ##
self.textStrings[StringContent.Name] = {
u'singular': translate('AlertsPlugin', 'Alert'),
u'plural': translate('AlertsPlugin', 'Alerts')
}
## Name for MediaDockManager, SettingsManager ##
self.textStrings[StringContent.VisibleName] = {
u'title': translate('AlertsPlugin', 'Alerts')
}

View File

@ -35,7 +35,7 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog):
"""
Provide UI for the alert system
"""
def __init__(self, plugin):
def __init__(self, title, visible_title):
"""
Initialise the alert form
"""

View File

@ -32,14 +32,13 @@ class AlertsTab(SettingsTab):
"""
AlertsTab is the alerts settings tab in the settings dialog.
"""
def __init__(self, parent):
def __init__(self, parent, visible_title):
self.parent = parent
self.manager = parent.manager
SettingsTab.__init__(self, parent.name)
SettingsTab.__init__(self, parent.name, visible_title)
def setupUi(self):
self.setObjectName(u'AlertsTab')
self.tabTitleVisible = translate('AlertsPlugin.AlertsTab', 'Alerts')
self.AlertsLayout = QtGui.QHBoxLayout(self)
self.AlertsLayout.setSpacing(8)
self.AlertsLayout.setMargin(8)
@ -296,4 +295,3 @@ class AlertsTab(SettingsTab):
self.FontPreview.setFont(font)
self.FontPreview.setStyleSheet(u'background-color: %s; color: %s' %
(self.bg_color, self.font_color))

View File

@ -24,6 +24,6 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`bibles' module provides the Bible plugin to enable OpenLP to display
The :mod:`bibles` module provides the Bible plugin to enable OpenLP to display
scripture.
"""

View File

@ -28,7 +28,7 @@ import logging
from PyQt4 import QtCore, QtGui
from openlp.core.lib import Plugin, build_icon, translate
from openlp.core.lib import Plugin, StringContent, build_icon, translate
from openlp.plugins.bibles.lib import BibleManager, BiblesTab, BibleMediaItem
log = logging.getLogger(__name__)
@ -58,11 +58,12 @@ class BiblePlugin(Plugin):
self.exportBibleItem.setVisible(False)
def getSettingsTab(self):
return BiblesTab(self.name)
visible_name = self.getString(StringContent.VisibleName)
return BiblesTab(self.name, visible_name[u'title'])
def getMediaManagerItem(self):
# Create the BibleManagerItem object.
return BibleMediaItem(self, self.icon, self.name)
return BibleMediaItem(self, self, self.icon)
def addImportMenuItem(self, import_menu):
self.importBibleItem = QtGui.QAction(import_menu)
@ -79,8 +80,7 @@ class BiblePlugin(Plugin):
self.exportBibleItem = QtGui.QAction(export_menu)
self.exportBibleItem.setObjectName(u'exportBibleItem')
export_menu.addAction(self.exportBibleItem)
self.exportBibleItem.setText(translate(
'BiblesPlugin', '&Bible'))
self.exportBibleItem.setText(translate('BiblesPlugin', '&Bible'))
self.exportBibleItem.setVisible(False)
def onBibleImportClick(self):
@ -96,7 +96,6 @@ class BiblePlugin(Plugin):
def usesTheme(self, theme):
"""
Called to find out if the bible plugin is currently using a theme.
Returns True if the theme is being used, otherwise returns False.
"""
if self.settings_tab.bible_theme == theme:
@ -116,3 +115,60 @@ class BiblePlugin(Plugin):
The new name the plugin should now use.
"""
self.settings_tab.bible_theme = newTheme
def setPluginTextStrings(self):
"""
Called to define all translatable texts of the plugin
"""
## Name PluginList ##
self.textStrings[StringContent.Name] = {
u'singular': translate('BiblesPlugin', 'Bible'),
u'plural': translate('BiblesPlugin', 'Bibles')
}
## Name for MediaDockManager, SettingsManager ##
self.textStrings[StringContent.VisibleName] = {
u'title': translate('BiblesPlugin', 'Bibles')
}
# Middle Header Bar
## Import Button ##
self.textStrings[StringContent.Import] = {
u'title': translate('BiblesPlugin', 'Import'),
u'tooltip': translate('BiblesPlugin',
'Import a Bible')
}
## New Button ##
self.textStrings[StringContent.New] = {
u'title': translate('BiblesPlugin', 'Add'),
u'tooltip': translate('BiblesPlugin',
'Add a new Bible')
}
## Edit Button ##
self.textStrings[StringContent.Edit] = {
u'title': translate('BiblesPlugin', 'Edit'),
u'tooltip': translate('BiblesPlugin',
'Edit the selected Bible')
}
## Delete Button ##
self.textStrings[StringContent.Delete] = {
u'title': translate('BiblesPlugin', 'Delete'),
u'tooltip': translate('BiblesPlugin',
'Delete the selected Bible')
}
## Preview ##
self.textStrings[StringContent.Preview] = {
u'title': translate('BiblesPlugin', 'Preview'),
u'tooltip': translate('BiblesPlugin',
'Preview the selected Bible')
}
## Live Button ##
self.textStrings[StringContent.Live] = {
u'title': translate('BiblesPlugin', 'Live'),
u'tooltip': translate('BiblesPlugin',
'Send the selected Bible live')
}
## Add to service Button ##
self.textStrings[StringContent.Service] = {
u'title': translate('BiblesPlugin', 'Service'),
u'tooltip': translate('BiblesPlugin',
'Add the selected Bible to the service')
}

View File

@ -275,14 +275,14 @@ class Ui_BibleImportWizard(object):
self.CopyrightEdit.setObjectName(u'CopyrightEdit')
self.LicenseDetailsLayout.setWidget(1, QtGui.QFormLayout.FieldRole,
self.CopyrightEdit)
self.PermissionLabel = QtGui.QLabel(self.LicenseDetailsPage)
self.PermissionLabel.setObjectName(u'PermissionLabel')
self.PermissionsLabel = QtGui.QLabel(self.LicenseDetailsPage)
self.PermissionsLabel.setObjectName(u'PermissionsLabel')
self.LicenseDetailsLayout.setWidget(2, QtGui.QFormLayout.LabelRole,
self.PermissionLabel)
self.PermissionEdit = QtGui.QLineEdit(self.LicenseDetailsPage)
self.PermissionEdit.setObjectName(u'PermissionEdit')
self.PermissionsLabel)
self.PermissionsEdit = QtGui.QLineEdit(self.LicenseDetailsPage)
self.PermissionsEdit.setObjectName(u'PermissionsEdit')
self.LicenseDetailsLayout.setWidget(2, QtGui.QFormLayout.FieldRole,
self.PermissionEdit)
self.PermissionsEdit)
BibleImportWizard.addPage(self.LicenseDetailsPage)
self.ImportPage = QtGui.QWizardPage()
self.ImportPage.setObjectName(u'ImportPage')
@ -372,8 +372,8 @@ class Ui_BibleImportWizard(object):
translate('BiblesPlugin.ImportWizardForm', 'Version name:'))
self.CopyrightLabel.setText(
translate('BiblesPlugin.ImportWizardForm', 'Copyright:'))
self.PermissionLabel.setText(
translate('BiblesPlugin.ImportWizardForm', 'Permission:'))
self.PermissionsLabel.setText(
translate('BiblesPlugin.ImportWizardForm', 'Permissions:'))
self.ImportPage.setTitle(
translate('BiblesPlugin.ImportWizardForm', 'Importing'))
self.ImportPage.setSubTitle(

View File

@ -282,7 +282,7 @@ class ImportWizardForm(QtGui.QWizard, Ui_BibleImportWizard):
self.LicenseDetailsPage.registerField(
u'license_copyright', self.CopyrightEdit)
self.LicenseDetailsPage.registerField(
u'license_permission', self.PermissionEdit)
u'license_permissions', self.PermissionsEdit)
def setDefaults(self):
settings = QtCore.QSettings()
@ -308,8 +308,8 @@ class ImportWizardForm(QtGui.QWizard, Ui_BibleImportWizard):
QtCore.QVariant(self.VersionNameEdit.text()))
self.setField(u'license_copyright',
QtCore.QVariant(self.CopyrightEdit.text()))
self.setField(u'license_permission',
QtCore.QVariant(self.PermissionEdit.text()))
self.setField(u'license_permissions',
QtCore.QVariant(self.PermissionsEdit.text()))
self.onLocationComboBoxChanged(WebDownload.Crosswalk)
settings.endGroup()
@ -391,8 +391,8 @@ class ImportWizardForm(QtGui.QWizard, Ui_BibleImportWizard):
bible_type = self.field(u'source_format').toInt()[0]
license_version = unicode(self.field(u'license_version').toString())
license_copyright = unicode(self.field(u'license_copyright').toString())
license_permission = \
unicode(self.field(u'license_permission').toString())
license_permissions = \
unicode(self.field(u'license_permissions').toString())
importer = None
if bible_type == BibleFormat.OSIS:
# Import an OSIS bible
@ -436,7 +436,7 @@ class ImportWizardForm(QtGui.QWizard, Ui_BibleImportWizard):
)
if importer.do_import():
self.manager.save_meta_data(license_version, license_version,
license_copyright, license_permission)
license_copyright, license_permissions)
self.manager.reload_bibles()
self.ImportProgressLabel.setText(
translate('BiblesPlugin.ImportWizardForm', 'Finished import.'))

View File

@ -60,22 +60,32 @@ def parse_reference(reference):
and converts it to a reference list, a list of references to be queried
from the Bible database files.
BIBLE_REFERENCE regular expression produces the following match groups:
0 This is a special group consisting of the whole string that matched.
1 [\w ]+ The book the reference is from.
2 [0-9]+ The first (or only) chapter in the reference.
3 None|[0-9]+ None or the only verse or the first verse in a
verse range or the start verse in a chapter range.
4 None|[0-9]+|end None or the end verse of the first verse range or
the end chapter of a chapter range.
5 None|[0-9]+ None or the second chapter in multiple
(non-ranged) chapters.
6 None|[0-9]+|end None, the start of the second verse range or the
end of a chapter range.
7 None|[0-9]+|end None or the end of the second verse range.
The ``BIBLE_REFERENCE`` constant regular expression produces the following
match groups:
0. (match string)
This is a special group consisting of the whole string that matched.
1. ``[\w ]+``
The book the reference is from.
2. ``[0-9]+``
The first (or only) chapter in the reference.
3. ``None`` or ``[0-9]+``
``None``, or the only verse, or the first verse in a verse range or,
the start verse in a chapter range.
4. ``None`` or ``[0-9]+`` or ``end``
``None``, or the end verse of the first verse range, or the end chapter
of a chapter range.
5. ``None`` or ``[0-9]+``
``None``, or the second chapter in multiple (non-ranged) chapters.
6. ``None`` or ``[0-9]+`` or ``end``
``None``, the start of the second verse range. or the end of a chapter
range.
7. ``None`` or ``[0-9]+`` or ``end``
``None``, or the end of the second verse range.
The reference list is a list of tuples, with each tuple structured like
this::
(book, chapter, start_verse, end_verse)
``reference``
@ -154,7 +164,7 @@ def parse_reference(reference):
class SearchResults(object):
"""
Encapsulate a set of search results. This is Bible-type independant.
Encapsulate a set of search results. This is Bible-type independent.
"""
def __init__(self, book, chapter, verselist):
"""

View File

@ -38,15 +38,14 @@ class BiblesTab(SettingsTab):
"""
log.info(u'Bible Tab loaded')
def __init__(self, title):
def __init__(self, title, visible_title):
self.paragraph_style = True
self.show_new_chapters = False
self.display_style = 0
SettingsTab.__init__(self, title)
SettingsTab.__init__(self, title, visible_title)
def setupUi(self):
self.setObjectName(u'BiblesTab')
self.tabTitleVisible = translate('BiblesPlugin.BiblesTab', 'Bibles')
self.BibleLayout = QtGui.QHBoxLayout(self)
self.BibleLayout.setSpacing(8)
self.BibleLayout.setMargin(8)

View File

@ -64,10 +64,10 @@ class Verse(BaseModel):
def init_schema(url):
"""
Setup a bible database connection and initialise the database schema
Setup a bible database connection and initialise the database schema.
``url``
The database to setup
The database to setup.
"""
session, metadata = init_db(url)
@ -281,23 +281,23 @@ class BibleDB(QtCore.QObject, Manager):
def create_meta(self, key, value):
"""
Utility method to save BibleMeta objects in a Bible database
Utility method to save BibleMeta objects in a Bible database.
``key``
The key for this instance
The key for this instance.
``value``
The value for this instance
The value for this instance.
"""
log.debug(u'save_meta %s/%s', key, value)
self.save_object(BibleMeta.populate(key=key, value=value))
def get_book(self, book):
"""
Return a book object from the database
Return a book object from the database.
``book``
The name of the book to return
The name of the book to return.
"""
log.debug(u'BibleDb.get_book("%s")', book)
db_book = self.get_object_filtered(Book, Book.name.like(book + u'%'))
@ -353,8 +353,8 @@ class BibleDB(QtCore.QObject, Manager):
QtGui.QMessageBox.information(self.bible_plugin.mediaItem,
translate('BiblesPlugin.BibleDB', 'Book not found'),
translate('BiblesPlugin.BibleDB', 'The book you requested '
'could not be found in this bible. Please check your '
'spelling and that this is a complete bible not just '
'could not be found in this Bible. Please check your '
'spelling and that this is a complete Bible not just '
'one testament.'))
return verse_list
@ -387,10 +387,10 @@ class BibleDB(QtCore.QObject, Manager):
def get_chapter_count(self, book):
"""
Return the number of chapters in a book
Return the number of chapters in a book.
``book``
The book to get the chapter count for
The book to get the chapter count for.
"""
log.debug(u'BibleDB.get_chapter_count("%s")', book)
count = self.session.query(Verse.chapter).join(Book)\
@ -403,13 +403,13 @@ class BibleDB(QtCore.QObject, Manager):
def get_verse_count(self, book, chapter):
"""
Return the number of verses in a chapter
Return the number of verses in a chapter.
``book``
The book containing the chapter
The book containing the chapter.
``chapter``
The chapter to get the verse count for
The chapter to get the verse count for.
"""
log.debug(u'BibleDB.get_verse_count("%s", %s)', book, chapter)
count = self.session.query(Verse).join(Book)\
@ -423,7 +423,7 @@ class BibleDB(QtCore.QObject, Manager):
def dump_bible(self):
"""
Utility debugging method to dump the contents of a bible
Utility debugging method to dump the contents of a bible.
"""
log.debug(u'.........Dumping Bible Database')
log.debug('...............................Books ')

View File

@ -187,16 +187,16 @@ class BGExtract(object):
def get_bible_chapter(self, version, bookname, chapter):
"""
Access and decode bibles via the BibleGateway website
Access and decode bibles via the BibleGateway website.
``version``
The version of the bible like 31 for New International version
The version of the bible like 31 for New International version.
``bookname``
Name of the Book
Name of the Book.
``chapter``
Chapter number
Chapter number.
"""
log.debug(u'get_bible_chapter %s, %s, %s', version, bookname, chapter)
url_params = urllib.urlencode(
@ -428,7 +428,7 @@ class HTTPBible(BibleDB):
def get_chapter(self, book, chapter):
"""
Receive the request and call the relevant handler methods
Receive the request and call the relevant handler methods.
"""
log.debug(u'get_chapter %s, %s', book, chapter)
log.debug(u'source = %s', self.download_source)

View File

@ -137,7 +137,7 @@ class BibleManager(object):
name = bible.get_name()
log.debug(u'Bible Name: "%s"', name)
self.db_cache[name] = bible
# look to see if lazy load bible exists and get create getter.
# Look to see if lazy load bible exists and get create getter.
source = self.db_cache[name].get_object(BibleMeta,
u'download source')
if source:
@ -181,10 +181,10 @@ class BibleManager(object):
def get_bibles(self):
"""
Returns a list of the names of available Bibles.
Returns a dict with all available Bibles.
"""
log.debug(u'get_bibles')
return self.db_cache.keys()
return self.db_cache
def get_books(self, bible):
"""
@ -204,7 +204,7 @@ class BibleManager(object):
def get_chapter_count(self, bible, book):
"""
Returns the number of Chapters for a given book
Returns the number of Chapters for a given book.
"""
log.debug(u'get_book_chapter_count %s', book)
return self.db_cache[bible].get_chapter_count(book)
@ -212,7 +212,7 @@ class BibleManager(object):
def get_verse_count(self, bible, book, chapter):
"""
Returns all the number of verses for a given
book and chapterMaxBibleBookVerses
book and chapterMaxBibleBookVerses.
"""
log.debug(u'BibleManager.get_verse_count("%s", "%s", %s)',
bible, book, chapter)
@ -254,12 +254,35 @@ class BibleManager(object):
'Book Chapter:Verse-Verse\n'
'Book Chapter:Verse-Verse,Verse-Verse\n'
'Book Chapter:Verse-Verse,Chapter:Verse-Verse\n'
'Book Chapter:Verse-Chapter:Verse\n'))
'Book Chapter:Verse-Chapter:Verse'))
return None
def verse_search(self, bible, text):
"""
Does a verse search for the given bible and text.
``bible``
The bible to seach in (unicode).
``text``
The text to search for (unicode).
"""
log.debug(u'BibleManager.verse_search("%s", "%s")', bible, text)
if text:
return self.db_cache[bible].verse_search(text)
else:
QtGui.QMessageBox.information(self.parent.mediaItem,
translate('BiblesPlugin.BibleManager',
'Scripture Reference Error'),
translate('BiblesPlugin.BibleManager', 'You did not enter a '
'search keyword.\nYou can separate different keywords by a '
'space to search for all of your keywords and you can seperate '
'them by a comma to search for one of them.'))
return None
def save_meta_data(self, bible, version, copyright, permissions):
"""
Saves the bibles meta data
Saves the bibles meta data.
"""
log.debug(u'save_meta data %s,%s, %s,%s',
bible, version, copyright, permissions)
@ -269,14 +292,14 @@ class BibleManager(object):
def get_meta_data(self, bible, key):
"""
Returns the meta data for a given key
Returns the meta data for a given key.
"""
log.debug(u'get_meta %s,%s', bible, key)
return self.db_cache[bible].get_object(BibleMeta, key)
def exists(self, name):
"""
Check cache to see if new bible
Check cache to see if new bible.
"""
if not isinstance(name, unicode):
name = unicode(name)

View File

@ -32,6 +32,7 @@ from PyQt4 import QtCore, QtGui
from openlp.core.lib import MediaManagerItem, Receiver, BaseListWithDnD, \
ItemCapabilities, translate
from openlp.plugins.bibles.forms import ImportWizardForm
from openlp.plugins.bibles.lib.db import BibleDB
log = logging.getLogger(__name__)
@ -374,7 +375,7 @@ class BibleMediaItem(MediaManagerItem):
self.AdvancedSecondBibleComboBox.clear()
self.QuickSecondBibleComboBox.addItem(u'')
self.AdvancedSecondBibleComboBox.addItem(u'')
bibles = self.parent.manager.get_bibles()
bibles = self.parent.manager.get_bibles().keys()
# load bibles into the combo boxes
first = True
for bible in bibles:
@ -407,21 +408,21 @@ class BibleMediaItem(MediaManagerItem):
self.initialiseChapterVerse(bible, book[u'name'],
book[u'chapters'])
def initialiseChapterVerse(self, bible, book, chapters):
def initialiseChapterVerse(self, bible, book, chapter_count):
log.debug(u'initialiseChapterVerse %s, %s', bible, book)
self.chapters_from = chapters
self.verses = self.parent.manager.get_verse_count(bible, book, 1)
if self.verses == 0:
self.chapter_count = chapter_count
verse_count = self.parent.manager.get_verse_count(bible, book, 1)
if verse_count == 0:
self.AdvancedSearchButton.setEnabled(False)
self.AdvancedMessage.setText(
translate('BiblesPlugin.MediaItem', 'Bible not fully loaded.'))
else:
self.AdvancedSearchButton.setEnabled(True)
self.AdvancedMessage.setText(u'')
self.adjustComboBox(1, self.chapters_from, self.AdvancedFromChapter)
self.adjustComboBox(1, self.chapters_from, self.AdvancedToChapter)
self.adjustComboBox(1, self.verses, self.AdvancedFromVerse)
self.adjustComboBox(1, self.verses, self.AdvancedToVerse)
self.adjustComboBox(1, self.chapter_count, self.AdvancedFromChapter)
self.adjustComboBox(1, self.chapter_count, self.AdvancedToChapter)
self.adjustComboBox(1, verse_count, self.AdvancedFromVerse)
self.adjustComboBox(1, verse_count, self.AdvancedToVerse)
def onAdvancedVersionComboBox(self):
self.initialiseBible(
@ -435,47 +436,69 @@ class BibleMediaItem(MediaManagerItem):
self.AdvancedBookComboBox.itemData(item).toInt()[0])
def onAdvancedFromVerse(self):
frm = int(self.AdvancedFromVerse.currentText())
chapter_frm = int(self.AdvancedFromChapter.currentText())
chapter_from = int(self.AdvancedFromChapter.currentText())
chapter_to = int(self.AdvancedToChapter.currentText())
if chapter_frm == chapter_to:
if chapter_from == chapter_to:
bible = unicode(self.AdvancedVersionComboBox.currentText())
book = unicode(self.AdvancedBookComboBox.currentText())
verses = self.parent.manager.get_verse_count(bible, book, chapter_to)
self.adjustComboBox(frm, verses, self.AdvancedToVerse)
verse_from = int(self.AdvancedFromVerse.currentText())
verse_count = self.parent.manager.get_verse_count(bible, book,
chapter_to)
self.adjustComboBox(verse_from, verse_count,
self.AdvancedToVerse, True)
def onAdvancedToChapter(self):
chapter_frm = int(self.AdvancedFromChapter.currentText())
chapter_to = int(self.AdvancedToChapter.currentText())
bible = unicode(self.AdvancedVersionComboBox.currentText())
book = unicode(self.AdvancedBookComboBox.currentText())
verses = self.parent.manager.get_verse_count(bible, book, chapter_to)
if chapter_frm != chapter_to:
self.adjustComboBox(1, verses, self.AdvancedToVerse)
chapter_from = int(self.AdvancedFromChapter.currentText())
chapter_to = int(self.AdvancedToChapter.currentText())
verse_from = int(self.AdvancedFromVerse.currentText())
verse_to = int(self.AdvancedToVerse.currentText())
verse_count = self.parent.manager.get_verse_count(bible, book,
chapter_to)
if chapter_from == chapter_to and verse_from > verse_to:
self.adjustComboBox(verse_from, verse_count, self.AdvancedToVerse)
else:
frm = int(self.AdvancedFromVerse.currentText())
to = int(self.AdvancedToVerse.currentText())
if to < frm:
self.adjustComboBox(frm, verses, self.AdvancedToVerse)
self.adjustComboBox(1, verse_count, self.AdvancedToVerse)
def onAdvancedFromChapter(self):
bible = unicode(self.AdvancedVersionComboBox.currentText())
book = unicode(self.AdvancedBookComboBox.currentText())
chapter_frm = int(self.AdvancedFromChapter.currentText())
self.adjustComboBox(chapter_frm, self.chapters_from,
chapter_from = int(self.AdvancedFromChapter.currentText())
chapter_to = int(self.AdvancedToChapter.currentText())
verse_count = self.parent.manager.get_verse_count(bible, book,
chapter_from)
self.adjustComboBox(1, verse_count, self.AdvancedFromVerse)
if chapter_from > chapter_to:
self.adjustComboBox(1, verse_count, self.AdvancedToVerse)
self.adjustComboBox(chapter_from, self.chapter_count,
self.AdvancedToChapter)
verse = self.parent.manager.get_verse_count(bible, book, chapter_frm)
self.adjustComboBox(1, verse, self.AdvancedToVerse)
self.adjustComboBox(1, verse, self.AdvancedFromVerse)
elif chapter_from == chapter_to:
self.adjustComboBox(chapter_from, self.chapter_count,
self.AdvancedToChapter)
self.adjustComboBox(1, verse_count, self.AdvancedToVerse, True)
else:
self.adjustComboBox(chapter_from, self.chapter_count,
self.AdvancedToChapter, True)
def adjustComboBox(self, range_from, range_to, combo):
def adjustComboBox(self, range_from, range_to, combo, restore=False):
"""
``restore``
If True, then the combo's currentText will be restored after
adjusting (if possible).
"""
log.debug(u'adjustComboBox %s, %s, %s', combo, range_from, range_to)
if restore:
old_text = unicode(combo.currentText())
combo.clear()
for i in range(int(range_from), int(range_to) + 1):
combo.addItem(unicode(i))
if restore and combo.findText(old_text) != -1:
combo.setCurrentIndex(combo.findText(old_text))
def onAdvancedSearchButton(self):
log.debug(u'Advanced Search Button pressed')
self.AdvancedSearchButton.setEnabled(False)
bible = unicode(self.AdvancedVersionComboBox.currentText())
dual_bible = unicode(self.AdvancedSecondBibleComboBox.currentText())
book = unicode(self.AdvancedBookComboBox.currentText())
@ -508,16 +531,30 @@ class BibleMediaItem(MediaManagerItem):
self.displayResults(bible, dual_bible)
else:
self.displayResults(bible, dual_bible)
self.AdvancedSearchButton.setEnabled(True)
def onQuickSearchButton(self):
log.debug(u'Quick Search Button pressed')
self.QuickSearchButton.setEnabled(False)
bible = unicode(self.QuickVersionComboBox.currentText())
dual_bible = unicode(self.QuickSecondBibleComboBox.currentText())
text = unicode(self.QuickSearchEdit.text())
if self.QuickSearchComboBox.currentIndex() == 0:
# We are doing a 'Verse Search'.
self.search_results = self.parent.manager.get_verses(bible, text)
if dual_bible:
if dual_bible and self.search_results:
self.dual_search_results = self.parent.manager.get_verses(
dual_bible, text)
else:
# We are doing a ' Text Search'.
bibles = self.parent.manager.get_bibles()
self.search_results = self.parent.manager.verse_search(bible, text)
if dual_bible and self.search_results:
text = []
for verse in self.search_results:
text.append((verse.book.name, verse.chapter, verse.verse,
verse.verse))
self.dual_search_results = bibles[dual_bible].get_verses(text)
if self.ClearQuickSearchComboBox.currentIndex() == 0:
self.listView.clear()
if self.listView.count() != 0 and self.search_results:
@ -537,6 +574,7 @@ class BibleMediaItem(MediaManagerItem):
self.displayResults(bible, dual_bible)
elif self.search_results:
self.displayResults(bible, dual_bible)
self.QuickSearchButton.setEnabled(True)
def displayResults(self, bible, dual_bible=u''):
"""
@ -545,16 +583,16 @@ class BibleMediaItem(MediaManagerItem):
"""
version = self.parent.manager.get_meta_data(bible, u'Version')
copyright = self.parent.manager.get_meta_data(bible, u'Copyright')
permission = self.parent.manager.get_meta_data(bible, u'Permissions')
permissions = self.parent.manager.get_meta_data(bible, u'Permissions')
if dual_bible:
dual_version = self.parent.manager.get_meta_data(dual_bible,
u'Version')
dual_copyright = self.parent.manager.get_meta_data(dual_bible,
u'Copyright')
dual_permission = self.parent.manager.get_meta_data(dual_bible,
dual_permissions = self.parent.manager.get_meta_data(dual_bible,
u'Permissions')
if not dual_permission:
dual_permission = u''
if not dual_permissions:
dual_permissions = u''
# We count the number of rows which are maybe already present.
start_count = self.listView.count()
for count, verse in enumerate(self.search_results):
@ -566,12 +604,12 @@ class BibleMediaItem(MediaManagerItem):
'bible': QtCore.QVariant(bible),
'version': QtCore.QVariant(version.value),
'copyright': QtCore.QVariant(copyright.value),
'permission': QtCore.QVariant(permission.value),
'permissions': QtCore.QVariant(permissions.value),
'text': QtCore.QVariant(verse.text),
'dual_bible': QtCore.QVariant(dual_bible),
'dual_version': QtCore.QVariant(dual_version.value),
'dual_copyright': QtCore.QVariant(dual_copyright.value),
'dual_permission': QtCore.QVariant(dual_permission.value),
'dual_permissions': QtCore.QVariant(dual_permissions.value),
'dual_text': QtCore.QVariant(
self.dual_search_results[count].text)
}
@ -586,12 +624,12 @@ class BibleMediaItem(MediaManagerItem):
'bible': QtCore.QVariant(bible),
'version': QtCore.QVariant(version.value),
'copyright': QtCore.QVariant(copyright.value),
'permission': QtCore.QVariant(permission.value),
'permissions': QtCore.QVariant(permissions.value),
'text': QtCore.QVariant(verse.text),
'dual_bible': QtCore.QVariant(u''),
'dual_version': QtCore.QVariant(u''),
'dual_copyright': QtCore.QVariant(u''),
'dual_permission': QtCore.QVariant(u''),
'dual_permissions': QtCore.QVariant(u''),
'dual_text': QtCore.QVariant(u'')
}
bible_text = u' %s %d:%d (%s)' % (verse.book.name,
@ -637,20 +675,20 @@ class BibleMediaItem(MediaManagerItem):
bible = self._decodeQtObject(bitem, 'bible')
version = self._decodeQtObject(bitem, 'version')
copyright = self._decodeQtObject(bitem, 'copyright')
permission = self._decodeQtObject(bitem, 'permission')
permissions = self._decodeQtObject(bitem, 'permissions')
text = self._decodeQtObject(bitem, 'text')
dual_bible = self._decodeQtObject(bitem, 'dual_bible')
dual_version = self._decodeQtObject(bitem, 'dual_version')
dual_copyright = self._decodeQtObject(bitem, 'dual_copyright')
dual_permission = self._decodeQtObject(bitem, 'dual_permission')
dual_permissions = self._decodeQtObject(bitem, 'dual_permissions')
dual_text = self._decodeQtObject(bitem, 'dual_text')
verse_text = self.formatVerse(old_chapter, chapter, verse)
footer = u'%s (%s %s %s)' % (book, version, copyright, permission)
footer = u'%s (%s %s %s)' % (book, version, copyright, permissions)
if footer not in raw_footer:
raw_footer.append(footer)
if dual_bible:
footer = u'%s (%s %s %s)' % (book, dual_version, dual_copyright,
dual_permission)
dual_permissions)
if footer not in raw_footer:
raw_footer.append(footer)
bible_text = u'%s %s\n\n%s %s' % (verse_text, text, verse_text,

View File

@ -28,7 +28,7 @@ import logging
from forms import EditCustomForm
from openlp.core.lib import Plugin, build_icon, translate
from openlp.core.lib import Plugin, StringContent, build_icon, translate
from openlp.core.lib.db import Manager
from openlp.plugins.custom.lib import CustomMediaItem, CustomTab
from openlp.plugins.custom.lib.db import CustomSlide, init_schema
@ -55,11 +55,12 @@ class CustomPlugin(Plugin):
self.icon = build_icon(self.icon_path)
def getSettingsTab(self):
return CustomTab(self.name)
visible_name = self.getString(StringContent.VisibleName)
return CustomTab(self.name, visible_name[u'title'])
def getMediaManagerItem(self):
# Create the CustomManagerItem object
return CustomMediaItem(self, self.icon, self.name)
return CustomMediaItem(self, self, self.icon)
def about(self):
about_text = translate('CustomPlugin', '<strong>Custom Plugin</strong>'
@ -96,3 +97,66 @@ class CustomPlugin(Plugin):
for custom in customsUsingTheme:
custom.theme_name = newTheme
self.custommanager.save_object(custom)
def setPluginTextStrings(self):
"""
Called to define all translatable texts of the plugin
"""
## Name PluginList ##
self.textStrings[StringContent.Name] = {
u'singular': translate('CustomsPlugin', 'Custom'),
u'plural': translate('CustomsPlugin', 'Customs')
}
## Name for MediaDockManager, SettingsManager ##
self.textStrings[StringContent.VisibleName] = {
u'title': translate('CustomsPlugin', 'Customs')
}
# Middle Header Bar
## Import Button ##
self.textStrings[StringContent.Import] = {
u'title': translate('CustomsPlugin', 'Import'),
u'tooltip': translate('CustomsPlugin',
'Import a Custom')
}
## Load Button ##
self.textStrings[StringContent.Load] = {
u'title': translate('CustomsPlugin', 'Load'),
u'tooltip': translate('CustomsPlugin',
'Load a new Custom')
}
## New Button ##
self.textStrings[StringContent.New] = {
u'title': translate('CustomsPlugin', 'Add'),
u'tooltip': translate('CustomsPlugin',
'Add a new Custom')
}
## Edit Button ##
self.textStrings[StringContent.Edit] = {
u'title': translate('CustomsPlugin', 'Edit'),
u'tooltip': translate('CustomsPlugin',
'Edit the selected Custom')
}
## Delete Button ##
self.textStrings[StringContent.Delete] = {
u'title': translate('CustomsPlugin', 'Delete'),
u'tooltip': translate('CustomsPlugin',
'Delete the selected Custom')
}
## Preview ##
self.textStrings[StringContent.Preview] = {
u'title': translate('CustomsPlugin', 'Preview'),
u'tooltip': translate('CustomsPlugin',
'Preview the selected Custom')
}
## Live Button ##
self.textStrings[StringContent.Live] = {
u'title': translate('CustomsPlugin', 'Live'),
u'tooltip': translate('CustomsPlugin',
'Send the selected Custom live')
}
## Add to service Button ##
self.textStrings[StringContent.Service] = {
u'title': translate('CustomsPlugin', 'Service'),
u'tooltip': translate('CustomsPlugin',
'Add the selected Custom to the service')
}

View File

@ -25,3 +25,4 @@
###############################################################################
from editcustomform import EditCustomForm
from editcustomslideform import EditCustomSlideForm

View File

@ -26,7 +26,7 @@
from PyQt4 import QtCore, QtGui
from openlp.core.lib import build_icon, translate, SpellTextEdit
from openlp.core.lib import build_icon, translate
class Ui_CustomEditDialog(object):
def setupUi(self, customEditDialog):
@ -36,6 +36,70 @@ class Ui_CustomEditDialog(object):
build_icon(u':/icon/openlp.org-icon-32.bmp'))
self.gridLayout = QtGui.QGridLayout(customEditDialog)
self.gridLayout.setObjectName(u'gridLayout')
self.horizontalLayout3 = QtGui.QHBoxLayout()
self.horizontalLayout3.setObjectName(u'horizontalLayout3')
self.themeLabel = QtGui.QLabel(customEditDialog)
self.themeLabel.setObjectName(u'themeLabel')
self.horizontalLayout3.addWidget(self.themeLabel)
self.themeComboBox = QtGui.QComboBox(customEditDialog)
self.themeLabel.setBuddy(self.themeComboBox)
self.themeComboBox.setObjectName(u'themeComboBox')
self.horizontalLayout3.addWidget(self.themeComboBox)
self.gridLayout.addLayout(self.horizontalLayout3, 2, 0, 1, 1)
self.horizontalLayout2 = QtGui.QHBoxLayout()
self.horizontalLayout2.setObjectName(u'horizontalLayout2')
self.creditLabel = QtGui.QLabel(customEditDialog)
self.creditLabel.setObjectName(u'creditLabel')
self.horizontalLayout2.addWidget(self.creditLabel)
self.creditEdit = QtGui.QLineEdit(customEditDialog)
self.creditLabel.setBuddy(self.creditEdit)
self.creditEdit.setObjectName(u'creditEdit')
self.horizontalLayout2.addWidget(self.creditEdit)
self.gridLayout.addLayout(self.horizontalLayout2, 3, 0, 1, 1)
self.buttonBox = QtGui.QDialogButtonBox(customEditDialog)
self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel |
QtGui.QDialogButtonBox.Save)
self.buttonBox.setObjectName(u'buttonBox')
self.gridLayout.addWidget(self.buttonBox, 4, 0, 1, 1)
self.horizontalLayout4 = QtGui.QHBoxLayout()
self.horizontalLayout4.setObjectName(u'horizontalLayout4')
self.slideListView = QtGui.QListWidget(customEditDialog)
self.slideListView.setAlternatingRowColors(True)
self.slideListView.setObjectName(u'slideListView')
self.horizontalLayout4.addWidget(self.slideListView)
self.verticalLayout = QtGui.QVBoxLayout()
self.verticalLayout.setObjectName(u'verticalLayout')
self.addButton = QtGui.QPushButton(customEditDialog)
self.addButton.setObjectName(u'addButton')
self.verticalLayout.addWidget(self.addButton)
self.editButton = QtGui.QPushButton(customEditDialog)
self.editButton.setObjectName(u'editButton')
self.verticalLayout.addWidget(self.editButton)
self.editAllButton = QtGui.QPushButton(customEditDialog)
self.editAllButton.setObjectName(u'editAllButton')
self.verticalLayout.addWidget(self.editAllButton)
self.deleteButton = QtGui.QPushButton(customEditDialog)
self.deleteButton.setObjectName(u'deleteButton')
self.verticalLayout.addWidget(self.deleteButton)
spacerItem = QtGui.QSpacerItem(20, 128, QtGui.QSizePolicy.Minimum,
QtGui.QSizePolicy.Expanding)
self.verticalLayout.addItem(spacerItem)
self.upButton = QtGui.QPushButton(customEditDialog)
icon1 = QtGui.QIcon()
icon1.addPixmap(QtGui.QPixmap(u':/services/service_up.png'),
QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.upButton.setIcon(icon1)
self.upButton.setObjectName(u'upButton')
self.verticalLayout.addWidget(self.upButton)
self.downButton = QtGui.QPushButton(customEditDialog)
icon2 = QtGui.QIcon()
icon2.addPixmap(QtGui.QPixmap(u':/services/service_down.png'),
QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.downButton.setIcon(icon2)
self.downButton.setObjectName(u'downButton')
self.verticalLayout.addWidget(self.downButton)
self.horizontalLayout4.addLayout(self.verticalLayout)
self.gridLayout.addLayout(self.horizontalLayout4, 1, 0, 1, 1)
self.horizontalLayout = QtGui.QHBoxLayout()
self.horizontalLayout.setObjectName(u'horizontalLayout')
self.titleLabel = QtGui.QLabel(customEditDialog)
@ -46,91 +110,6 @@ class Ui_CustomEditDialog(object):
self.titleEdit.setObjectName(u'titleEdit')
self.horizontalLayout.addWidget(self.titleEdit)
self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 1)
self.horizontalLayout4 = QtGui.QHBoxLayout()
self.horizontalLayout4.setObjectName(u'horizontalLayout4')
self.verseListView = QtGui.QListWidget(customEditDialog)
self.verseListView.setAlternatingRowColors(True)
self.verseListView.setObjectName(u'verseListView')
self.horizontalLayout4.addWidget(self.verseListView)
self.verticalLayout = QtGui.QVBoxLayout()
self.verticalLayout.setObjectName(u'verticalLayout')
self.upButton = QtGui.QPushButton(customEditDialog)
self.upButton.setIcon(build_icon(u':/services/service_up.png'))
self.upButton.setObjectName(u'upButton')
self.verticalLayout.addWidget(self.upButton)
spacerItem = QtGui.QSpacerItem(20, 128, QtGui.QSizePolicy.Minimum,
QtGui.QSizePolicy.Expanding)
self.verticalLayout.addItem(spacerItem)
self.downButton = QtGui.QPushButton(customEditDialog)
self.downButton.setIcon(build_icon(u':/services/service_down.png'))
self.downButton.setObjectName(u'downButton')
self.verticalLayout.addWidget(self.downButton)
self.horizontalLayout4.addLayout(self.verticalLayout)
self.gridLayout.addLayout(self.horizontalLayout4, 1, 0, 1, 1)
self.editWidget = QtGui.QWidget(customEditDialog)
self.editWidget.setObjectName(u'editWidget')
self.editLayout3 = QtGui.QHBoxLayout(self.editWidget)
self.editLayout3.setSpacing(8)
self.editLayout3.setMargin(0)
self.editLayout3.setObjectName(u'editLayout3')
self.verseTextEdit = SpellTextEdit(self)
self.verseTextEdit.setObjectName(u'verseTextEdit')
self.editLayout3.addWidget(self.verseTextEdit)
self.buttonWidget = QtGui.QWidget(self.editWidget)
self.buttonWidget.setObjectName(u'buttonWidget')
self.verticalLayout2 = QtGui.QVBoxLayout(self.buttonWidget)
self.verticalLayout2.setObjectName(u'verticalLayout2')
self.addButton = QtGui.QPushButton(self.buttonWidget)
self.addButton.setObjectName(u'addButton')
self.verticalLayout2.addWidget(self.addButton)
self.editButton = QtGui.QPushButton(self.buttonWidget)
self.editButton.setObjectName(u'editButton')
self.verticalLayout2.addWidget(self.editButton)
self.editAllButton = QtGui.QPushButton(self.buttonWidget)
self.editAllButton.setObjectName(u'editAllButton')
self.verticalLayout2.addWidget(self.editAllButton)
self.saveButton = QtGui.QPushButton(self.buttonWidget)
self.saveButton.setObjectName(u'saveButton')
self.verticalLayout2.addWidget(self.saveButton)
self.deleteButton = QtGui.QPushButton(self.buttonWidget)
self.deleteButton.setObjectName(u'deleteButton')
self.verticalLayout2.addWidget(self.deleteButton)
self.clearButton = QtGui.QPushButton(self.buttonWidget)
self.clearButton.setObjectName(u'clearButton')
self.verticalLayout2.addWidget(self.clearButton)
self.splitButton = QtGui.QPushButton(self.buttonWidget)
self.splitButton.setObjectName(u'splitButton')
self.verticalLayout2.addWidget(self.splitButton)
spacerItem1 = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum,
QtGui.QSizePolicy.Expanding)
self.verticalLayout2.addItem(spacerItem1)
self.editLayout3.addWidget(self.buttonWidget)
self.gridLayout.addWidget(self.editWidget, 2, 0, 1, 1)
self.horizontalLayout3 = QtGui.QHBoxLayout()
self.horizontalLayout3.setObjectName(u'horizontalLayout3')
self.themeLabel = QtGui.QLabel(customEditDialog)
self.themeLabel.setObjectName(u'themeLabel')
self.horizontalLayout3.addWidget(self.themeLabel)
self.themeComboBox = QtGui.QComboBox(customEditDialog)
self.themeLabel.setBuddy(self.themeComboBox)
self.themeComboBox.setObjectName(u'themeComboBox')
self.horizontalLayout3.addWidget(self.themeComboBox)
self.gridLayout.addLayout(self.horizontalLayout3, 3, 0, 1, 1)
self.horizontalLayout2 = QtGui.QHBoxLayout()
self.horizontalLayout2.setObjectName(u'horizontalLayout2')
self.creditLabel = QtGui.QLabel(customEditDialog)
self.creditLabel.setObjectName(u'creditLabel')
self.horizontalLayout2.addWidget(self.creditLabel)
self.creditEdit = QtGui.QLineEdit(customEditDialog)
self.creditLabel.setBuddy(self.creditEdit)
self.creditEdit.setObjectName(u'creditEdit')
self.horizontalLayout2.addWidget(self.creditEdit)
self.gridLayout.addLayout(self.horizontalLayout2, 4, 0, 1, 1)
self.buttonBox = QtGui.QDialogButtonBox(customEditDialog)
self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel |
QtGui.QDialogButtonBox.Save)
self.buttonBox.setObjectName(u'buttonBox')
self.gridLayout.addWidget(self.buttonBox, 5, 0, 1, 1)
self.retranslateUi(customEditDialog)
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(u'accepted()'),
customEditDialog.accept)
@ -150,39 +129,25 @@ class Ui_CustomEditDialog(object):
self.titleLabel.setText(
translate('CustomPlugin.EditCustomForm', '&Title:'))
self.addButton.setText(
translate('CustomPlugin.EditCustomForm', 'Add New'))
translate('CustomPlugin.EditCustomForm', '&Add'))
self.addButton.setToolTip(
translate('CustomPlugin.EditCustomForm', 'Add a new slide at '
'bottom.'))
self.editButton.setText(
translate('CustomPlugin.EditCustomForm', 'Edit'))
translate('CustomPlugin.EditCustomForm', '&Edit'))
self.editButton.setToolTip(
translate('CustomPlugin.EditCustomForm', 'Edit the selected '
'slide.'))
self.editAllButton.setText(
translate('CustomPlugin.EditCustomForm', 'Edit All'))
translate('CustomPlugin.EditCustomForm', 'Ed&it All'))
self.editAllButton.setToolTip(
translate('CustomPlugin.EditCustomForm', 'Edit all the slides at '
'once.'))
self.saveButton.setText(
translate('CustomPlugin.EditCustomForm', 'Save'))
self.saveButton.setToolTip(
translate('CustomPlugin.EditCustomForm', 'Save the slide currently '
'being edited.'))
self.deleteButton.setText(
translate('CustomPlugin.EditCustomForm', 'Delete'))
translate('CustomPlugin.EditCustomForm', '&Delete'))
self.deleteButton.setToolTip(
translate('CustomPlugin.EditCustomForm', 'Delete the selected '
'slide.'))
self.clearButton.setText(
translate('CustomPlugin.EditCustomForm', 'Clear'))
self.clearButton.setToolTip(
translate('CustomPlugin.EditCustomForm', 'Clear edit area'))
self.splitButton.setText(
translate('CustomPlugin.EditCustomForm', 'Split Slide'))
self.splitButton.setToolTip(
translate('CustomPlugin.EditCustomForm', 'Split a slide into two '
'by inserting a slide splitter.'))
self.themeLabel.setText(
translate('CustomPlugin.EditCustomForm', 'The&me:'))
self.creditLabel.setText(

View File

@ -32,6 +32,7 @@ from openlp.core.lib import Receiver, translate
from openlp.plugins.custom.lib import CustomXMLBuilder, CustomXMLParser
from openlp.plugins.custom.lib.db import CustomSlide
from editcustomdialog import Ui_CustomEditDialog
from editcustomslideform import EditCustomSlideForm
log = logging.getLogger(__name__)
@ -61,28 +62,20 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
QtCore.SIGNAL(u'pressed()'), self.onEditButtonPressed)
QtCore.QObject.connect(self.editAllButton,
QtCore.SIGNAL(u'pressed()'), self.onEditAllButtonPressed)
QtCore.QObject.connect(self.saveButton,
QtCore.SIGNAL(u'pressed()'), self.onSaveButtonPressed)
QtCore.QObject.connect(self.deleteButton,
QtCore.SIGNAL(u'pressed()'), self.onDeleteButtonPressed)
QtCore.QObject.connect(self.clearButton,
QtCore.SIGNAL(u'pressed()'), self.onClearButtonPressed)
QtCore.QObject.connect(self.upButton,
QtCore.SIGNAL(u'pressed()'), self.onUpButtonPressed)
QtCore.QObject.connect(self.downButton,
QtCore.SIGNAL(u'pressed()'), self.onDownButtonPressed)
QtCore.QObject.connect(self.splitButton,
QtCore.SIGNAL(u'pressed()'), self.onSplitButtonPressed)
QtCore.QObject.connect(self.verseListView,
QtCore.SIGNAL(u'itemDoubleClicked(QListWidgetItem*)'),
self.onVerseListViewSelected)
QtCore.QObject.connect(self.verseListView,
QtCore.QObject.connect(self.slideListView,
QtCore.SIGNAL(u'itemClicked(QListWidgetItem*)'),
self.onVerseListViewPressed)
self.onSlideListViewPressed)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'theme_update_list'), self.loadThemes)
# Create other objects and forms
# Create other objects and forms.
self.custommanager = custommanager
self.editSlideForm = EditCustomSlideForm(self)
self.initialise()
def onPreview(self, button):
@ -92,21 +85,15 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
Receiver.send_message(u'custom_preview')
def initialise(self):
self.editAll = False
self.addButton.setEnabled(True)
self.deleteButton.setEnabled(False)
self.editButton.setEnabled(False)
self.editAllButton.setEnabled(True)
self.saveButton.setEnabled(False)
self.clearButton.setEnabled(False)
self.splitButton.setEnabled(False)
self.titleEdit.setText(u'')
self.creditEdit.setText(u'')
self.verseTextEdit.clear()
self.verseListView.clear()
#make sure we have a new item
self.slideListView.clear()
# Make sure we have a new item.
self.customSlide = CustomSlide()
self.themeComboBox.addItem(u'')
def loadThemes(self, themelist):
self.themeComboBox.clear()
@ -115,6 +102,16 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
self.themeComboBox.addItem(themename)
def loadCustom(self, id, preview=False):
"""
Called when editing or creating a new custom.
``id``
The cutom's id. If zero, then a new custom is created.
``preview``
States whether the custom is edited while being previewed in the
preview panel.
"""
self.customSlide = CustomSlide()
self.initialise()
if id != 0:
@ -122,9 +119,9 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
self.titleEdit.setText(self.customSlide.title)
self.creditEdit.setText(self.customSlide.credits)
customXML = CustomXMLParser(self.customSlide.text)
verseList = customXML.get_verses()
for verse in verseList:
self.verseListView.addItem(verse[1])
slideList = customXML.get_verses()
for slide in slideList:
self.slideListView.addItem(slide[1])
theme = self.customSlide.theme_name
id = self.themeComboBox.findText(theme, QtCore.Qt.MatchExactly)
if id == -1:
@ -132,7 +129,8 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
self.themeComboBox.setCurrentIndex(id)
else:
self.themeComboBox.setCurrentIndex(0)
#if not preview hide the preview button
self.editAllButton.setEnabled(False)
# If not preview hide the preview button.
self.previewButton.setVisible(False)
if preview:
self.previewButton.setVisible(True)
@ -148,6 +146,9 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
self.close()
def saveCustom(self):
"""
Saves the custom.
"""
valid, message = self._validate()
if not valid:
QtGui.QMessageBox.critical(self,
@ -157,9 +158,9 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
sxml.new_document()
sxml.add_lyrics_to_song()
count = 1
for i in range(0, self.verseListView.count()):
for i in range(0, self.slideListView.count()):
sxml.add_verse_to_lyrics(u'custom', unicode(count),
unicode(self.verseListView.item(i).text()))
unicode(self.slideListView.item(i).text()))
count += 1
self.customSlide.title = unicode(self.titleEdit.displayText(), u'utf-8')
self.customSlide.text = unicode(sxml.extract_xml(), u'utf-8')
@ -170,114 +171,103 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
return self.custommanager.save_object(self.customSlide)
def onUpButtonPressed(self):
selectedRow = self.verseListView.currentRow()
selectedRow = self.slideListView.currentRow()
if selectedRow != 0:
qw = self.verseListView.takeItem(selectedRow)
self.verseListView.insertItem(selectedRow - 1, qw)
self.verseListView.setCurrentRow(selectedRow - 1)
qw = self.slideListView.takeItem(selectedRow)
self.slideListView.insertItem(selectedRow - 1, qw)
self.slideListView.setCurrentRow(selectedRow - 1)
def onDownButtonPressed(self):
selectedRow = self.verseListView.currentRow()
selectedRow = self.slideListView.currentRow()
# zero base arrays
if selectedRow != self.verseListView.count() - 1:
qw = self.verseListView.takeItem(selectedRow)
self.verseListView.insertItem(selectedRow + 1, qw)
self.verseListView.setCurrentRow(selectedRow + 1)
if selectedRow != self.slideListView.count() - 1:
qw = self.slideListView.takeItem(selectedRow)
self.slideListView.insertItem(selectedRow + 1, qw)
self.slideListView.setCurrentRow(selectedRow + 1)
def onClearButtonPressed(self):
self.verseTextEdit.clear()
self.editAll = False
self.addButton.setEnabled(True)
self.editAllButton.setEnabled(True)
self.saveButton.setEnabled(False)
def onVerseListViewPressed(self, item):
def onSlideListViewPressed(self, item):
self.deleteButton.setEnabled(True)
self.editButton.setEnabled(True)
def onVerseListViewSelected(self, item):
self.editText(item.text())
def onAddButtonPressed(self):
self.verseListView.addItem(self.verseTextEdit.toPlainText())
self.deleteButton.setEnabled(False)
self.verseTextEdit.clear()
self.editSlideForm.setText(u'')
if self.editSlideForm.exec_():
for slide in self.editSlideForm.getText():
self.slideListView.addItem(slide)
self.editAllButton.setEnabled(True)
def onEditButtonPressed(self):
self.editText(self.verseListView.currentItem().text())
self.editSlideForm.setText(self.slideListView.currentItem().text())
if self.editSlideForm.exec_():
self.updateSlideList(self.editSlideForm.getText())
def onEditAllButtonPressed(self):
self.editAll = True
self.addButton.setEnabled(False)
self.splitButton.setEnabled(True)
if self.verseListView.count() > 0:
verse_list = u''
for row in range(0, self.verseListView.count()):
item = self.verseListView.item(row)
verse_list += item.text()
if row != self.verseListView.count() - 1:
verse_list += u'\n[---]\n'
self.editText(verse_list)
"""
Edits all slides.
"""
if self.slideListView.count() > 0:
slide_list = u''
for row in range(0, self.slideListView.count()):
item = self.slideListView.item(row)
slide_list += item.text()
if row != self.slideListView.count() - 1:
slide_list += u'\n[---]\n'
self.editSlideForm.setText(slide_list)
if self.editSlideForm.exec_():
self.updateSlideList(self.editSlideForm.getText(), True)
def editText(self, text):
self.beforeText = text
self.verseTextEdit.setPlainText(text)
def updateSlideList(self, slides, edit_all=False):
"""
Updates the slide list after editing slides.
``slides``
A list of all slides which have been edited.
``edit_all``
Indicates if all slides or only one slide has been edited.
"""
if len(slides) == 1:
self.slideListView.currentItem().setText(slides[0])
else:
if edit_all:
self.slideListView.clear()
for slide in slides:
self.slideListView.addItem(slide)
else:
old_slides = []
old_row = self.slideListView.currentRow()
# Create a list with all (old/unedited) slides.
old_slides = [self.slideListView.item(row).text() for row in \
range(0, self.slideListView.count())]
self.slideListView.clear()
old_slides.pop(old_row)
# Insert all slides to make the old_slides list complete.
for slide in slides:
old_slides.insert(old_row, slide)
for slide in old_slides:
self.slideListView.addItem(slide)
self.slideListView.repaint()
def onDeleteButtonPressed(self):
self.slideListView.takeItem(self.slideListView.currentRow())
self.editButton.setEnabled(True)
self.editAllButton.setEnabled(True)
if self.slideListView.count() == 0:
self.deleteButton.setEnabled(False)
self.editButton.setEnabled(False)
self.editAllButton.setEnabled(False)
self.saveButton.setEnabled(True)
self.clearButton.setEnabled(True)
def onSaveButtonPressed(self):
if self.editAll:
self.verseListView.clear()
for row in unicode(self.verseTextEdit.toPlainText()).split(
u'\n[---]\n'):
self.verseListView.addItem(row)
else:
self.verseListView.currentItem().setText(
self.verseTextEdit.toPlainText())
#number of lines has change
if len(self.beforeText.split(u'\n')) != \
len(self.verseTextEdit.toPlainText().split(u'\n')):
tempList = {}
for row in range(0, self.verseListView.count()):
tempList[row] = self.verseListView.item(row).text()
self.verseListView.clear()
for row in range (0, len(tempList)):
self.verseListView.addItem(tempList[row])
self.verseListView.repaint()
self.addButton.setEnabled(True)
self.saveButton.setEnabled(False)
self.editButton.setEnabled(False)
self.editAllButton.setEnabled(True)
self.splitButton.setEnabled(False)
self.verseTextEdit.clear()
def onSplitButtonPressed(self):
if self.verseTextEdit.textCursor().columnNumber() != 0:
self.verseTextEdit.insertPlainText(u'\n')
self.verseTextEdit.insertPlainText(u'[---]\n' )
self.verseTextEdit.setFocus()
def onDeleteButtonPressed(self):
self.verseListView.takeItem(self.verseListView.currentRow())
self.editButton.setEnabled(False)
self.editAllButton.setEnabled(True)
def _validate(self):
"""
Checks whether a custom is valid or not.
"""
# We must have a title.
if len(self.titleEdit.displayText()) == 0:
self.titleEdit.setFocus()
return False, translate('CustomPlugin.EditCustomForm',
'You need to type in a title.')
# must have 1 slide
if self.verseListView.count() == 0:
self.verseTextEdit.setFocus()
# We must have one slide.
if self.slideListView.count() == 0:
return False, translate('CustomPlugin.EditCustomForm',
'You need to add at least one slide')
if self.verseTextEdit.toPlainText():
self.verseTextEdit.setFocus()
return False, translate('CustomPlugin.EditCustomForm',
'You have one or more unsaved slides, please either save your '
'slide(s) or clear your changes.')
return True, u''

View File

@ -0,0 +1,59 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2010 Raoul Snyman #
# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
# Gorven, Scott Guerrieri, Meinert Jordan, Andreas Preikschat, Christian #
# Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon Tibble, #
# Carsten Tinggaard, Frode Woldsund #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
from PyQt4 import QtCore, QtGui
from openlp.core.lib import translate, SpellTextEdit
class Ui_CustomSlideEditDialog(object):
def setupUi(self, customSlideEditDialog):
customSlideEditDialog.setObjectName(u'customSlideEditDialog')
customSlideEditDialog.resize(474, 442)
self.buttonBox = QtGui.QDialogButtonBox(customSlideEditDialog)
self.buttonBox.setGeometry(QtCore.QRect(8, 407, 458, 32))
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel |
QtGui.QDialogButtonBox.Save)
self.buttonBox.setObjectName(u'buttonBox')
self.slideTextEdit = SpellTextEdit(self)
self.slideTextEdit.setGeometry(QtCore.QRect(8, 8, 458, 349))
self.slideTextEdit.setObjectName(u'slideTextEdit')
self.splitButton = QtGui.QPushButton(customSlideEditDialog)
self.splitButton.setGeometry(QtCore.QRect(380, 370, 85, 27))
self.splitButton.setObjectName(u'splitButton')
self.retranslateUi(customSlideEditDialog)
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(u'accepted()'),
customSlideEditDialog.accept)
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(u'rejected()'),
customSlideEditDialog.reject)
QtCore.QMetaObject.connectSlotsByName(customSlideEditDialog)
def retranslateUi(self, customSlideEditDialog):
self.splitButton.setText(
translate('CustomPlugin.EditCustomForm', 'Split Slide'))
self.splitButton.setToolTip(
translate('CustomPlugin.EditCustomForm', 'Split a slide into two '
'by inserting a slide splitter.'))

View File

@ -0,0 +1,76 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2010 Raoul Snyman #
# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
# Gorven, Scott Guerrieri, Meinert Jordan, Andreas Preikschat, Christian #
# Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon Tibble, #
# Carsten Tinggaard, Frode Woldsund #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
import logging
from PyQt4 import QtCore, QtGui
from openlp.core.lib import Receiver, translate
from editcustomslidedialog import Ui_CustomSlideEditDialog
log = logging.getLogger(__name__)
class EditCustomSlideForm(QtGui.QDialog, Ui_CustomSlideEditDialog):
"""
Class documentation goes here.
"""
log.info(u'Custom Verse Editor loaded')
def __init__(self, parent=None):
"""
Constructor
"""
QtGui.QDialog.__init__(self, parent)
self.setupUi(self)
# Connecting signals and slots
QtCore.QObject.connect(self.splitButton,
QtCore.SIGNAL(u'pressed()'), self.onSplitButtonPressed)
def setText(self, text):
"""
Set the text for slideTextEdit.
``text``
The text (unicode).
"""
self.slideTextEdit.clear()
if text:
self.slideTextEdit.setPlainText(text)
self.slideTextEdit.setFocus()
def getText(self):
"""
Returns a list with all slides.
"""
return self.slideTextEdit.toPlainText().split(u'\n[---]\n')
def onSplitButtonPressed(self):
"""
Splits a slide in two slides.
"""
if self.slideTextEdit.textCursor().columnNumber() != 0:
self.slideTextEdit.insertPlainText(u'\n')
self.slideTextEdit.insertPlainText(u'[---]\n' )
self.slideTextEdit.setFocus()

View File

@ -32,12 +32,11 @@ class CustomTab(SettingsTab):
"""
CustomTab is the Custom settings tab in the settings dialog.
"""
def __init__(self, title):
SettingsTab.__init__(self, title)
def __init__(self, title, visible_title):
SettingsTab.__init__(self, title, visible_title)
def setupUi(self):
self.setObjectName(u'CustomTab')
self.tabTitleVisible = translate('CustomPlugin.CustomTab', 'Custom')
self.customLayout = QtGui.QFormLayout(self)
self.customLayout.setSpacing(8)
self.customLayout.setMargin(8)

View File

@ -46,14 +46,12 @@ class CustomMediaItem(MediaManagerItem):
"""
log.info(u'Custom Media Item loaded')
def __init__(self, parent, icon, title):
self.PluginNameShort = u'Custom'
self.pluginNameVisible = translate('CustomPlugin.MediaItem', 'Custom')
def __init__(self, parent, plugin, icon):
self.IconPath = u'custom/custom'
# this next is a class, not an instance of a class - it will
# be instanced by the base MediaManagerItem
self.ListViewWithDnD_class = CustomListView
MediaManagerItem.__init__(self, parent, icon, title)
MediaManagerItem.__init__(self, parent, self, icon)
self.singleServiceItem = False
# Holds information about whether the edit is remotly triggered and
# which Custom is required.

View File

@ -26,7 +26,7 @@
import logging
from openlp.core.lib import Plugin, build_icon, translate
from openlp.core.lib import Plugin, StringContent, build_icon, translate
from openlp.plugins.images.lib import ImageMediaItem
log = logging.getLogger(__name__)
@ -42,7 +42,7 @@ class ImagePlugin(Plugin):
def getMediaManagerItem(self):
# Create the MediaManagerItem object
return ImageMediaItem(self, self.icon, self.name)
return ImageMediaItem(self, self, self.icon)
def about(self):
about_text = translate('ImagePlugin', '<strong>Image Plugin</strong>'
@ -57,3 +57,60 @@ class ImagePlugin(Plugin):
'selected image as a background instead of the background '
'provided by the theme.')
return about_text
def setPluginTextStrings(self):
"""
Called to define all translatable texts of the plugin
"""
## Name PluginList ##
self.textStrings[StringContent.Name] = {
u'singular': translate('ImagePlugin', 'Image'),
u'plural': translate('ImagePlugin', 'Images')
}
## Name for MediaDockManager, SettingsManager ##
self.textStrings[StringContent.VisibleName] = {
u'title': translate('ImagePlugin', 'Images')
}
# Middle Header Bar
## Load Button ##
self.textStrings[StringContent.Load] = {
u'title': translate('ImagePlugin', 'Load'),
u'tooltip': translate('ImagePlugin',
'Load a new Image')
}
## New Button ##
self.textStrings[StringContent.New] = {
u'title': translate('ImagePlugin', 'Add'),
u'tooltip': translate('ImagePlugin',
'Add a new Image')
}
## Edit Button ##
self.textStrings[StringContent.Edit] = {
u'title': translate('ImagePlugin', 'Edit'),
u'tooltip': translate('ImagePlugin',
'Edit the selected Image')
}
## Delete Button ##
self.textStrings[StringContent.Delete] = {
u'title': translate('ImagePlugin', 'Delete'),
u'tooltip': translate('ImagePlugin',
'Delete the selected Image')
}
## Preview ##
self.textStrings[StringContent.Preview] = {
u'title': translate('ImagePlugin', 'Preview'),
u'tooltip': translate('ImagePlugin',
'Preview the selected Image')
}
## Live Button ##
self.textStrings[StringContent.Live] = {
u'title': translate('ImagePlugin', 'Live'),
u'tooltip': translate('ImagePlugin',
'Send the selected Image live')
}
## Add to service Button ##
self.textStrings[StringContent.Service] = {
u'title': translate('ImagePlugin', 'Service'),
u'tooltip': translate('ImagePlugin',
'Add the selected Image to the service')
}

View File

@ -49,14 +49,12 @@ class ImageMediaItem(MediaManagerItem):
"""
log.info(u'Image Media Item loaded')
def __init__(self, parent, icon, title):
self.PluginNameShort = u'Image'
self.pluginNameVisible = translate('ImagePlugin.MediaItem', 'Image')
def __init__(self, parent, plugin, icon):
self.IconPath = u'images/image'
# this next is a class, not an instance of a class - it will
# be instanced by the base MediaManagerItem
self.ListViewWithDnD_class = ImageListView
MediaManagerItem.__init__(self, parent, icon, title)
MediaManagerItem.__init__(self, parent, self, icon)
def retranslateUi(self):
self.OnNewPrompt = translate('ImagePlugin.MediaItem',

View File

@ -25,5 +25,6 @@
###############################################################################
from mediaitem import MediaMediaItem
from mediatab import MediaTab
__all__ = ['MediaMediaItem']

View File

@ -46,9 +46,7 @@ class MediaMediaItem(MediaManagerItem):
"""
log.info(u'%s MediaMediaItem loaded', __name__)
def __init__(self, parent, icon, title):
self.PluginNameShort = u'Media'
self.pluginNameVisible = translate('MediaPlugin.MediaItem', 'Media')
def __init__(self, parent, plugin, icon):
self.IconPath = u'images/image'
self.background = False
# this next is a class, not an instance of a class - it will
@ -56,7 +54,7 @@ class MediaMediaItem(MediaManagerItem):
self.ListViewWithDnD_class = MediaListView
self.PreviewFunction = QtGui.QPixmap(
u':/media/media_video.png').toImage()
MediaManagerItem.__init__(self, parent, icon, title)
MediaManagerItem.__init__(self, parent, self, icon)
self.singleServiceItem = False
self.serviceItemIconName = u':/media/media_video.png'
@ -115,7 +113,7 @@ class MediaMediaItem(MediaManagerItem):
'You must select a media file to replace the background with.')):
item = self.listView.currentItem()
filename = unicode(item.data(QtCore.Qt.UserRole).toString())
self.parent.liveController.display.video(filename, 0)
self.parent.liveController.display.video(filename, 0, True)
self.resetButton.setVisible(True)
def generateSlideData(self, service_item, item=None):

View File

@ -0,0 +1,84 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2010 Raoul Snyman #
# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
# Gorven, Scott Guerrieri, Meinert Jordan, Andreas Preikschat, Christian #
# Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon Tibble, #
# Carsten Tinggaard, Frode Woldsund #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
from PyQt4 import QtCore, QtGui
from openlp.core.lib import SettingsTab, translate, Receiver
class MediaTab(SettingsTab):
"""
MediaTab is the Media settings tab in the settings dialog.
"""
def __init__(self, title):
SettingsTab.__init__(self, title)
def setupUi(self):
self.setObjectName(u'MediaTab')
self.tabTitleVisible = translate('MediaPlugin.MediaTab', 'Media')
self.mediaLayout = QtGui.QFormLayout(self)
self.mediaLayout.setSpacing(8)
self.mediaLayout.setMargin(8)
self.mediaLayout.setObjectName(u'mediaLayout')
self.mediaModeGroupBox = QtGui.QGroupBox(self)
self.mediaModeGroupBox.setObjectName(u'mediaModeGroupBox')
self.mediaModeLayout = QtGui.QVBoxLayout(self.mediaModeGroupBox)
self.mediaModeLayout.setSpacing(8)
self.mediaModeLayout.setMargin(8)
self.mediaModeLayout.setObjectName(u'mediaModeLayout')
self.usePhononCheckBox = QtGui.QCheckBox(self.mediaModeGroupBox)
self.usePhononCheckBox.setObjectName(u'usePhononCheckBox')
self.mediaModeLayout.addWidget(self.usePhononCheckBox)
self.mediaLayout.setWidget(
0, QtGui.QFormLayout.LabelRole, self.mediaModeGroupBox)
QtCore.QObject.connect(self.usePhononCheckBox,
QtCore.SIGNAL(u'stateChanged(int)'),
self.onUsePhononCheckBoxChanged)
def retranslateUi(self):
self.mediaModeGroupBox.setTitle(translate('MediaPlugin.MediaTab',
'Media Display'))
self.usePhononCheckBox.setText(
translate('MediaPlugin.MediaTab', 'Use Phonon for video playback'))
def onUsePhononCheckBoxChanged(self, check_state):
self.usePhonon = (check_state == QtCore.Qt.Checked)
self.usePhononChanged = True
def load(self):
self.usePhonon = QtCore.QSettings().value(
self.settingsSection + u'/use phonon',
QtCore.QVariant(True)).toBool()
self.usePhononCheckBox.setChecked(self.usePhonon)
def save(self):
oldUsePhonon = QtCore.QSettings().value(
u'media/use phonon', QtCore.QVariant(True)).toBool()
if oldUsePhonon != self.usePhonon:
QtCore.QSettings().setValue(self.settingsSection + u'/use phonon',
QtCore.QVariant(self.usePhonon))
Receiver.send_message(u'config_screen_changed')

View File

@ -28,8 +28,8 @@ import logging
from PyQt4.phonon import Phonon
from openlp.core.lib import Plugin, build_icon, translate
from openlp.plugins.media.lib import MediaMediaItem
from openlp.core.lib import Plugin, StringContent, build_icon, translate
from openlp.plugins.media.lib import MediaMediaItem, MediaTab
log = logging.getLogger(__name__)
@ -68,11 +68,71 @@ class MediaPlugin(Plugin):
type = u''
return list, type
def getSettingsTab(self):
return MediaTab(self.name)
def getMediaManagerItem(self):
# Create the MediaManagerItem object
return MediaMediaItem(self, self.icon, self.name)
return MediaMediaItem(self, self, self.icon)
def about(self):
about_text = translate('MediaPlugin', '<strong>Media Plugin</strong>'
'<br />The media plugin provides playback of audio and video.')
return about_text
def setPluginTextStrings(self):
"""
Called to define all translatable texts of the plugin
"""
## Name PluginList ##
self.textStrings[StringContent.Name] = {
u'singular': translate('MediaPlugin', 'Media'),
u'plural': translate('MediaPlugin', 'Media')
}
## Name for MediaDockManager, SettingsManager ##
self.textStrings[StringContent.VisibleName] = {
u'title': translate('MediaPlugin', 'Media')
}
# Middle Header Bar
## Load Button ##
self.textStrings[StringContent.Load] = {
u'title': translate('MediaPlugin', 'Load'),
u'tooltip': translate('MediaPlugin',
'Load a new Media')
}
## New Button ##
self.textStrings[StringContent.New] = {
u'title': translate('MediaPlugin', 'Add'),
u'tooltip': translate('MediaPlugin',
'Add a new Media')
}
## Edit Button ##
self.textStrings[StringContent.Edit] = {
u'title': translate('MediaPlugin', 'Edit'),
u'tooltip': translate('MediaPlugin',
'Edit the selected Media')
}
## Delete Button ##
self.textStrings[StringContent.Delete] = {
u'title': translate('MediaPlugin', 'Delete'),
u'tooltip': translate('MediaPlugin',
'Delete the selected Media')
}
## Preview ##
self.textStrings[StringContent.Preview] = {
u'title': translate('MediaPlugin', 'Preview'),
u'tooltip': translate('MediaPlugin',
'Preview the selected Media')
}
## Live Button ##
self.textStrings[StringContent.Live] = {
u'title': translate('MediaPlugin', 'Live'),
u'tooltip': translate('MediaPlugin',
'Send the selected Media live')
}
## Add to service Button ##
self.textStrings[StringContent.Service] = {
u'title': translate('MediaPlugin', 'Service'),
u'tooltip': translate('MediaPlugin',
'Add the selected Media to the service')
}

View File

@ -58,15 +58,12 @@ class PresentationMediaItem(MediaManagerItem):
Constructor. Setup defaults
"""
self.controllers = controllers
self.PluginNameShort = u'Presentation'
self.pluginNameVisible = translate('PresentationPlugin.MediaItem',
'Presentation')
self.IconPath = u'presentations/presentation'
self.Automatic = u''
# this next is a class, not an instance of a class - it will
# be instanced by the base MediaManagerItem
self.ListViewWithDnD_class = PresentationListView
MediaManagerItem.__init__(self, parent, icon, title)
MediaManagerItem.__init__(self, parent, self, icon)
self.message_listener = MessageListener(self)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'mediaitem_presentation_rebuild'), self.rebuild)

View File

@ -143,11 +143,14 @@ class PowerpointDocument(PresentationDocument):
def create_thumbnails(self):
"""
Create the thumbnail images for the current presentation.
Note an alternative and quicker method would be do
Note an alternative and quicker method would be do::
self.presentation.Slides[n].Copy()
thumbnail = QApplication.clipboard.image()
But for now we want a physical file since it makes
life easier elsewhere
However, for the moment, we want a physical file since it makes life
easier elsewhere.
"""
if self.check_thumbnails():
return
@ -156,9 +159,8 @@ class PowerpointDocument(PresentationDocument):
def close_presentation(self):
"""
Close presentation and clean up objects
Triggerent by new object being added to SlideController orOpenLP
being shut down
Close presentation and clean up objects. This is triggered by a new
object being added to SlideController or OpenLP being shut down.
"""
log.debug(u'ClosePresentation')
if self.presentation:
@ -171,7 +173,7 @@ class PowerpointDocument(PresentationDocument):
def is_loaded(self):
"""
Returns true if a presentation is loaded
Returns ``True`` if a presentation is loaded.
"""
try:
if not self.controller.process.Visible:
@ -187,7 +189,7 @@ class PowerpointDocument(PresentationDocument):
def is_active(self):
"""
Returns true if a presentation is currently active
Returns ``True`` if a presentation is currently active.
"""
if not self.is_loaded():
return False
@ -202,7 +204,7 @@ class PowerpointDocument(PresentationDocument):
def unblank_screen(self):
"""
Unblanks (restores) the presentationn
Unblanks (restores) the presentation.
"""
self.presentation.SlideShowSettings.Run()
self.presentation.SlideShowWindow.View.State = 1
@ -210,13 +212,13 @@ class PowerpointDocument(PresentationDocument):
def blank_screen(self):
"""
Blanks the screen
Blanks the screen.
"""
self.presentation.SlideShowWindow.View.State = 3
def is_blank(self):
"""
Returns true if screen is blank
Returns ``True`` if screen is blank.
"""
if self.is_active():
return self.presentation.SlideShowWindow.View.State == 3
@ -225,14 +227,14 @@ class PowerpointDocument(PresentationDocument):
def stop_presentation(self):
"""
Stops the current presentation and hides the output
Stops the current presentation and hides the output.
"""
self.presentation.SlideShowWindow.View.Exit()
if os.name == u'nt':
def start_presentation(self):
"""
Starts a presentation from the beginning
Starts a presentation from the beginning.
"""
#SlideShowWindow measures its size/position by points, not pixels
try:
@ -254,40 +256,40 @@ class PowerpointDocument(PresentationDocument):
def get_slide_number(self):
"""
Returns the current slide number
Returns the current slide number.
"""
return self.presentation.SlideShowWindow.View.CurrentShowPosition
def get_slide_count(self):
"""
Returns total number of slides
Returns total number of slides.
"""
return self.presentation.Slides.Count
def goto_slide(self, slideno):
"""
Moves to a specific slide in the presentation
Moves to a specific slide in the presentation.
"""
self.presentation.SlideShowWindow.View.GotoSlide(slideno)
def next_step(self):
"""
Triggers the next effect of slide on the running presentation
Triggers the next effect of slide on the running presentation.
"""
self.presentation.SlideShowWindow.View.Next()
def previous_step(self):
"""
Triggers the previous slide on the running presentation
Triggers the previous slide on the running presentation.
"""
self.presentation.SlideShowWindow.View.Previous()
def get_slide_text(self, slide_no):
"""
Returns the text on the slide
Returns the text on the slide.
``slide_no``
The slide the text is required for, starting at 1
The slide the text is required for, starting at 1.
"""
text = ''
shapes = self.presentation.Slides(slide_no).Shapes
@ -299,10 +301,10 @@ class PowerpointDocument(PresentationDocument):
def get_slide_notes(self, slide_no):
"""
Returns the text on the slide
Returns the text on the slide.
``slide_no``
The slide the notes are required for, starting at 1
The slide the notes are required for, starting at 1.
"""
text = ''
shapes = self.presentation.Slides(slide_no).NotesPage.Shapes

View File

@ -37,16 +37,21 @@ log = logging.getLogger(__name__)
class PresentationController(object):
"""
Base class for presentation controllers to inherit from
Class to control interactions with presentations.
It creates the runtime environment
To create a new controller, take a copy of this file and name it
so it ends in controller.py, i.e. foobarcontroller.py
Make sure it inherits PresentationController
Then fill in the blanks. If possible try and make sure it loads
on all platforms, using for example os.name checks, although
__init__, check_available and presentation_deleted should always work.
See impresscontroller, powerpointcontroller or pptviewcontroller
This class is used to control interactions with presentation applications
by creating a runtime environment. This is a base class for presentation
controllers to inherit from.
To create a new controller, take a copy of this file and name it so it ends
with ``controller.py``, i.e. ``foobarcontroller.py``. Make sure it inherits
:class:`~openlp.plugins.presentations.lib.presentationcontroller.PresentationController`,
and then fill in the blanks. If possible try to make sure it loads on all
platforms, usually by using :mod:``os.name`` checks, although
``__init__``, ``check_available`` and ``presentation_deleted`` should
always be implemented.
See :class:`~openlp.plugins.presentations.lib.impresscontroller.ImpressController`,
:class:`~openlp.plugins.presentations.lib.powerpointcontroller.PowerpointController` or
:class:`~openlp.plugins.presentations.lib.pptviewcontroller.PptviewController`
for examples.
**Basic Attributes**

View File

@ -32,20 +32,18 @@ class PresentationTab(SettingsTab):
"""
PresentationsTab is the Presentations settings tab in the settings dialog.
"""
def __init__(self, title, controllers):
def __init__(self, title, visible_title, controllers):
"""
Constructor
"""
self.controllers = controllers
SettingsTab.__init__(self, title)
SettingsTab.__init__(self, title, visible_title)
def setupUi(self):
"""
Create the controls for the settings tab
"""
self.setObjectName(u'PresentationTab')
self.tabTitleVisible = translate('PresentationPlugin.PresentationTab',
'Presentations')
self.PresentationLayout = QtGui.QHBoxLayout(self)
self.PresentationLayout.setSpacing(8)
self.PresentationLayout.setMargin(8)

View File

@ -30,7 +30,7 @@ presentations from a variety of document formats.
import os
import logging
from openlp.core.lib import Plugin, build_icon, translate
from openlp.core.lib import Plugin, StringContent, build_icon, translate
from openlp.core.utils import AppLocation
from openlp.plugins.presentations.lib import PresentationController, \
PresentationMediaItem, PresentationTab
@ -60,7 +60,8 @@ class PresentationPlugin(Plugin):
"""
Create the settings Tab
"""
return PresentationTab(self.name, self.controllers)
visible_name = self.getString(StringContent.VisibleName)
return PresentationTab(self.name, visible_name[u'title'], self.controllers)
def initialise(self):
"""
@ -143,3 +144,48 @@ class PresentationPlugin(Plugin):
'programs. The choice of available presentation programs is '
'available to the user in a drop down box.')
return about_text
def setPluginTextStrings(self):
"""
Called to define all translatable texts of the plugin
"""
## Name PluginList ##
self.textStrings[StringContent.Name] = {
u'singular': translate('PresentationPlugin', 'Presentation'),
u'plural': translate('PresentationPlugin', 'Presentations')
}
## Name for MediaDockManager, SettingsManager ##
self.textStrings[StringContent.VisibleName] = {
u'title': translate('PresentationPlugin', 'Presentations')
}
# Middle Header Bar
## Load Button ##
self.textStrings[StringContent.Load] = {
u'title': translate('PresentationPlugin', 'Load'),
u'tooltip': translate('PresentationPlugin',
'Load a new Presentation')
}
## Delete Button ##
self.textStrings[StringContent.Delete] = {
u'title': translate('PresentationPlugin', 'Delete'),
u'tooltip': translate('PresentationPlugin',
'Delete the selected Presentation')
}
## Preview ##
self.textStrings[StringContent.Preview] = {
u'title': translate('PresentationPlugin', 'Preview'),
u'tooltip': translate('PresentationPlugin',
'Preview the selected Presentation')
}
## Live Button ##
self.textStrings[StringContent.Live] = {
u'title': translate('PresentationPlugin', 'Live'),
u'tooltip': translate('PresentationPlugin',
'Send the selected Presentation live')
}
## Add to service Button ##
self.textStrings[StringContent.Service] = {
u'title': translate('PresentationPlugin', 'Service'),
u'tooltip': translate('PresentationPlugin',
'Add the selected Presentation to the service')
}

View File

@ -32,12 +32,11 @@ class RemoteTab(SettingsTab):
"""
RemoteTab is the Remotes settings tab in the settings dialog.
"""
def __init__(self, title):
SettingsTab.__init__(self, title)
def __init__(self, title, visible_title):
SettingsTab.__init__(self, title, visible_title)
def setupUi(self):
self.setObjectName(u'RemoteTab')
self.tabTitleVisible = translate('RemotePlugin.RemoteTab', 'Remotes')
self.remoteLayout = QtGui.QFormLayout(self)
self.remoteLayout.setSpacing(8)
self.remoteLayout.setMargin(8)

View File

@ -26,7 +26,7 @@
import logging
from openlp.core.lib import Plugin, translate, build_icon
from openlp.core.lib import Plugin, StringContent, translate, build_icon
from openlp.plugins.remotes.lib import RemoteTab, HttpServer
log = logging.getLogger(__name__)
@ -65,7 +65,8 @@ class RemotesPlugin(Plugin):
"""
Create the settings Tab
"""
return RemoteTab(self.name)
visible_name = self.getString(StringContent.VisibleName)
return RemoteTab(self.name, visible_name[u'title'])
def about(self):
"""
@ -76,3 +77,17 @@ class RemotesPlugin(Plugin):
'a running version of OpenLP on a different computer via a web '
'browser or through the remote API.')
return about_text
def setPluginTextStrings(self):
"""
Called to define all translatable texts of the plugin
"""
## Name PluginList ##
self.textStrings[StringContent.Name] = {
u'singular': translate('RemotePlugin', 'Remote'),
u'plural': translate('RemotePlugin', 'Remotes')
}
## Name for MediaDockManager, SettingsManager ##
self.textStrings[StringContent.VisibleName] = {
u'title': translate('RemotePlugin', 'Remotes')
}

View File

@ -483,6 +483,8 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
self.VerseListWidget.resizeRowsToContents()
self.VerseListWidget.repaint()
self.tagRows()
self.VerseEditButton.setEnabled(False)
self.VerseDeleteButton.setEnabled(False)
def onVerseDeleteButtonClicked(self):
self.VerseListWidget.removeRow(self.VerseListWidget.currentRow())

View File

@ -53,6 +53,9 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog):
QtCore.QObject.connect(self.verseTextEdit,
QtCore.SIGNAL(u'cursorPositionChanged()'),
self.onCursorPositionChanged)
QtCore.QObject.connect(self.verseTypeComboBox,
QtCore.SIGNAL(u'currentIndexChanged(int)'),
self.onVerseTypeComboBoxChanged)
self.verse_regex = re.compile(r'---\[([-\w]+):([\d]+)\]---')
def contextMenu(self, point):
@ -66,27 +69,43 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog):
self.verseTextEdit.setFocus()
def onInsertButtonClicked(self):
if self.verseTextEdit.textCursor().columnNumber() != 0:
self.verseTextEdit.insertPlainText(u'\n')
verse_type = self.verseTypeComboBox.currentIndex()
if verse_type == VerseType.Verse:
self.insertVerse(VerseType.to_string(VerseType.Verse),
if VerseType.to_string(verse_type) is not None:
self.insertVerse(VerseType.to_string(verse_type),
self.verseNumberBox.value())
elif verse_type == VerseType.Chorus:
self.insertVerse(VerseType.to_string(VerseType.Chorus),
self.verseNumberBox.value())
elif verse_type == VerseType.Bridge:
self.insertVerse(VerseType.to_string(VerseType.Bridge))
elif verse_type == VerseType.PreChorus:
self.insertVerse(VerseType.to_string(VerseType.PreChorus))
elif verse_type == VerseType.Intro:
self.insertVerse(VerseType.to_string(VerseType.Intro))
elif verse_type == VerseType.Ending:
self.insertVerse(VerseType.to_string(VerseType.Ending))
elif verse_type == VerseType.Other:
self.insertVerse(VerseType.to_string(VerseType.Other))
def onVerseTypeComboBoxChanged(self):
"""
Adjusts the verse number SpinBox in regard to the selected verse type
and the cursor's position.
"""
position = self.verseTextEdit.textCursor().position()
text = unicode(self.verseTextEdit.toPlainText())
verse_type = VerseType.to_string(self.verseTypeComboBox.currentIndex())
if not text:
return
position = text.rfind(u'---[%s' % verse_type, 0, position)
if position == -1:
self.verseNumberBox.setValue(1)
return
text = text[position:]
position = text.find(u']---')
if position == -1:
return
text = text[:position + 4]
match = self.verse_regex.match(text)
if match:
verse_type = match.group(1)
verse_number = int(match.group(2))
verse_type_index = VerseType.from_string(verse_type)
if verse_type_index is not None:
self.verseNumberBox.setValue(verse_number)
def onCursorPositionChanged(self):
"""
Determines the previous verse type and number in regard to the cursor's
position and adjusts the ComboBox and SpinBox to these values.
"""
position = self.verseTextEdit.textCursor().position()
text = unicode(self.verseTextEdit.toPlainText())
if not text:

View File

@ -112,6 +112,12 @@ class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard):
QtCore.QObject.connect(self.ewBrowseButton,
QtCore.SIGNAL(u'clicked()'),
self.onEWBrowseButtonClicked)
QtCore.QObject.connect(self.songBeamerAddButton,
QtCore.SIGNAL(u'clicked()'),
self.onSongBeamerAddButtonClicked)
QtCore.QObject.connect(self.songBeamerRemoveButton,
QtCore.SIGNAL(u'clicked()'),
self.onSongBeamerRemoveButtonClicked)
QtCore.QObject.connect(self.cancelButton,
QtCore.SIGNAL(u'clicked(bool)'),
self.onCancelButtonClicked)
@ -227,23 +233,39 @@ class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard):
'file to import from.'))
self.ewBrowseButton.setFocus()
return False
elif source_format == SongFormat.SongBeamer:
if self.songBeamerFileListWidget.count() == 0:
QtGui.QMessageBox.critical(self,
translate('SongsPlugin.ImportWizardForm',
'No SongBeamer File Selected'),
translate('SongsPlugin.ImportWizardForm',
'You need to add at least one SongBeamer '
'file to import from.'))
self.songBeamerAddButton.setFocus()
return False
return True
elif self.currentId() == 2:
# Progress page
return True
def getFileName(self, title, editbox):
def getFileName(self, title, editbox,
filters = '%s (*)' % translate('SongsPlugin.ImportWizardForm',
'All Files')):
filename = QtGui.QFileDialog.getOpenFileName(self, title,
SettingsManager.get_last_dir(self.plugin.settingsSection, 1))
SettingsManager.get_last_dir(self.plugin.settingsSection, 1),
filters)
if filename:
editbox.setText(filename)
SettingsManager.set_last_dir(
self.plugin.settingsSection,
os.path.split(unicode(filename))[0], 1)
def getFiles(self, title, listbox):
def getFiles(self, title, listbox,
filters = u'%s (*)' % translate('SongsPlugin.ImportWizardForm',
'All Files')):
filenames = QtGui.QFileDialog.getOpenFileNames(self, title,
SettingsManager.get_last_dir(self.plugin.settingsSection, 1))
SettingsManager.get_last_dir(self.plugin.settingsSection, 1),
filters)
if filenames:
listbox.addItems(filenames)
SettingsManager.set_last_dir(
@ -265,14 +287,24 @@ class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard):
self.getFileName(
translate('SongsPlugin.ImportWizardForm',
'Select OpenLP 2.0 Database File'),
self.openLP2FilenameEdit
self.openLP2FilenameEdit,
u'%s (*.sqlite);;%s (*)'
% (translate('SongsPlugin.ImportWizardForm',
'OpenLP 2.0 Databases'),
translate('SongsPlugin.ImportWizardForm',
'All Files'))
)
def onOpenLP1BrowseButtonClicked(self):
self.getFileName(
translate('SongsPlugin.ImportWizardForm',
'Select openlp.org 1.x Database File'),
self.openLP1FilenameEdit
self.openLP1FilenameEdit,
u'%s (*.olp);;%s (*)'
% (translate('SongsPlugin.ImportWizardForm',
'openlp.org v1.x Databases'),
translate('SongsPlugin.ImportWizardForm',
'All Files'))
)
#def onOpenLyricsAddButtonClicked(self):
@ -299,7 +331,12 @@ class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard):
self.getFiles(
translate('SongsPlugin.ImportWizardForm',
'Select Words of Worship Files'),
self.wordsOfWorshipFileListWidget
self.wordsOfWorshipFileListWidget,
u'%s (*.wsg *.wow-song);;%s (*)'
% (translate('SongsPlugin.ImportWizardForm',
'Words Of Worship Song Files'),
translate('SongsPlugin.ImportWizardForm',
'All Files'))
)
def onWordsOfWorshipRemoveButtonClicked(self):
@ -319,7 +356,12 @@ class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard):
self.getFiles(
translate('SongsPlugin.ImportWizardForm',
'Select Songs of Fellowship Files'),
self.songsOfFellowshipFileListWidget
self.songsOfFellowshipFileListWidget,
u'%s (*.rtf);;%s (*)'
% (translate('SongsPlugin.ImportWizardForm',
'Songs Of Felloship Song Files'),
translate('SongsPlugin.ImportWizardForm',
'All Files'))
)
def onSongsOfFellowshipRemoveButtonClicked(self):
@ -342,6 +384,16 @@ class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard):
self.ewFilenameEdit
)
def onSongBeamerAddButtonClicked(self):
self.getFiles(
translate('SongsPlugin.ImportWizardForm',
'Select SongBeamer Files'),
self.songBeamerFileListWidget
)
def onSongBeamerRemoveButtonClicked(self):
self.removeSelectedItems(self.songBeamerFileListWidget)
def onCancelButtonClicked(self, checked):
"""
Stop the import on pressing the cancel button.
@ -373,6 +425,7 @@ class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard):
self.songsOfFellowshipFileListWidget.clear()
self.genericFileListWidget.clear()
self.ewFilenameEdit.setText(u'')
self.songBeamerFileListWidget.clear()
#self.csvFilenameEdit.setText(u'')
def incrementProgressBar(self, status_text, increment=1):
@ -448,6 +501,12 @@ class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard):
importer = self.plugin.importSongs(SongFormat.EasyWorship,
filename=unicode(self.ewFilenameEdit.text())
)
elif source_format == SongFormat.SongBeamer:
# Import SongBeamer songs
importer = self.plugin.importSongs(SongFormat.SongBeamer,
filenames=self.getListOfFiles(
self.songBeamerFileListWidget)
)
success = importer.do_import()
if success:
# reload songs

View File

@ -116,6 +116,8 @@ class Ui_SongImportWizard(object):
self.addMultiFileSelectItem(u'generic', None, True)
# EasyWorship
self.addSingleFileSelectItem(u'ew')
# Words of Worship
self.addMultiFileSelectItem(u'songBeamer')
# Commented out for future use.
# self.addSingleFileSelectItem(u'csv', u'CSV')
self.sourceLayout.addWidget(self.formatStackedWidget)
@ -180,6 +182,8 @@ class Ui_SongImportWizard(object):
'Generic Document/Presentation'))
self.formatComboBox.setItemText(8,
translate('SongsPlugin.ImportWizardForm', 'EasyWorship'))
self.formatComboBox.setItemText(9,
translate('SongsPlugin.ImportWizardForm', 'SongBeamer'))
# self.formatComboBox.setItemText(9,
# translate('SongsPlugin.ImportWizardForm', 'CSV'))
self.openLP2FilenameLabel.setText(
@ -236,6 +240,10 @@ class Ui_SongImportWizard(object):
translate('SongsPlugin.ImportWizardForm', 'Filename:'))
self.ewBrowseButton.setText(
translate('SongsPlugin.ImportWizardForm', 'Browse...'))
self.songBeamerAddButton.setText(
translate('SongsPlugin.ImportWizardForm', 'Add Files...'))
self.songBeamerRemoveButton.setText(
translate('SongsPlugin.ImportWizardForm', 'Remove File(s)'))
# self.csvFilenameLabel.setText(
# translate('SongsPlugin.ImportWizardForm', 'Filename:'))
# self.csvBrowseButton.setText(

View File

@ -38,9 +38,9 @@ class CCLIFileImportError(Exception):
class CCLIFileImport(SongImport):
"""
The :class:`CCLIFileImport` class provides OpenLP with the
ability to import CCLI SongSelect song files in both .txt and
.usr formats. See http://www.ccli.com
The :class:`CCLIFileImport` class provides OpenLP with the ability to
import CCLI SongSelect song files in both .txt and .usr formats.
See http://www.ccli.com/ for more details.
"""
def __init__(self, manager, **kwargs):
@ -49,6 +49,7 @@ class CCLIFileImport(SongImport):
``manager``
The song manager for the running OpenLP installation.
``filenames``
The files to be imported.
"""
@ -97,7 +98,7 @@ class CCLIFileImport(SongImport):
def do_import_usr_file(self, textList):
"""
The :method:`do_import_usr_file` method provides OpenLP
The :func:`do_import_usr_file` method provides OpenLP
with the ability to import CCLI SongSelect songs in
*USR* file format
@ -105,6 +106,7 @@ class CCLIFileImport(SongImport):
An array of strings containing the usr file content.
**SongSelect .usr file format**
``[File]``
USR file format first line
``Type=``
@ -140,6 +142,7 @@ class CCLIFileImport(SongImport):
Contains the songs various lyrics in order as shown by the
*Fields* description
e.g. *Words=Above all powers....* [/n = CR, /n/t = CRLF]
"""
log.debug(u'USR file text: %s', textList)
lyrics = []
@ -191,48 +194,32 @@ class CCLIFileImport(SongImport):
def do_import_txt_file(self, textList):
"""
The :method:`do_import_txt_file` method provides OpenLP
The :func:`do_import_txt_file` method provides OpenLP
with the ability to import CCLI SongSelect songs in
*TXT* file format
``textList``
An array of strings containing the txt file content.
**SongSelect .txt file format**
``Song Title``
Contains the song title
SongSelect .txt file format::
Song Title # Contains the song title
<Empty line>
``Title of following verse/chorus and number``
e.g. Verse 1, Chorus 1
``Verse/Chorus lyrics``
Verse type and number # e.g. Verse 1, Chorus 1
Verse lyrics
<Empty line>
<Empty line>
``Title of next verse/chorus (repeats)``
``Verse/Chorus lyrics``
Verse type and number (repeats)
Verse lyrics
<Empty line>
<Empty line>
``Song CCLI Number``
e.g. CCLI Number (e.g.CCLI-Liednummer: 2672885)
``Song Copyright``
e.g. © 1999 Integrity's Hosanna! Music | LenSongs Publishing
``Song Authors``
e.g. Lenny LeBlanc | Paul Baloche
``Licencing info``
e.g. For use solely with the SongSelect Terms of Use.
Song CCLI number # e.g. CCLI Number (e.g.CCLI-Liednummer: 2672885)
Song copyright # e.g. © 1999 Integrity's Hosanna! Music | LenSongs Publishing
Song authors # e.g. Lenny LeBlanc | Paul Baloche
Licencing info # e.g. For use solely with the SongSelect Terms of Use.
All rights Reserved. www.ccli.com
``CCLI Licence number of user``
e.g. CCL-Liedlizenznummer: 14 / CCLI License No. 14
CCLI Licence number of user # e.g. CCL-Liedlizenznummer: 14 / CCLI License No. 14
"""
log.debug(u'TXT file text: %s', textList)
self.set_defaults()

View File

@ -35,7 +35,7 @@ import struct
from openlp.core.lib import translate
from songimport import SongImport
def strip_rtf(blob):
def strip_rtf(blob, encoding):
depth = 0
control = False
clear_text = []
@ -69,12 +69,42 @@ def strip_rtf(blob):
if control_str == 'par' or control_str == 'line':
clear_text.append(u'\n')
elif control_str == 'tab':
clear_text.append(u'\n')
clear_text.append(u'\t')
# Prefer the encoding specified by the RTF data to that
# specified by the Paradox table header
# West European encoding
elif control_str == 'fcharset0':
encoding = u'cp1252'
# Greek encoding
elif control_str == 'fcharset161':
encoding = u'cp1253'
# Turkish encoding
elif control_str == 'fcharset162':
encoding = u'cp1254'
# Vietnamese encoding
elif control_str == 'fcharset163':
encoding = u'cp1258'
# Hebrew encoding
elif control_str == 'fcharset177':
encoding = u'cp1255'
# Arabic encoding
elif control_str == 'fcharset178':
encoding = u'cp1256'
# Baltic encoding
elif control_str == 'fcharset186':
encoding = u'cp1257'
# Cyrillic encoding
elif control_str == 'fcharset204':
encoding = u'cp1251'
# Thai encoding
elif control_str == 'fcharset222':
encoding = u'cp874'
# Central+East European encoding
elif control_str == 'fcharset238':
encoding = u'cp1250'
elif control_str[0] == '\'':
# Really should take RTF character set into account but
# for now assume ANSI (Windows-1252) and call it good
s = chr(int(control_str[1:3], 16))
clear_text.append(s.decode(u'windows-1252'))
clear_text.append(s.decode(encoding))
del control_word[:]
if c == '\\' and new_control:
control = True
@ -126,6 +156,30 @@ class EasyWorshipSongImport(SongImport):
db_file.close()
self.memo_file.close()
return False
# Take a stab at how text is encoded
self.encoding = u'cp1252'
db_file.seek(106)
code_page, = struct.unpack('<h', db_file.read(2))
if code_page == 852:
self.encoding = u'cp1250'
# The following codepage to actual encoding mappings have not been
# observed, but merely guessed. Actual example files are needed.
#if code_page == 737:
# self.encoding = u'cp1253'
#if code_page == 775:
# self.encoding = u'cp1257'
#if code_page == 855:
# self.encoding = u'cp1251'
#if code_page == 857:
# self.encoding = u'cp1254'
#if code_page == 866:
# self.encoding = u'cp1251'
#if code_page == 869:
# self.encoding = u'cp1253'
#if code_page == 862:
# self.encoding = u'cp1255'
#if code_page == 874:
# self.encoding = u'cp874'
# There does not appear to be a _reliable_ way of getting the number
# of songs/records, so let's use file blocks for measuring progress.
total_blocks = (db_size - header_size) / (block_size * 1024)
@ -204,7 +258,7 @@ class EasyWorshipSongImport(SongImport):
self.add_author(author_name.strip())
if words:
# Format the lyrics
words = strip_rtf(words)
words = strip_rtf(words, self.encoding)
for verse in words.split(u'\n\n'):
self.add_verse(verse.strip(), u'V')
if self.stop_import_flag:
@ -263,7 +317,7 @@ class EasyWorshipSongImport(SongImport):
# Format the field depending on the field type
if field_desc.type == 1:
# string
return field.rstrip('\0').decode(u'windows-1252')
return field.rstrip('\0').decode(self.encoding)
elif field_desc.type == 3:
# 16-bit int
return field ^ 0x8000

View File

@ -29,6 +29,7 @@ from olpimport import OpenLPSongImport
from wowimport import WowImport
from cclifileimport import CCLIFileImport
from ewimport import EasyWorshipSongImport
from songbeamerimport import SongBeamerImport
# Imports that might fail
try:
from olp1import import OpenLP1SongImport
@ -64,6 +65,7 @@ class SongFormat(object):
Generic = 7
#CSV = 8
EasyWorship = 8
SongBeamer = 9
@staticmethod
def get_class(format):
@ -89,6 +91,8 @@ class SongFormat(object):
return CCLIFileImport
elif format == SongFormat.EasyWorship:
return EasyWorshipSongImport
elif format == SongFormat.SongBeamer:
return SongBeamerImport
# else:
return None
@ -106,7 +110,8 @@ class SongFormat(object):
SongFormat.CCLI,
SongFormat.SongsOfFellowship,
SongFormat.Generic,
SongFormat.EasyWorship
SongFormat.EasyWorship,
SongFormat.SongBeamer
]
@staticmethod

View File

@ -48,12 +48,10 @@ class SongMediaItem(MediaManagerItem):
"""
log.info(u'Song Media Item loaded')
def __init__(self, parent, icon, title):
self.PluginNameShort = u'Song'
self.pluginNameVisible = translate('SongsPlugin.MediaItem', 'Song')
def __init__(self, parent, plugin, icon):
self.IconPath = u'songs/song'
self.ListViewWithDnD_class = SongListView
MediaManagerItem.__init__(self, parent, icon, title)
MediaManagerItem.__init__(self, parent, self, icon)
self.edit_song_form = EditSongForm(self, self.parent.manager)
self.singleServiceItem = False
#self.edit_song_form = EditSongForm(self.parent.manager, self)
@ -62,6 +60,7 @@ class SongMediaItem(MediaManagerItem):
# Holds information about whether the edit is remotly triggered and
# which Song is required.
self.remoteSong = -1
self.editItem = None
def requiredIcons(self):
MediaManagerItem.requiredIcons(self)
@ -125,7 +124,7 @@ class SongMediaItem(MediaManagerItem):
QtCore.SIGNAL(u'textChanged(const QString&)'),
self.onSearchTextEditChanged)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'songs_load_list'), self.onSearchTextButtonClick)
QtCore.SIGNAL(u'songs_load_list'), self.onSongListLoad)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'config_updated'), self.configUpdated)
QtCore.QObject.connect(Receiver.get_receiver(),
@ -139,6 +138,12 @@ class SongMediaItem(MediaManagerItem):
self.searchAsYouType = QtCore.QSettings().value(
self.settingsSection + u'/search as type',
QtCore.QVariant(u'False')).toBool()
self.updateServiceOnEdit = QtCore.QSettings().value(
self.settingsSection + u'/update service on edit',
QtCore.QVariant(u'False')).toBool()
self.AddSongFromServide = QtCore.QSettings().value(
self.settingsSection + u'/add song from service',
QtCore.QVariant(u'True')).toBool()
def retranslateUi(self):
self.SearchTextLabel.setText(
@ -181,14 +186,26 @@ class SongMediaItem(MediaManagerItem):
Author.display_name.like(u'%' + search_keywords + u'%'),
Author.display_name.asc())
self.displayResultsAuthor(search_results)
#Called to redisplay the song list screen edith from a search
def onSongListLoad(self):
"""
Handle the exit from the edit dialog and trigger remote updates
of songs
"""
# Called to redisplay the song list screen edit from a search
# or from the exit of the Song edit dialog. If remote editing is active
# Trigger it and clean up so it will not update again.
if self.remoteTriggered == u'L':
self.onAddClick()
if self.remoteTriggered == u'P':
self.onPreviewClick()
# Push edits to the service manager to update items
if self.editItem and self.updateServiceOnEdit and \
not self.remoteTriggered:
item = self.buildServiceItem(self.editItem)
self.parent.serviceManager.replaceServiceItem(item)
self.onRemoteEditClear()
self.onSearchTextButtonClick()
def displayResultsSong(self, searchresults):
log.debug(u'display results Song')
@ -273,8 +290,8 @@ class SongMediaItem(MediaManagerItem):
if check_item_selected(self.listView,
translate('SongsPlugin.MediaItem',
'You must select an item to edit.')):
item = self.listView.currentItem()
item_id = (item.data(QtCore.Qt.UserRole)).toInt()[0]
self.editItem = self.listView.currentItem()
item_id = (self.editItem.data(QtCore.Qt.UserRole)).toInt()[0]
self.edit_song_form.loadSong(item_id, False)
self.edit_song_form.exec_()
@ -324,6 +341,8 @@ class SongMediaItem(MediaManagerItem):
service_item.add_capability(ItemCapabilities.AllowsEdit)
service_item.add_capability(ItemCapabilities.AllowsPreview)
service_item.add_capability(ItemCapabilities.AllowsLoop)
service_item.add_capability(ItemCapabilities.OnLoadUpdate)
service_item.add_capability(ItemCapabilities.AddIfNewItem)
song = self.parent.manager.get_object(Song, item_id)
service_item.theme = song.theme_name
service_item.editId = item_id
@ -370,4 +389,31 @@ class SongMediaItem(MediaManagerItem):
service_item.audit = [
song.title, author_audit, song.copyright, unicode(song.ccli_number)
]
service_item.data_string = {u'title':song.search_title, u'authors':author_list}
return True
def serviceLoad(self, item):
"""
Triggered by a song being loaded by the service item
"""
if item.data_string:
search_results = self.parent.manager.get_all_objects(Song,
Song.search_title.like(u'%' +
item.data_string[u'title'].split(u'@')[0] + u'%'),
Song.search_title.asc())
author_list = item.data_string[u'authors'].split(u',')
editId = 0
uuid = 0
if search_results:
for song in search_results:
count = 0
for author in song.authors:
if author.display_name in author_list:
count += 1
if count == len(author_list):
editId = song.id
uuid = item._uuid
if editId != 0:
Receiver.send_message(u'service_item_update',
u'%s:%s' %(editId, uuid))

View File

@ -0,0 +1,236 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2010 Raoul Snyman #
# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
# Gorven, Scott Guerrieri, Meinert Jordan, Andreas Preikschat, Christian #
# Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon Tibble, #
# Carsten Tinggaard, Frode Woldsund #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`songbeamerimport` module provides the functionality for importing
SongBeamer songs into the OpenLP database.
"""
import logging
import os
import re
import chardet
import codecs
from openlp.plugins.songs.lib.songimport import SongImport
log = logging.getLogger(__name__)
class SongBeamerTypes(object):
MarkTypes = {
u'Refrain': u'C',
u'Chorus': u'C',
u'Vers': u'V',
u'Verse': u'V',
u'Strophe': u'V',
u'Intro': u'I',
u'Coda': u'E',
u'Ending': u'E',
u'Bridge': u'B',
u'Interlude': u'B',
u'Zwischenspiel': u'B',
u'Pre-Chorus': u'P',
u'Pre-Refrain': u'P',
u'Pre-Bridge': u'O',
u'Pre-Coda': u'O',
u'Unbekannt': u'O',
u'Unknown': u'O'
}
class SongBeamerImport(SongImport):
"""
Import Song Beamer files(s)
Song Beamer file format is text based
in the beginning are one or more control tags written
"""
def __init__(self, master_manager, **kwargs):
"""
Initialise the import.
``master_manager``
The song manager for the running OpenLP installation.
"""
SongImport.__init__(self, master_manager)
self.master_manager = master_manager
if kwargs.has_key(u'filename'):
self.import_source = kwargs[u'filename']
if kwargs.has_key(u'filenames'):
self.import_source = kwargs[u'filenames']
log.debug(self.import_source)
def do_import(self):
"""
Recieve a single file, or a list of files to import.
"""
if isinstance(self.import_source, list):
self.import_wizard.importProgressBar.setMaximum(
len(self.import_source))
for file in self.import_source:
# TODO: check that it is a valid SongBeamer file
self.current_verse = u''
self.current_verse_type = u'V'
self.file_name = os.path.split(file)[1]
self.import_wizard.incrementProgressBar(
"Importing %s" % (self.file_name), 0)
if os.path.isfile(file):
detect_file = open(file, u'r')
details = chardet.detect(detect_file.read(2048))
detect_file.close()
infile = codecs.open(file, u'r', details['encoding'])
self.songData = infile.readlines()
else:
return False
for line in self.songData:
line = line.strip()
if line.startswith('#'):
log.debug(u'find tag: %s' % line)
if not self.parse_tags(line):
return False
elif line.startswith('---'):
log.debug(u'find ---')
if len(self.current_verse) > 0:
self.add_verse(self.current_verse,
self.current_verse_type)
self.current_verse = u''
self.current_verse_type = u'V'
self.read_verse = True
self.verse_start = True
elif self.read_verse:
if self.verse_start:
self.check_verse_marks(line)
self.verse_start = False
else:
self.current_verse += u'%s\n' % line
if len(self.current_verse) > 0:
self.add_verse(self.current_verse, self.current_verse_type)
self.finish()
self.import_wizard.incrementProgressBar(
"Importing %s" % (self.file_name))
return True
def parse_tags(self, line):
tag_val = line.split('=')
if len(tag_val[0]) == 0 or \
len(tag_val[1]) == 0:
return True
if tag_val[0] == '#(c)':
self.add_copyright(tag_val[1])
elif tag_val[0] == '#AddCopyrightInfo':
pass
elif tag_val[0] == '#Author':
#TODO split Authors
self.add_author(tag_val[1])
elif tag_val[0] == '#BackgroundImage':
pass
elif tag_val[0] == '#Bible':
pass
elif tag_val[0] == '#Categories':
self.topics = line.split(',')
elif tag_val[0] == '#CCLI':
self.ccli_number = tag_val[1]
elif tag_val[0] == '#Chords':
pass
elif tag_val[0] == '#ChurchSongID':
pass
elif tag_val[0] == '#ColorChords':
pass
elif tag_val[0] == '#Comments':
self.comments = tag_val[1]
elif tag_val[0] == '#Editor':
pass
elif tag_val[0] == '#Font':
pass
elif tag_val[0] == '#FontLang2':
pass
elif tag_val[0] == '#FontSize':
pass
elif tag_val[0] == '#Format':
pass
elif tag_val[0] == '#Format_PreLine':
pass
elif tag_val[0] == '#Format_PrePage':
pass
elif tag_val[0] == '#ID':
pass
elif tag_val[0] == '#Key':
pass
elif tag_val[0] == '#Keywords':
pass
elif tag_val[0] == '#LangCount':
pass
elif tag_val[0] == '#Melody':
#TODO split Authors
self.add_author(tag_val[1])
elif tag_val[0] == '#NatCopyright':
pass
elif tag_val[0] == '#OTitle':
pass
elif tag_val[0] == '#OutlineColor':
pass
elif tag_val[0] == '#OutlinedFont':
pass
elif tag_val[0] == '#QuickFind':
pass
elif tag_val[0] == '#Rights':
song_book_pub = tag_val[1]
elif tag_val[0] == '#Songbook':
book_num = tag_val[1].split(' / ')
self.song_book_name = book_num[0]
if len(book_num) == book_num[1]:
self.song_number = u''
elif tag_val[0] == '#Speed':
pass
elif tag_val[0] == '#TextAlign':
pass
elif tag_val[0] == '#Title':
self.title = u'%s' % tag_val[1]
elif tag_val[0] == '#TitleAlign':
pass
elif tag_val[0] == '#TitleFontSize':
pass
elif tag_val[0] == '#TitleLang2':
pass
elif tag_val[0] == '#TitleLang3':
pass
elif tag_val[0] == '#TitleLang4':
pass
elif tag_val[0] == '#Translation':
pass
elif tag_val[0] == '#Transpose':
pass
elif tag_val[0] == '#TransposeAccidental':
pass
elif tag_val[0] == '#Version':
pass
else:
pass
return True
def check_verse_marks(self, line):
marks = line.split(' ')
if len(marks) <= 2 and \
marks[0] in SongBeamerTypes.MarkTypes:
self.current_verse_type = SongBeamerTypes.MarkTypes[marks[0]]
if len(marks) == 2:
#TODO: may check, because of only digits are allowed
self.current_verse_type += marks[1]

View File

@ -32,12 +32,11 @@ class SongsTab(SettingsTab):
"""
SongsTab is the Songs settings tab in the settings dialog.
"""
def __init__(self, title):
SettingsTab.__init__(self, title)
def __init__(self, title, visible_title):
SettingsTab.__init__(self, title, visible_title)
def setupUi(self):
self.setObjectName(u'SongsTab')
self.tabTitleVisible = translate('SongsPlugin.SongsTab', 'Songs')
self.SongsLayout = QtGui.QFormLayout(self)
self.SongsLayout.setSpacing(8)
self.SongsLayout.setMargin(8)
@ -52,8 +51,14 @@ class SongsTab(SettingsTab):
self.SearchAsTypeCheckBox.setObjectName(u'SearchAsTypeCheckBox')
self.SongsModeLayout.addWidget(self.SearchAsTypeCheckBox)
self.SongBarActiveCheckBox = QtGui.QCheckBox(self.SongsModeGroupBox)
self.SongBarActiveCheckBox.setObjectName(u'SearchAsTypeCheckBox')
self.SongBarActiveCheckBox.setObjectName(u'SongBarActiveCheckBox')
self.SongsModeLayout.addWidget(self.SongBarActiveCheckBox)
self.SongUpdateOnEditCheckBox = QtGui.QCheckBox(self.SongsModeGroupBox)
self.SongUpdateOnEditCheckBox.setObjectName(u'SongUpdateOnEditCheckBox')
self.SongsModeLayout.addWidget(self.SongUpdateOnEditCheckBox)
self.SongAddFromServiceCheckBox = QtGui.QCheckBox(self.SongsModeGroupBox)
self.SongAddFromServiceCheckBox.setObjectName(u'SongAddFromServiceCheckBox')
self.SongsModeLayout.addWidget(self.SongAddFromServiceCheckBox)
self.SongsLayout.setWidget(
0, QtGui.QFormLayout.LabelRole, self.SongsModeGroupBox)
QtCore.QObject.connect(self.SearchAsTypeCheckBox,
@ -61,7 +66,13 @@ class SongsTab(SettingsTab):
self.onSearchAsTypeCheckBoxChanged)
QtCore.QObject.connect(self.SongBarActiveCheckBox,
QtCore.SIGNAL(u'stateChanged(int)'),
self.SongBarActiveCheckBoxChanged)
self.onSongBarActiveCheckBoxChanged)
QtCore.QObject.connect(self.SongUpdateOnEditCheckBox,
QtCore.SIGNAL(u'stateChanged(int)'),
self.onSongUpdateOnEditCheckBoxChanged)
QtCore.QObject.connect(self.SongBarActiveCheckBox,
QtCore.SIGNAL(u'stateChanged(int)'),
self.onSongAddFromServiceCheckBoxChanged)
def retranslateUi(self):
self.SongsModeGroupBox.setTitle(
@ -70,6 +81,10 @@ class SongsTab(SettingsTab):
translate('SongsPlugin.SongsTab', 'Enable search as you type'))
self.SongBarActiveCheckBox.setText(translate('SongsPlugin.SongsTab',
'Display verses on live tool bar'))
self.SongUpdateOnEditCheckBox.setText(
translate('SongsPlugin.SongsTab', 'Update service from song edit'))
self.SongAddFromServiceCheckBox.setText(translate('SongsPlugin.SongsTab',
'Add missing songs when opening service'))
def onSearchAsTypeCheckBoxChanged(self, check_state):
self.song_search = False
@ -77,12 +92,24 @@ class SongsTab(SettingsTab):
if check_state == QtCore.Qt.Checked:
self.song_search = True
def SongBarActiveCheckBoxChanged(self, check_state):
def onSongBarActiveCheckBoxChanged(self, check_state):
self.song_bar = False
# we have a set value convert to True/False
if check_state == QtCore.Qt.Checked:
self.song_bar = True
def onSongUpdateOnEditCheckBoxChanged(self, check_state):
self.update_edit = False
# we have a set value convert to True/False
if check_state == QtCore.Qt.Checked:
self.update_edit = True
def onSongAddFromServiceCheckBoxChanged(self, check_state):
self.update_load = False
# we have a set value convert to True/False
if check_state == QtCore.Qt.Checked:
self.update_load = True
def load(self):
settings = QtCore.QSettings()
settings.beginGroup(self.settingsSection)
@ -90,8 +117,14 @@ class SongsTab(SettingsTab):
u'search as type', QtCore.QVariant(False)).toBool()
self.song_bar = settings.value(
u'display songbar', QtCore.QVariant(True)).toBool()
self.update_edit = settings.value(
u'update service on edit', QtCore.QVariant(False)).toBool()
self.update_load = settings.value(
u'add song from service', QtCore.QVariant(True)).toBool()
self.SearchAsTypeCheckBox.setChecked(self.song_search)
self.SongBarActiveCheckBox.setChecked(self.song_bar)
self.SongUpdateOnEditCheckBox.setChecked(self.update_edit)
self.SongAddFromServiceCheckBox.setChecked(self.update_load)
settings.endGroup()
def save(self):
@ -99,4 +132,6 @@ class SongsTab(SettingsTab):
settings.beginGroup(self.settingsSection)
settings.setValue(u'search as type', QtCore.QVariant(self.song_search))
settings.setValue(u'display songbar', QtCore.QVariant(self.song_bar))
settings.setValue(u'update service on edit', QtCore.QVariant(self.update_edit))
settings.setValue(u'add song from service', QtCore.QVariant(self.update_load))
settings.endGroup()

View File

@ -282,11 +282,9 @@ class Song(object):
def get_author_list(self, asOneString = True):
"""Return the list of authors as a string
asOneString
True -- string:
'John Newton, A Parker'
False -- list of strings
['John Newton', u'A Parker']
``asOneString``
If ``True``, returns 'John Newton, A Parker'. If ``False``, returns
[u'John Newton', u'A Parker']
"""
if asOneString:
res = self._assure_string(self.author_list)
@ -297,7 +295,8 @@ class Song(object):
def set_author_list(self, author_list):
"""Set the author_list
author_list -- a string or list of strings
``author_list``
a string or list of strings
"""
if author_list is None:
self.author_list = None
@ -307,11 +306,9 @@ class Song(object):
def get_category_array(self, asOneString = True):
"""Return the list of categories as a string
asOneString
True -- string:
'Hymn, Gospel'
False -- list of strings
['Hymn', u'Gospel']
``asOneString``
If ``True``, returns 'Hymn, Gospel'. If ``False``, returns
[u'Hymn', u'Gospel']
"""
if asOneString:
res = self._assure_string(self.category_array)
@ -381,6 +378,7 @@ class Song(object):
properties
slideNumber -- 1 .. numberOfSlides
Returns a list as:
[theme_name (string),
title (string),

View File

@ -41,8 +41,7 @@ class WowImport(SongImport):
The :class:`WowImport` class provides the ability to import song files from
Words of Worship.
Words Of Worship Song File Format
`````````````````````````````````
**Words Of Worship Song File Format:**
The Words Of Worship song file format is as follows:
@ -65,12 +64,12 @@ class WowImport(SongImport):
Each block ends with 4 bytes, the first of which defines what type of
block it is, and the rest which are null bytes:
* ``NUL`` (\x00) - Verse
* ``SOH`` (\x01) - Chorus
* ``STX`` (\x02) - Bridge
* ``NUL`` (0x00) - Verse
* ``SOH`` (0x01) - Chorus
* ``STX`` (0x02) - Bridge
Blocks are seperated by two bytes. The first byte is ``SOH`` (\x01),
and the second byte is ```` (\x80).
Blocks are seperated by two bytes. The first byte is 0x01, and the
second byte is 0x80.
Lines:
Each line starts with a byte which specifies how long that line is,
@ -116,16 +115,16 @@ class WowImport(SongImport):
self.import_wizard.importProgressBar.setMaximum(
len(self.import_source))
for file in self.import_source:
# TODO: check that it is a valid words of worship file (could
# check header for WoW File Song Word)
self.author = u''
self.copyright = u''
# Get the song title
self.file_name = os.path.split(file)[1]
self.import_wizard.incrementProgressBar(
"Importing %s" % (self.file_name), 0)
# Get the song title
self.title = self.file_name.rpartition(u'.')[0]
self.songData = open(file, 'rb')
if self.songData.read(19) != u'WoW File\nSong Words':
continue
# Seek to byte which stores number of blocks in the song
self.songData.seek(56)
self.no_of_blocks = ord(self.songData.read(1))

View File

@ -28,7 +28,7 @@ import logging
from PyQt4 import QtCore, QtGui
from openlp.core.lib import Plugin, build_icon, translate
from openlp.core.lib import Plugin, StringContent, build_icon, translate
from openlp.core.lib.db import Manager
from openlp.plugins.songs.lib import SongMediaItem, SongsTab
from openlp.plugins.songs.lib.db import init_schema, Song
@ -57,7 +57,8 @@ class SongsPlugin(Plugin):
self.icon = build_icon(self.icon_path)
def getSettingsTab(self):
return SongsTab(self.name)
visible_name = self.getString(StringContent.VisibleName)
return SongsTab(self.name, visible_name[u'title'])
def initialise(self):
log.info(u'Songs Initialising')
@ -70,7 +71,7 @@ class SongsPlugin(Plugin):
Create the MediaManagerItem object, which is displaed in the
Media Manager.
"""
return SongMediaItem(self, self.icon, self.name)
return SongMediaItem(self, self, self.icon)
def addImportMenuItem(self, import_menu):
"""
@ -147,3 +148,54 @@ class SongsPlugin(Plugin):
importer = class_(self.manager, **kwargs)
importer.register(self.mediaItem.import_wizard)
return importer
def setPluginTextStrings(self):
"""
Called to define all translatable texts of the plugin
"""
## Name PluginList ##
self.textStrings[StringContent.Name] = {
u'singular': translate('SongsPlugin', 'Song'),
u'plural': translate('SongsPlugin', 'Songs')
}
## Name for MediaDockManager, SettingsManager ##
self.textStrings[StringContent.VisibleName] = {
u'title': translate('SongsPlugin', 'Songs')
}
# Middle Header Bar
## New Button ##
self.textStrings[StringContent.New] = {
u'title': translate('SongsPlugin', 'Add'),
u'tooltip': translate('SongsPlugin',
'Add a new Song')
}
## Edit Button ##
self.textStrings[StringContent.Edit] = {
u'title': translate('SongsPlugin', 'Edit'),
u'tooltip': translate('SongsPlugin',
'Edit the selected Song')
}
## Delete Button ##
self.textStrings[StringContent.Delete] = {
u'title': translate('SongsPlugin', 'Delete'),
u'tooltip': translate('SongsPlugin',
'Delete the selected Song')
}
## Preview ##
self.textStrings[StringContent.Preview] = {
u'title': translate('SongsPlugin', 'Preview'),
u'tooltip': translate('SongsPlugin',
'Preview the selected Song')
}
## Live Button ##
self.textStrings[StringContent.Live] = {
u'title': translate('SongsPlugin', 'Live'),
u'tooltip': translate('SongsPlugin',
'Send the selected Song live')
}
## Add to service Button ##
self.textStrings[StringContent.Service] = {
u'title': translate('SongsPlugin', 'Service'),
u'tooltip': translate('SongsPlugin',
'Add the selected Song to the service')
}

View File

@ -29,7 +29,7 @@ from datetime import datetime
from PyQt4 import QtCore, QtGui
from openlp.core.lib import Plugin, Receiver, build_icon, translate
from openlp.core.lib import Plugin, StringContent, Receiver, build_icon, translate
from openlp.core.lib.db import Manager
from openlp.plugins.songusage.forms import SongUsageDetailForm, \
SongUsageDeleteForm
@ -162,3 +162,17 @@ class SongUsagePlugin(Plugin):
'</strong><br />This plugin tracks the usage of songs in '
'services.')
return about_text
def setPluginTextStrings(self):
"""
Called to define all translatable texts of the plugin
"""
## Name PluginList ##
self.textStrings[StringContent.Name] = {
u'singular': translate('SongUsagePlugin', 'SongUsage'),
u'plural': translate('SongUsagePlugin', 'SongUsage')
}
## Name for MediaDockManager, SettingsManager ##
self.textStrings[StringContent.VisibleName] = {
u'title': translate('SongUsagePlugin', 'SongUsage')
}

View File

@ -18,20 +18,48 @@
<normaloff>:/icon/openlp.org-icon-32.bmp</normaloff>:/icon/openlp.org-icon-32.bmp</iconset>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<item row="2" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="TitleLabel">
<widget class="QLabel" name="ThemeLabel">
<property name="text">
<string>Title:</string>
<string>Theme:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="TitleEdit"/>
<widget class="QComboBox" name="ThemeComboBox">
<property name="toolTip">
<string extracomment="Select custom theme for slide"/>
</property>
</widget>
</item>
</layout>
</item>
<item row="3" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="CreditLabel">
<property name="text">
<string>Credits:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="CreditEdit"/>
</item>
</layout>
</item>
<item row="4" column="0">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="toolTip">
<string extracomment="Edit dialog"/>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Save</set>
</property>
</widget>
</item>
<item row="1" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
@ -43,66 +71,6 @@
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QPushButton" name="UpButton">
<property name="toolTip">
<string extracomment="Move slide up 1"/>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../images/openlp-2.qrc">
<normaloff>:/services/service_up.png</normaloff>:/services/service_up.png</iconset>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>128</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="DownButton">
<property name="toolTip">
<string extracomment="Move slide down 1"/>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../images/openlp-2.qrc">
<normaloff>:/services/service_down.png</normaloff>:/services/service_down.png</iconset>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item row="2" column="0">
<widget class="QWidget" name="EditWidget" native="true">
<layout class="QHBoxLayout" name="EditLayout_3">
<property name="spacing">
<number>8</number>
</property>
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QTextEdit" name="VerseTextEdit"/>
</item>
<item>
<widget class="QWidget" name="ButtonWidge" native="true">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QPushButton" name="AddButton">
<property name="toolTip">
@ -133,16 +101,6 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="SaveButton">
<property name="toolTip">
<string extracomment="Replace edited slide"/>
</property>
<property name="text">
<string>Save</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="DeleteButton">
<property name="toolTip">
@ -154,100 +112,70 @@
</widget>
</item>
<item>
<widget class="QPushButton" name="ClearButton">
<property name="toolTip">
<string extracomment="Clear selection"/>
</property>
<property name="text">
<string>Clear</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="SplitButton">
<property name="toolTip">
<string extracomment="Add new slide split"/>
</property>
<property name="text">
<string>Split Slide</string>
</property>
</widget>
</item>
<item>
<spacer name="ButtonSpacer">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
<height>128</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item row="3" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="ThemeLabel">
<property name="text">
<string>Theme:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="ThemeComboBox">
<widget class="QPushButton" name="UpButton">
<property name="toolTip">
<string extracomment="Select custom theme for slide"/>
<string extracomment="Move slide up 1"/>
</property>
</widget>
</item>
</layout>
</item>
<item row="4" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="CreditLabel">
<property name="text">
<string>Credits:</string>
<string/>
</property>
<property name="icon">
<iconset resource="../images/openlp-2.qrc">
<normaloff>:/services/service_up.png</normaloff>:/services/service_up.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="CreditEdit"/>
<widget class="QPushButton" name="DownButton">
<property name="toolTip">
<string extracomment="Move slide down 1"/>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../images/openlp-2.qrc">
<normaloff>:/services/service_down.png</normaloff>:/services/service_down.png</iconset>
</property>
</widget>
</item>
</layout>
</item>
<item row="5" column="0">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="toolTip">
<string extracomment="Edit dialog"/>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Save</set>
</layout>
</item>
<item row="0" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="TitleLabel">
<property name="text">
<string>Title:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="TitleEdit"/>
</item>
</layout>
</item>
</layout>
</widget>
<tabstops>
<tabstop>TitleEdit</tabstop>
<tabstop>VerseTextEdit</tabstop>
<tabstop>AddButton</tabstop>
<tabstop>VerseListView</tabstop>
<tabstop>EditButton</tabstop>
<tabstop>EditAllButton</tabstop>
<tabstop>SaveButton</tabstop>
<tabstop>DeleteButton</tabstop>
<tabstop>CreditEdit</tabstop>
<tabstop>UpButton</tabstop>
<tabstop>DownButton</tabstop>
<tabstop>ThemeComboBox</tabstop>
</tabstops>
<resources>

View File

@ -0,0 +1,96 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>customSlideEditDialog</class>
<widget class="QDialog" name="customSlideEditDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>474</width>
<height>442</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="geometry">
<rect>
<x>8</x>
<y>407</y>
<width>458</width>
<height>32</height>
</rect>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Save</set>
</property>
</widget>
<widget class="QTextEdit" name="VerseTextEdit">
<property name="geometry">
<rect>
<x>8</x>
<y>8</y>
<width>458</width>
<height>349</height>
</rect>
</property>
</widget>
<widget class="QPushButton" name="SplitButton">
<property name="geometry">
<rect>
<x>380</x>
<y>370</y>
<width>85</width>
<height>27</height>
</rect>
</property>
<property name="toolTip">
<string extracomment="Add new slide split"/>
</property>
<property name="text">
<string>Split Slide</string>
</property>
</widget>
</widget>
<resources>
<include location="../images/openlp-2.qrc"/>
</resources>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>customSlideEditDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>customSlideEditDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -27,6 +27,7 @@ DefaultDirName={pf}\{#AppName}
DefaultGroupName={#AppVerName}
AllowNoIcons=true
LicenseFile=LICENSE.txt
OutputDir=..\..\dist
OutputBaseFilename=OpenLP-{#RealVersion}-setup
Compression=lzma
SolidCompression=true

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -0,0 +1,14 @@
# -*- mode: python -*-
a = Analysis([
os.path.join(HOMEPATH, 'support\\_mountzlib.py'),
os.path.join(HOMEPATH, 'support\\useUnicode.py'),
os.path.abspath('openlp.pyw')],
pathex=[os.path.abspath('.')])
pyz = PYZ(a.pure)
exe = EXE(pyz, a.scripts, exclude_binaries=1,
name=os.path.abspath(os.path.join('build', 'pyi.win32', 'OpenLP',
'OpenLP.exe')),
debug=False, strip=False, upx=True, console=False,
icon=os.path.abspath(os.path.join('resources', 'images', 'OpenLP.ico')))
coll = COLLECT(exe, a.binaries, a.zipfiles, a.datas, strip=False, upx=True,
name=os.path.abspath(os.path.join('dist', 'OpenLP')))

View File

@ -0,0 +1,611 @@
W: no module named openlp.core.lib.build_html (top-level import by openlp.core.ui.maindisplay)
W: no module named mx (top-level import by sqlite.main)
W: no module named ctypes.create_string_buffer (delayed import by urllib)
W: no module named openlp.core.ui.ServiceNoteForm (top-level import by openlp.core.ui.servicemanager)
W: no module named openlp.core.lib.MediaManagerItem (top-level import by openlp.plugins.images.lib.mediaitem)
W: no module named openlp.core.lib.SettingsManager (top-level import by openlp.core.ui.mainwindow)
W: no module named email.Iterators (delayed import by email.message)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.custom.lib.mediaitem)
W: no module named sqlalchemy.sql.join (top-level import by sqlalchemy)
W: no module named java (conditional import by xml.sax._exceptions)
W: no module named openlp.plugins.images.lib.ImageMediaItem (top-level import by openlp.plugins.images.imageplugin)
W: no module named sqlalchemy.SMALLINT (top-level import by sqlalchemy.databases.sybase)
W: no module named sqlalchemy.engine.create_engine (top-level import by sqlalchemy)
W: no module named sqlalchemy.sql.asc (top-level import by sqlalchemy)
W: no module named openlp.plugins.bibles.lib.BiblesTab (top-level import by openlp.plugins.bibles.bibleplugin)
W: no module named PyQt4._qt (top-level import by PyQt4.QtCore)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.alerts.lib.alertstab)
W: no module named sqlalchemy.Column (top-level import by openlp.plugins.custom.lib.db)
W: no module named openlp.core.lib.build_icon (top-level import by openlp.plugins.songusage.songusageplugin)
W: no module named openlp.plugins.alerts.lib.AlertsManager (top-level import by openlp.plugins.alerts.alertsplugin)
W: no module named openlp.core.lib.Receiver (top-level import by openlp.core.ui.generaltab)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.alerts.forms.alertdialog)
W: no module named openlp.core.lib.check_item_selected (top-level import by openlp.plugins.custom.lib.mediaitem)
W: no module named sqlalchemy.orm.MapperExtension (top-level import by sqlalchemy.orm.scoping)
W: no module named pyodbc (delayed import by sqlalchemy.databases.access)
W: no module named openlp.core.lib.expand_tags (top-level import by openlp.core.lib.renderer)
W: no module named openlp.core.lib.Receiver (top-level import by openlp.core.ui.servicemanager)
W: no module named sqlalchemy.exceptions (top-level import by sqlalchemy.orm.dynamic)
W: no module named ctypes._SimpleCData (top-level import by ctypes.wintypes)
W: no module named openlp.core.lib.SettingsTab (top-level import by openlp.core.ui.generaltab)
W: no module named simplejson (conditional import by openlp.plugins.remotes.lib.httpserver)
W: no module named openlp.core.lib.build_icon (top-level import by openlp.plugins.alerts.forms.alertdialog)
W: no module named sqlalchemy.exceptions (top-level import by sqlalchemy.orm.collections)
W: no module named openlp.core.lib.resize_image (top-level import by openlp.core.lib.serviceitem)
W: no module named openlp.plugins.songs.lib.SongXMLParser (top-level import by openlp.plugins.songs.forms.editsongform)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.bibles.bibleplugin)
W: no module named xml.dom.XMLNS_NAMESPACE (top-level import by xml.dom.minidom)
W: no module named openlp.plugins.songs.lib.VerseType (top-level import by openlp.plugins.songs.lib.songimport)
W: no module named openlp.plugins.songs.lib.SongXMLBuilder (top-level import by openlp.plugins.songs.forms.editsongform)
W: no module named openlp.core.ui.GeneralTab (top-level import by openlp.core.ui.settingsform)
W: no module named openlp.core.lib.SettingsManager (top-level import by openlp.plugins.images.lib.mediaitem)
W: no module named openlp.core.lib.BaseListWithDnD (top-level import by openlp.plugins.presentations.lib.mediaitem)
W: no module named openlp.core.lib.build_icon (top-level import by openlp.plugins.presentations.presentationplugin)
W: no module named informixdb (delayed import by sqlalchemy.databases.informix)
W: no module named openlp.core.lib.Plugin (top-level import by openlp.plugins.custom.customplugin)
W: no module named cjkcodecs (top-level import by BeautifulSoup)
W: no module named readline (delayed, conditional import by cmd)
W: no module named openlp.core.lib.Receiver (top-level import by openlp.plugins.songs.lib.songimport)
W: no module named openlp.core.lib.Plugin (top-level import by openlp.plugins.media.mediaplugin)
W: no module named openlp.core.lib.ThemeXML (top-level import by openlp.core.ui.amendthemeform)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.bibles.lib.manager)
W: no module named openlp.core.lib.Receiver (top-level import by openlp.plugins.custom.lib.mediaitem)
W: no module named openlp.core.lib.ServiceItem (top-level import by openlp.core.ui.maindisplay)
W: no module named openlp.plugins.songs.forms.EditVerseForm (top-level import by openlp.plugins.songs.forms.editsongform)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.songs.lib.ewimport)
W: no module named openlp.core.lib.SettingsTab (top-level import by openlp.plugins.songs.lib.songstab)
W: no module named openlp.core.utils.AppLocation (top-level import by openlp.core.ui.thememanager)
W: no module named openlp.core.ui.HideMode (top-level import by openlp.core.ui.maindisplay)
W: no module named sqlalchemy.Column (top-level import by sqlalchemy.databases.sybase)
W: no module named openlp.core.lib.build_icon (top-level import by openlp.core.ui.servicemanager)
W: no module named openlp.core.lib.translate (top-level import by openlp.core.ui.slidecontroller)
W: no module named openlp.core.lib.Receiver (top-level import by openlp.plugins.songs.forms.songimportform)
W: no module named openlp.core.lib.Receiver (top-level import by openlp.plugins.presentations.lib.mediaitem)
W: no module named openlp.core.lib.translate (top-level import by openlp.core.ui.aboutdialog)
W: no module named sqlalchemy.sql.insert (top-level import by sqlalchemy)
W: no module named openlp.core.lib.str_to_bool (top-level import by openlp.core.ui.thememanager)
W: no module named sqlalchemy.MetaData (top-level import by sqlalchemy.databases.sybase)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.bibles.lib.biblestab)
W: no module named openlp.plugins.bibles.lib.BibleManager (top-level import by openlp.plugins.bibles.bibleplugin)
W: no module named openlp.core.ui.SlideController (top-level import by openlp.core.ui.mainwindow)
W: no module named MacOS (delayed import by platform)
W: no module named openlp.core.lib.ThemeXML (top-level import by openlp.core.ui.thememanager)
W: no module named cx_Oracle (delayed import by sqlalchemy.databases.oracle)
W: no module named openlp.core.lib.Receiver (top-level import by openlp.core.ui.slidecontroller)
W: no module named openlp.core.lib.translate (top-level import by openlp.core.ui.servicenotedialog)
W: no module named sqlalchemy.sql.except_ (top-level import by sqlalchemy)
W: no module named openlp.core.ui.AboutForm (top-level import by openlp.core.ui.mainwindow)
W: no module named EasyDialogs (conditional import by getpass)
W: no module named openlp.core.lib.SettingsManager (top-level import by openlp.core.lib.mediamanageritem)
W: no module named sqlalchemy.orm.SessionExtension (top-level import by sqlalchemy.orm.session)
W: no module named sqlalchemy.orm.relation (top-level import by openlp.plugins.bibles.lib.db)
W: no module named openlp.plugins.songs.lib.VerseType (top-level import by openlp.plugins.songs.forms.editsongform)
W: no module named openlp.core.utils.AppLocation (top-level import by openlp.plugins.bibles.lib.http)
W: no module named sqlalchemy.sql.func (top-level import by sqlalchemy)
W: no module named openlp.core.lib.translate (top-level import by openlp.core.utils.languagemanager)
W: no module named openlp.core.lib.Receiver (top-level import by openlp.core.ui.mainwindow)
W: no module named uno (conditional import by openlp.plugins.songs.lib.oooimport)
W: no module named kinterbasdb (delayed import by sqlalchemy.databases.firebird)
W: no module named multiprocessing.RLock (top-level import by multiprocessing.sharedctypes)
W: no module named openlp.core.lib.translate (top-level import by openlp.core.ui.filerenameform)
W: no module named sqlalchemy.ForeignKey (top-level import by sqlalchemy.databases.mssql)
W: no module named openlp.core.lib.Renderer (top-level import by openlp.core.lib.rendermanager)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.songs.forms.songmaintenancedialog)
W: no module named openlp.core.lib.check_item_selected (top-level import by openlp.plugins.songs.lib.mediaitem)
W: no module named openlp.core.lib.build_icon (top-level import by openlp.core.lib.mediamanageritem)
W: no module named openlp.core.ui.FileRenameForm (top-level import by openlp.core.ui.thememanager)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.songs.songsplugin)
W: no module named openlp.core.lib.build_icon (top-level import by openlp.plugins.bibles.bibleplugin)
W: no module named vms_lib (delayed, conditional import by platform)
W: no module named openlp.core.lib.resize_image (top-level import by openlp.core.ui.slidecontroller)
W: no module named openlp.core.lib.Receiver (top-level import by openlp.plugins.alerts.lib.alertsmanager)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.songusage.forms.songusagedetaildialog)
W: no module named openlp.plugins.remotes.lib.RemoteTab (top-level import by openlp.plugins.remotes.remoteplugin)
W: no module named openlp.core.ui.ServiceManager (top-level import by openlp.core.ui.mainwindow)
W: no module named openlp.core.lib.SettingsManager (top-level import by openlp.plugins.songusage.forms.songusagedetailform)
W: no module named openlp.core.ui.SettingsForm (top-level import by openlp.core.ui.mainwindow)
W: no module named openlp.plugins.alerts.lib.AlertsTab (top-level import by openlp.plugins.alerts.alertsplugin)
W: no module named xdg (delayed, conditional import by openlp.core.utils)
W: no module named openlp.core.lib.build_icon (top-level import by openlp.plugins.custom.customplugin)
W: no module named openlp.core.ui.AmendThemeForm (top-level import by openlp.core.ui.thememanager)
W: no module named openlp.core.lib.ItemCapabilities (top-level import by openlp.plugins.songs.lib.mediaitem)
W: no module named openlp.core.lib.ItemCapabilities (top-level import by openlp.plugins.custom.lib.mediaitem)
W: no module named posix (delayed, conditional import by iu)
W: no module named openlp.plugins.songs.lib.VerseType (top-level import by openlp.plugins.songs.forms.editversedialog)
W: no module named multiprocessing.dummy.Process (delayed import by __main__)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.presentations.presentationplugin)
W: no module named sqlalchemy.String (top-level import by sqlalchemy.databases.mssql)
W: no module named xml.dom.EMPTY_PREFIX (top-level import by xml.dom.expatbuilder)
W: no module named openlp.core.lib.MediaManagerItem (top-level import by openlp.plugins.custom.lib.mediaitem)
W: no module named openlp.core.lib.ServiceItem (top-level import by openlp.core.lib.mediamanageritem)
W: no module named openlp.core.lib.PluginManager (top-level import by openlp.core.ui.mainwindow)
W: no module named multiprocessing.current_process (top-level import by multiprocessing.reduction)
W: no module named openlp.core.lib.MediaManagerItem (top-level import by openlp.plugins.songs.lib.mediaitem)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.songs.forms.songbookform)
W: no module named openlp.core.lib.Plugin (top-level import by openlp.plugins.presentations.presentationplugin)
W: no module named xmltok (top-level import by pyexpat)
W: no module named openlp.plugins.bibles.lib.SearchResults (top-level import by openlp.plugins.bibles.lib.http)
W: no module named sqlalchemy.sql.delete (top-level import by sqlalchemy)
W: no module named openlp.core.lib.Receiver (top-level import by openlp.plugins.songs.lib.oooimport)
W: no module named _emx_link (conditional import by os)
W: no module named openlp.core.lib.build_icon (top-level import by openlp.core.ui.aboutdialog)
W: no module named openlp.core.lib.build_icon (top-level import by openlp.plugins.bibles.forms.bibleimportwizard)
W: no module named openlp.core.lib.Plugin (top-level import by openlp.core.lib.pluginmanager)
W: no module named openlp.plugins.songs.lib.SongsTab (top-level import by openlp.plugins.songs.songsplugin)
W: no module named sqlalchemy.CHAR (top-level import by sqlalchemy.databases.sybase)
W: no module named sqlalchemy.sql.collate (top-level import by sqlalchemy)
W: no module named sqlalchemy.sql.outparam (top-level import by sqlalchemy)
W: no module named openlp.core.utils.AppLocation (top-level import by openlp.core.lib.db)
W: no module named openlp.core.ui.PluginForm (top-level import by openlp.core.ui.mainwindow)
W: no module named gobject (top-level import by enchant.checker.GtkSpellCheckerDialog)
W: no module named openlp.core.utils.VersionThread (top-level import by __main__)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.songs.forms.topicsform)
W: no module named sqlalchemy.Integer (top-level import by sqlalchemy.databases.mssql)
W: no module named openlp.core.lib.translate (top-level import by openlp.core.ui.exceptiondialog)
W: no module named pwd (delayed, conditional import by distutils.util)
W: no module named uno (conditional import by openlp.plugins.presentations.lib.impresscontroller)
W: no module named openlp.core.lib.Receiver (top-level import by openlp.core.utils)
W: no module named sqlalchemy.orm.class_mapper (top-level import by openlp.plugins.songs.lib.olpimport)
W: no module named sqlalchemy.orm.relation (top-level import by openlp.plugins.songs.lib.olpimport)
W: no module named readline (delayed import by pdb)
W: no module named openlp.core.ui.MainDisplay (top-level import by openlp.core.lib.rendermanager)
W: no module named openlp.core.lib.build_icon (top-level import by openlp.plugins.media.lib.mediaitem)
W: no module named sqlalchemy.Table (top-level import by openlp.plugins.songusage.lib.db)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.alerts.alertsplugin)
W: no module named openlp.core.lib.SettingsManager (top-level import by openlp.plugins.media.lib.mediaitem)
W: no module named openlp.core.lib.BaseListWithDnD (top-level import by openlp.plugins.images.lib.mediaitem)
W: no module named openlp.core.lib.Receiver (top-level import by openlp.plugins.bibles.forms.importwizardform)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.remotes.remoteplugin)
W: no module named openlp.core.lib.build_icon (top-level import by openlp.plugins.images.imageplugin)
W: no module named openlp.core.lib.SettingsTab (top-level import by openlp.plugins.alerts.lib.alertstab)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.songs.forms.editversedialog)
W: no module named openlp.core.lib.Receiver (top-level import by openlp.plugins.songusage.songusageplugin)
W: no module named openlp.core.ui.HideMode (top-level import by openlp.core.ui.slidecontroller)
W: no module named sqlalchemy.sql.between (top-level import by sqlalchemy)
W: no module named xml.dom.EMPTY_PREFIX (top-level import by xml.dom.minidom)
W: no module named pysqlite2 (delayed import by sqlalchemy.databases.sqlite)
W: no module named openlp.core.lib.SettingsManager (top-level import by openlp.core.ui.thememanager)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.custom.lib.customtab)
W: no module named gtk (top-level import by enchant.checker.GtkSpellCheckerDialog)
W: no module named xml.dom.EMPTY_NAMESPACE (top-level import by xml.dom.expatbuilder)
W: no module named openlp.core.lib.Receiver (top-level import by openlp.plugins.remotes.lib.httpserver)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.songusage.forms.songusagedeleteform)
W: no module named sqlalchemy.orm.scoped_session (top-level import by openlp.core.lib.db)
W: no module named openlp.core.lib.clean_tags (top-level import by openlp.core.lib.serviceitem)
W: no module named openlp.core.utils.get_filesystem_encoding (top-level import by openlp.core.ui.thememanager)
W: no module named xml.dom.EMPTY_NAMESPACE (top-level import by xml.dom.minidom)
W: no module named openlp.core.lib.build_icon (top-level import by openlp.core.lib.toolbar)
W: no module named openlp.core.lib.build_icon (top-level import by openlp.plugins.remotes.remoteplugin)
W: no module named sqlalchemy.exceptions (top-level import by sqlalchemy.orm.attributes)
W: no module named sqlalchemy.ForeignKey (top-level import by sqlalchemy.databases.sybase)
W: no module named openlp.core.lib.translate (top-level import by openlp.core.ui.servicemanager)
W: no module named sqlalchemy.Column (top-level import by openlp.plugins.alerts.lib.db)
W: no module named openlp.core.lib.SettingsTab (top-level import by openlp.core.ui.advancedtab)
W: no module named AES (delayed, conditional import by archive)
W: no module named openlp.core.lib.Receiver (top-level import by openlp.plugins.songs.forms.songmaintenanceform)
W: no module named openlp.core.lib.context_menu_separator (top-level import by openlp.core.lib.mediamanageritem)
W: no module named fcntl (top-level import by tempfile)
W: no module named openlp.core.lib.translate (top-level import by openlp.core.ui.thememanager)
W: no module named mx (top-level import by sqlalchemy.databases.mxODBC)
W: no module named sqlalchemy.sql.union (top-level import by sqlalchemy)
W: no module named openlp.plugins.songs.forms.TopicsForm (top-level import by openlp.plugins.songs.forms.songmaintenanceform)
W: no module named openlp.core.lib.ItemCapabilities (top-level import by openlp.plugins.images.lib.mediaitem)
W: no module named MacOS (delayed import by distutils.sysconfig)
W: no module named openlp.core.lib.SpellTextEdit (top-level import by openlp.plugins.custom.forms.editcustomdialog)
W: no module named ic (top-level import by webbrowser)
W: no module named com (conditional import by openlp.plugins.presentations.lib.impresscontroller)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.media.mediaplugin)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.custom.forms.editcustomform)
W: no module named openlp.core.lib.translate (top-level import by openlp.core.lib.spelltextedit)
W: no module named openlp.core.lib.html_expands (top-level import by openlp.core.lib.spelltextedit)
W: no module named openlp.core.lib.context_menu_action (top-level import by openlp.plugins.images.lib.mediaitem)
W: no module named sqlalchemy.Column (top-level import by openlp.plugins.songs.lib.db)
W: no module named py2exe (delayed import by enchant.tests)
W: no module named openlp.plugins.songs.forms.AuthorsForm (top-level import by openlp.plugins.songs.forms.songmaintenanceform)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.songs.forms.authorsform)
W: no module named openlp.plugins.remotes.lib.HttpServer (top-level import by openlp.plugins.remotes.remoteplugin)
W: no module named sqlalchemy.Table (top-level import by openlp.plugins.bibles.lib.db)
W: no module named openlp.core.lib.Plugin (top-level import by openlp.plugins.remotes.remoteplugin)
W: no module named openlp.core.lib.translate (top-level import by openlp.core.ui.filerenamedialog)
W: no module named openlp.core.lib.BaseListWithDnD (top-level import by openlp.plugins.media.lib.mediaitem)
W: no module named sapdb (delayed import by sqlalchemy.databases.maxdb)
W: no module named ctypes.cdll (delayed import by ctypes.util)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.presentations.lib.presentationtab)
W: no module named openlp.core.lib.MediaManagerItem (top-level import by openlp.plugins.presentations.lib.mediaitem)
W: no module named sqlalchemy.sql.text (top-level import by sqlalchemy)
W: no module named openlp.core.lib.image_to_byte (top-level import by openlp.core.lib.renderer)
W: no module named openlp.core.utils.AppLocation (top-level import by openlp.plugins.bibles.forms.importwizardform)
W: no module named openlp.core.lib.image_to_byte (top-level import by openlp.core.ui.maindisplay)
W: no module named iconv_codec (top-level import by BeautifulSoup)
W: no module named openlp.plugins.songs.forms.SongBookForm (top-level import by openlp.plugins.songs.forms.songmaintenanceform)
W: no module named sqlalchemy.sql.not_ (top-level import by sqlalchemy)
W: no module named multiprocessing.Pipe (top-level import by multiprocessing.queues)
W: no module named openlp.core.lib.check_item_selected (top-level import by openlp.plugins.images.lib.mediaitem)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.songusage.forms.songusagedetailform)
W: no module named sqlalchemy.sql.subquery (top-level import by sqlalchemy)
W: no module named openlp.core.lib.build_icon (top-level import by openlp.plugins.songs.songsplugin)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.songs.forms.editsongdialog)
W: no module named openlp.core.lib.Plugin (top-level import by openlp.plugins.bibles.bibleplugin)
W: no module named openlp.plugins.songs.forms.SongMaintenanceForm (top-level import by openlp.plugins.songs.lib.mediaitem)
W: no module named xmlparse (top-level import by pyexpat)
W: no module named sqlalchemy.sql.exists (top-level import by sqlalchemy)
W: no module named sqlalchemy.sql.and_ (top-level import by openlp.plugins.songs.forms.songmaintenanceform)
W: no module named multiprocessing.Process (top-level import by multiprocessing.pool)
W: no module named openlp.core.lib.translate (top-level import by openlp.core.ui.settingsdialog)
W: no module named sqlalchemy.exceptions (top-level import by openlp.core.lib.db)
W: no module named sqlalchemy.sql.outerjoin (top-level import by sqlalchemy)
W: no module named openlp.core.lib.build_icon (top-level import by openlp.plugins.songs.forms.editsongdialog)
W: no module named openlp.plugins.custom.lib.CustomXMLParser (top-level import by openlp.plugins.custom.lib.mediaitem)
W: no module named openlp.core.lib.build_icon (top-level import by openlp.plugins.custom.forms.editcustomdialog)
W: no module named sqlalchemy.Integer (top-level import by sqlalchemy.databases.sybase)
W: no module named sqlalchemy.exceptions (top-level import by sqlalchemy.orm.properties)
W: no module named multiprocessing.current_process (top-level import by multiprocessing.managers)
W: no module named openlp.core.ui.SplashScreen (top-level import by __main__)
W: no module named multiprocessing.TimeoutError (top-level import by multiprocessing.dummy)
W: no module named openlp.core.lib.SettingsManager (top-level import by openlp.plugins.songs.forms.songimportform)
W: no module named xml.dom.XMLNS_NAMESPACE (top-level import by xml.dom.expatbuilder)
W: no module named ctypes.c_int32 (delayed import by urllib)
W: no module named openlp.core.lib.translate (top-level import by openlp.core.ui.amendthemedialog)
W: no module named openlp.core.lib.build_icon (top-level import by openlp.core.lib.serviceitem)
W: no module named openlp.core.utils.LanguageManager (top-level import by __main__)
W: no module named sqlalchemy.orm.object_mapper (top-level import by sqlalchemy.orm.properties)
W: no module named openlp.core.utils.AppLocation (top-level import by openlp.core.utils.languagemanager)
W: no module named sqlalchemy.sql.literal_column (top-level import by sqlalchemy)
W: no module named openlp.plugins.songs.lib.SongXMLParser (top-level import by openlp.plugins.songs.lib.mediaitem)
W: no module named ctypes.c_char_p (delayed import by urllib)
W: no module named openlp.core.lib.Plugin (top-level import by openlp.plugins.images.imageplugin)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.remotes.lib.remotetab)
W: no module named openlp.core.lib.build_icon (top-level import by openlp.core.ui.mainwindow)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.bibles.lib.opensong)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.songs.forms.songimportform)
W: no module named sqlalchemy.sql.select (top-level import by sqlalchemy)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.songs.forms.songbookdialog)
W: no module named openlp.plugins.bibles.lib.BibleMediaItem (top-level import by openlp.plugins.bibles.bibleplugin)
W: no module named PyQt4._qt (top-level import by PyQt4.QtNetwork)
W: no module named openlp.core.lib.Plugin (top-level import by openlp.plugins.songs.songsplugin)
W: no module named sqlalchemy.sql.case (top-level import by sqlalchemy)
W: no module named wx (top-level import by enchant.checker.wxSpellCheckerDialog)
W: no module named openlp.core.lib.build_icon (top-level import by openlp.plugins.alerts.alertsplugin)
W: no module named com (conditional import by openlp.plugins.songs.lib.sofimport)
W: no module named PyQt4._qt (top-level import by PyQt4)
W: no module named SOCKS (top-level import by ftplib)
W: no module named openlp.plugins.songusage.forms.SongUsageDetailForm (top-level import by openlp.plugins.songusage.songusageplugin)
W: no module named sqlalchemy.sql.null (top-level import by sqlalchemy)
W: no module named sqlalchemy.MetaData (top-level import by openlp.core.lib.db)
W: no module named openlp.core.lib.ItemCapabilities (top-level import by openlp.core.ui.servicemanager)
W: no module named openlp.plugins.custom.forms.EditCustomForm (top-level import by openlp.plugins.custom.customplugin)
W: no module named org (delayed import by xml.sax)
W: no module named openlp.core.lib.SpellTextEdit (top-level import by openlp.plugins.songs.forms.editversedialog)
W: no module named sqlalchemy.orm.EXT_CONTINUE (top-level import by sqlalchemy.orm.scoping)
W: no module named openlp.core.lib.build_lyrics_outline_css (top-level import by openlp.core.lib.renderer)
W: no module named openlp.plugins.songs.lib.VerseType (top-level import by openlp.plugins.songs.forms.editverseform)
W: no module named com (conditional import by openlp.plugins.songs.lib.oooimport)
W: no module named openlp.core.lib.str_to_bool (top-level import by openlp.core.lib.theme)
W: no module named sqlalchemy.sql.literal (top-level import by sqlalchemy)
W: no module named termios (top-level import by getpass)
W: no module named openlp.core.lib.build_lyrics_format_css (top-level import by openlp.core.lib.renderer)
W: no module named ctypes.byref (delayed import by urllib)
W: no module named openlp.plugins.custom.lib.CustomTab (top-level import by openlp.plugins.custom.customplugin)
W: no module named openlp.core.lib.BaseListWithDnD (top-level import by openlp.plugins.songs.lib.mediaitem)
W: no module named openlp.core.lib.build_icon (top-level import by openlp.plugins.images.lib.mediaitem)
W: no module named openlp.plugins.bibles.lib.parse_reference (top-level import by openlp.plugins.bibles.lib.manager)
W: no module named java (delayed import by platform)
W: no module named openlp.core.ui.ServiceItemEditForm (top-level import by openlp.core.ui.servicemanager)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.custom.customplugin)
W: no module named openlp.core.lib.ThemeLevel (top-level import by openlp.core.lib.rendermanager)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.bibles.lib.db)
W: no module named _xmlrpclib (top-level import by xmlrpclib)
W: no module named openlp.core.lib.SettingsManager (top-level import by openlp.plugins.presentations.lib.mediaitem)
W: no module named openlp.plugins.media.lib.MediaMediaItem (top-level import by openlp.plugins.media.mediaplugin)
W: no module named openlp.plugins.custom.lib.CustomXMLBuilder (top-level import by openlp.plugins.custom.forms.editcustomform)
W: no module named rourl2path (conditional import by urllib)
W: no module named pwd (delayed import by webbrowser)
W: no module named openlp.core.lib.Receiver (top-level import by openlp.core.ui.themestab)
W: no module named PyQt4._qt (top-level import by PyQt4.QtWebKit)
W: no module named sqlalchemy.orm.class_mapper (delayed, conditional import by sqlalchemy.orm.interfaces)
W: no module named PyQt4._qt (top-level import by PyQt4.phonon)
W: no module named openlp.core.ui.HideMode (top-level import by openlp.plugins.presentations.lib.messagelistener)
W: no module named openlp.plugins.songusage.forms.SongUsageDeleteForm (top-level import by openlp.plugins.songusage.songusageplugin)
W: no module named openlp.core.lib.context_menu_separator (top-level import by openlp.core.ui.thememanager)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.media.lib.mediaitem)
W: no module named openlp.core.lib.translate (top-level import by openlp.core.ui.plugindialog)
W: no module named fcntl (conditional import by subprocess)
W: no module named openlp.core.lib.BaseListWithDnD (top-level import by openlp.plugins.bibles.lib.mediaitem)
W: no module named openlp.core.lib.PluginStatus (top-level import by openlp.core.lib.pluginmanager)
W: no module named openlp.core.lib.Receiver (top-level import by openlp.plugins.songs.forms.editsongform)
W: no module named openlp.core.ui.ScreenList (top-level import by __main__)
W: no module named sqlalchemy.or_ (top-level import by openlp.plugins.bibles.lib.db)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.songs.forms.editsongform)
W: no module named openlp.plugins.songs.forms.ImportWizardForm (top-level import by openlp.plugins.songs.lib.mediaitem)
W: no module named openlp.core.lib.check_item_selected (top-level import by openlp.core.ui.thememanager)
W: no module named openlp.core.ui.ThemeManager (top-level import by openlp.core.ui.mainwindow)
W: no module named pyodbc (delayed, conditional import by sqlalchemy.databases.mssql)
W: no module named openlp.core.utils.AppLocation (top-level import by openlp.core.ui.servicemanager)
W: no module named openlp.core.lib.translate (top-level import by openlp.core.lib.mediamanageritem)
W: no module named openlp.core.lib.Receiver (top-level import by openlp.plugins.bibles.lib.biblestab)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.songusage.songusageplugin)
W: no module named multiprocessing.active_children (top-level import by multiprocessing.managers)
W: no module named openlp.plugins.songs.forms.EditSongForm (top-level import by openlp.plugins.songs.lib.mediaitem)
W: no module named email.Generator (delayed import by email.message)
W: no module named mx (delayed import by sqlalchemy.databases.mxODBC)
W: no module named sqlalchemy.sql.or_ (top-level import by sqlalchemy)
W: no module named sqlalchemy.Table (top-level import by openlp.plugins.custom.lib.db)
W: no module named sqlalchemy.Table (top-level import by sqlalchemy.databases.sybase)
W: no module named openlp.core.lib.get_text_file_string (top-level import by openlp.core.ui.thememanager)
W: no module named sqlalchemy.orm.object_session (top-level import by sqlalchemy.orm.scoping)
W: no module named openlp.core.lib.MediaManagerItem (top-level import by openlp.plugins.bibles.lib.mediaitem)
W: no module named sqlalchemy.Table (top-level import by sqlalchemy.databases.mssql)
W: no module named openlp.core.utils.AppLocation (top-level import by openlp.core.ui.mainwindow)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.bibles.forms.bibleimportwizard)
W: no module named openlp.core.lib.resize_image (top-level import by openlp.core.lib.renderer)
W: no module named pymssql (delayed import by sqlalchemy.databases.mssql)
W: no module named sqlalchemy.orm.sessionmaker (top-level import by openlp.plugins.songs.lib.olpimport)
W: no module named openlp.core.lib.context_menu_action (top-level import by openlp.core.ui.thememanager)
W: no module named openlp.core.lib.expand_tags (top-level import by openlp.core.lib.serviceitem)
W: no module named gestalt (delayed import by platform)
W: no module named enchant.checker.SpellChecker (top-level import by enchant.checker.CmdLineChecker)
W: no module named openlp.core.lib.translate (top-level import by openlp.core.ui.themestab)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.songs.lib.olp1import)
W: no module named openlp.core.lib.Receiver (top-level import by openlp.plugins.presentations.lib.messagelistener)
W: no module named sqlalchemy.exceptions (top-level import by sqlalchemy.orm.interfaces)
W: no module named sqlalchemy.orm.object_mapper (top-level import by sqlalchemy.orm.query)
W: no module named sqlalchemy.sql.distinct (top-level import by sqlalchemy)
W: no module named openlp.core.lib.context_menu_action (top-level import by openlp.plugins.media.lib.mediaitem)
W: no module named sqlalchemy.sql.extract (top-level import by sqlalchemy)
W: no module named sqlalchemy.Column (top-level import by openlp.plugins.bibles.lib.db)
W: no module named psycopg2 (delayed import by sqlalchemy.databases.postgres)
W: no module named enchant.checker.SpellChecker (delayed import by enchant.checker.GtkSpellCheckerDialog)
W: no module named clr (conditional import by adodbapi.adodbapi)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.images.lib.mediaitem)
W: no module named openlp.plugins.custom.lib.CustomXMLParser (top-level import by openlp.plugins.custom.forms.editcustomform)
W: no module named openlp.core.theme.Theme (top-level import by openlp.core.ui.thememanager)
W: no module named openlp.core.lib.Receiver (top-level import by openlp.plugins.custom.forms.editcustomform)
W: no module named openlp.core.lib.Receiver (top-level import by openlp.plugins.songs.lib.mediaitem)
W: no module named openlp.core.utils.AppLocation (top-level import by openlp.core.lib.settingsmanager)
W: no module named openlp.core.lib.Receiver (top-level import by __main__)
W: no module named openlp.core.lib.SettingsManager (top-level import by openlp.plugins.bibles.lib.manager)
W: no module named org (top-level import by pickle)
W: no module named enchant.DictNotFoundError (top-level import by openlp.core.lib.spelltextedit)
W: no module named sqlalchemy.sql.except_all (top-level import by sqlalchemy)
W: no module named openlp.plugins.presentations.lib.PresentationTab (top-level import by openlp.plugins.presentations.presentationplugin)
W: no module named sqlalchemy.sql.cast (top-level import by sqlalchemy)
W: no module named sqlalchemy.orm.relation (top-level import by openlp.plugins.songs.lib.db)
W: no module named openlp.core.lib.build_icon (top-level import by openlp.core.ui.settingsdialog)
W: no module named openlp.core.utils.LanguageManager (top-level import by openlp.core.ui.mainwindow)
W: no module named openlp.core.lib.ItemCapabilities (top-level import by openlp.plugins.media.lib.mediaitem)
W: no module named sqlalchemy.sql.intersect (top-level import by sqlalchemy)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.songs.lib.songimport)
W: no module named sqlalchemy.orm.class_mapper (top-level import by sqlalchemy.orm.scoping)
W: no module named sqlalchemy.exceptions (top-level import by sqlalchemy.orm.util)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.songs.lib.opensongimport)
W: no module named openlp.core.lib.SettingsTab (top-level import by openlp.plugins.bibles.lib.biblestab)
W: no module named openlp.core.lib.translate (top-level import by openlp.core.ui.aboutform)
W: no module named openlp.plugins.custom.lib.CustomMediaItem (top-level import by openlp.plugins.custom.customplugin)
W: no module named sqlalchemy.orm.scoped_session (top-level import by openlp.plugins.songs.lib.olpimport)
W: no module named openlp.core.lib.translate (top-level import by openlp.core.ui.amendthemeform)
W: no module named sqlalchemy.engine.engine_from_config (top-level import by sqlalchemy)
W: no module named openlp.core.lib.SettingsTab (top-level import by openlp.core.ui.themestab)
W: no module named openlp.core.lib.OpenLPToolbar (top-level import by openlp.core.ui.servicemanager)
W: no module named openlp.core.lib.Receiver (top-level import by openlp.core.ui.maindisplay)
W: no module named openlp.core.lib.PluginStatus (top-level import by openlp.core.ui.pluginform)
W: no module named openlp.core.lib.Receiver (top-level import by openlp.plugins.bibles.lib.http)
W: no module named openlp.core.utils.AppLocation (top-level import by openlp.plugins.remotes.lib.httpserver)
W: no module named sqlalchemy.Table (top-level import by openlp.plugins.songs.lib.db)
W: no module named openlp.core.lib.translate (top-level import by openlp.core.utils)
W: no module named openlp.core.lib.RenderManager (top-level import by openlp.core.ui.mainwindow)
W: no module named openlp.core.lib.Plugin (top-level import by openlp.plugins.alerts.alertsplugin)
W: no module named openlp.core.lib.Receiver (top-level import by openlp.core.lib.plugin)
W: no module named sqlalchemy.ForeignKey (top-level import by openlp.plugins.bibles.lib.db)
W: no module named openlp.plugins.songs.lib.SongMediaItem (top-level import by openlp.plugins.songs.songsplugin)
W: no module named sqlalchemy.Index (top-level import by openlp.plugins.songs.lib.db)
W: no module named multiprocessing.TimeoutError (top-level import by multiprocessing.pool)
W: no module named openlp.core.lib.build_icon (top-level import by openlp.plugins.songusage.forms.songusagedetaildialog)
W: no module named enchant.DictWithPWL (delayed import by enchant.checker.tests)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.songs.lib.songstab)
W: no module named openlp.core.ui.AdvancedTab (top-level import by openlp.core.ui.settingsform)
W: no module named MySQLdb (delayed import by sqlalchemy.databases.mysql)
W: no module named openlp.plugins.presentations.lib.PresentationMediaItem (top-level import by openlp.plugins.presentations.presentationplugin)
W: no module named openlp.plugins.alerts.forms.AlertForm (top-level import by openlp.plugins.alerts.alertsplugin)
W: no module named ctypes.c_int (delayed import by urllib)
W: no module named xml.dom.XML_NAMESPACE (delayed import by xml.dom.pulldom)
W: no module named ctypes.c_void_p (delayed import by urllib)
W: no module named openlp.core.utils.AppLocation (top-level import by openlp.plugins.bibles.lib.osis)
W: no module named sqlalchemy.create_engine (top-level import by openlp.core.lib.db)
W: no module named win32com.client._get_good_object_ (top-level import by win32com.client.util)
W: no module named openlp.core.ui.MainDisplay (top-level import by openlp.core.ui.slidecontroller)
W: no module named openlp.core.lib.resize_image (top-level import by openlp.plugins.presentations.lib.presentationcontroller)
W: no module named openlp.core.lib.SettingsTab (top-level import by openlp.plugins.remotes.lib.remotetab)
W: no module named openlp.core.ui.MediaDockManager (top-level import by openlp.core.ui.mainwindow)
W: no module named sqlalchemy.exceptions (top-level import by sqlalchemy.orm.session)
W: no module named sqlalchemy.Column (top-level import by sqlalchemy.databases.mssql)
W: no module named openlp.core.lib.build_icon (top-level import by openlp.plugins.songs.forms.editversedialog)
W: no module named multiprocessing.Process (top-level import by multiprocessing.managers)
W: no module named openlp.core.lib.Receiver (top-level import by openlp.plugins.presentations.lib.presentationcontroller)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.songs.lib.mediaitem)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.custom.forms.editcustomdialog)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.alerts.lib.alertsmanager)
W: no module named sgmlop (top-level import by xmlrpclib)
W: no module named MacOS (conditional import by py_compile)
W: no module named multiprocessing.cpu_count (top-level import by multiprocessing.dummy)
W: no module named _dummy_threading (top-level import by dummy_threading)
W: no module named openlp.core.lib.translate (top-level import by openlp.core.ui.mainwindow)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.songs.forms.songmaintenanceform)
W: no module named openlp.plugins.presentations.lib.PresentationController (top-level import by openlp.plugins.presentations.presentationplugin)
W: no module named openlp.core.lib.OpenLPToolbar (top-level import by openlp.core.lib.mediamanageritem)
W: no module named sqlalchemy.sql.union_all (top-level import by sqlalchemy)
W: no module named openlp.core.lib.Receiver (top-level import by openlp.plugins.bibles.lib.opensong)
W: no module named openlp.core.lib.ItemCapabilities (top-level import by openlp.plugins.bibles.lib.mediaitem)
W: no module named openlp.core.lib.Receiver (top-level import by openlp.plugins.bibles.lib.osis)
W: no module named openlp.core.lib.Receiver (top-level import by openlp.core.ui.settingsform)
W: no module named enchant.tokenize.get_tokenizer (top-level import by enchant.checker)
W: no module named openlp.core.utils.AppLocation (top-level import by openlp.plugins.bibles.lib.manager)
W: no module named org (top-level import by copy)
W: no module named openlp.core.lib.Receiver (top-level import by openlp.core.ui.thememanager)
W: no module named openlp.core.lib.SettingsManager (top-level import by openlp.core.ui.servicemanager)
W: no module named sqlalchemy.MetaData (top-level import by openlp.plugins.songs.lib.olpimport)
W: no module named openlp.core.lib.build_icon (top-level import by openlp.plugins.songs.forms.songmaintenancedialog)
W: no module named sqlalchemy.sql.select (top-level import by sqlalchemy.databases.mssql)
W: no module named openlp.core.lib.SettingsManager (top-level import by openlp.plugins.bibles.forms.importwizardform)
W: no module named multiprocessing.current_process (top-level import by multiprocessing.connection)
W: no module named sqlalchemy.orm.sessionmaker (top-level import by openlp.core.lib.db)
W: no module named sqlalchemy.sql.desc (top-level import by sqlalchemy)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.songusage.forms.songusagedeletedialog)
W: no module named openlp.core.lib.Receiver (top-level import by openlp.plugins.bibles.lib.mediaitem)
W: no module named ctypes.cdll (delayed import by urllib)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.songs.lib)
W: no module named openlp.core.lib.build_icon (top-level import by openlp.plugins.media.mediaplugin)
W: no module named openlp.core.lib.SettingsTab (top-level import by openlp.plugins.presentations.lib.presentationtab)
W: no module named MySQLdb (delayed, conditional import by sqlalchemy.databases.mysql)
W: no module named openlp.core.lib.build_icon (top-level import by openlp.plugins.presentations.lib.mediaitem)
W: no module named openlp.core.lib.MediaManagerItem (top-level import by openlp.plugins.media.lib.mediaitem)
W: no module named sqlalchemy.orm.object_session (top-level import by sqlalchemy.orm.dynamic)
W: no module named sqlalchemy.sql.modifier (top-level import by sqlalchemy)
W: no module named _xmlplus (top-level import by xml)
W: no module named sqlalchemy.Column (top-level import by openlp.plugins.songusage.lib.db)
W: no module named openlp.core.lib.translate (top-level import by openlp.core.ui.advancedtab)
W: no module named sqlalchemy.sql.and_ (top-level import by sqlalchemy)
W: no module named sqlalchemy.MetaData (top-level import by sqlalchemy.databases.mssql)
W: no module named sqlalchemy.exceptions (top-level import by sqlalchemy.orm.dependency)
W: no module named openlp.core.lib.ThemeLevel (top-level import by openlp.core.ui.themestab)
W: no module named openlp.core.lib.Receiver (top-level import by openlp.plugins.presentations.lib.presentationtab)
W: no module named openlp.core.utils.get_images_filter (top-level import by openlp.core.ui.amendthemeform)
W: no module named openlp.core.utils.AppLocation (top-level import by openlp.plugins.presentations.presentationplugin)
W: no module named openlp.plugins.presentations.lib.MessageListener (top-level import by openlp.plugins.presentations.lib.mediaitem)
W: no module named openlp.plugins.bibles.forms.ImportWizardForm (top-level import by openlp.plugins.bibles.lib.mediaitem)
W: no module named openlp.core.utils.AppLocation (top-level import by __main__)
W: no module named sqlalchemy.ForeignKey (top-level import by openlp.plugins.songs.lib.db)
W: no module named openlp.core.lib.OpenLPToolbar (top-level import by openlp.core.ui.thememanager)
W: no module named ctypes.cdll (conditional import by openlp.plugins.presentations.lib.pptviewcontroller)
W: no module named pwd (delayed import by getpass)
W: no module named sqlalchemy.sql.and_ (top-level import by openlp.plugins.songusage.forms.songusagedetailform)
W: no module named openlp.core.lib.build_icon (top-level import by openlp.core.ui.amendthemedialog)
W: no module named openlp.core.lib.build_icon (top-level import by openlp.plugins.songs.forms.songimportwizard)
W: no module named openlp.core.lib.translate (top-level import by openlp.core.ui.serviceitemeditdialog)
W: no module named openlp.core.lib.resize_image (top-level import by openlp.core.ui.maindisplay)
W: no module named openlp.core.lib.BaseListWithDnD (top-level import by openlp.plugins.custom.lib.mediaitem)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.songs.forms.topicsdialog)
W: no module named PyQt4._qt (top-level import by PyQt4.QtGui)
W: no module named sqlalchemy.sql.update (top-level import by sqlalchemy)
W: no module named multiprocessing.current_process (delayed, conditional import by logging)
W: no module named multiprocessing.Pool (top-level import by multiprocessing.managers)
W: no module named sqlalchemy.create_engine (delayed, conditional import by sqlalchemy.schema)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.bibles.forms.importwizardform)
W: no module named openlp.core.lib.context_menu_action (top-level import by openlp.core.lib.mediamanageritem)
W: no module named posix (conditional import by os)
W: no module named sqlalchemy.sql.bindparam (top-level import by sqlalchemy)
W: no module named xml.dom.DOMImplementation (top-level import by xml.dom.domreg)
W: no module named openlp.core.utils.add_actions (top-level import by openlp.core.ui.mainwindow)
W: no module named sqlalchemy.create_engine (top-level import by openlp.plugins.songs.lib.olpimport)
W: no module named multiprocessing.cpu_count (top-level import by multiprocessing.pool)
W: no module named multiprocessing.AuthenticationError (top-level import by multiprocessing.connection)
W: no module named openlp.core.ui.ThemesTab (top-level import by openlp.core.ui.settingsform)
W: no module named openlp.core.lib.check_item_selected (top-level import by openlp.plugins.media.lib.mediaitem)
W: no module named sqlalchemy.orm.class_mapper (top-level import by openlp.plugins.bibles.lib.db)
W: no module named sqlalchemy.String (top-level import by sqlalchemy.databases.sybase)
W: no module named openlp.core.lib.context_menu_action (top-level import by openlp.core.ui.servicemanager)
W: no module named openlp.core.utils.AppLocation (top-level import by openlp.plugins.images.lib.mediaitem)
W: no module named pwd (delayed, conditional import by posixpath)
W: no module named sqlalchemy.exceptions (top-level import by sqlalchemy.orm.strategies)
W: no module named mx (top-level import by adodbapi.adodbapi)
W: no module named sqlalchemy.sql.alias (top-level import by sqlalchemy)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.songs.forms.authorsdialog)
W: no module named sqlalchemy.Table (top-level import by openlp.plugins.alerts.lib.db)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.bibles.lib.mediaitem)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.images.imageplugin)
W: no module named sqlalchemy.orm.mapperlib (delayed import by sqlalchemy.orm.util)
W: no module named openlp.core.lib.ServiceItem (top-level import by openlp.core.lib.rendermanager)
W: no module named openlp.core.lib.OpenLPDockWidget (top-level import by openlp.core.ui.mainwindow)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.songs.forms.songimportwizard)
W: no module named openlp.core.lib.Plugin (top-level import by openlp.plugins.songusage.songusageplugin)
W: no module named openlp.core.utils.AppLocation (top-level import by openlp.plugins.presentations.lib.presentationcontroller)
W: no module named openlp.core.lib.context_menu_action (top-level import by openlp.core.lib.spelltextedit)
W: no module named openlp.core.lib.build_icon (top-level import by openlp.core.ui.thememanager)
W: no module named openlp.core.lib.check_item_selected (top-level import by openlp.plugins.presentations.lib.mediaitem)
W: no module named openlp.core.lib.translate (top-level import by openlp.core.ui.pluginform)
W: no module named enchant.checker.SpellChecker (delayed import by enchant.checker.wxSpellCheckerDialog)
W: no module named sqlalchemy.DefaultClause (top-level import by sqlalchemy.databases.sqlite)
W: no module named openlp.core.lib.ServiceItem (top-level import by openlp.core.ui.servicemanager)
W: no module named openlp.core.lib.ItemCapabilities (top-level import by openlp.core.ui.slidecontroller)
W: no module named openlp.core.utils.get_images_filter (top-level import by openlp.plugins.images.lib.mediaitem)
W: no module named pyodbc (delayed import by sqlalchemy.databases.mssql)
W: no module named openlp.core.lib.OpenLPToolbar (top-level import by openlp.core.ui.slidecontroller)
W: no module named System (conditional import by adodbapi.adodbapi)
W: no module named openlp.core.lib.SettingsTab (top-level import by openlp.plugins.custom.lib.customtab)
W: no module named openlp.core.lib.Receiver (top-level import by openlp.plugins.bibles.lib.csvbible)
W: no module named openlp.core.lib.translate (top-level import by openlp.core.ui.generaltab)
W: no module named openlp.core.lib.ThemeLevel (top-level import by openlp.core.ui.servicemanager)
W: no module named sqlalchemy.exceptions (top-level import by sqlalchemy.orm.scoping)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.alerts.forms.alertform)
W: no module named mypyodbc (delayed import by sqlalchemy.databases.sybase)
W: no module named sqlalchemy.sql.intersect_all (top-level import by sqlalchemy)
W: no module named openlp.core.lib.translate (top-level import by openlp.plugins.presentations.lib.mediaitem)
W: __all__ is built strangely at line 0 - dummy_threading (C:\Python26\lib\dummy_threading.pyc)
W: delayed exec statement detected at line 0 - bdb (C:\Python26\lib\bdb.pyc)
W: delayed eval hack detected at line 0 - bdb (C:\Python26\lib\bdb.pyc)
W: delayed eval hack detected at line 0 - bdb (C:\Python26\lib\bdb.pyc)
W: delayed __import__ hack detected at line 0 - optparse (C:\Python26\lib\optparse.pyc)
W: delayed conditional __import__ hack detected at line 0 - pkg_resources (build/bdist.linux-i686/egg/pkg_resources.pyc)
W: delayed conditional exec statement detected at line 0 - pkg_resources (build/bdist.linux-i686/egg/pkg_resources.pyc)
W: delayed conditional __import__ hack detected at line 0 - pkg_resources (build/bdist.linux-i686/egg/pkg_resources.pyc)
W: delayed __import__ hack detected at line 0 - pkg_resources (build/bdist.linux-i686/egg/pkg_resources.pyc)
W: delayed conditional __import__ hack detected at line 0 - doctest (C:\Python26\lib\doctest.pyc)
W: delayed exec statement detected at line 0 - doctest (C:\Python26\lib\doctest.pyc)
W: delayed conditional __import__ hack detected at line 0 - doctest (C:\Python26\lib\doctest.pyc)
W: __all__ is built strangely at line 0 - sqlalchemy.orm.interfaces (C:\Python26\lib\site-packages\sqlalchemy-0.5.8-py2.6.egg\sqlalchemy\orm\interfaces.pyc)
W: __all__ is built strangely at line 0 - tokenize (C:\Python26\lib\tokenize.pyc)
W: __all__ is built strangely at line 0 - sqlalchemy.engine (C:\Python26\lib\site-packages\sqlalchemy-0.5.8-py2.6.egg\sqlalchemy\engine\__init__.pyc)
W: delayed __import__ hack detected at line 0 - pickle (C:\Python26\lib\pickle.pyc)
W: delayed __import__ hack detected at line 0 - pickle (C:\Python26\lib\pickle.pyc)
W: top-level conditional exec statement detected at line 0 - sqlalchemy.sql.util (C:\Python26\lib\site-packages\sqlalchemy-0.5.8-py2.6.egg\sqlalchemy\sql\util.pyc)
W: top-level conditional exec statement detected at line 0 - sqlalchemy.sql.util (C:\Python26\lib\site-packages\sqlalchemy-0.5.8-py2.6.egg\sqlalchemy\sql\util.pyc)
W: delayed conditional __import__ hack detected at line 0 - openlp.core.lib.pluginmanager (c:\Documents and Settings\raoul\My Documents\My Projects\openlp\movements\openlp\core\lib\pluginmanager.pyc)
W: delayed conditional exec statement detected at line 0 - multiprocessing.sharedctypes (C:\Python26\lib\multiprocessing\sharedctypes.pyc)
W: delayed __import__ hack detected at line 0 - encodings (C:\Python26\lib\encodings\__init__.pyc)
W: __all__ is built strangely at line 0 - sqlalchemy.databases.mysql (C:\Python26\lib\site-packages\sqlalchemy-0.5.8-py2.6.egg\sqlalchemy\databases\mysql.pyc)
W: delayed exec statement detected at line 0 - sqlalchemy.orm.attributes (C:\Python26\lib\site-packages\sqlalchemy-0.5.8-py2.6.egg\sqlalchemy\orm\attributes.pyc)
W: delayed conditional __import__ hack detected at line 0 - openlp.plugins.presentations.presentationplugin (c:\Documents and Settings\raoul\My Documents\My Projects\openlp\movements\openlp\plugins\presentations\presentationplugin.pyc)
W: delayed __import__ hack detected at line 0 - enchant.tokenize (C:\Python26\lib\site-packages\enchant\tokenize\__init__.pyc)
W: __all__ is built strangely at line 0 - multiprocessing (C:\Python26\lib\multiprocessing\__init__.pyc)
W: __all__ is built strangely at line 0 - dis (C:\Python26\lib\dis.pyc)
W: __all__ is built strangely at line 0 - sqlalchemy.databases (C:\Python26\lib\site-packages\sqlalchemy-0.5.8-py2.6.egg\sqlalchemy\databases\__init__.pyc)
W: delayed __import__ hack detected at line 0 - win32com.server.policy (C:\Python26\lib\site-packages\win32com\server\policy.pyc)
W: __all__ is built strangely at line 0 - sqlalchemy.orm.mapper (C:\Python26\lib\site-packages\sqlalchemy-0.5.8-py2.6.egg\sqlalchemy\orm\mapper.pyc)
W: top-level exec statement detected at line 0 - hashlib (C:\Python26\lib\hashlib.pyc)
W: top-level conditional exec statement detected at line 0 - hashlib (C:\Python26\lib\hashlib.pyc)
W: delayed conditional eval hack detected at line 0 - warnings (C:\Python26\lib\warnings.pyc)
W: delayed conditional __import__ hack detected at line 0 - warnings (C:\Python26\lib\warnings.pyc)
W: delayed exec statement detected at line 0 - cgi (C:\Python26\lib\cgi.pyc)
W: delayed __import__ hack detected at line 0 - email (C:\Python26\lib\email\__init__.pyc)
W: __all__ is built strangely at line 0 - sqlalchemy.orm (C:\Python26\lib\site-packages\sqlalchemy-0.5.8-py2.6.egg\sqlalchemy\orm\__init__.pyc)
W: delayed __import__ hack detected at line 0 - ctypes (C:\Python26\lib\ctypes\__init__.pyc)
W: delayed __import__ hack detected at line 0 - ctypes (C:\Python26\lib\ctypes\__init__.pyc)
W: delayed conditional __import__ hack detected at line 0 - xml.dom.domreg (C:\Python26\lib\xml\dom\domreg.pyc)
W: delayed exec statement detected at line 0 - pdb (C:\Python26\lib\pdb.pyc)
W: delayed conditional eval hack detected at line 0 - pdb (C:\Python26\lib\pdb.pyc)
W: delayed eval hack detected at line 0 - pdb (C:\Python26\lib\pdb.pyc)
W: delayed conditional eval hack detected at line 0 - pdb (C:\Python26\lib\pdb.pyc)
W: delayed eval hack detected at line 0 - pdb (C:\Python26\lib\pdb.pyc)
W: delayed conditional __import__ hack detected at line 0 - unittest (C:\Python26\lib\unittest.pyc)
W: delayed conditional __import__ hack detected at line 0 - unittest (C:\Python26\lib\unittest.pyc)
W: delayed conditional __import__ hack detected at line 0 - pkgutil (C:\Python26\lib\pkgutil.pyc)
W: delayed conditional __import__ hack detected at line 0 - pkgutil (C:\Python26\lib\pkgutil.pyc)
W: __all__ is built strangely at line 0 - sqlalchemy.orm.properties (C:\Python26\lib\site-packages\sqlalchemy-0.5.8-py2.6.egg\sqlalchemy\orm\properties.pyc)
W: delayed conditional exec statement detected at line 0 - iu (c:\Documents and Settings\raoul\My Documents\My Projects\pyinstaller\iu.pyc)
W: delayed conditional exec statement detected at line 0 - iu (c:\Documents and Settings\raoul\My Documents\My Projects\pyinstaller\iu.pyc)
W: __all__ is built strangely at line 0 - sqlalchemy.sql (C:\Python26\lib\site-packages\sqlalchemy-0.5.8-py2.6.egg\sqlalchemy\sql\__init__.pyc)
W: __all__ is built strangely at line 0 - collections (C:\Python26\lib\collections.pyc)
W: delayed exec statement detected at line 0 - collections (C:\Python26\lib\collections.pyc)
W: delayed __import__ hack detected at line 0 - sqlalchemy.engine.url (C:\Python26\lib\site-packages\sqlalchemy-0.5.8-py2.6.egg\sqlalchemy\engine\url.pyc)
W: delayed exec statement detected at line 0 - multiprocessing.managers (C:\Python26\lib\multiprocessing\managers.pyc)
W: delayed exec statement detected at line 0 - socket (C:\Python26\lib\socket.pyc)
W: delayed conditional __import__ hack detected at line 0 - win32com.client.gencache (C:\Python26\lib\site-packages\win32com\client\gencache.pyc)
W: delayed __import__ hack detected at line 0 - win32com.client.gencache (C:\Python26\lib\site-packages\win32com\client\gencache.pyc)
W: delayed eval hack detected at line 0 - os (C:\Python26\lib\os.pyc)
W: __all__ is built strangely at line 0 - __future__ (C:\Python26\lib\__future__.pyc)
W: delayed __import__ hack detected at line 0 - win32com.client.makepy (C:\Python26\lib\site-packages\win32com\client\makepy.pyc)
W: delayed exec statement detected at line 0 - win32com.client.dynamic (C:\Python26\lib\site-packages\win32com\client\dynamic.pyc)
W: __all__ is built strangely at line 0 - sqlalchemy (C:\Python26\lib\site-packages\sqlalchemy-0.5.8-py2.6.egg\sqlalchemy\__init__.pyc)
W: delayed __import__ hack detected at line 0 - xml.sax (C:\Python26\lib\xml\sax\__init__.pyc)
W: delayed eval hack detected at line 0 - gettext (C:\Python26\lib\gettext.pyc)
W: delayed eval hack detected at line 0 - sqlalchemy.util (C:\Python26\lib\site-packages\sqlalchemy-0.5.8-py2.6.egg\sqlalchemy\util.pyc)
W: delayed exec statement detected at line 0 - sqlalchemy.util (C:\Python26\lib\site-packages\sqlalchemy-0.5.8-py2.6.egg\sqlalchemy\util.pyc)

View File

@ -63,6 +63,7 @@ IGNORED_PATHS = [u'scripts']
IGNORED_FILES = [u'setup.py']
verbose_mode = False
quiet_mode = False
class Command(object):
"""
@ -128,6 +129,20 @@ class CommandStack(object):
results.append(str((item[u'command'], )))
return u'[%s]' % u', '.join(results)
def print_quiet(text, linefeed=True):
"""
This method checks to see if we are in quiet mode, and if not prints
``text`` out.
``text``
The text to print.
"""
global quiet_mode
if not quiet_mode:
if linefeed:
print text
else:
print text,
def print_verbose(text):
"""
@ -137,8 +152,8 @@ def print_verbose(text):
``text``
The text to print.
"""
global verbose_mode
if verbose_mode:
global verbose_mode, quiet_mode
if not quiet_mode and verbose_mode:
print u' %s' % text
def run(command):
@ -155,7 +170,6 @@ def run(command):
print_verbose(u'ReadyRead: %s' % QtCore.QString(process.readAll()))
print_verbose(u'Error(s):\n%s' % process.readAllStandardError())
print_verbose(u'Output:\n%s' % process.readAllStandardOutput())
print u' Done.'
def update_export_at_pootle(source_filename):
"""
@ -194,7 +208,7 @@ def download_translations():
"""
This method downloads the translation files from the Pootle server.
"""
print 'Download translation files from Pootle'
print_quiet(u'Download translation files from Pootle')
page = urllib.urlopen(SERVER_URL)
soup = BeautifulSoup(page)
languages = soup.findAll(text=re.compile(r'.*\.ts'))
@ -205,14 +219,14 @@ def download_translations():
language_file)
print_verbose(u'Get Translation File: %s' % filename)
download_file(language_file, filename)
print u' Done.'
print_quiet(u' Done.')
def prepare_project():
"""
This method creates the project file needed to update the translation files
and compile them into .qm files.
"""
print u'Generating the openlp.pro file'
print_quiet(u'Generating the openlp.pro file')
lines = []
start_dir = os.path.abspath(u'..')
start_dir = start_dir + os.sep
@ -251,10 +265,10 @@ def prepare_project():
file = open(os.path.join(start_dir, u'openlp.pro'), u'w')
file.write(u'\n'.join(lines).encode('utf8'))
file.close()
print u' Done.'
print_quiet(u' Done.')
def update_translations():
print u'Update the translation files'
print_quiet(u'Update the translation files')
if not os.path.exists(os.path.join(os.path.abspath(u'..'), u'openlp.pro')):
print u'You have no generated a project file yet, please run this ' + \
u'script with the -p option.'
@ -265,7 +279,7 @@ def update_translations():
os.chdir(os.path.abspath(u'scripts'))
def generate_binaries():
print u'Generate the related *.qm files'
print_quiet(u'Generate the related *.qm files')
if not os.path.exists(os.path.join(os.path.abspath(u'..'), u'openlp.pro')):
print u'You have not generated a project file yet, please run this ' + \
u'script with the -p option. It is also recommended that you ' + \
@ -285,6 +299,7 @@ def generate_binaries():
if re.search('.qm$', file):
copy(os.path.join(src_path, u'%s' % file),
os.path.join(dest_path, u'%s' % file))
print_quiet(u' Done.')
def create_translation(language):
@ -294,17 +309,17 @@ def create_translation(language):
``language``
The language file to create.
"""
print "Create new Translation File"
print_quiet(u'Create new Translation File')
if not language.endswith(u'.ts'):
language += u'.ts'
filename = os.path.join(os.path.abspath(u'..'), u'resources', u'i18n', language)
download_file(u'en.ts', filename)
print u' ** Please Note **'
print u' In order to get this file into OpenLP and onto the Pootle ' + \
u'translation server you will need to subscribe to the OpenLP' + \
u'Translators mailing list, and request that your language file ' + \
u'be added to the project.'
print u' Done'
print_quiet(u' ** Please Note **')
print_quiet(u' In order to get this file into OpenLP and onto the '
u'Pootle translation server you will need to subscribe to the '
u'OpenLP Translators mailing list, and request that your language '
u'file be added to the project.')
print_quiet(u' Done.')
def process_stack(command_stack):
"""
@ -315,9 +330,9 @@ def process_stack(command_stack):
The command stack to process.
"""
if command_stack:
print u'Processing %d commands...' % len(command_stack)
print_quiet(u'Processing %d commands...' % len(command_stack))
for command in command_stack:
print u'%d.' % (command_stack.current_index),
print_quiet(u'%d.' % (command_stack.current_index), False)
if command == Command.Download:
download_translations()
elif command == Command.Prepare:
@ -329,12 +344,12 @@ def process_stack(command_stack):
elif command == Command.Create:
arguments = command_stack.arguments()
create_translation(*arguments)
print u'Finished processing commands.'
print_quiet(u'Finished processing commands.')
else:
print u'No commands to process.'
print_quiet(u'No commands to process.')
def main():
global verbose_mode
global verbose_mode, quiet_mode
# Set up command line options.
usage = u'%prog [options]\nOptions are parsed in the order they are ' + \
u'listed below. If no options are given, "-dpug" will be used.\n\n' + \
@ -352,6 +367,8 @@ def main():
help='compile .ts files into .qm files')
parser.add_option('-v', '--verbose', dest='verbose', action='store_true',
help='show extra information while processing translations')
parser.add_option('-q', '--quiet', dest='quiet', action='store_true',
help='suppress all output other than errors')
(options, args) = parser.parse_args()
# Create and populate the command stack
command_stack = CommandStack()
@ -366,6 +383,7 @@ def main():
if options.generate:
command_stack.append(Command.Generate)
verbose_mode = options.verbose
quiet_mode = options.quiet
if not command_stack:
command_stack.append(Command.Download)
command_stack.append(Command.Prepare)

View File

@ -87,20 +87,33 @@ windows-builder.py
"""
import os
import sys
from shutil import copy
from subprocess import Popen, PIPE
python_exe = sys.executable
innosetup_exe = os.path.join(os.getenv(u'PROGRAMFILES'), 'Inno Setup 5',
u'ISCC.exe')
# Base paths
script_path = os.path.split(os.path.abspath(__file__))[0]
branch_path = os.path.abspath(os.path.join(script_path, u'..'))
site_packages = os.path.join(os.path.split(python_exe)[0], u'Lib',
u'site-packages')
# Files and executables
pyi_build = os.path.abspath(os.path.join(branch_path, u'..', u'..',
u'pyinstaller', u'Build.py'))
lrelease_exe = os.path.join(site_packages, u'PyQt4', u'bin', u'lrelease.exe')
i18n_utils = os.path.join(script_path, u'translation_utils.py')
# Paths
source_path = os.path.join(branch_path, u'openlp')
i18n_path = os.path.join(branch_path, u'resources', u'i18n')
winres_path = os.path.join(branch_path, u'resources', u'windows')
build_path = os.path.join(branch_path, u'build', u'pyi.win32', u'OpenLP')
dist_path = os.path.join(branch_path, u'dist', u'OpenLP')
pyinstaller_path = os.path.abspath(os.path.join(branch_path, u'..', u'..', u'pyinstaller'))
innosetup_path = os.path.join(os.getenv(u'PROGRAMFILES'), 'Inno Setup 5')
iss_path = os.path.join(branch_path, u'resources', u'innosetup')
lrelease_path = u'C:\\Python26\\Lib\\site-packages\\PyQt4\\bin\\lrelease.exe'
enchant_path = u'C:\\Python26\\Lib\\site-packages\\enchant'
enchant_path = os.path.join(site_packages, u'enchant')
def clean_build_directories():
#if not os.path.exists(build_path)
@ -117,11 +130,13 @@ def clean_build_directories():
def run_pyinstaller():
print u'Running PyInstaller...'
os.chdir(branch_path)
pyinstaller = Popen((u'python', os.path.join(pyinstaller_path, u'Build.py'),
u'-y', u'OpenLP.spec'))
pyinstaller = Popen((python_exe, pyi_build, u'-y', u'-o', build_path,
os.path.join(winres_path, u'OpenLP.spec')), stdout=PIPE)
output, error = pyinstaller.communicate()
code = pyinstaller.wait()
if code != 0:
raise Exception(u'Error running PyInstaller Build.py')
print output
raise Exception(u'Error running PyInstaller')
def write_version_file():
print u'Writing version file...'
@ -176,16 +191,18 @@ def copy_plugins():
def copy_windows_files():
print u'Copying extra files for Windows...'
copy(os.path.join(iss_path, u'OpenLP.ico'), os.path.join(dist_path, u'OpenLP.ico'))
copy(os.path.join(iss_path, u'LICENSE.txt'), os.path.join(dist_path, u'LICENSE.txt'))
copy(os.path.join(winres_path, u'OpenLP.ico'),
os.path.join(dist_path, u'OpenLP.ico'))
copy(os.path.join(winres_path, u'LICENSE.txt'),
os.path.join(dist_path, u'LICENSE.txt'))
def update_translations():
print u'Updating translations...'
os.chdir(script_path)
translation_utils = Popen(u'python translation_utils.py -dpu')
translation_utils = Popen((python_exe, i18n_utils, u'-qdpu'))
code = translation_utils.wait()
if code != 0:
print u'Error running translation_utils.py'
raise Exception(u'Error running translation_utils.py')
def compile_translations():
print u'Compiling translations...'
@ -197,19 +214,17 @@ def compile_translations():
source_path = os.path.join(i18n_path, file)
dest_path = os.path.join(dist_path, u'i18n',
file.replace(u'.ts', u'.qm'))
lconvert = Popen(u'"%s" "%s" -qm "%s"' % (lrelease_path, \
source_path, dest_path))
lconvert = Popen((lrelease_exe, u'-compress', u'-silent',
source_path, u'-qm', dest_path))
code = lconvert.wait()
if code != 0:
print 'Error running lconvert on %s' % source_path
raise Exception('Error running lconvert on %s' % source_path)
def run_innosetup():
print u'Running Inno Setup...'
os.chdir(iss_path)
run_command = u'"%s" "%s"' % (os.path.join(innosetup_path, u'ISCC.exe'),
os.path.join(iss_path, u'OpenLP-2.0.iss'))
print run_command
innosetup = Popen(run_command)
os.chdir(winres_path)
innosetup = Popen((innosetup_exe,
os.path.join(winres_path, u'OpenLP-2.0.iss'), u'/q'))
code = innosetup.wait()
if code != 0:
raise Exception(u'Error running Inno Setup')
@ -221,9 +236,9 @@ def main():
print "Branch path:", branch_path
print "Source path:", source_path
print "\"dist\" path:", dist_path
print "PyInstaller path:", pyinstaller_path
print "PyInstaller:", pyi_build
print "Inno Setup path:", innosetup_path
print "ISS file path:", iss_path
print "Windows resources:", winres_path
#clean_build_directories()
run_pyinstaller()
write_version_file()