forked from openlp/openlp
Added some fixes to the operation and layout of the slide controllers.
This commit is contained in:
commit
7a0f9d3e06
@ -8,3 +8,5 @@
|
||||
.eric4project
|
||||
list
|
||||
openlp.org 2.0.e4*
|
||||
documentation/build/html
|
||||
documentation/build/doctrees
|
||||
|
42
cnvdb.py
42
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.'
|
||||
|
73
demo.py
73
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()
|
||||
|
88
documentation/Makefile
Normal file
88
documentation/Makefile
Normal 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
112
documentation/make.bat
Normal 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
|
194
documentation/source/conf.py
Normal file
194
documentation/source/conf.py
Normal 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
|
44
documentation/source/core/index.rst
Normal file
44
documentation/source/core/index.rst
Normal 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:
|
||||
|
25
documentation/source/index.rst
Normal file
25
documentation/source/index.rst
Normal 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`
|
||||
|
32
documentation/source/migration/index.rst
Normal file
32
documentation/source/migration/index.rst
Normal 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:
|
||||
|
7
documentation/source/openlp.rst
Normal file
7
documentation/source/openlp.rst
Normal file
@ -0,0 +1,7 @@
|
||||
.. _openlp:
|
||||
|
||||
:mod:`openlp` Module
|
||||
====================
|
||||
|
||||
.. automodule:: openlp
|
||||
:members:
|
44
documentation/source/plugins/index.rst
Normal file
44
documentation/source/plugins/index.rst
Normal 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:
|
||||
|
18
openlp.pyw
18
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()
|
||||
|
@ -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
|
||||
"""
|
@ -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' ]
|
||||
|
||||
|
@ -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']
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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')
|
||||
|
@ -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)
|
||||
|
@ -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']
|
||||
|
@ -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
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
|
@ -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'))
|
||||
|
@ -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):
|
||||
"""
|
||||
|
@ -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()
|
||||
|
@ -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]
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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): ]
|
||||
|
@ -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):
|
||||
|
@ -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)
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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):
|
||||
"""
|
||||
|
@ -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])
|
||||
|
Loading…
Reference in New Issue
Block a user