Added some fixes to the operation and layout of the slide controllers.

This commit is contained in:
Raoul Snyman 2009-07-12 22:38:34 +02:00
commit 7a0f9d3e06
49 changed files with 1848 additions and 654 deletions

View File

@ -8,3 +8,5 @@
.eric4project
list
openlp.org 2.0.e4*
documentation/build/html
documentation/build/doctrees

View File

@ -21,27 +21,35 @@ Place, Suite 330, Boston, MA 02111-1307 USA
import codecs
import sys
def convert_file(self, inname, outname):
"""
Convert a file from another encoding into UTF-8.
class Convert():
def __init__(self):
pass
``inname``
The name of the file to be opened and converted.
def process(self, inname, outname):
infile = codecs.open(inname, 'r', encoding='iso-8859-1')
writefile = codecs.open(outname, 'w', encoding='utf-8')
for line in infile:
#replace the quotes with quotes
line, replace("''", "'")
writefile.write(line)
infile.close()
writefile.close()
``outname``
The output file name.
"""
infile = codecs.open(inname, 'r', encoding='iso-8859-1')
writefile = codecs.open(outname, 'w', encoding='utf-8')
for line in infile:
#replace the quotes with quotes
line = line.replace(u'\'\'', u'\'')
writefile.write(line)
infile.close()
writefile.close()
if __name__ == '__main__':
"""
Run the conversion script.
"""
if len(sys.argv) < 2:
print 'No action specified.'
sys.exit()
print u'Uncode conversion '
print u'Input file = ', sys.argv[1:]
print u'Output file = ', sys.argv[2:]
mig = Convert()
mig.process(sys.argv[1:],sys.argv[2:])
print 'Uncode conversion:'
print 'Input file = ', sys.argv[1]
print 'Output file = ', sys.argv[2]
print 'Converting...'
convert_file(sys.argv[1], sys.argv[2])
print 'Done.'

73
demo.py
View File

@ -16,12 +16,14 @@ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA
"""
from openlp.core import Renderer
from openlp.theme import Theme
import sys
import time
from PyQt4 import QtGui, QtCore
from openlp.core import Renderer
from openlp.theme import Theme
words="""How sweet the name of Jesus sounds
In a believer's ear!
It soothes his sorrows, heals his wounds,
@ -29,53 +31,74 @@ And drives away his fear.
"""
class TstFrame(QtGui.QMainWindow):
""" We simply derive a new class of QMainWindow"""
# {{{ init
"""
We simply derive a new class of QMainWindow
"""
def __init__(self, *args, **kwargs):
"""Create the DemoPanel."""
"""
Create the DemoPanel.
"""
QtGui.QMainWindow.__init__(self)
self.resize(1024,768)
self.size=(1024,768)
self.v=0
self._font=QtGui.QFont(u'Decorative', 32)
self.framecount=0
self.resize(1024, 768)
self.size = (1024, 768)
self.v = 0
self._font = QtGui.QFont(u'Decorative', 32)
self.framecount = 0
self.totaltime = 0
self.dir=1
self.y=1
# self.startTimer(10)
self.frame=QtGui.QFrame()
self.dir = 1
self.y = 1
self.frame = QtGui.QFrame()
self.setCentralWidget(self.frame)
self.r=Renderer()
self.r = Renderer()
self.r.set_theme(Theme(u'demo_theme.xml'))
self.r.set_text_rectangle(self.frame.frameRect())
self.r.set_paint_dest(self)
self.r.set_words_openlp(words)
def timerEvent(self, event):
"""
Update the form on a timer event.
``event``
The event which triggered this update.
"""
self.update()
def paintEvent(self, event):
"""
Repaint the canvas.
``event``
The event which triggered this repaint.
"""
self.r.set_text_rectangle(self.frame.frameRect())
self.r.scale_bg_image()
t1=time.clock()
t1 = time.clock()
self.r.render_screen(0)
t2 = time.clock()
deltat=t2-t1
deltat = t2 - t1
self.totaltime += deltat
self.framecount+=1
self.framecount += 1
print "Timing result: %5.3ffps" %(self.framecount/float(self.totaltime))
# }}}
class Demo:
class Demo(object):
"""
The demo application itself.
"""
def __init__(self):
"""
Construct the application.
"""
app = QtGui.QApplication(sys.argv)
main=TstFrame()
main = TstFrame()
main.show()
sys.exit(app.exec_())
if __name__=="__main__":
t=Demo()
"""
Run the demo.
"""
t = Demo()

88
documentation/Makefile Normal file
View File

@ -0,0 +1,88 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
.PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean:
-rm -rf build/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) build/html
@echo
@echo "Build finished. The HTML pages are in build/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) build/dirhtml
@echo
@echo "Build finished. The HTML pages are in build/dirhtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) build/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) build/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) build/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in build/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) build/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in build/qthelp, like this:"
@echo "# qcollectiongenerator build/qthelp/OpenLP.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile build/qthelp/OpenLP.qhc"
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) build/latex
@echo
@echo "Build finished; the LaTeX files are in build/latex."
@echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
"run these through (pdf)latex."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) build/changes
@echo
@echo "The overview file is in build/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) build/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in build/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) build/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in build/doctest/output.txt."

112
documentation/make.bat Normal file
View File

@ -0,0 +1,112 @@
@ECHO OFF
REM Command file for Sphinx documentation
set SPHINXBUILD=sphinx-build
set ALLSPHINXOPTS=-d build/doctrees %SPHINXOPTS% source
if NOT "%PAPER%" == "" (
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
)
if "%1" == "" goto help
if "%1" == "help" (
:help
echo.Please use `make ^<target^>` where ^<target^> is one of
echo. html to make standalone HTML files
echo. dirhtml to make HTML files named index.html in directories
echo. pickle to make pickle files
echo. json to make JSON files
echo. htmlhelp to make HTML files and a HTML help project
echo. qthelp to make HTML files and a qthelp project
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
echo. changes to make an overview over all changed/added/deprecated items
echo. linkcheck to check all external links for integrity
echo. doctest to run all doctests embedded in the documentation if enabled
goto end
)
if "%1" == "clean" (
for /d %%i in (build\*) do rmdir /q /s %%i
del /q /s build\*
goto end
)
if "%1" == "html" (
%SPHINXBUILD% -b html %ALLSPHINXOPTS% build/html
echo.
echo.Build finished. The HTML pages are in build/html.
goto end
)
if "%1" == "dirhtml" (
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% build/dirhtml
echo.
echo.Build finished. The HTML pages are in build/dirhtml.
goto end
)
if "%1" == "pickle" (
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% build/pickle
echo.
echo.Build finished; now you can process the pickle files.
goto end
)
if "%1" == "json" (
%SPHINXBUILD% -b json %ALLSPHINXOPTS% build/json
echo.
echo.Build finished; now you can process the JSON files.
goto end
)
if "%1" == "htmlhelp" (
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% build/htmlhelp
echo.
echo.Build finished; now you can run HTML Help Workshop with the ^
.hhp project file in build/htmlhelp.
goto end
)
if "%1" == "qthelp" (
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% build/qthelp
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in build/qthelp, like this:
echo.^> qcollectiongenerator build\qthelp\OpenLP.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile build\qthelp\OpenLP.ghc
goto end
)
if "%1" == "latex" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% build/latex
echo.
echo.Build finished; the LaTeX files are in build/latex.
goto end
)
if "%1" == "changes" (
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% build/changes
echo.
echo.The overview file is in build/changes.
goto end
)
if "%1" == "linkcheck" (
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% build/linkcheck
echo.
echo.Link check complete; look for any errors in the above output ^
or in build/linkcheck/output.txt.
goto end
)
if "%1" == "doctest" (
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% build/doctest
echo.
echo.Testing of doctests in the sources finished, look at the ^
results in build/doctest/output.txt.
goto end
)
:end

View File

@ -0,0 +1,194 @@
# -*- coding: utf-8 -*-
#
# OpenLP documentation build configuration file, created by
# sphinx-quickstart on Fri Jul 10 17:20:40 2009.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys, os
# 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('..', '..')))
# -- General configuration -----------------------------------------------------
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The encoding of source files.
source_encoding = 'utf-8'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'OpenLP'
copyright = u'2009, Raoul Snyman'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '2.0'
# The full version, including alpha/beta/rc tags.
release = '1.9.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of documents that shouldn't be included in the build.
#unused_docs = []
# List of directories, relative to source directory, that shouldn't be searched
# for source files.
exclude_trees = []
# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
add_module_names = False
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# -- Options for HTML output ---------------------------------------------------
# The theme to use for HTML and HTML Help pages. Major themes that come with
# Sphinx are currently 'default' and 'sphinxdoc'.
html_theme = 'default'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_use_modindex = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = ''
# Output file base name for HTML help builder.
htmlhelp_basename = 'OpenLPdoc'
# -- Options for LaTeX output --------------------------------------------------
# The paper size ('letter' or 'a4').
#latex_paper_size = 'letter'
# The font size ('10pt', '11pt' or '12pt').
#latex_font_size = '10pt'
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('index', 'OpenLP.tex', u'OpenLP Documentation',
u'Raoul Snyman', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# Additional stuff for the LaTeX preamble.
#latex_preamble = ''
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_use_modindex = True

View File

@ -0,0 +1,44 @@
.. _core-index:
:mod:`core` Module
==================
.. automodule:: openlp.core
:members:
:mod:`lib` Module
-----------------
.. automodule:: openlp.core.lib
:members:
:mod:`baselistwithdnd` Submodule
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. automodule:: openlp.core.lib.baselistwithdnd
:members:
:mod:`event` Submodule
^^^^^^^^^^^^^^^^^^^^^^
.. automodule:: openlp.core.lib.event
:members:
:mod:`eventmanager` Submodule
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. automodule:: openlp.core.lib.eventmanager
:members:
:mod:`eventreceiver` Submodule
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. automodule:: openlp.core.lib.eventreceiver
:members:
:mod:`theme` Submodule
----------------------
.. automodule:: openlp.core.theme
:members:

View File

@ -0,0 +1,25 @@
.. OpenLP documentation master file, created by
sphinx-quickstart on Fri Jul 10 17:20:40 2009.
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
openlp
core/index
migration/index
plugins/index
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

View File

@ -0,0 +1,32 @@
.. _migration-index:
:mod:`migration` Module
=======================
.. automodule:: openlp.migration
:members:
:mod:`display` Submodule
------------------------
.. automodule:: openlp.migration.display
:members:
:mod:`migratebibles` Submodule
------------------------------
.. automodule:: openlp.migration.migratebibles
:members:
:mod:`migratefiles` Submodule
-----------------------------
.. automodule:: openlp.migration.migratefiles
:members:
:mod:`migratesongs` Submodule
-----------------------------
.. automodule:: openlp.migration.migratesongs
:members:

View File

@ -0,0 +1,7 @@
.. _openlp:
:mod:`openlp` Module
====================
.. automodule:: openlp
:members:

View File

@ -0,0 +1,44 @@
.. _plugins-index:
:mod:`plugins` Module
=====================
.. automodule:: openlp.plugins
:members:
:mod:`songs` Plugin
-------------------
.. automodule:: openlp.plugins.songs
:members:
:mod:`bibles` Plugin
--------------------
.. automodule:: openlp.plugins.bibles
:members:
:mod:`presentations` Plugin
---------------------------
.. automodule:: openlp.plugins.presentations
:members:
:mod:`media` Plugin
-------------------
.. automodule:: openlp.plugins.media
:members:
:mod:`images` Plugin
--------------------
.. automodule:: openlp.plugins.images
:members:
:mod:`custom` Plugin
--------------------
.. automodule:: openlp.plugins.custom
:members:

View File

@ -23,22 +23,29 @@ import sys
import logging
from PyQt4 import QtCore, QtGui
from openlp.core.lib import Receiver
from openlp.core.resources import *
from openlp.core.ui import MainWindow, SplashScreen
logging.basicConfig(level=logging.DEBUG,
format=u'%(asctime)s:%(msecs)3d %(name)-15s %(levelname)-8s %(message)s',
datefmt=u'%m-%d %H:%M:%S', filename=u'openlp.log', filemode=u'w')
from openlp.core.resources import *
from openlp.core.ui import MainWindow, SplashScreen
class OpenLP(QtGui.QApplication):
"""
The core application class. This class inherits from Qt's QApplication
class in order to provide the core of the application.
"""
global log
log = logging.getLogger(u'OpenLP Application')
log.info(u'Application Loaded')
def run(self):
#set the default string encoding
"""
Run the OpenLP application.
"""
#set the default string encoding
try:
sys.setappdefaultencoding(u'utf-8')
except:
@ -68,5 +75,8 @@ class OpenLP(QtGui.QApplication):
sys.exit(app.exec_())
if __name__ == u'__main__':
"""
Instantiate and run the application.
"""
app = OpenLP(sys.argv)
app.run()

View File

@ -1,17 +0,0 @@
"""
OpenLP - Open Source Lyrics Projection
Copyright (c) 2008 Raoul Snyman
Portions copyright (c) 2008 Martin Thompson, Tim Bentley
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
"""

View File

@ -17,8 +17,9 @@ 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 settingsmanager import SettingsManager
from openlp.core.lib.pluginmanager import PluginManager
__all__ = ['SettingsManager', 'PluginManager' ]
#from settingsmanager import SettingsManager
#from openlp.core.lib.pluginmanager import PluginManager
#
#__all__ = ['SettingsManager', 'PluginManager' ]

View File

@ -57,13 +57,15 @@ def contextMenuSeparator(base):
action.setSeparator(True)
return action
from settingsmanager import SettingsManager
from pluginconfig import PluginConfig
from plugin import Plugin
from eventmanager import EventManager
from pluginmanager import PluginManager
from settingstab import SettingsTab
from mediamanageritem import MediaManagerItem
from event import Event
from event import EventType
from eventmanager import EventManager
from xmlrootclass import XmlRootClass
from serviceitem import ServiceItem
from eventreceiver import Receiver
@ -79,5 +81,4 @@ from baselistwithdnd import BaseListWithDnD
from listwithpreviews import ListWithPreviews
__all__ = [ 'translate', 'file_to_xml', 'str_to_bool',
'contextMenuAction', 'contextMenuSeparator','ServiceItem'
]
'contextMenuAction', 'contextMenuSeparator','ServiceItem']

View File

@ -2,9 +2,11 @@
# vim: autoindent shiftwidth=4 expandtab textwidth=80
"""
OpenLP - Open Source Lyrics Projection
Copyright (c) 2008 Raoul Snyman
Portions copyright (c) 2008-2009 Martin Thompson, Tim Bentley, Scott Guerreri,
Carsten Tingaard, Jonathan Corwin
Carsten Tingaard, Jonathan Corwin
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

View File

@ -2,9 +2,11 @@
# vim: autoindent shiftwidth=4 expandtab textwidth=80
"""
OpenLP - Open Source Lyrics Projection
Copyright (c) 2008 Raoul Snyman
Portions copyright (c) 2008-2009 Martin Thompson, Tim Bentley, Scott Guerreri,
Carsten Tingaard, Jonathan Corwin
Carsten Tingaard, Jonathan Corwin
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
@ -32,14 +34,27 @@ class EventManager(object):
log = logging.getLogger(u'EventManager')
def __init__(self):
"""
Defines the class and a list of endpoints
"""
self.endpoints = []
log.info(u'Initialising')
def register(self, plugin):
"""
Called by plugings who wish to receive event notifications
"""
log.debug(u'plugin %s registered with EventManager', plugin)
self.endpoints.append(plugin)
def post_event(self, event):
"""
Called by any part of the system which wants send events to the plugins
``event``
The event type to be triggered
"""
log.debug(u'post event called for event %s', event.event_type)
for point in self.endpoints:
point.handle_event(event)

View File

@ -1,7 +1,9 @@
# -*- coding: utf-8 -*-
"""
OpenLP - Open Source Lyrics Projection
Copyright (c) 2008 Raoul Snyman
Portions copyright (c) 2008-2009 Martin Thompson, Tim Bentley,
This program is free software; you can redistribute it and/or modify it under
@ -40,6 +42,7 @@ class Receiver():
This is a static wrapper around the EventReceiver class.
As there is only one instance of it in the systems the QT signal/slot architecture
can send messages across the system
Send message
Receiver().send_message(u'messageid',data)

View File

@ -233,24 +233,25 @@ class MediaManagerItem(QtGui.QWidget):
def onPreviewClick(self):
log.debug(self.PluginTextShort+u' Preview Requested')
service_item = ServiceItem(self.parent)
service_item.addIcon(u':/media/media_'+self.PluginTextShort.lower()+u'.png')
self.generateSlideData(service_item)
service_item = self.buildServiceItem()
self.parent.preview_controller.addServiceItem(service_item)
self.ListView.clearSelection()
def onLiveClick(self):
log.debug(self.PluginTextShort + u' Live Requested')
service_item = ServiceItem(self.parent)
service_item.addIcon(u':/media/media_'+self.PluginTextShort.lower()+u'.png')
self.generateSlideData(service_item)
service_item = self.buildServiceItem()
self.parent.live_controller.addServiceItem(service_item)
self.ListView.clearSelection()
def onAddClick(self):
log.debug(self.PluginTextShort+u' Add Requested')
service_item = self.buildServiceItem()
self.parent.service_manager.addServiceItem(service_item)
def buildServiceItem(self):
"""
Common method for generating a service item
"""
service_item = ServiceItem(self.parent)
service_item.addIcon(u':/media/media_'+self.PluginTextShort.lower()+u'.png')
self.generateSlideData(service_item)
self.parent.service_manager.addServiceItem(service_item)
self.ListView.clearSelection()
return service_item

View File

@ -31,42 +31,58 @@ class Plugin(object):
Base class for openlp plugins to inherit from.
Basic attributes are:
* name
``name``
The name that should appear in the plugins list.
* version
``version``
The version number of this iteration of the plugin.
* icon
``icon``
An instance of QIcon, which holds an icon for this plugin.
* config
``config``
An instance of PluginConfig, which allows plugins to read and write to
openlp.org's configuration. This is pre-instantiated.
* log
``log``
A log object used to log debugging messages. This is pre-instantiated.
Hook functions:
* check_pre_conditions()
``check_pre_conditions()``
Provides the Plugin with a handle to check if it can be loaded.
* get_media_manager_item()
``get_media_manager_item()``
Returns an instance of MediaManagerItem to be used in the Media Manager.
* add_import_menu_item(import_menu)
``add_import_menu_item(import_menu)``
Add an item to the Import menu.
* add_export_menu_item(export_menu)
``add_export_menu_item(export_menu)``
Add an item to the Export menu.
* get_settings_tab()
``get_settings_tab()``
Returns an instance of SettingsTabItem to be used in the Settings dialog.
* add_to_menu(menubar)
``add_to_menu(menubar)``
A method to add a menu item to anywhere in the menu, given the menu bar.
* handle_event(event)
``handle_event(event)``
A method use to handle events, given an Event object.
* about()
``about()``
Used in the plugin manager, when a person clicks on the 'About' button.
* save(data)
``save(data)``
A method to convert the plugin's data to a string to be stored in the
Service file.
* load(string)
``load(string)``
A method to convert the string from a Service file into the plugin's
own data format.
* render(theme, screen_number)
``render(theme, screen_number)``
A method used to render something to the screen, given the current theme
and screen number.
"""
@ -78,11 +94,20 @@ class Plugin(object):
"""
This is the constructor for the plugin object. This provides an easy
way for descendent plugins to populate common data. This method *must*
be overridden, like so:
class MyPlugin(Plugin):
def __init__(self):
Plugin.__init(self, 'MyPlugin', '0.1')
...
be overridden, like so::
class MyPlugin(Plugin):
def __init__(self):
Plugin.__init(self, u'MyPlugin', u'0.1')
``name``
Defaults to *None*. The name of the plugin.
``version``
Defaults to *None*. The version of the plugin.
``plugin_helpers``
Defaults to *None*. A list of helper objects.
"""
if name is not None:
self.name = name
@ -102,56 +127,64 @@ class Plugin(object):
self.render_manager = plugin_helpers[u'render']
self.service_manager = plugin_helpers[u'service']
self.settings = plugin_helpers[u'settings']
self.slideManager = plugin_helpers[u'slideManager']
self.dnd_id=None
def check_pre_conditions(self):
"""
Provides the Plugin with a handle to check if it can be loaded.
Returns True or False.
"""
return True
def get_media_manager_item(self):
"""
Construct a MediaManagerItem object with all the buttons and things you
need, and return it for integration into openlp.org.
Construct a MediaManagerItem object with all the buttons and things
you need, and return it for integration into openlp.org.
"""
pass
def add_import_menu_item(self, import_menu):
"""
Create a menu item and add it to the "Import" menu.
``import_menu``
The Import menu.
"""
pass
def add_export_menu_item(self, export_menu):
"""
Create a menu item and add it to the "Export" menu.
``export_menu``
The Export menu
"""
pass
def get_settings_tab(self):
"""
Create a menu item and add it to the "Import" menu.
Create a tab for the settings window.
"""
pass
def add_to_menu(self, menubar):
"""
Add menu items to the menu, given the menubar.
``menubar``
The application's menu bar.
"""
pass
def handle_event(self, event):
"""
Handle the event contained in the event object.
"""
def handle_event(self, event):
"""
Handle the event contained in the event object. If you want
to use this default behaviour, you must set self.dnd_id equal
to that sent by the dnd source - eg the MediaItem
``event``
An object describing the event.
"""
# default behaviour - can be overridden if desired
log.debug(u'Handle event called with event %s with payload %s'%(event.event_type, event.payload))
@ -176,6 +209,9 @@ class Plugin(object):
"""
Service item data is passed to this function, which should return a
string which can be written to the service file.
``data``
The data to be saved.
"""
pass
@ -183,12 +219,21 @@ class Plugin(object):
"""
A string from the service file is passed in. This function parses and
sets up the internals of the plugin.
``string``
The data to be loaded into the plugin.
"""
pass
def render(self, theme, screen=None):
"""
Render the screenth screenful of data using theme settings in theme.
``theme``
The theme to use when rendering.
``screen``
Defaults to *None*. The screen to render to.
"""
pass

View File

@ -29,29 +29,51 @@ class PluginConfig(object):
"""
Initialise the plugin config object, setting the section name to the
plugin name.
``plugin_name``
The name of the plugin to use as a section name.
"""
self.section = plugin_name.lower()
def get_config(self, key, default=None):
"""
Get a configuration value from the configuration registry.
``key``
The name of configuration to load.
``default``
Defaults to *None*. The default value to return if there is no
other value.
"""
return ConfigHelper.get_config(self.section, key, default)
def delete_config(self, key):
"""
Delete a configuration value from the configuration registry.
``key``
The name of the configuration to remove.
"""
return ConfigHelper.delete_config(self.section, key)
def set_config(self, key, value):
"""
Set a configuration value in the configuration registry.
``key``
The name of the configuration to save.
``value``
The value of the configuration to save.
"""
return ConfigHelper.set_config(self.section, key, value)
def get_data_path(self):
app_data = ConfigHelper.get_data_path()
"""
Dynamically build the data file path for a plugin.
"""
#app_data = ConfigHelper.get_data_path()
app_data = ConfigHelper.get_data_path()
safe_name = self.section.replace(u' ',u'-')
plugin_data = self.get_config(u'data path', safe_name)
@ -61,9 +83,21 @@ class PluginConfig(object):
return path
def set_data_path(self, path):
"""
Set the data file path.
``path``
The path to save.
"""
return self.set_config(u'data path', os.path.basename(path))
def get_files(self, suffix=None):
"""
Get a list of files from the data files path.
``suffix``
Defaults to *None*. The extension to search for.
"""
try:
files = os.listdir(self.get_data_path())
except:
@ -86,7 +120,10 @@ class PluginConfig(object):
def load_list(self, name):
"""
Load a list from the config file
Load a list from the config file.
``name``
The name of the list.
"""
list_count = self.get_config(u'%s count' % name)
if list_count is not None:
@ -102,7 +139,13 @@ class PluginConfig(object):
def set_list(self, name, list):
"""
Save a list to the config file
Save a list to the config file.
``name``
The name of the list to save.
``list``
The list of values to save.
"""
old_count = int(self.get_config(u'%s count' % name, int(0)))
new_count = len(list)
@ -116,7 +159,10 @@ class PluginConfig(object):
def get_last_dir(self, num=None):
"""
Read the last directory used for plugin
Read the last directory used for plugin.
``num``
Defaults to *None*. A further qualifier.
"""
if num is not None:
name = u'last directory %d' % num
@ -129,7 +175,10 @@ class PluginConfig(object):
def set_last_dir(self, directory, num=None):
"""
Save the last directory used for plugin
Save the last directory used for plugin.
``num``
Defaults to *None*. A further qualifier.
"""
if num is not None:
name = u'last directory %d' % num

View File

@ -34,8 +34,11 @@ class PluginManager(object):
def __init__(self, dir):
"""
The constructor for the plugin manager.
Passes the controllers on to the plugins for them to interact with via their ServiceItems
The constructor for the plugin manager. Passes the controllers on to
the plugins for them to interact with via their ServiceItems.
``dir``
The directory to search for plugins.
"""
log.info(u'Plugin manager initing')
if not dir in sys.path:
@ -49,11 +52,20 @@ class PluginManager(object):
def find_plugins(self, dir, plugin_helpers, eventmanager):
"""
Scan the directory dir for objects inheriting from openlp.plugin
Scan the directory dir for objects inheriting from ``openlp.plugin``.
``dir``
The directory to scan.
``plugin_helpers``
A list of helper objects to pass to the plugins.
``eventmanager``
The event manager to pass to the plugins.
"""
self.plugin_helpers = plugin_helpers
startdepth = len(os.path.abspath(dir).split(os.sep))
log.debug(u'find plugins %s at depth %d' %( unicode(dir), startdepth))
log.debug(u'find plugins %s at depth %d', unicode(dir), startdepth)
for root, dirs, files in os.walk(dir):
for name in files:
@ -69,34 +81,46 @@ class PluginManager(object):
modulename = modulename[len(prefix) + 1:]
modulename = modulename.replace(os.path.sep, '.')
# import the modules
log.debug(u'Importing %s from %s. Depth %d' % (modulename, path, thisdepth))
log.debug(u'Importing %s from %s. Depth %d', modulename, path, thisdepth)
try:
__import__(modulename, globals(), locals(), [])
except ImportError, e:
log.error(u'Failed to import module %s on path %s for reason %s', modulename, path, sys.exc_info()[1])
log.error(u'Failed to import module %s on path %s for reason %s', modulename, path, e.args[0])
self.plugin_classes = Plugin.__subclasses__()
self.plugins = []
plugin_objects = []
for p in self.plugin_classes:
try:
plugin = p(self.plugin_helpers)
log.debug(u'loaded plugin %s with helpers'%unicode(p))
log.debug(u'loaded plugin %s with helpers', unicode(p))
log.debug(u'Plugin: %s', unicode(p))
if plugin.check_pre_conditions():
log.debug(u'Appending %s ', unicode(p))
log.debug(u'Appending %s ', unicode(p))
plugin_objects.append(plugin)
eventmanager.register(plugin)
except TypeError:
log.error(u'loaded plugin %s has no helpers'%unicode(p))
log.error(u'loaded plugin %s has no helpers', unicode(p))
self.plugins = sorted(plugin_objects, self.order_by_weight)
def order_by_weight(self, x, y):
"""
Sort two plugins and order them by their weight.
``x``
The first plugin.
``y``
The second plugin.
"""
return cmp(x.weight, y.weight)
def hook_media_manager(self, mediatoolbox):
"""
Loop through all the plugins. If a plugin has a valid media manager item,
add it to the media manager.
Loop through all the plugins. If a plugin has a valid media manager
item, add it to the media manager.
``mediatoolbox``
The Media Manager itself.
"""
for plugin in self.plugins:
media_manager_item = plugin.get_media_manager_item()
@ -106,8 +130,11 @@ class PluginManager(object):
def hook_settings_tabs(self, settingsform=None):
"""
Loop through all the plugins. If a plugin has a valid settings tab item,
add it to the settings tab.
Loop through all the plugins. If a plugin has a valid settings tab
item, add it to the settings tab.
``settingsform``
Defaults to *None*. The settings form to add tabs to.
"""
for plugin in self.plugins:
settings_tab = plugin.get_settings_tab()
@ -119,24 +146,31 @@ class PluginManager(object):
def hook_import_menu(self, import_menu):
"""
Loop through all the plugins and give them an opportunity to add an item
to the import menu.
Loop through all the plugins and give them an opportunity to add an
item to the import menu.
``import_menu``
The Import menu.
"""
for plugin in self.plugins:
plugin.add_import_menu_item(import_menu)
def hook_export_menu(self, export_menu):
"""
Loop through all the plugins and give them an opportunity to add an item
to the export menu.
Loop through all the plugins and give them an opportunity to add an
item to the export menu.
``export_menu``
The Export menu.
"""
for plugin in self.plugins:
plugin.add_export_menu_item(export_menu)
def initialise_plugins(self):
"""
Loop through all the plugins and give them an opportunity to add an item
to the export menu.
Loop through all the plugins and give them an opportunity to
initialise themselves.
"""
for plugin in self.plugins:
plugin.initialise()

View File

@ -18,12 +18,12 @@ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA
"""
import logging
import os, os.path
import os
import sys
from PyQt4 import QtGui, QtCore
class Renderer:
class Renderer(object):
"""
Genarates a pixmap image of a array of text. The Text is formatted to
make sure it fits on the screen and if not extra frames a generated.
@ -33,6 +33,9 @@ class Renderer:
log.info(u'Renderer Loaded')
def __init__(self):
"""
Initialise the renderer.
"""
self._rect = None
self._debug = 0
self._right_margin = 64 # the amount of right indent
@ -47,11 +50,20 @@ class Renderer:
self._bg_frame_small = None
def set_debug(self, debug):
"""
Set the debug mode of the renderer.
``debug``
The debug mode.
"""
self._debug=debug
def set_theme(self, theme):
"""
External API to pass in the theme to be used
Set the theme to be used.
``theme``
The theme to be used.
"""
log.debug(u'set theme')
self._theme = theme
@ -64,12 +76,21 @@ class Renderer:
self.set_bg_image(theme.background_filename)
def set_bg_image(self, filename):
"""
Set a background image.
``filename``
The name of the image file.
"""
log.debug(u'set bg image %s', filename)
self._bg_image_filename = unicode(filename)
if self._frame is not None:
self.scale_bg_image()
def scale_bg_image(self):
"""
Scale the background image to fit the screen.
"""
assert self._frame
preview = QtGui.QImage(self._bg_image_filename)
width = self._frame.width()
@ -89,7 +110,16 @@ class Renderer:
def set_frame_dest(self, frame_width, frame_height, preview=False):
"""
External API to pass the frame size to be painted
Set the size of the slide.
``frame_width``
The width of the slide.
``frame_height``
The height of the slide.
``preview``
Defaults to *False*. Whether or not to generate a preview.
"""
if preview == True:
self._bg_frame = None
@ -103,7 +133,14 @@ class Renderer:
def format_slide(self, words, footer):
"""
External API to sort out the text to pe placed on the frame
Figure out how much text can appear on a slide, using the current
theme settings.
``words``
The words to be fitted on the slide.
``footer``
The footer of the slide.
"""
log.debug(u'format_slide - Start')
verses = []
@ -120,15 +157,28 @@ class Renderer:
def set_text_rectangle(self, rect_main, rect_footer):
"""
Sets the rectangle within which text should be rendered
Sets the rectangle within which text should be rendered.
``rect_main``
The main text block.
``rect_footer``
The footer text block.
"""
self._rect = rect_main
self._rect_footer = rect_footer
def generate_frame_from_lines(self, lines, footer_lines=None):
"""
Render a set of lines according to the theme, return bounding box
"""
Render a set of lines according to the theme, and return the block
dimensions.
``lines``
The lines to be rendered.
``footer_lines``
Defaults to *None*. The footer to render.
"""
log.debug(u'generate_frame_from_lines - Start')
#print "Render Lines ", lines
bbox = self._render_lines_unaligned(lines, False)
@ -139,14 +189,15 @@ class Renderer:
x, y = self._correctAlignment(self._rect, bbox)
bbox = self._render_lines_unaligned(lines, False, (x, y), True)
if footer_lines is not None:
bbox = self._render_lines_unaligned(footer_lines, True, (self._rect_footer.left(), self._rect_footer.top()), True )
bbox = self._render_lines_unaligned(footer_lines, True,
(self._rect_footer.left(), self._rect_footer.top()), True)
log.debug(u'generate_frame_from_lines - Finish')
return self._frame
def _generate_background_frame(self):
"""
Generate a background frame to the same size as the frame to be used
Results cached for performance reasons.
Generate a background frame to the same size as the frame to be used.
Results are cached for performance reasons.
"""
assert(self._theme)
self._bg_frame = QtGui.QImage(self._frame.width(), self._frame.height(),
@ -196,11 +247,19 @@ class Renderer:
def _split_set_of_lines(self, lines, footer):
"""
Given a list of lines, decide how to split them best if they don't all fit on the screen
- this is done by splitting at 1/2, 1/3 or 1/4 of the set
If it doesn't fit, even at this size, just split at each opportunity.
We'll do this by getting the bounding box of each line, and then summing them appropriately
Returns a list of [lists of lines], one set for each screenful
Given a list of lines, decide how to split them best if they don't all
fit on the screen. This is done by splitting at 1/2, 1/3 or 1/4 of the
set. If it doesn't fit, even at this size, just split at each
opportunity. We'll do this by getting the bounding box of each line,
and then summing them appropriately.
Returns a list of [lists of lines], one set for each screenful.
``lines``
The lines of text to split.
``footer``
The footer text.
"""
bboxes = []
for line in lines:
@ -254,6 +313,15 @@ class Renderer:
return retval
def _correctAlignment(self, rect, bbox):
"""
Corrects the vertical alignment of text.
``rect``
The block dimentions.
``bbox``
Footer dimensions?
"""
x = rect.left()
if int(self._theme.display_verticalAlign) == 0:
# top align
@ -268,13 +336,26 @@ class Renderer:
log.error(u'Invalid value for theme.VerticalAlign:%s' % self._theme.display_verticalAlign)
return x, y
def _render_lines_unaligned(self, lines, footer, tlcorner=(0,0), live=False):
def _render_lines_unaligned(self, lines, footer, tlcorner=(0, 0), live=False):
"""
Given a list of lines to render, render each one in turn
(using the _render_single_line fn - which may result in going
off the bottom) They are expected to be pre-arranged to less
than a screenful (eg. by using split_set_of_lines)
Returns the bounding box of the text as QRect
Given a list of lines to render, render each one in turn (using the
``_render_single_line`` fn - which may result in going off the bottom).
They are expected to be pre-arranged to less than a screenful (eg. by
using split_set_of_lines).
Returns the bounding box of the text as QRect.
``lines``
The lines of text to render.
``footer``
The slide footer.
``tlcorner``
Defaults to *``(0, 0)``*. Co-ordinates of the top left corner.
``live``
Defaults to *False*. Whether or not this is a live screen.
"""
x, y = tlcorner
brx = x
@ -282,25 +363,37 @@ class Renderer:
for line in lines:
# render after current bottom, but at original left edge
# keep track of right edge to see which is biggest
(thisx, bry) = self._render_and_wrap_single_line(line, footer, (x , bry), live)
(thisx, bry) = self._render_and_wrap_single_line(line, footer, (x, bry), live)
if (thisx > brx):
brx = thisx
retval = QtCore.QRect(x, y,brx-x, bry-y)
retval = QtCore.QRect(x, y, brx - x, bry - y)
if self._debug:
painter = QtGui.QPainter()
painter.begin(self._frame)
painter.setPen(QtGui.QPen(QtGui.QColor(0,0,255)))
painter.setPen(QtGui.QPen(QtGui.QColor(0, 0, 255)))
painter.drawRect(retval)
painter.end()
return retval
return retval
def _render_and_wrap_single_line(self, line, footer, tlcorner=(0,0), live=False):
def _render_and_wrap_single_line(self, line, footer, tlcorner=(0, 0), live=False):
"""
Render a single line of words onto the DC, top left corner
specified.
If the line is too wide for the context, it wraps, but
right-aligns the surplus words in the manner of song lyrics
Render a single line of words onto the DC, top left corner specified.
If the line is too wide for the context, it wraps, but right-aligns
the surplus words in the manner of song lyrics.
Returns the bottom-right corner (of what was rendered) as a tuple(x, y).
``line``
Line of text to be rendered.
``footer``
The footer of the slide.
``tlcorner``
Defaults to *``(0, 0)``*. The top left corner.
``live``
Defaults to *False*. Whether or not this is a live screen.
"""
x, y = tlcorner
# We draw the text to see how big it is and then iterate to make it fit
@ -397,6 +490,9 @@ class Renderer:
return brcorner
def _set_theme_font(self):
"""
Set the fonts from the current theme settings.
"""
self.footerFont = QtGui.QFont(self._theme.font_footer_name,
int(self._theme.font_footer_proportion), # size
QtGui.QFont.Normal, # weight
@ -408,11 +504,26 @@ class Renderer:
0)# italic
self.mainFont.setPixelSize(int(self._theme.font_main_proportion))
def _get_extent_and_render(self, line, footer, tlcorner=(0,0), draw=False, color=None):
def _get_extent_and_render(self, line, footer, tlcorner=(0, 0), draw=False, color=None):
"""
Find bounding box of text - as render_single_line.
If draw is set, actually draw the text to the current DC as well
return width and height of text as a tuple (w,h)
Find bounding box of text - as render_single_line. If draw is set,
actually draw the text to the current DC as well return width and
height of text as a tuple (w, h).
``line``
The line of text to render.
``footer``
The footer text.
``tlcorner``
Defaults to *``(0, 0)``*. The top left corner co-ordinates.
``draw``
Defaults to *False*. Draw the text to the current surface.
``color``
Defaults to *None*. The colour to draw with.
"""
# setup defaults
painter = QtGui.QPainter()
@ -424,7 +535,7 @@ class Renderer:
else:
font = self.mainFont
painter.setFont(font)
if color == None:
if color is None:
if footer:
painter.setPen(QtGui.QColor(self._theme.font_footer_color))
else:
@ -443,7 +554,13 @@ class Renderer:
def snoop_Image(self, image, image2=None):
"""
Debugging method to allow images to be viewed
Debugging method to allow images to be viewed.
``image``
An image to save to disk.
``image2``
Defaults to *None*. Another image to save to disk.
"""
im = image.toImage()
im.save(u'renderer.png', u'png')

View File

@ -18,26 +18,37 @@ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA
"""
import logging
import os, os.path
import sys
from PyQt4 import QtGui, QtCore
from renderer import Renderer
import os
import sys
import linecache
class RenderManager:
from PyQt4 import QtGui, QtCore
from renderer import Renderer
class RenderManager(object):
"""
Class to pull all Renderer interactions into one place.
The plugins will call helper methods to do the rendering but
this class will provide display defense code.
Class to pull all Renderer interactions into one place. The plugins will
call helper methods to do the rendering but this class will provide
display defense code.
"""
global log
log=logging.getLogger(u'RenderManager')
log.info(u'RenderManager Loaded')
def __init__(self, theme_manager, screen_list, screen_number=0):
"""
Initialise the render manager.
``theme_manager``
The ThemeManager instance, used to get the current theme details.
``screen_list``
The list of screens available.
``screen_number``
Defaults to *0*. The index of the output/display screen.
"""
log.debug(u'Initilisation started')
self.screen_list = screen_list
self.theme_manager = theme_manager
@ -52,21 +63,46 @@ class RenderManager:
def update_display(self, screen_number):
"""
Updates the render manager's information about the current screen.
``screen_number``
The updated index of the output/display screen.
"""
log.debug(u'Update Display')
if self.current_display != screen_number:
self.current_display = screen_number
self.calculate_default(self.screen_list[self.current_display][u'size'])
def set_global_theme(self, global_theme, global_style = u'Global'):
def set_global_theme(self, global_theme, global_style=u'Global'):
"""
Set the global-level theme and the theme level.
``global_theme``
The global-level theme to be set.
``global_style``
Defaults to *"Global"*. The theme level, can be "Global",
"Service" or "Song".
"""
self.global_theme = global_theme
self.global_style = global_style
def set_service_theme(self, service_theme):
"""
Set the service-level theme.
``service_theme``
The service-level theme to be set.
"""
self.service_theme = service_theme
def set_override_theme(self, theme):
log.debug(u'set override theme to %s', theme)
"""
Set the appropriate theme depending on the theme level.
``theme``
The name of the song-level theme.
"""
log.debug(u'set override theme to %s', theme)
if self.global_style == u'Global':
self.theme = self.global_theme
elif self.global_style == u'Service':
@ -84,7 +120,7 @@ class RenderManager:
self.theme = self.service_theme
else:
self.theme = self.global_theme
if self.theme is not self.renderer.theme_name:
if self.theme != self.renderer.theme_name:
log.debug(u'theme is now %s', self.theme)
self.themedata = self.theme_manager.getThemeData(self.theme)
self.calculate_default(self.screen_list[self.current_display][u'size'])
@ -92,7 +128,13 @@ class RenderManager:
self.build_text_rectangle(self.themedata)
def build_text_rectangle(self, theme):
log.debug(u'build_text_rectangle ')
"""
Builds a text block using the settings in ``theme``.
``theme``
The theme to build a text block for.
"""
log.debug(u'build_text_rectangle')
main_rect = None
footer_rect = None
if theme.font_main_override == False:
@ -108,31 +150,52 @@ class RenderManager:
self.renderer.set_text_rectangle(main_rect,footer_rect)
def generate_preview(self, themedata):
"""
Generate a preview of a theme.
``themedata``
The theme to generated a preview for.
"""
log.debug(u'generate preview')
self.calculate_default(QtCore.QSize(1024, 768))
self.renderer.set_theme(themedata)
self.build_text_rectangle(themedata)
self.renderer.set_frame_dest(self.width, self.height, True)
lines = []
lines.append(u'Amazing Grace!')
lines.append(u'How sweet the sound')
lines.append(u'To save a wretch like me;')
lines.append(u'I once was lost but now am found,')
lines.append(u'Was blind, but now I see.')
lines1 = []
lines1.append(u'Amazing Grace (John Newton)' )
lines1.append(u'Public Domain')
lines1.append(u'CCLI xxx')
return self.renderer.generate_frame_from_lines(lines, lines1)
verse = []
verse.append(u'Amazing Grace!')
verse.append(u'How sweet the sound')
verse.append(u'To save a wretch like me;')
verse.append(u'I once was lost but now am found,')
verse.append(u'Was blind, but now I see.')
footer = []
footer.append(u'Amazing Grace (John Newton)' )
footer.append(u'Public Domain')
footer.append(u'CCLI xxx')
return self.renderer.generate_frame_from_lines(verse, footer)
def format_slide(self, words):
"""
Calculate how much text can fid on a slide.
``words``
The words to go on the slides.
"""
log.debug(u'format slide')
self.calculate_default(self.screen_list[self.current_display][u'size'])
self.build_text_rectangle(self.themedata)
self.renderer.set_frame_dest(self.width, self.height)
return self.renderer.format_slide(words, False)
def generate_slide(self,main_text, footer_text):
def generate_slide(self, main_text, footer_text):
"""
Generate the actual slide image.
``main_text``
The text for the main area of the slide.
``footer_text``
The text for the slide footer.
"""
log.debug(u'generate slide')
self.calculate_default(self.screen_list[self.current_display][u'size'])
self.build_text_rectangle(self.themedata)
@ -140,6 +203,12 @@ class RenderManager:
return self.renderer.generate_frame_from_lines(main_text, footer_text)
def resize_image(self, image):
"""
Resize an image to fit on the current screen.
``image``
The image to resize.
"""
preview = QtGui.QImage(image)
w = self.width
h = self.height
@ -154,13 +223,19 @@ class RenderManager:
return newImage
def calculate_default(self, screen):
log.debug(u'calculate default %s' , screen)
"""
Calculate the default dimentions of the screen.
``screen``
The QWidget instance of the screen.
"""
log.debug(u'calculate default %s', screen)
if self.current_display == 0:
self.width = 1024
self.height = 768
else:
self.width = screen.width()
self.height = screen.height()
log.debug(u'calculate default %d,%d' , self.width, self.height)
log.debug(u'calculate default %d, %d', self.width, self.height)
# 90% is start of footer
self.footer_start = int(self.height * 0.90)

View File

@ -20,10 +20,12 @@ Place, Suite 330, Boston, MA 02111-1307 USA
import logging
import os
import time
from openlp.core.lib import buildIcon
from PyQt4 import QtCore, QtGui
class ServiceItem():
from openlp.core.lib import buildIcon
class ServiceItem(object):
"""
The service item is a base class for the plugins to use to interact with
the service manager, the slide controller, and the projection screen
@ -35,7 +37,10 @@ class ServiceItem():
def __init__(self, hostplugin=None):
"""
Init Method
Set up the service item.
``hostplugin``
The plugin that this service item belongs to.
"""
self.plugin = hostplugin
if hostplugin is not None:
@ -56,6 +61,14 @@ class ServiceItem():
self.service_frames = []
def addIcon(self, icon):
"""
Add an icon to the service item. This is used when displaying the
service item in the service manager.
``icon``
An instance of QIcon or a string to an icon in the resource or on
disk.
"""
self.icon = icon
self.iconic_representation = buildIcon(icon)
@ -89,27 +102,63 @@ class ServiceItem():
else:
log.error(u'Invalid value renderer :%s' % self.service_item_type)
def add_from_image(self, path, frame_title, image):
def add_from_image(self, path, frame_title, image):
"""
Add an image slide to the service item.
``path``
The directory in which the image file is located.
``frame_title``
A title for the slide in the service item.
``image``
The actual image file name.
"""
self.service_item_type = u'image'
self.service_item_path = path
self.service_frames.append({u'title': frame_title, u'image': image})
def add_from_text(self, frame_title, raw_slide):
"""
Add a text slide to the service item.
``frame_title``
The title of the slide in the service item.
``raw_slide``
The raw text of the slide.
"""
self.service_item_type = u'text'
frame_title = frame_title.split(u'\n')[0]
self.service_frames.append({u'title': frame_title, u'raw_slide': raw_slide})
def add_from_command(self, frame_title, command):
"""
Add a slide from a command.
``frame_title``
The title of the slide in the service item.
``command``
The command of/for the slide.
"""
self.service_item_type = u'command'
self.service_frames.append({u'title': frame_title, u'command': command})
def get_oos_repr(self):
"""
This method returns some text which can be saved into the OOS
file to represent this item
file to represent this item.
"""
oos_header = {u'plugin': self.shortname,u'theme':self.theme, u'title':self.title,
u'icon':self.icon, u'footer':self.raw_footer, u'type':self.service_item_type}
oos_header = {
u'plugin': self.shortname,
u'theme':self.theme,
u'title':self.title,
u'icon':self.icon,
u'footer':self.raw_footer,
u'type':self.service_item_type
}
oos_data = []
if self.service_item_type == u'text':
for slide in self.service_frames:
@ -124,8 +173,14 @@ class ServiceItem():
def set_from_oos(self, serviceitem, path=None):
"""
This method takes some oos list (passed from the ServiceManager)
and extracts the data actually required
This method takes a service item from a saved service file (passed
from the ServiceManager) and extracts the data actually required.
``serviceitem``
The item to extract data from.
``path``
Defaults to *None*. Any path data, usually for images.
"""
#print "sfs", serviceitem
header = serviceitem[u'serviceitem'][u'header']

View File

@ -3,7 +3,7 @@
"""
OpenLP - Open Source Lyrics Projection
Copyright (c) 2008 Raoul Snyman
Portions copyright (c) 2008 Martin Thompson, Tim Bentley
Portions copyright (c) 2008-2009 Martin Thompson, Tim Bentley
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
@ -19,5 +19,15 @@ Place, Suite 330, Boston, MA 02111-1307 USA
"""
class SettingsManager(object):
def __init__(self):
pass
"""
Class to control the size of the UI components so they size correctly
This class is created by the main window and then calculates the size of individual components
"""
def __init__(self, screen):
self.screen = screen[0]
self.width = self.screen[u'size'].width()
self.height = self.screen[u'size'].height()
self.mainwindow_width = self.width * 0.8
self.mainwindow_height = self.height * 0.8
self.mainwindow_docbars = self.width / 3
self.mainwindow_slidecontroller = self.width / 6

View File

@ -23,11 +23,20 @@ from openlp.core.lib import PluginConfig
class SettingsTab(QtGui.QWidget):
"""
SettingsTab is a helper widget for plugins to define Tabs for the settings dialog.
SettingsTab is a helper widget for plugins to define Tabs for the settings
dialog.
"""
def __init__(self, title=None, section=None):
"""
Constructor to create the Steetings tab item.
Constructor to create the Settings tab item.
``title``
Defaults to *None*. The title of the tab, which is usually
displayed on the tab.
``section``
Defaults to *None*. This is the section in the configuration file
to write to when the ``save`` method is called.
"""
QtGui.QWidget.__init__(self)
self.tabTitle = title
@ -43,6 +52,9 @@ class SettingsTab(QtGui.QWidget):
def setTitle(self, title):
"""
Set the title of the tab.
``title``
The title of the tab, which is usually displayed on the tab.
"""
self.tabTitle = title

View File

@ -30,21 +30,34 @@ from xml.etree.ElementTree import ElementTree, XML, dump
"""
import logging
from xml.dom.minidom import Document
from xml.dom.minidom import Document
from xml.etree.ElementTree import ElementTree, XML, dump
class SongXMLBuilder():
"""
This class builds the XML used to describe songs.
"""
def __init__(self):
"""
Set up the song builder.
"""
# Create the minidom document
self.song_xml = Document()
def new_document(self):
"""
Create a new song XML document.
"""
# Create the <song> base element
self.song = self.song_xml.createElement(u'song')
self.song_xml.appendChild(self.song)
self.song.setAttribute(u'version', u'1.0')
def add_lyrics_to_song(self):
"""
Set up and add a ``<lyrics>`` tag which contains the lyrics of the
song.
"""
# Create the main <lyrics> element
self.lyrics = self.song_xml.createElement(u'lyrics')
self.lyrics.setAttribute(u'language', u'en')
@ -52,50 +65,72 @@ class SongXMLBuilder():
def add_verse_to_lyrics(self, type, number, content):
"""
type - type of verse (Chorus, Verse , Bridge, Custom etc
number - number of item eg verse 1
content - the text to be stored
Add a verse to the ``<lyrics>`` tag.
``type``
A string denoting the type of verse. Possible values are "Chorus",
"Verse", "Bridge", and "Custom".
``number``
An integer denoting the number of the item, for example: verse 1.
``content``
The actual text of the verse to be stored.
"""
verse = self.song_xml.createElement(u'verse')
verse.setAttribute(u'type', type)
verse.setAttribute(u'label', number)
self.lyrics.appendChild(verse)
# add data as a CDATA section
# add data as a CDATA section to protect the XML from special chars
cds = self.song_xml.createCDATASection(content)
verse.appendChild(cds)
def dump_xml(self):
# Debugging aid to see what we have
"""
Debugging aid to dump XML so that we can see what we have.
"""
print self.song_xml.toprettyxml(indent=u' ')
def extract_xml(self):
# Print our newly created XML
"""
Extract our newly created XML song.
"""
return self.song_xml.toxml(u'utf-8')
class SongXMLParser():
"""
A class to read in and parse a song's XML.
"""
global log
log = logging.getLogger(u'SongXMLParser')
log.info(u'SongXMLParser Loaded')
def __init__(self, xml):
#print xml
"""
Set up our song XML parser.
``xml``
The XML of the song to be parsed.
"""
try:
self.song_xml = ElementTree(element=XML(xml))
except:
#print "invalid xml ", xml
log.debug(u'invalid xml %s', xml)
log.debug(u'Invalid xml %s', xml)
def get_verses(self):
#return a list of verse's and attributes
iter=self.song_xml.getiterator()
"""
Iterates through the verses in the XML and returns a list of verses
and their attributes.
"""
iter = self.song_xml.getiterator()
verse_list = []
for element in iter:
#print element.tag, element.attrib, element.text
if element.tag == u'verse':
verse_list.append([element.attrib, element.text])
return verse_list
def dump_xml(self):
# Debugging aid to see what we have
"""
Debugging aid to dump XML so that we can see what we have.
"""
print dump(self.song_xml)

View File

@ -19,11 +19,13 @@ Place, Suite 330, Boston, MA 02111-1307 USA
For XML Schema see wiki.openlp.org
"""
import os, os.path
from openlp.core.lib import str_to_bool
from xml.dom.minidom import Document
import os
from xml.dom.minidom import Document
from xml.etree.ElementTree import ElementTree, XML, dump
from openlp.core.lib import str_to_bool
blankthemexml=\
'''<?xml version="1.0" encoding="iso-8859-1"?>
<theme version="1.0">
@ -62,26 +64,38 @@ blankthemexml=\
</theme>
'''
class ThemeXML():
class ThemeXML(object):
"""
A class to encapsulate the Theme XML.
"""
def __init__(self):
"""
Initialise the theme object.
"""
# Create the minidom document
self.theme_xml = Document()
def extend_image_filename(self, path):
"""
Add the path name to the image name so the background can be rendered.
``path``
The path name to be added.
"""
if self.background_filename is not None:
self.background_filename = os.path.join(path, self.theme_name, self.background_filename)
if self.background_filename is not None and path is not None:
self.background_filename = os.path.join(path, self.theme_name,
self.background_filename)
def new_document(self, name):
"""
Create a new theme XML document.
"""
self.theme = self.theme_xml.createElement(u'theme')
self.theme_xml.appendChild(self.theme)
self.theme.setAttribute(u'version', u'1.0')
self.name = self.theme_xml.createElement(u'name')
ctn = self.theme_xml.createTextNode(name)
self.name.appendChild(ctn)
text_node = self.theme_xml.createTextNode(name)
self.name.appendChild(text_node)
self.theme.appendChild(self.name)
def add_background_transparent(self):
@ -95,23 +109,33 @@ class ThemeXML():
def add_background_solid(self, bkcolor):
"""
Add a Solid background.
``bkcolor``
The color of the background.
"""
background = self.theme_xml.createElement(u'background')
background.setAttribute(u'mode', u'opaque')
background.setAttribute(u'type', u'solid')
self.theme.appendChild(background)
self.child_element(background, u'color', bkcolor)
def add_background_gradient(self, startcolor, endcolor, direction):
"""
Add a gradient background.
``startcolor``
The gradient's starting colour.
``endcolor``
The gradient's ending colour.
``direction``
The direction of the gradient.
"""
background = self.theme_xml.createElement(u'background')
background.setAttribute(u'mode', u'opaque')
background.setAttribute(u'type', u'gradient')
self.theme.appendChild(background)
# Create startColor element
self.child_element(background, u'startColor', startcolor)
# Create endColor element
@ -122,39 +146,63 @@ class ThemeXML():
def add_background_image(self, filename):
"""
Add a image background.
``filename``
The file name of the image.
"""
background = self.theme_xml.createElement(u'background')
background.setAttribute(u'mode', u'opaque')
background.setAttribute(u'type', u'image')
self.theme.appendChild(background)
#Create Filename element
self.child_element(background, u'filename', filename)
def add_font(self, name, color, proportion, override, fonttype=u'main', xpos=0, ypos=0 ,width=0, height=0):
def add_font(self, name, color, proportion, override, fonttype=u'main',
xpos=0, ypos=0, width=0, height=0):
"""
Add a Font.
``name``
The name of the font.
``color``
The colour of the font.
``proportion``
The size of the font.
``override``
Whether or not to override the default positioning of the theme.
``fonttype``
The type of font, ``main`` or ``footer``. Defaults to ``main``.
``xpos``
The X position of the text block.
``ypos``
The Y position of the text block.
``width``
The width of the text block.
``height``
The height of the text block.
"""
background = self.theme_xml.createElement(u'font')
background.setAttribute(u'type',fonttype)
self.theme.appendChild(background)
#Create Font name element
self.child_element(background, u'name', name)
#Create Font color element
self.child_element(background, u'color', color)
#Create Proportion name element
self.child_element(background, u'proportion', proportion)
#Create Proportion name element
self.child_element(background, u'proportion', proportion)
#Create Location element
element = self.theme_xml.createElement(u'location')
element.setAttribute(u'override',override)
if override == u'True':
element.setAttribute(u'x', xpos)
element.setAttribute(u'y', ypos)
@ -162,79 +210,120 @@ class ThemeXML():
element.setAttribute(u'height', height)
background.appendChild(element)
def add_display(self, shadow, shadowColor, outline, outlineColor, horizontal, vertical, wrap):
def add_display(self, shadow, shadow_color, outline, outline_color,
horizontal, vertical, wrap):
"""
Add a Display options.
``shadow``
Whether or not to show a shadow.
``shadow_color``
The colour of the shadow.
``outline``
Whether or not to show an outline.
``outline_color``
The colour of the outline.
``horizontal``
The horizontal alignment of the text.
``vertical``
The vertical alignment of the text.
``wrap``
Wrap style.
"""
background = self.theme_xml.createElement(u'display')
self.theme.appendChild(background)
tagElement = self.theme_xml.createElement(u'shadow')
tagElement.setAttribute(u'color',shadowColor)
tagValue = self.theme_xml.createTextNode(shadow)
tagElement.appendChild(tagValue)
background.appendChild(tagElement)
tagElement = self.theme_xml.createElement(u'outline')
tagElement.setAttribute(u'color',outlineColor)
tagValue = self.theme_xml.createTextNode(outline)
tagElement.appendChild(tagValue)
background.appendChild(tagElement)
tagElement = self.theme_xml.createElement(u'horizontalAlign')
tagValue = self.theme_xml.createTextNode(horizontal)
tagElement.appendChild(tagValue)
background.appendChild(tagElement)
tagElement = self.theme_xml.createElement(u'verticalAlign')
tagValue = self.theme_xml.createTextNode(vertical)
tagElement.appendChild(tagValue)
background.appendChild(tagElement)
tagElement = self.theme_xml.createElement(u'wrapStyle')
tagValue = self.theme_xml.createTextNode(wrap)
tagElement.appendChild(tagValue)
background.appendChild(tagElement)
# Shadow
element = self.theme_xml.createElement(u'shadow')
element.setAttribute(u'color', shadow_color)
value = self.theme_xml.createTextNode(shadow)
element.appendChild(value)
background.appendChild(element)
# Outline
element = self.theme_xml.createElement(u'outline')
element.setAttribute(u'color', outline_color)
value = self.theme_xml.createTextNode(outline)
element.appendChild(value)
background.appendChild(element)
# Horizontal alignment
element = self.theme_xml.createElement(u'horizontalAlign')
value = self.theme_xml.createTextNode(horizontal)
element.appendChild(value)
background.appendChild(element)
# Vertical alignment
element = self.theme_xml.createElement(u'verticalAlign')
value = self.theme_xml.createTextNode(vertical)
element.appendChild(value)
background.appendChild(element)
# Wrap style
element = self.theme_xml.createElement(u'wrapStyle')
value = self.theme_xml.createTextNode(wrap)
element.appendChild(value)
background.appendChild(element)
def child_element(self, element, tag, value):
"""
Generic child element creator.
"""
child = self.theme_xml.createElement(tag)
child.appendChild(self.theme_xml.createTextNode(value))
element.appendChild(child)
return child
def dump_xml(self):
"""
Dump the XML to file.
"""
# Debugging aid to see what we have
print self.theme_xml.toprettyxml(indent=u' ')
def extract_xml(self):
"""
Pull out the XML string.
"""
# Print our newly created XML
return self.theme_xml.toxml()
def parse(self, xml):
self.baseParseXml()
"""
Read in an XML string and parse it.
``xml``
The XML string to parse.
"""
self.base_parse_xml()
self.parse_xml(xml)
self.theme_filename_extended = False
def baseParseXml(self):
def base_parse_xml(self):
"""
Pull in the blank theme XML as a starting point.
"""
self.parse_xml(blankthemexml)
def parse_xml(self, xml):
"""
Parse an XML string.
``xml``
The XML string to parse.
"""
theme_xml = ElementTree(element=XML(xml))
iter = theme_xml.getiterator()
master = u''
for element in iter:
#print element.tag, element.text
if len(element.getchildren()) > 0:
master = element.tag + u'_'
if len(element.attrib) > 0:
#print "D", element.tag , element.attrib
for e in element.attrib.iteritems():
#print "A", master, e[0], e[1]
if master == u'font_' and e[0] == u'type':
master += e[1] + u'_'
elif master == u'display_' and (element.tag == u'shadow' or element.tag == u'outline'):
#print "b", master, element.tag, element.text, e[0], e[1]
et = str_to_bool(element.text)
setattr(self, master + element.tag , et)
setattr(self, master + element.tag + u'_'+ e[0], e[1])
@ -245,14 +334,16 @@ class ThemeXML():
e1 = str_to_bool(e[1])
setattr(self, field, e1)
else:
#print "c", element.tag, element.text
if element.tag is not None:
field = master + element.tag
setattr(self, field, element.text)
def __str__(self):
"""
Return a string representation of this object.
"""
s = u''
for k in dir(self):
if k[0:1] != u'_':
s += u'%30s : %s\n' %(k, getattr(self, k))
s += u'%30s: %s\n' %(k, getattr(self, k))
return s

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
"""
@ -19,15 +18,19 @@ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA
"""
import types
import logging
from PyQt4 import QtCore, QtGui
import logging
class OpenLPToolbar(QtGui.QToolBar):
"""
Lots of toolbars around the place, so it makes sense to have a common way to manage them
Lots of toolbars around the place, so it makes sense to have a common way
to manage them. This is the base toolbar class.
"""
def __init__(self, parent):
"""
Initialise the toolbar.
"""
QtGui.QToolBar.__init__(self, None)
# useful to be able to reuse button icons...
self.icons = {}
@ -37,6 +40,23 @@ class OpenLPToolbar(QtGui.QToolBar):
def addToolbarButton(self, title, icon, tooltip=None, slot=None, objectname=None):
"""
A method to help developers easily add a button to the toolbar.
``title``
The title of the button.
``icon``
The icon of the button. This can be an instance of QIcon, or a
string cotaining either the absolute path to the image, or an
internal resource path starting with ':/'.
``tooltip``
A hint or tooltip for this button.
``slot``
The method to run when this button is clicked.
``objectname``
The name of the object, as used in `<button>.setObjectName()`.
"""
ButtonIcon = None
if type(icon) is QtGui.QIcon:
@ -58,6 +78,13 @@ class OpenLPToolbar(QtGui.QToolBar):
self.icons[title] = ButtonIcon
def getIconFromTitle(self, title):
"""
Search through the list of icons for an icon with a particular title,
and return that icon.
``title``
The title of the icon to search for.
"""
if self.icons.has_key(title):
return self.icons[title]
else:

View File

@ -22,81 +22,80 @@ import platform
import sys
import os
from types import StringType, NoneType, UnicodeType
sys.path.append(os.path.abspath(u'./../..'))
from xml.etree.ElementTree import ElementTree, XML
sys.path.append(os.path.abspath(os.path.join('.', '..', '..')))
class XmlRootClass(object):
"""Root class for themes, songs etc
provides interface for parsing xml files into object attributes
if you overload this class and provide a function called
post_tag_hook, it will be called thusly for each tag,value pair:
(element.tag, val) = self.post_tag_hook(element.tag, val)
"""
def _setFromXml(self, xml, rootTag):
"""Set song properties from given xml content
Root class for themes, songs etc
xml (string) -- formatted as xml tags and values
rootTag -- main tag of the xml
This class provides interface for parsing xml files into object attributes.
If you overload this class and provide a function called `post_tag_hook`,
it will be called thusly for each `tag, value` pair::
(element.tag, val) = self.post_tag_hook(element.tag, val)
"""
def _setFromXml(self, xml, root_tag):
"""
Set song properties from given xml content.
``xml``
Formatted xml tags and values.
``root_tag``
The root tag of the xml.
"""
root = ElementTree(element=XML(xml))
iter = root.getiterator()
for element in iter:
if element.tag != rootTag:
t = element.text
#print element.tag, t, type(t)
if type(t) == NoneType:
# easy!
val=t
elif type(t) == UnicodeType :
val=t
elif type(t) == StringType:
# strings need special handling to sort the colours out
#print "str",
if t[0] == '$':
# might be a hex number
#print "hex",
if element.tag != root_tag:
text = element.text
if type(text) is NoneType:
val = text
elif type(text) is UnicodeType :
val = text
elif type(text) is StringType:
# Strings need special handling to sort the colours out
if text[0] == '$':
# This might be a hex number, let's try to convert it.
try:
val = int(t[1:], 16)
val = int(text[1:], 16)
except ValueError:
# nope
#print "nope",
pass
else:
#print "last chance",
# Let's just see if it's a integer.
try:
val=int(t)
#print "int",
val = int(text)
except ValueError:
#print "give up",
val=t
# Ok, it seems to be a string.
val = text
if hasattr(self, u'post_tag_hook'):
(element.tag, val) = self.post_tag_hook(element.tag, val)
setattr(self, element.tag, val)
pass
def __str__(self):
"""Return string with all public attributes
"""
Return string with all public attributes
The string is formatted with one attribute per line
If the string is split on newline then the length of the
list is equal to the number of attributes
"""
l = []
for k in dir(self):
if not k.startswith(u'_'):
l.append(u'%30s : %s' %(k,getattr(self,k)))
return u'\n'.join(l)
attributes = []
for attrib in dir(self):
if not attrib.startswith(u'_'):
attributes.append(u'%30s : %s' % (attrib, getattr(self, attrib)))
return u'\n'.join(attributes)
def _get_as_string(self):
"""Return one string with all public attributes"""
s=""
for k in dir(self):
if not k.startswith(u'_'):
s+= u'_%s_' %(getattr(self,k))
return s
"""
Return one string with all public attributes
"""
result = u''
for attrib in dir(self):
if not attrib.startswith(u'_'):
result += u'_%s_' % getattr(self, attrib)
return result

View File

@ -18,7 +18,6 @@ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA
"""
from slidecontroller import MasterToolbar
from slidecontrollermanager import SlideControllerManager
from maindisplay import MainDisplay
from amendthemeform import AmendThemeForm
from slidecontroller import SlideController

View File

@ -128,9 +128,7 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
unicode(self.theme.display_outline), unicode(self.theme.display_outline_color),
unicode(self.theme.display_horizontalAlign), unicode(self.theme.display_verticalAlign),
unicode(self.theme.display_wrapStyle))
theme = new_theme.extract_xml()
self.thememanager.saveTheme(theme_name, theme, save_from, save_to)
return QtGui.QDialog.accept(self)
@ -526,4 +524,4 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
def previewTheme(self, theme):
if self.allowPreview:
frame = self.thememanager.generateImage(theme)
self.ThemePreview.setPixmap(QtGui.QPixmap.fromImage(frame))
self.ThemePreview.setPixmap(QtGui.QPixmap.fromImage(frame))

View File

@ -23,10 +23,9 @@ import logging
from PyQt4 import QtCore, QtGui
from openlp.core.ui import AboutForm, SettingsForm, AlertForm, ServiceManager, \
ThemeManager, MainDisplay, SlideController, SlideControllerManager
ThemeManager, MainDisplay, SlideController
from openlp.core.lib import translate, Plugin, MediaManagerItem, SettingsTab, \
EventManager, RenderManager, PluginConfig
from openlp.core import PluginManager
EventManager, RenderManager, PluginConfig, SettingsManager, PluginManager
class MainWindow(object):
"""
@ -41,6 +40,8 @@ class MainWindow(object):
This constructor sets up the interface, the various managers, and the
plugins.
"""
self.oosNotSaved = False
self.settingsmanager = SettingsManager(screens)
self.mainWindow = QtGui.QMainWindow()
self.mainWindow.__class__.closeEvent = self.onCloseEvent
self.mainDisplay = MainDisplay(None, screens)
@ -50,7 +51,6 @@ class MainWindow(object):
self.alertForm = AlertForm(self)
self.aboutForm = AboutForm()
self.settingsForm = SettingsForm(self.screenList, self)
self.slideControllerManager = SlideControllerManager(self)
# Set up the path with plugins
pluginpath = os.path.split(os.path.abspath(__file__))[0]
pluginpath = os.path.abspath(
@ -73,7 +73,6 @@ class MainWindow(object):
self.plugin_helpers[u'render'] = self.RenderManager
self.plugin_helpers[u'service'] = self.ServiceManagerContents
self.plugin_helpers[u'settings'] = self.settingsForm
self.plugin_helpers[u'slideManager'] = self.slideControllerManager
self.plugin_manager.find_plugins(pluginpath, self.plugin_helpers,
self.EventManager)
# hook methods have to happen after find_plugins. Find plugins needs the
@ -129,15 +128,53 @@ class MainWindow(object):
"""
Hook to close the main window and display windows on exit
"""
self.mainDisplay.close()
event.accept()
if self.oosNotSaved == True:
box = QtGui.QMessageBox()
box.setWindowTitle(translate(u'mainWindow', u'Question?'))
box.setText(translate(u'mainWindow', u'Save changes to Order of Service?'))
box.setIcon(QtGui.QMessageBox.Question)
box.setStandardButtons(QtGui.QMessageBox.Save | QtGui.QMessageBox.Discard | QtGui.QMessageBox.Cancel);
box.setDefaultButton(QtGui.QMessageBox.Save);
ret = box.exec_()
if ret == QtGui.QMessageBox.Save:
self.ServiceManagerContents.onSaveService()
self.mainDisplay.close()
event.accept()
elif ret == QtGui.QMessageBox.Discard:
self.mainDisplay.close()
event.accept()
else:
event.ignore()
else:
self.mainDisplay.close()
event.accept()
def OosChanged(self, reset = False, oosName = None):
"""
Hook to change the title if the OOS has been changed
reset - tells if the OOS has been cleared or saved
oosName - is the name of the OOS (if it has one)
"""
if reset == True:
self.oosNotSaved = False
if oosName is None:
title = self.mainTitle
else:
title = self.mainTitle + u' - (' + oosName + u')'
else:
self.oosNotSaved = True
if oosName is None:
title = self.mainTitle + u' - *'
else:
title = self.mainTitle + u' - *(' + oosName + u')'
self.mainWindow.setWindowTitle(title)
def setupUi(self):
"""
Set up the user interface
"""
self.mainWindow.setObjectName(u'mainWindow')
self.mainWindow.resize(1087, 847)
self.mainWindow.resize(self.settingsmanager.width, self.settingsmanager.height)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding,
QtGui.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
@ -411,7 +448,8 @@ class MainWindow(object):
"""
Set up the translation system
"""
self.mainWindow.setWindowTitle(translate(u'mainWindow', u'OpenLP 2.0'))
self.mainTitle = translate(u'mainWindow', u'OpenLP 2.0')
self.mainWindow.setWindowTitle(self.mainTitle)
self.FileMenu.setTitle(translate(u'mainWindow', u'&File'))
self.FileImportMenu.setTitle(translate(u'mainWindow', u'&Import'))
self.FileExportMenu.setTitle(translate(u'mainWindow', u'&Export'))

View File

@ -63,6 +63,7 @@ class ServiceManager(QtGui.QWidget):
QtGui.QWidget.__init__(self)
self.parent = parent
self.serviceItems = []
self.serviceName = u''
self.Layout = QtGui.QVBoxLayout(self)
self.Layout.setSpacing(0)
self.Layout.setMargin(0)
@ -134,10 +135,18 @@ class ServiceManager(QtGui.QWidget):
self.service_theme = self.config.get_config(u'theme service theme', u'')
def collapsed(self, item):
"""
Record if an item is collapsed
Used when repainting the list to get the correct state
"""
pos = item.data(0, QtCore.Qt.UserRole).toInt()[0]
self.serviceItems[pos -1 ][u'expanded'] = False
def expanded(self, item):
"""
Record if an item is collapsed
Used when repainting the list to get the correct state
"""
pos = item.data(0, QtCore.Qt.UserRole).toInt()[0]
self.serviceItems[pos -1 ][u'expanded'] = True
@ -151,6 +160,7 @@ class ServiceManager(QtGui.QWidget):
self.serviceItems.remove(self.serviceItems[item])
self.serviceItems.insert(0, temp)
self.repaintServiceList()
self.parent.OosChanged(False, self.serviceName)
def onServiceUp(self):
"""
@ -163,6 +173,7 @@ class ServiceManager(QtGui.QWidget):
self.serviceItems.remove(self.serviceItems[item])
self.serviceItems.insert(item - 1, temp)
self.repaintServiceList()
self.parent.OosChanged(False, self.serviceName)
def onServiceDown(self):
"""
@ -175,6 +186,7 @@ class ServiceManager(QtGui.QWidget):
self.serviceItems.remove(self.serviceItems[item])
self.serviceItems.insert(item + 1, temp)
self.repaintServiceList()
self.parent.OosChanged(False, self.serviceName)
def onServiceEnd(self):
"""
@ -186,6 +198,7 @@ class ServiceManager(QtGui.QWidget):
self.serviceItems.remove(self.serviceItems[item])
self.serviceItems.insert(len(self.serviceItems), temp)
self.repaintServiceList()
self.parent.OosChanged(False, self.serviceName)
def onNewService(self):
"""
@ -193,6 +206,8 @@ class ServiceManager(QtGui.QWidget):
"""
self.ServiceManagerList.clear()
self.serviceItems = []
self.serviceName = u''
self.parent.OosChanged(True, self.serviceName)
def onDeleteFromService(self):
"""
@ -202,8 +217,14 @@ class ServiceManager(QtGui.QWidget):
if item is not -1:
self.serviceItems.remove(self.serviceItems[item])
self.repaintServiceList()
self.parent.OosChanged(False, self.serviceName)
def repaintServiceList(self):
"""
Clear the existing service list and prepaint all the items
Used when moving items as the move takes place in supporting array,
and when regenerating all the items due to theme changes
"""
#Correct order of idems in array
count = 1
for item in self.serviceItems:
@ -228,7 +249,10 @@ class ServiceManager(QtGui.QWidget):
def onSaveService(self):
"""
Save the current service
Save the current service in a zip file
This file contains
* An ood which is a pickle of the service items
* All image , presentation and video files needed to run the service.
"""
filename = QtGui.QFileDialog.getSaveFileName(self, u'Save Order of Service',self.config.get_last_dir() )
filename = unicode(filename)
@ -252,14 +276,18 @@ class ServiceManager(QtGui.QWidget):
os.remove(servicefile)
except:
pass #if not present do not worry
self.parent.OosChanged(True, self.serviceName)
def onLoadService(self):
"""
Load an existing service from disk
Load an existing service from disk and rebuilds the serviceitems
All files retrieved from the zip file are placed in a temporary directory and
will only be used for this service.
"""
filename = QtGui.QFileDialog.getOpenFileName(self, u'Open Order of Service',self.config.get_last_dir(),
u'Services (*.oos)')
filename = unicode(filename)
name = filename.split(os.path.sep)
if filename != u'':
self.config.set_last_dir(filename)
zip = zipfile.ZipFile(unicode(filename))
@ -279,7 +307,6 @@ class ServiceManager(QtGui.QWidget):
f.close()
self.onNewService()
for item in items:
#print item
serviceitem = ServiceItem()
serviceitem.RenderManager = self.parent.RenderManager
serviceitem.set_from_oos(item, self.servicePath )
@ -287,7 +314,10 @@ class ServiceManager(QtGui.QWidget):
try:
os.remove(p_file)
except:
pass #if not present do not worry
#if not present do not worry
pass
self.serviceName = name[len(name) - 1]
self.parent.OosChanged(True, self.serviceName)
def onThemeComboBoxSelected(self, currentIndex):
"""
@ -323,6 +353,7 @@ class ServiceManager(QtGui.QWidget):
treewidgetitem1.setText(0,text[:40])
treewidgetitem1.setData(0, QtCore.Qt.UserRole,QtCore.QVariant(count))
count = count + 1
self.parent.OosChanged(False, self.serviceName)
def makePreview(self):
"""

View File

@ -61,6 +61,7 @@ class SlideController(QtGui.QWidget):
Set up the Slide Controller.
"""
self.toolbarList = {}
self.previewList = {}
QtGui.QWidget.__init__(self, parent.mainWindow)
self.isLive = isLive
self.parent = parent
@ -114,7 +115,119 @@ class SlideController(QtGui.QWidget):
self.grid.setMargin(8)
self.grid.setObjectName(u'grid')
# Actual preview screen
self.SlidePreview = QtGui.QLabel(self.PreviewFrame)
masterPreview = MasterPreview(self.PreviewFrame).getPreview()
self.registerPreview(u'master', masterPreview)
self.SlidePreview = self.retrievePreview(u'master')
self.grid.addWidget(self.SlidePreview, 0, 0, 1, 1)
# Signals
QtCore.QObject.connect(self.PreviewListWidget,
QtCore.SIGNAL(u'clicked(QModelIndex)'), self.BaseToolbar.onSlideSelected)
QtCore.QObject.connect(self.PreviewListWidget,
QtCore.SIGNAL(u'activated(QModelIndex)'), self.BaseToolbar.onSlideSelected)
# Add Late Arrivals
self.BaseToolbar.PreviewListWidget = self.PreviewListWidget
self.BaseToolbar.SlidePreview = self.SlidePreview
self.BaseToolbar.mainDisplay = self.parent.mainDisplay
def registerToolbar(self, handle,controller):
"""
Register a new toolbar with the controller
``handle``
Identifier for the toolbar being stored this should equal the
plugins name.
``controller``
The toolbar class which should extend MasterToolbar
"""
#store the handle name in lower case so no probems later
self.toolbarList[handle.lower()] = controller
def registerPreview(self, handle,controller):
"""
Register a new preview with the controller
``handle``
Identifier for the preview being stored this should equal the
plugins name.
``controller``
The preview class which should extend MasterToolbar
"""
#store the handle name in lower case so no probems later
self.previewList[handle.lower()] = controller
def retrieveToolbar(self, handle):
"""
Find the toolbar and return master if none present
Add extra information back into toolbar class
``handle``
Identifier for the toolbar being requested
"""
try:
toolbar = self.toolbarList[handle.lower()]
except:
toolbar = self.toolbarList[u'master']
toolbar.PreviewListWidget = self.PreviewListWidget
toolbar.SlidePreview = self.SlidePreview
toolbar.mainDisplay = self.parent.mainDisplay
return toolbar
def retrievePreview(self, handle):
"""
Find the preview and return master if none present
Add extra information back into toolbar class
``handle``
Identifier for the toolbar being requested
"""
try:
preview = self.previewList[handle.lower()]
except:
preview = self.previewList[u'master']
return preview
def addServiceItem(self, item):
"""
Method to install the service item into the controller and
request the correct the toolbar of the plugin
Called by plugins
"""
self.SlidePreview = self.retrievePreview(item.shortname)
self.BaseToolbar = self.retrieveToolbar(item.shortname)
self.ControllerLayout.removeWidget(self.Toolbar)
#remove the old toolbar
self.Toolbar.clear()
self.Toolbar = self.BaseToolbar.getToolbar()
self.ControllerLayout.addWidget(self.Toolbar)
self.BaseToolbar.addServiceItem(item)
def addServiceManagerItem(self, item, slideno):
"""
Method to install the service item into the controller and
request the correct the toolbar of the plugin
Called by ServiceManager
"""
self.SlidePreview = self.retrievePreview(item.shortname)
self.BaseToolbar = self.retrieveToolbar(item.shortname)
self.ControllerLayout.removeWidget(self.Toolbar)
#remove the old toolbar
self.Toolbar.clear()
self.Toolbar = self.BaseToolbar.getToolbar()
self.ControllerLayout.addWidget(self.Toolbar)
self.BaseToolbar.addServiceManagerItem(item, slideno)
class MasterPreview(QtCore.QObject):
"""
Class from which all Previews should extend allowing plugins to
have their own previews
"""
def __init__(self, parent):
self.parent = parent
QtCore.QObject.__init__(self)
self.definePreview()
def getPreview(self):
return self.SlidePreview
def definePreview(self):
self.SlidePreview = QtGui.QLabel(self.parent)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed,
QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
@ -128,62 +241,11 @@ class SlideController(QtGui.QWidget):
self.SlidePreview.setLineWidth(1)
self.SlidePreview.setScaledContents(True)
self.SlidePreview.setObjectName(u'SlidePreview')
self.grid.addWidget(self.SlidePreview, 0, 0, 1, 1)
# Signals
QtCore.QObject.connect(self.PreviewListWidget,
QtCore.SIGNAL(u'clicked(QModelIndex)'), self.BaseToolbar.onSlideSelected)
QtCore.QObject.connect(self.PreviewListWidget,
QtCore.SIGNAL(u'activated(QModelIndex)'), self.BaseToolbar.onSlideSelected)
# Add Late Arrivals
self.BaseToolbar.PreviewListWidget = self.PreviewListWidget
self.BaseToolbar.SlidePreview = self.SlidePreview
self.BaseToolbar.mainDisplay = self.parent.mainDisplay
def registerToolbar(self, handle,controller):
#store the handle name in lower case so no probems later
self.toolbarList[handle.lower()] = controller
def retrieveToolbar(self, handle):
"""
Find the toolbar and return master if none present
Add extra information back into toolbar class
"""
try:
toolbar = self.toolbarList[handle.lower()]
except:
toolbar = self.toolbarList[u'master']
toolbar.PreviewListWidget = self.PreviewListWidget
toolbar.SlidePreview = self.SlidePreview
toolbar.mainDisplay = self.parent.mainDisplay
return toolbar
def addServiceItem(self, item):
"""
helper method to pass item to correct toolbar
"""
self.BaseToolbar = self.retrieveToolbar(item.shortname)
self.ControllerLayout.removeWidget(self.Toolbar)
#remove the old toolbar
self.Toolbar.clear()
self.Toolbar = self.BaseToolbar.getToolbar()
self.ControllerLayout.addWidget(self.Toolbar)
self.BaseToolbar.addServiceItem(item)
def addServiceManagerItem(self, item, slideno):
"""
helper method to pass item to correct toolbar
"""
self.BaseToolbar = self.retrieveToolbar(item.shortname)
self.ControllerLayout.removeWidget(self.Toolbar)
#remove the old toolbar
self.Toolbar.clear()
self.Toolbar = self.BaseToolbar.getToolbar()
self.ControllerLayout.addWidget(self.Toolbar)
self.BaseToolbar.addServiceManagerItem(item, slideno)
class MasterToolbar(QtCore.QObject):
"""
Class from which all tollbars should extend
Class from which all toolbars should extend
"""
def __init__(self, isLive):
self.Toolbar = None
@ -232,6 +294,13 @@ class MasterToolbar(QtCore.QObject):
translate(u'SlideController', u'Close Screen'),
self.onBlankScreen)
def serviceLoaded(self):
"""
method to allow toolbars to know when the service item
is fully in place
"""
pass
def onSlideSelectedFirst(self):
"""
Go to the first slide.
@ -298,30 +367,33 @@ class MasterToolbar(QtCore.QObject):
def addServiceManagerItem(self, serviceitem, slideno):
"""
Loads a ServiceItem into the system from ServiceManager
Display the Slide Passed
Display the slide number passed
"""
log.debug(u'add Service Manager Item')
self.serviceitem = serviceitem
slide_pixmap = QtGui.QPixmap.fromImage(self.serviceitem.frames[0][u'image'])
slide_width = 300
slide_height = slide_width * slide_pixmap.height() / slide_pixmap.width()
self.PreviewListWidget.clear()
self.PreviewListWidget.setRowCount(0)
self.serviceitem = serviceitem
framenumber = 0
for frame in self.serviceitem.frames:
self.PreviewListWidget.setColumnWidth(0, slide_width)
for framenumber, frame in enumerate(self.serviceitem.frames):
self.PreviewListWidget.setRowCount(self.PreviewListWidget.rowCount() + 1)
pixmap = QtGui.QPixmap.fromImage(frame[u'image'])
item = QtGui.QTableWidgetItem()
label = QtGui.QLabel()
label.setMargin(15)
label.setMargin(8)
label.setScaledContents(True)
width = 300
height = width * pixmap.height() / pixmap.width()
label.setPixmap(pixmap)
self.PreviewListWidget.setCellWidget(framenumber, 0,label)
self.PreviewListWidget.setItem( framenumber, 0, item)
self.PreviewListWidget.setRowHeight(framenumber, height)
self.PreviewListWidget.setColumnWidth(0, width)
framenumber += 1
self.PreviewListWidget.setCellWidget(framenumber, 0, label)
self.PreviewListWidget.setItem(framenumber, 0, item)
self.PreviewListWidget.setRowHeight(framenumber, slide_height)
slide_width = self.PreviewListWidget.viewport().size().width()
self.PreviewListWidget.setColumnWidth(0, slide_width)
if slideno > self.PreviewListWidget.rowCount():
self.PreviewListWidget.selectRow(self.PreviewListWidget.rowCount())
else:
self.PreviewListWidget.selectRow(slideno)
self.onSlideSelected()
self.serviceLoaded()
self.PreviewListWidget.setFocus()

View File

@ -1,52 +0,0 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
"""
OpenLP - Open Source Lyrics Projection
Copyright (c) 2008 Raoul Snyman
Portions copyright (c) 2008-2009 Martin Thompson, Tim Bentley,
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
import os
class SlideControllerManager():
"""
This class controls which SlideController is availabe to the
main window
"""
global log
log = logging.getLogger(u'SlideControllerManager')
def __init__(self, parent):
"""
Set up the Slide Controller. Manager
"""
self.parent = parent
self.live = {}
self.preview = {}
def add_controllers(self, handle, preview, live):
self.live[handle] = live
self.preview[handle] = preview
print self.live
def getPreviewController(self, handle):
return self.preview[handle]
def getLiveController(self, handle):
print "---"
print self.live
print handle
print self.live[handle]
return self.live[handle]

View File

@ -21,109 +21,16 @@ import os
import sys
import zipfile
import shutil
import logging
from time import sleep
from xml.etree.ElementTree import ElementTree, XML
from PyQt4 import QtCore, QtGui
from openlp.core.ui import AmendThemeForm, ServiceManager
from openlp.core.theme import Theme
from openlp.core.lib import Event, EventType, EventManager, OpenLPToolbar, ThemeXML, Renderer, translate, file_to_xml
from openlp.core.lib import Event, EventType, EventManager, OpenLPToolbar, ThemeXML, Renderer, translate, file_to_xml, buildIcon
from openlp.core.utils import ConfigHelper
import logging
class ThemeData(QtCore.QAbstractListModel):
"""
Tree of items for an order of Theme.
Includes methods for reading and writing the contents to an OOS file
Root contains a list of ThemeItems
"""
global log
log = logging.getLogger(u'ThemeData')
def __init__(self):
QtCore.QAbstractListModel.__init__(self)
self.items = []
self.rowheight = 50
self.maximagewidth = self.rowheight * 16 / 9.0;
log.info(u'Starting')
def clearItems(self):
self.items = []
def rowCount(self, parent):
return len(self.items)
def insertRow(self, row, filename):
self.beginInsertRows(QtCore.QModelIndex(), row, row)
log.debug(u'insert row %d:%s' % (row, filename))
(prefix, shortfilename) = os.path.split(unicode(filename))
log.debug(u'shortfilename = %s' % shortfilename)
theme = shortfilename.split(u'.')
# create a preview image
if os.path.exists(filename):
preview = QtGui.QImage(unicode(filename))
width = self.maximagewidth
height = self.rowheight
preview = preview.scaled(width, height, QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation)
realwidth = preview.width()
realheight = preview.height()
# and move it to the centre of the preview space
pixmap = QtGui.QImage(width, height, QtGui.QImage.Format_ARGB32_Premultiplied)
pixmap.fill(QtCore.Qt.black)
painter = QtGui.QPainter(pixmap)
painter.drawImage((width - realwidth) / 2, (height - realheight) / 2, preview)
else:
width = self.maximagewidth
height = self.rowheight
pixmap = QtGui.QImage(width, height, QtGui.QImage.Format_ARGB32_Premultiplied)
pixmap.fill(QtCore.Qt.black)
# finally create the row
self.items.insert(row, (filename, pixmap, shortfilename, theme[0]))
log.debug(u'Items: %s' % self.items)
self.endInsertRows()
def removeRow(self, row):
self.beginRemoveRows(QtCore.QModelIndex(), row, row)
self.items.pop(row)
self.endRemoveRows()
def addRow(self, item):
self.insertRow(len(self.items), item)
def data(self, index, role):
row = index.row()
if row > len(self.items):
# if the last row is selected and deleted, we then get called with an empty row!
return QtCore.QVariant()
if role == QtCore.Qt.DisplayRole:
retval = self.items[row][3]
elif role == QtCore.Qt.DecorationRole:
retval = self.items[row][1]
else:
retval = QtCore.QVariant()
if type(retval) is not type(QtCore.QVariant):
return QtCore.QVariant(retval)
else:
return retval
def __iter__(self):
for item in self.items:
yield item
def getValue(self, index):
row = index.row()
return self.items[row]
def getItem(self, row):
log.info(u'Get Item:%d -> %s' % (row, unicode(self.items)))
return self.items[row]
def getList(self):
filelist = [item[3] for item in self.items]
return filelist
class ThemeManager(QtGui.QWidget):
"""
Manages the orders of Theme.
@ -157,13 +64,10 @@ class ThemeManager(QtGui.QWidget):
translate(u'ThemeManager', u'Export a theme'), self.onExportTheme)
self.ThemeWidget = QtGui.QWidgetAction(self.Toolbar)
self.Layout.addWidget(self.Toolbar)
self.ThemeListView = QtGui.QListView(self)
self.themeData = ThemeData()
self.ThemeListView.setModel(self.themeData)
self.ThemeListView.setAlternatingRowColors(True)
self.Layout.addWidget(self.ThemeListView)
self.ThemeListWidget = QtGui.QListWidget(self)
self.ThemeListWidget.setAlternatingRowColors(True)
self.ThemeListWidget.setIconSize(QtCore.QSize(88,50))
self.Layout.addWidget(self.ThemeListWidget)
self.themelist = []
self.path = os.path.join(ConfigHelper.get_data_path(), u'themes')
self.checkThemesExists(self.path)
@ -174,21 +78,18 @@ class ThemeManager(QtGui.QWidget):
self.amendThemeForm.exec_()
def onEditTheme(self):
items = self.ThemeListView.selectedIndexes()
if len(items) > 0:
for item in items:
data = self.themeData.getValue(item)
self.amendThemeForm.loadTheme(data[3])
item = self.ThemeListWidget.currentItem()
if item is not None:
self.amendThemeForm.loadTheme(unicode(item.text()))
self.amendThemeForm.exec_()
def onDeleteTheme(self):
items = self.ThemeListView.selectedIndexes()
if len(items) > 0:
theme = u''
for item in items:
data = self.themeData.getValue(item)
theme = data[3]
item = self.ThemeListWidget.currentItem()
if item is not None:
theme = unicode(item.text())
th = theme + u'.png'
row = self.ThemeListWidget.row(item)
self.ThemeListWidget.takeItem(row)
try:
os.remove(os.path.join(self.path, th))
except:
@ -199,8 +100,6 @@ class ThemeManager(QtGui.QWidget):
except:
#if not present do not worry
pass
self.themeData.clearItems()
self.loadThemes()
def onExportTheme(self):
pass
@ -213,24 +112,37 @@ class ThemeManager(QtGui.QWidget):
if len(files) > 0:
for file in files:
self.unzipTheme(file, self.path)
self.themeData.clearItems()
self.loadThemes()
def loadThemes(self):
"""
Loads the theme lists and triggers updates accross
the whole system using direct calls or core functions
and events for the plugins.
The plugins will call back in to get the real list if they want it.
"""
log.debug(u'Load themes from dir')
self.themelist = []
self.ThemeListWidget.clear()
for root, dirs, files in os.walk(self.path):
for name in files:
if name.endswith(u'.png'):
#check to see file is in route directory
#check to see file is in theme root directory
theme = os.path.join(self.path, name)
if os.path.exists(theme):
self.themeData.addRow(theme)
(path, filename) = os.path.split(unicode(file))
textName = os.path.splitext(name)[0]
item_name = QtGui.QListWidgetItem(textName)
item_name.setIcon(buildIcon(theme))
item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(textName))
self.ThemeListWidget.addItem(item_name)
self.themelist.append(textName)
self.parent.EventManager.post_event(Event(EventType.ThemeListChanged))
self.parent.ServiceManagerContents.updateThemeList(self.getThemes())
self.parent.settingsForm.ThemesTab.updateThemeList(self.getThemes())
def getThemes(self):
return self.themeData.getList()
return self.themelist
def getThemeData(self, themename):
log.debug(u'getthemedata for theme %s', themename)
@ -337,6 +249,10 @@ class ThemeManager(QtGui.QWidget):
return newtheme.extract_xml()
def saveTheme(self, name, theme_xml, image_from, image_to) :
"""
Called by thememaintenance Dialog to save the theme
and to trigger the reload of the theme list
"""
log.debug(u'saveTheme %s %s', name, theme_xml)
theme_dir = os.path.join(self.path, name)
if os.path.exists(theme_dir) == False:
@ -348,7 +264,6 @@ class ThemeManager(QtGui.QWidget):
if image_from is not None and image_from != image_to:
shutil.copyfile(image_from, image_to)
self.generateAndSaveImage(self.path, name, theme_xml)
self.themeData.clearItems()
self.loadThemes()
def generateAndSaveImage(self, dir, name, theme_xml):
@ -357,7 +272,6 @@ class ThemeManager(QtGui.QWidget):
theme.parse(theme_xml)
theme.extend_image_filename(dir)
frame = self.generateImage(theme)
#im = frame.toImage()
samplepathname = os.path.join(self.path, name + u'.png')
if os.path.exists(samplepathname):
os.unlink(samplepathname)
@ -365,6 +279,9 @@ class ThemeManager(QtGui.QWidget):
log.debug(u'Theme image written to %s', samplepathname)
def generateImage(self, themedata):
"""
Call the RenderManager to build a Sample Image
"""
log.debug(u'generateImage %s ', themedata)
frame = self.parent.RenderManager.generate_preview(themedata)
return frame

View File

@ -157,7 +157,7 @@ class BibleImportForm(QtGui.QDialog, Ui_BibleImportDialog):
self.close()
def onImportButtonClicked(self):
self.message = u'Bible import completed'
message = u'Bible import completed'
if self.biblemanager != None:
if not self.bible_type == None and len(self.BibleNameEdit.displayText()) > 0:
self.MessageLabel.setText(u'Import Started')
@ -165,14 +165,16 @@ class BibleImportForm(QtGui.QDialog, Ui_BibleImportDialog):
self.setMax(65)
self.ProgressBar.setValue(0)
self.biblemanager.process_dialog(self)
self.importBible()
self.MessageLabel.setText(u'Import Complete')
status, msg = self.importBible()
if msg is not None:
message = msg
self.MessageLabel.setText(message)
self.ProgressBar.setValue(self.barmax)
# tell bibleplugin to reload the bibles
Receiver().send_message(u'openlpreloadbibles')
reply = QtGui.QMessageBox.information(self,
translate(u'BibleMediaItem', u'Information'),
translate(u'BibleMediaItem', self.message))
translate(u'BibleMediaItem', message))
def setMax(self, max):
log.debug(u'set Max %s', max)
@ -185,7 +187,8 @@ class BibleImportForm(QtGui.QDialog, Ui_BibleImportDialog):
self.ProgressBar.setValue(self.ProgressBar.value()+1)
def importBible(self):
log.debug(u'Import Bible ')
log.debug(u'Import Bible')
message = None
if self.bible_type == u'OSIS':
loaded = self.biblemanager.register_osis_file_bible(unicode(self.BibleNameEdit.displayText()),
self.OSISLocationEdit.displayText())
@ -207,11 +210,14 @@ class BibleImportForm(QtGui.QDialog, Ui_BibleImportDialog):
unicode(self.VersionNameEdit.displayText()),
unicode(self.CopyrightEdit.displayText()),
unicode(self.PermisionEdit.displayText()))
else:
message = u'Bible import failed'
self.bible_type = None
# free the screen state restrictions
self.resetScreenFieldStates()
# reset all the screen fields
self.resetEntryFields()
return loaded, message
def checkOsis(self):
if len(self.BooksLocationEdit.displayText()) > 0 or len(self.VerseLocationEdit.displayText()) > 0:
@ -286,4 +292,4 @@ class BibleImportForm(QtGui.QDialog, Ui_BibleImportDialog):
self.OSISLocationEdit.setText(u'')
self.BibleNameEdit.setText(u'')
self.LocationComboBox.setCurrentIndex(0)
self.BibleComboBox.setCurrentIndex(0)
self.BibleComboBox.setCurrentIndex(0)

View File

@ -16,6 +16,7 @@ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA
"""
import logging
import chardet
from openlp.plugins.bibles.lib.bibleDBimpl import BibleDBImpl
from openlp.plugins.bibles.lib.common import BibleCommon
@ -23,57 +24,64 @@ from openlp.core.lib import Receiver
class BibleCSVImpl(BibleCommon):
global log
global log
log=logging.getLogger(u'BibleCSVImpl')
log.info(u'BibleCVSImpl loaded')
log.info(u'BibleCVSImpl loaded')
def __init__(self, bibledb):
"""
Loads a Bible from a pair of CVS files passed in
This class assumes the files contain all the information and
This class assumes the files contain all the information and
a clean bible is being loaded.
"""
"""
self.bibledb = bibledb
self.loadbible = True
QtCore.QObject.connect(Receiver().get_receiver(),QtCore.SIGNAL(u'openlpstopimport'),self.stop_import)
def stop_import(self):
self.loadbible= False
def load_data(self, booksfile, versesfile, dialogobject):
#Populate the Tables
fbooks=open(booksfile, 'r')
fverse=open(versesfile, 'r')
count = 0
for line in fbooks:
#log.debug( line)
if self.loadbible == False: # cancel pressed
break
# cancel pressed
if self.loadbible == False:
break
details = chardet.detect(line)
line = unicode(line, details['encoding'])
p = line.split(u',')
p1 = p[1].replace(u'"', u'')
p1 = p[1].replace(u'"', u'')
p2 = p[2].replace(u'"', u'')
p3 = p[3].replace(u'"', u'')
p3 = p[3].replace(u'"', u'')
self.bibledb.create_book(p2, p3, int(p1))
count += 1
if count % 3 == 0: #Every x verses repaint the screen
Receiver().send_message(u'openlpprocessevents')
#Flush the screen events
if count % 3 == 0:
Receiver().send_message(u'openlpprocessevents')
count = 0
count = 0
book_ptr = None
for line in fverse:
if self.loadbible == False: # cancel pressed
break
#log.debug( line)
p = line.split(u',', 3) # split into 3 units and leave the rest as a single field
break
details = chardet.detect(line)
line = unicode(line, details['encoding'])
# split into 3 units and leave the rest as a single field
p = line.split(u',', 3)
p0 = p[0].replace(u'"', u'')
p3 = p[3].replace(u'"',u'')
if book_ptr is not p0:
book = self.bibledb.get_bible_book(p0)
book_ptr = book.name
dialogobject.incrementProgressBar(book.name) # increament the progress bar
# increament the progress bar
dialogobject.incrementProgressBar(book.name)
self.bibledb.add_verse(book.id, p[1], p[2], p3)
count += 1
if count % 3 == 0: #Every x verses repaint the screen
Receiver().send_message(u'openlpprocessevents')
count = 0
#Every x verses repaint the screen
if count % 3 == 0:
Receiver().send_message(u'openlpprocessevents')
count = 0

View File

@ -18,6 +18,8 @@ Place, Suite 330, Boston, MA 02111-1307 USA
import os
import os.path
import logging
import chardet
import codecs
from openlp.plugins.bibles.lib.bibleDBimpl import BibleDBImpl
from openlp.core.lib import Receiver
from PyQt4 import QtCore
@ -45,44 +47,37 @@ class BibleOSISImpl():
QtCore.QObject.connect(Receiver().get_receiver(),QtCore.SIGNAL(u'openlpstopimport'),self.stop_import)
def stop_import(self):
self.loadbible= False
def load_data(self, osisfile, dialogobject=None):
osis=open(osisfile, u'r')
self.loadbible = False
def load_data(self, osisfile_record, dialogobject=None):
osis = codecs.open(osisfile_record, u'r')
book_ptr = None
id = 0
count = 0
verseText = u'<verse osisID='
testament = 1
for file in osis.readlines():
for file_record in osis.readlines():
# cancel pressed on UI
if self.loadbible == False:
break
# print file
pos = file.find(verseText)
pos = file_record.find(verseText)
if pos > -1: # we have a verse
epos= file.find(u'>', pos)
ref = file[pos+15:epos-1] # Book Reference
epos= file_record.find(u'>', pos)
ref = file_record[pos+15:epos-1] # Book Reference
#lets find the bible text only
# find start of text
pos = epos + 1
# end of text
epos = file.find(u'</verse>', pos)
text = unicode(file[pos : epos], u'utf8')
#print pos, e, f[pos:e] # Found Basic Text
epos = file_record.find(u'</verse>', pos)
text = file_record[pos : epos]
#remove tags of extra information
text = self.remove_block(u'<title', u'</title>', text)
text = self.remove_block(u'<note', u'</note>', text)
text = self.remove_block(u'<divineName', u'</divineName>', text)
text = self.remove_tag(u'<lb', text)
text = self.remove_tag(u'<q', text)
text = self.remove_tag(u'<l', text)
text = self.remove_tag(u'<lg', text)
# Strange tags where the end is not the same as the start
# The must be in this order as at least one bible has them
# crossing and the removal does not work.
@ -95,17 +90,14 @@ class BibleOSISImpl():
else:
text = text[:pos] + text[epos + 4: ]
pos = text.find(u'<FI>')
pos = text.find(u'<RF>')
while pos > -1:
epos = text.find(u'<Rf>', pos)
text = text[:pos] + text[epos + 4: ]
#print "X", pos, epos, text
pos = text.find(u'<RF>')
p = ref.split(u'.', 3) # split up the reference
#print p, ">>>", text
# split up the reference
p = ref.split(u'.', 3)
if book_ptr != p[0]:
# first time through
if book_ptr == None:
@ -138,7 +130,6 @@ class BibleOSISImpl():
while pos > -1:
epos = text.find(end_tag, pos)
if epos == -1:
#print "Y", pos, epos
pos = -1
else:
text = text[:pos] + text[epos + len(end_tag): ]

View File

@ -49,7 +49,6 @@ class BibleManager():
self.proxyname = self.config.get_config(u'proxy name') #get proxy name for screen
self.bibleSuffix = u'sqlite'
self.dialogobject = None
self.reload_bibles()
def reload_bibles(self):

View File

@ -494,7 +494,7 @@ class BibleMediaItem(MediaManagerItem):
if end_verse == '':
end_verse = 99
if start_chapter == '':
message = u'No chapter found for search'
message = u'No chapter found for search criteria'
#print 'message = ' + unicode(message)
#print 'search = ' + unicode(original)
#print 'results = ' + unicode(book) + ' @ '+ unicode(start_chapter)+' @ '+ unicode(end_chapter)+' @ '+ unicode(start_verse)+ ' @ '+ unicode(end_verse)

View File

@ -74,14 +74,26 @@ class ImageToolbar(MasterToolbar):
u':/media/media_stop.png',
translate(u'SlideController', u'Stop continuous loop'),
self.onStopLoop)
self.Toolbar.addSeparator()
self.DelaySpinBox = QtGui.QSpinBox(self.Toolbar)
self.SpinWidget = QtGui.QWidgetAction(self.Toolbar)
self.SpinWidget.setDefaultWidget(self.DelaySpinBox)
self.Toolbar.addAction(self.SpinWidget)
#self.Layout.addWidget(self.Toolbar)
self.Toolbar.setSizePolicy(sizeToolbarPolicy)
self.DelaySpinBox.setSuffix(translate(u'ImageSlideController', u's'))
def serviceLoaded(self):
self.DelaySpinBox.setValue(self.parent.parent.ImageTab.loop_delay)
if self.PreviewListWidget.rowCount() == 1:
self.DelaySpinBox.setEnabled(False)
def onStartLoop(self):
"""
Go to the last slide.
"""
delay = self.parent.parent.ImageTab.loop_delay
self.timer_id = self.startTimer(delay * 1000)
if self.PreviewListWidget.rowCount() > 1:
self.timer_id = self.startTimer(int(self.TimeoutSpinBox.value()) * 1000)
def onStopLoop(self):
"""
@ -92,4 +104,3 @@ class ImageToolbar(MasterToolbar):
def timerEvent(self, event):
if event.timerId() == self.timer_id:
self.onSlideSelectedNext()

View File

@ -49,7 +49,6 @@ class ImageTab(SettingsTab):
self.TimeoutSpacer = QtGui.QSpacerItem(147, 20,
QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.TimeoutLayout.addItem(self.TimeoutSpacer)
self.ImageLayout.setWidget(0, QtGui.QFormLayout.LabelRole, self.ImageModeGroupBox)
# Signals and slots
QtCore.QObject.connect(self.TimeoutSpinBox,
@ -57,6 +56,7 @@ class ImageTab(SettingsTab):
def retranslateUi(self):
self.TimeoutLabel.setText(translate(u'ImageTab', u'Slide Loop Delay:'))
self.TimeoutSpinBox.setSuffix(translate(u'ImageTab', u's'))
def onTimeoutSpinBoxChanged(self):
self.loop_delay = self.TimeoutSpinBox.value()

View File

@ -70,9 +70,7 @@ class PresentationMediaItem(MediaManagerItem):
self.DisplayTypeLabel = QtGui.QLabel(self.PresentationWidget)
self.DisplayTypeLabel.setObjectName(u'SearchTypeLabel')
self.DisplayLayout.addWidget(self.DisplayTypeLabel, 0, 0, 1, 1)
self.DisplayTypeLabel.setText(translate(u'PresentationMediaItem', u'Present using:'))
# Add the Presentation widget to the page layout
self.PageLayout.addWidget(self.PresentationWidget)

View File

@ -52,5 +52,7 @@ class PresentationPlugin(Plugin):
def check_pre_conditions(self):
log.debug('check_pre_conditions')
self.openoffice = Openoffice()
return self.openoffice.checkOoPid()
return True
# self.openoffice = Openoffice()
# return self.openoffice.checkOoPid()

View File

@ -47,8 +47,7 @@ class SongManager():
self.db_url = u''
db_type = self.config.get_config(u'db type', u'sqlite')
if db_type == u'sqlite':
self.db_url = u'sqlite:///' + self.config.get_data_path() + \
u'/songs.sqlite'
self.db_url = u'sqlite:///%s/songs.sqlite' % self.config.get_data_path()
else:
self.db_url = db_type + 'u://' + \
self.config.get_config(u'db username') + u':' + \
@ -73,13 +72,17 @@ class SongManager():
"""
Searches the song title for keywords.
"""
return self.session.query(Song).filter(Song.search_title.like(u'%' + keywords + u'%')).order_by(Song.search_title.asc()).all()
return self.session.query(Song).filter(
Song.search_title.like(u'%' + keywords + u'%')).order_by(
Song.search_title.asc()).all()
def search_song_lyrics(self, keywords):
"""
Searches the song lyrics for keywords.
"""
return self.session.query(Song).filter(Song.search_lyrics.like(u'%' + keywords + u'%')).order_by(Song.search_lyrics.asc()).all()
return self.session.query(Song).filter(
Song.search_lyrics.like(u'%' + keywords + u'%')).order_by(
Song.search_lyrics.asc()).all()
def get_song_from_author(self, keywords):
"""

View File

@ -1,4 +1,23 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
"""
OpenLP - Open Source Lyrics Projection
Copyright (c) 2008 Raoul Snyman
Portions copyright (c) 2008-2009 Martin Thompson, Tim Bentley,
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 os
import sys
@ -17,20 +36,30 @@ logging.basicConfig(level=logging.DEBUG,
filename='openlp-migration.log',
filemode='w')
class Migration():
class Migration(object):
"""
A class to take care of the migration process.
"""
def __init__(self):
"""
Initialise the process.
"""
self.display = Display()
self.stime = time.strftime(u'%Y-%m-%d-%H%M%S', time.localtime())
self.display.output(u'OpenLp v1.9.0 Migration Utility Started')
def process(self):
"""
Perform the conversion.
"""
#MigrateFiles(self.display).process()
MigrateSongs(self.display).process()
#MigrateBibles(self.display).process()
def move_log_file(self):
"""
Move the log file to a new location.
"""
fname = 'openlp-migration.log'
c = os.path.splitext(fname)
b = (c[0]+'-'+ unicode(self.stime) + c[1])