diff --git a/.bzrignore b/.bzrignore index fedd1a25e..9df0cdf95 100644 --- a/.bzrignore +++ b/.bzrignore @@ -8,3 +8,5 @@ .eric4project list openlp.org 2.0.e4* +documentation/build/html +documentation/build/doctrees diff --git a/cnvdb.py b/cnvdb.py index a1e200ea8..f33b5dc03 100644 --- a/cnvdb.py +++ b/cnvdb.py @@ -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.' diff --git a/demo.py b/demo.py index c06bbd26a..c6b1cf571 100644 --- a/demo.py +++ b/demo.py @@ -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() diff --git a/documentation/Makefile b/documentation/Makefile new file mode 100644 index 000000000..70c821142 --- /dev/null +++ b/documentation/Makefile @@ -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 ' where 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." diff --git a/documentation/make.bat b/documentation/make.bat new file mode 100644 index 000000000..8d21b45ce --- /dev/null +++ b/documentation/make.bat @@ -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 ^` where ^ 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 diff --git a/documentation/source/conf.py b/documentation/source/conf.py new file mode 100644 index 000000000..05a3045df --- /dev/null +++ b/documentation/source/conf.py @@ -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 +# " v 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 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 diff --git a/documentation/source/core/index.rst b/documentation/source/core/index.rst new file mode 100644 index 000000000..11597067c --- /dev/null +++ b/documentation/source/core/index.rst @@ -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: + diff --git a/documentation/source/index.rst b/documentation/source/index.rst new file mode 100644 index 000000000..d57a43543 --- /dev/null +++ b/documentation/source/index.rst @@ -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` + diff --git a/documentation/source/migration/index.rst b/documentation/source/migration/index.rst new file mode 100644 index 000000000..a1a64abc8 --- /dev/null +++ b/documentation/source/migration/index.rst @@ -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: + diff --git a/documentation/source/openlp.rst b/documentation/source/openlp.rst new file mode 100644 index 000000000..76a1a2098 --- /dev/null +++ b/documentation/source/openlp.rst @@ -0,0 +1,7 @@ +.. _openlp: + +:mod:`openlp` Module +==================== + +.. automodule:: openlp + :members: diff --git a/documentation/source/plugins/index.rst b/documentation/source/plugins/index.rst new file mode 100644 index 000000000..e618fa188 --- /dev/null +++ b/documentation/source/plugins/index.rst @@ -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: + diff --git a/openlp.pyw b/openlp.pyw index 33ae56f16..d7e43ede0 100755 --- a/openlp.pyw +++ b/openlp.pyw @@ -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() diff --git a/openlp/controls/__init__.py b/openlp/controls/__init__.py deleted file mode 100644 index b16ed4f5a..000000000 --- a/openlp/controls/__init__.py +++ /dev/null @@ -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 -""" diff --git a/openlp/core/__init__.py b/openlp/core/__init__.py index e123886b5..e3518b436 100644 --- a/openlp/core/__init__.py +++ b/openlp/core/__init__.py @@ -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' ] diff --git a/openlp/core/lib/__init__.py b/openlp/core/lib/__init__.py index d442e3c2b..c940bd649 100644 --- a/openlp/core/lib/__init__.py +++ b/openlp/core/lib/__init__.py @@ -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'] diff --git a/openlp/core/lib/event.py b/openlp/core/lib/event.py index a68ebe222..dcb84ffbb 100644 --- a/openlp/core/lib/event.py +++ b/openlp/core/lib/event.py @@ -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 diff --git a/openlp/core/lib/eventmanager.py b/openlp/core/lib/eventmanager.py index 659d018bf..3b84a8d10 100644 --- a/openlp/core/lib/eventmanager.py +++ b/openlp/core/lib/eventmanager.py @@ -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) diff --git a/openlp/core/lib/eventreceiver.py b/openlp/core/lib/eventreceiver.py index 189228dfc..73a908a2d 100644 --- a/openlp/core/lib/eventreceiver.py +++ b/openlp/core/lib/eventreceiver.py @@ -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) diff --git a/openlp/core/lib/mediamanageritem.py b/openlp/core/lib/mediamanageritem.py index f8a710246..430e4dbfb 100644 --- a/openlp/core/lib/mediamanageritem.py +++ b/openlp/core/lib/mediamanageritem.py @@ -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 diff --git a/openlp/core/lib/plugin.py b/openlp/core/lib/plugin.py index 4db4480cc..7b306ec76 100644 --- a/openlp/core/lib/plugin.py +++ b/openlp/core/lib/plugin.py @@ -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 diff --git a/openlp/core/lib/pluginconfig.py b/openlp/core/lib/pluginconfig.py index e966fb2ed..3c9d2b70d 100644 --- a/openlp/core/lib/pluginconfig.py +++ b/openlp/core/lib/pluginconfig.py @@ -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 diff --git a/openlp/core/lib/pluginmanager.py b/openlp/core/lib/pluginmanager.py index 38cb9b477..e8eb308a5 100644 --- a/openlp/core/lib/pluginmanager.py +++ b/openlp/core/lib/pluginmanager.py @@ -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() + diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index e3774ba10..3f389afa7 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -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') diff --git a/openlp/core/lib/rendermanager.py b/openlp/core/lib/rendermanager.py index 4fa8a88e9..6c3d11001 100644 --- a/openlp/core/lib/rendermanager.py +++ b/openlp/core/lib/rendermanager.py @@ -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) diff --git a/openlp/core/lib/serviceitem.py b/openlp/core/lib/serviceitem.py index 4f1e5abf4..f9dfa2097 100644 --- a/openlp/core/lib/serviceitem.py +++ b/openlp/core/lib/serviceitem.py @@ -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'] diff --git a/openlp/core/settingsmanager.py b/openlp/core/lib/settingsmanager.py similarity index 57% rename from openlp/core/settingsmanager.py rename to openlp/core/lib/settingsmanager.py index 84ff69765..bc66c2375 100644 --- a/openlp/core/settingsmanager.py +++ b/openlp/core/lib/settingsmanager.py @@ -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 diff --git a/openlp/core/lib/settingstab.py b/openlp/core/lib/settingstab.py index 1eddbee0e..421d0744d 100644 --- a/openlp/core/lib/settingstab.py +++ b/openlp/core/lib/settingstab.py @@ -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 diff --git a/openlp/core/lib/songxmlhandler.py b/openlp/core/lib/songxmlhandler.py index 14ed4ea0b..9cb0bb4e9 100644 --- a/openlp/core/lib/songxmlhandler.py +++ b/openlp/core/lib/songxmlhandler.py @@ -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 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 ```` tag which contains the lyrics of the + song. + """ # Create the main 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 ```` 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) diff --git a/openlp/core/lib/themexmlhandler.py b/openlp/core/lib/themexmlhandler.py index 12880bfa6..acb451653 100644 --- a/openlp/core/lib/themexmlhandler.py +++ b/openlp/core/lib/themexmlhandler.py @@ -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=\ ''' @@ -62,26 +64,38 @@ blankthemexml=\ ''' -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 diff --git a/openlp/core/lib/toolbar.py b/openlp/core/lib/toolbar.py index 9bd124aa2..0f89abed4 100644 --- a/openlp/core/lib/toolbar.py +++ b/openlp/core/lib/toolbar.py @@ -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 `