This commit is contained in:
Raoul Snyman 2010-10-28 07:24:31 +02:00
commit a249393b2c
125 changed files with 3496 additions and 1593 deletions

View File

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

View File

@ -17,7 +17,7 @@ import sys
# If extensions (or modules to document with autodoc) are in another directory, # 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 # 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. # documentation root, use os.path.abspath to make it absolute, like shown here.
sys.path.append(os.path.abspath(os.path.join('..', '..'))) sys.path.insert(0, os.path.abspath(os.path.join('..', '..', '..')))
# -- General configuration ----------------------------------------------------- # -- General configuration -----------------------------------------------------
@ -39,7 +39,7 @@ master_doc = 'index'
# General information about the project. # General information about the project.
project = u'OpenLP' project = u'OpenLP'
copyright = u'2009, Raoul Snyman' copyright = u'2004-2010, Raoul Snyman'
# The version info for the project you're documenting, acts as replacement for # The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the # |version| and |release|, also used in various other places throughout the
@ -48,7 +48,7 @@ copyright = u'2009, Raoul Snyman'
# The short X.Y version. # The short X.Y version.
version = '2.0' version = '2.0'
# The full version, including alpha/beta/rc tags. # The full version, including alpha/beta/rc tags.
release = '2.0.pre' release = '1.9.3'
# The language for content autogenerated by Sphinx. Refer to documentation # The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages. # for a list of supported languages.
@ -111,7 +111,7 @@ html_theme_options = {
# The name for this set of Sphinx documents. If None, it defaults to # The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation". # "<project> v<release> documentation".
#html_title = None html_title = 'OpenLP 2.0 Developer API'
# A shorter title for the navigation bar. Default is the same as html_title. # A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None #html_short_title = None
@ -166,7 +166,7 @@ html_static_path = ['_static']
#html_file_suffix = '' #html_file_suffix = ''
# Output file base name for HTML help builder. # Output file base name for HTML help builder.
htmlhelp_basename = 'OpenLPdoc' htmlhelp_basename = 'OpenLP-2.0-api'
# -- Options for LaTeX output -------------------------------------------------- # -- Options for LaTeX output --------------------------------------------------
@ -180,7 +180,7 @@ htmlhelp_basename = 'OpenLPdoc'
# Grouping the document tree into LaTeX files. List of tuples # Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]). # (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [ latex_documents = [
('index', 'OpenLP.tex', u'OpenLP Documentation', ('index', 'OpenLP.tex', u'OpenLP 2.0 Developer API',
u'Raoul Snyman', 'manual'), u'Raoul Snyman', 'manual'),
] ]

View File

@ -3,9 +3,13 @@
:mod:`core` Module :mod:`core` Module
================== ==================
.. automodule:: openlp.core
:members:
.. toctree:: .. toctree::
:maxdepth: 2 :maxdepth: 2
lib lib
theme theme
ui
utils

View File

@ -1,7 +1,7 @@
.. _core-lib: .. _core-lib:
:mod:`lib` Module Object Library
================= ==============
.. automodule:: openlp.core.lib .. automodule:: openlp.core.lib
:members: :members:
@ -60,12 +60,6 @@
.. autoclass:: openlp.core.lib.settingstab.SettingsTab .. autoclass:: openlp.core.lib.settingstab.SettingsTab
:members: :members:
:mod:`ThemeXML`
---------------
.. autoclass:: openlp.core.lib.themexmlhandler.ThemeXML
:members:
:mod:`OpenLPToolbar` :mod:`OpenLPToolbar`
-------------------- --------------------

View File

@ -0,0 +1,27 @@
.. _core-ui:
User Interface
==============
.. automodule:: openlp.core.ui
Main Windows
------------
.. autoclass:: openlp.core.ui.mainwindow.MainWindow
:members:
.. autoclass:: openlp.core.ui.maindisplay.MainDisplay
:members:
Managers
--------
.. autoclass:: openlp.core.ui.servicemanager.ServiceManager
:members:
.. autoclass:: openlp.core.ui.mediadockmanager.MediaDockManager
:members:
.. autoclass:: openlp.core.ui.thememanager.ThemeManager
:members:

View File

@ -0,0 +1,7 @@
.. _core-utils:
Utilities
=========
.. automodule:: openlp.core.utils
:members:

View File

@ -15,7 +15,6 @@ Contents:
.. toctree:: .. toctree::
:maxdepth: 2 :maxdepth: 2
openlp
core/index core/index
plugins/index plugins/index

View File

@ -0,0 +1,31 @@
.. _plugins-alerts:
Alerts Plugin
=============
.. automodule:: openlp.plugins.alerts
:members:
Plugin Class
------------
.. autoclass:: openlp.plugins.alerts.alertsplugin.AlertsPlugin
:members:
Forms
-----
.. automodule:: openlp.plugins.alerts.forms
:members:
.. autoclass:: openlp.plugins.alerts.forms.alertform.AlertForm
:members:
Helper Classes & Functions
--------------------------
.. automodule:: openlp.plugins.alerts.lib
:members:
.. automodule:: openlp.plugins.alerts.lib.db
:members:

View File

@ -0,0 +1,55 @@
.. _plugins-bibles:
Bibles Plugin
=============
.. automodule:: openlp.plugins.bibles
:members:
Plugin Class
------------
.. autoclass:: openlp.plugins.bibles.bibleplugin.BiblePlugin
:members:
Forms
-----
.. automodule:: openlp.plugins.bibles.forms
:members:
.. autoclass:: openlp.plugins.bibles.forms.importwizardform.ImportWizardForm
:members:
Helper Classes & Functions
--------------------------
.. automodule:: openlp.plugins.bibles.lib
:members:
.. automodule:: openlp.plugins.bibles.lib.db
:members:
.. automodule:: openlp.plugins.bibles.lib.biblestab
:members:
.. automodule:: openlp.plugins.bibles.lib.manager
:members:
.. automodule:: openlp.plugins.bibles.lib.mediaitem
:members:
Bible Importers
---------------
.. automodule:: openlp.plugins.bibles.lib.csvbible
:members:
.. automodule:: openlp.plugins.bibles.lib.http
:members:
.. automodule:: openlp.plugins.bibles.lib.osis
:members:
.. automodule:: openlp.plugins.bibles.lib.opensong
:members:

View File

@ -0,0 +1,34 @@
.. _plugins-custom:
Custom Slides Plugin
====================
.. automodule:: openlp.plugins.custom
:members:
Plugin Class
------------
.. autoclass:: openlp.plugins.custom.customplugin.CustomPlugin
:members:
Forms
-----
.. automodule:: openlp.plugins.custom.forms
:members:
.. autoclass:: openlp.plugins.custom.forms.editcustomform.EditCustomForm
:members:
.. autoclass:: openlp.plugins.custom.forms.editcustomslideform.EditCustomSlideForm
:members:
Helper Classes & Functions
--------------------------
.. automodule:: openlp.plugins.custom.lib
:members:
.. automodule:: openlp.plugins.custom.lib.mediaitem
:members:

View File

@ -0,0 +1,22 @@
.. _plugins-images:
Images Plugin
=============
.. automodule:: openlp.plugins.images
:members:
Plugin Class
------------
.. autoclass:: openlp.plugins.images.imageplugin.ImagePlugin
:members:
Helper Classes & Functions
--------------------------
.. automodule:: openlp.plugins.images.lib
:members:
.. automodule:: openlp.plugins.images.lib.mediaitem
:members:

View File

@ -0,0 +1,20 @@
.. _plugins-index:
Plugins
=======
.. automodule:: openlp.plugins
:members:
.. toctree::
:maxdepth: 2
songs
bibles
presentations
media
images
custom
remotes
songusage
alerts

View File

@ -0,0 +1,22 @@
.. _plugins-media:
Media Plugin
============
.. automodule:: openlp.plugins.media
:members:
Plugin Class
------------
.. autoclass:: openlp.plugins.media.mediaplugin.MediaPlugin
:members:
Helper Classes & Functions
--------------------------
.. automodule:: openlp.plugins.media.lib
:members:
.. automodule:: openlp.plugins.media.lib.mediaitem
:members:

View File

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

View File

@ -0,0 +1,19 @@
.. _plugins-remotes:
Remotes Plugin
==============
.. automodule:: openlp.plugins.remotes
:members:
Plugin Class
------------
.. autoclass:: openlp.plugins.remotes.remoteplugin.RemotesPlugin
:members:
Helper Classes & Functions
--------------------------
.. automodule:: openlp.plugins.remotes.lib
:members:

View File

@ -0,0 +1,103 @@
.. _plugins-songs:
Songs Plugin
============
.. automodule:: openlp.plugins.songs
:members:
Plugin Class
------------
.. autoclass:: openlp.plugins.songs.songsplugin.SongsPlugin
:members:
Forms
-----
.. automodule:: openlp.plugins.songs.forms
:members:
.. autoclass:: openlp.plugins.songs.forms.authorsform.AuthorsForm
:members:
.. autoclass:: openlp.plugins.songs.forms.editsongform.EditSongForm
:members:
.. autoclass:: openlp.plugins.songs.forms.editverseform.EditVerseForm
:members:
.. autoclass:: openlp.plugins.songs.forms.songbookform.SongBookForm
:members:
.. autoclass:: openlp.plugins.songs.forms.songimportform.SongImportForm
:members:
.. autoclass:: openlp.plugins.songs.forms.songmaintenanceform.SongMaintenanceForm
:members:
.. autoclass:: openlp.plugins.songs.forms.topicsform.TopicsForm
:members:
Helper Classes & Functions
--------------------------
.. automodule:: openlp.plugins.songs.lib
:members:
.. automodule:: openlp.plugins.songs.lib.db
:members:
.. automodule:: openlp.plugins.songs.lib.importer
:members:
.. automodule:: openlp.plugins.songs.lib.mediaitem
:members:
.. autoclass:: openlp.plugins.songs.lib.mediaitem.SongListView
:members:
.. automodule:: openlp.plugins.songs.lib.songimport
:members:
.. automodule:: openlp.plugins.songs.lib.songstab
:members:
.. automodule:: openlp.plugins.songs.lib.xml
:members:
Song Importers
--------------
.. automodule:: openlp.plugins.songs.lib.cclifileimport
:members:
.. autoclass:: openlp.plugins.songs.lib.cclifileimport.CCLIFileImportError
:members:
.. automodule:: openlp.plugins.songs.lib.ewimport
:members:
.. autoclass:: openlp.plugins.songs.lib.ewimport.FieldDescEntry
:members:
.. automodule:: openlp.plugins.songs.lib.olp1import
:members:
.. automodule:: openlp.plugins.songs.lib.olpimport
:members:
.. automodule:: openlp.plugins.songs.lib.oooimport
:members:
.. automodule:: openlp.plugins.songs.lib.opensongimport
:members:
.. automodule:: openlp.plugins.songs.lib.sofimport
:members:
.. automodule:: openlp.plugins.songs.lib.songbeamerimport
:members:
.. automodule:: openlp.plugins.songs.lib.wowimport
:members:

View File

@ -0,0 +1,34 @@
.. _plugins-songusage:
Song Usage Plugin
=================
.. automodule:: openlp.plugins.songusage
:members:
Plugin Class
------------
.. autoclass:: openlp.plugins.songusage.songusageplugin.SongUsagePlugin
:members:
Forms
-----
.. automodule:: openlp.plugins.songusage.forms
:members:
.. autoclass:: openlp.plugins.songusage.forms.songusagedeleteform.SongUsageDeleteForm
:members:
.. autoclass:: openlp.plugins.songusage.forms.songusagedetailform.SongUsageDetailForm
:members:
Helper Classes & Functions
--------------------------
.. automodule:: openlp.plugins.songusage.lib
:members:
.. automodule:: openlp.plugins.songusage.lib.db
:members:

View File

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

View File

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

View File

@ -0,0 +1,208 @@
# -*- 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 os
import sys
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, 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'2004-2010 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.3'
# 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 = {
'sidebarbgcolor': '#3a60a9',
'relbarbgcolor': '#203b6f',
'footerbgcolor': '#26437c',
'headtextcolor': '#203b6f',
'linkcolor': '#26437c',
'sidebarlinkcolor': '#ceceff'
}
# 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 = u'OpenLP 2.0 User Manual'
# 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 = 'OpenLP-2.0-manual'
# -- 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 2.0 User Manual',
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
# A dictionary that contains LaTeX snippets that override those Sphinx usually
# puts into the generated .tex files.
latex_elements = {
'fontpkg': '\\usepackage{helvet}'
}

View File

@ -0,0 +1,180 @@
==================
Dual Monitor Setup
==================
The first step in getting OpenLP working on your system is to setup your
computer properly for dual monitors. This is not very difficult, but the steps
do vary depending on operating system.
Most modern computers do have the ability for dual monitors. To be certain
check your computer's documentation. A typical desktop computer capable of dual
monitors will have two of, or a combination of the two connectors below.
**VGA**
.. image:: pics/vga.png
**DVI**
.. image:: pics/dvi.png
A laptop computer setup only varies slightly, generally you will need only one
of outputs pictured above since your laptops screen serves as one of the
monitors. Sometimes with older laptops a key stroke generally involving the
:kbd:`Fn` key and another key is required to enable the second monitor on
laptops.
Some computers also incorporate the use of :abbr:`S-Video (Separate Video)` or
:abbr:`HDMI (High-Definition Multimedia Interface)` connections.
A typical OpenLP set up consist of your normal single monitor setup, with your
projector setup as the second monitor. With the option of extending your
desktop across the second monitor, or your operating system's equivalent.
Microsoft Windows
-----------------
Dual monitor setup is similar among all the currently supported Windows
releases (XP, Vista, Windows 7), but does vary slightly from one release to the
next.
Windows 7
^^^^^^^^^
Windows 7 has using a projector in mind. Simply connect your projector and
press :kbd:`Windows+P`.
The more traditional way is also fairly straight forward. Go to
:guilabel:`Control Panel` and click on :guilabel:`Display`. This will open up
the :guilabel:`Display` dialog. You can also bypass this step by right click on
a blank area on your desktop and selecting :guilabel:`Resolution`.
.. image:: pics/winsevendisplay.png
Then click on the :guilabel:`Adjust resolution` link in the left pane. Enable
your projector and make sure that the selected value for :guilabel:`Multiple
displays` is :guilabel:`Extend these displays`.
.. image:: pics/winsevenresolution.png
Windows Vista
^^^^^^^^^^^^^
From :guilabel:`Control Panel` click on :guilabel:`Personalize`, or right click
a blank place on the desktop and click :guilabel:`Personalization`.
.. image:: pics/vistapersonalize.png
From the :guilabel:`Personalization` window click on :guilabel:`Display
Settings`. Then enable the montior that represents your projector and make sure
you have checked :guilabel:`Extend the desktop onto this monitor`.
.. image:: pics/vistadisplaysettings.png
Windows XP
^^^^^^^^^^
From :guilabel:`Control Panel` select :guilabel:`Display`, or right click on a
blank area of the desktop and select :guilabel:`Properties`. From the
:guilabel:`Display Properties` window click on the :guilabel:`Settings` tab.
Then click on the monitor that represents your projector and make sure you have
checked :guilabel:`Extend my Windows desktop onto this monitor`.
.. image:: pics/xpdisplaysettings.png
Linux
-----
Due to the vast varieties of hardware, distributions, desktops, and drivers
this is not an exhaustive guide to dual monitor setup on Linux. This guide
assumes that you have properly set up any proprietary drivers if needed. You
should seek out your distributions documentation if this general guide does not
work.
GNOME
^^^^^
This guide is for users of the GNOME desktop who do not use proprietary drivers.
From most distros go to :menuselection:`System --> Preferences --> Display
Settings (Monitors)`. Set up your projector with the correct resolution and make
sure that :guilabel:`Same image on all monitors` is **unchecked**.
.. image:: pics/gnome.png
KDE
^^^
This guide is for users of the KDE desktop who do not use proprietary drivers.
From most distros click the Kick Off menu and navigate to
:guilabel:`System Settings`
.. image:: pics/kdesystemsettings.png
Click on the display and monitor icon.
.. image:: pics/kdedisplay.png
From here you will need to set up your projector with the appropriate
resolution, and position. OpenLP works best projecting to the monitor on the
right.
Linux Systems Using nVidia Drivers
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This guide is for users of the proprietary nVidia driver on Linux Distributions.
It is assumed that you have properly setup your drivers according to your
distribution's documentation, and you have a working ``xorg.conf`` file in place.
If you wish to make the changes permanent in setting up your system for dual
monitors it will be necessary to modify your ``xorg.conf`` file. It is always a
good idea to make a backup of any critical file before making changes::
user@linux:~ $ sudo cp /etc/X11/xorg.conf /etc/X11/xorg.conf.old
Or for those using systems that use the root user instead of sudo, change to
root and enter::
root@linux: # cp /etc/X11/xorg.conf /etc/X11/xorg.conf.old
The exact location of the ``xorg.conf`` file can vary so check your
distribution's documentation.
If you want to make your changes permanent run nVidia settings from the
terminal::
user@linux:~ $ sudo nvidia-settings
Or, as root::
root@linux: # nividia-settings
If you do not want to write the changes to your ``xorg.conf`` file simply run
the nVidia Settings program (``nvidia-settings``) from your desktop's menu,
usually in an administration or system menu, or from the terminal as a normal
user run::
user@linux:~ $ nvidia-settings
Once you have opened nVidia Settings, click on
:guilabel:`X Server Display Configuration`. Then select the monitor you are
wanting to use as your second monitor and click :guilabel:`Configure`.
.. image:: pics/nvlinux1.png
After clicking :guilabel:`Configure`, select :guilabel:`TwinView`. Then click
:guilabel:`OK`.
.. image:: pics/twinview.png
Then click :guilabel:`Apply` and if you are happy with the way things look click
:guilabel:`Keep` to keep your new settings. Don't worry if all goes wrong the
settings will return back to the previous settings in 15 seconds without any
action. nVidia Settings should take care of selecting your optimum resolution
etc, but that can be changed as needed. When you are happy with everything click
on :guilabel:`Save to X Configuration File`.
.. image:: pics/xorgwrite.png
Then click :guilabel:`Save` and you should be set. You may want to restart X or
your machine just to make sure all the settings carry over the next time you log
in.

View File

@ -0,0 +1,70 @@
========
Glossary
========
The developers of OpenLP have strived to make it a straightforward and easy to
use application. However, it is good to be familiar with a few terms that will
be used throughout this documentation, and when seeking support.
Main Window
-----------
The Main Window is what you will see when you first open OpenLP
.. image:: pics/mainwindow.png
The Main Window contains all the tools and plugins that make OpenLP function
Media Manager
-------------
The Media Manager contains a number of tabs that plugins supply to OpenLP.
Each tab in the Media Manager is called a **Media Item**
.. image:: pics/mediamanager.png
From the Media Manager you can send Media Items to the Preview or Live screens.
Preview
-------
The preview pane is a section to preview your media items before you go live
with them.
.. image:: pics/preview.png
Service File
------------
A service file, is the file that is created when you save your work on OpenLP.
The service file consist of **Service Items**
Service Item
------------
A service item are the **media items** that are in the **service manager**
Service Manger
--------------
The service manager contains the media items in your service file. This is the
area from wich your media items go live, and you can also save, open, and edit
services files.
.. image:: pics/servicemanager.png
Slide Controller
----------------
The Slide Controller controls which slide from a **Service Item** is currently
being displayed, and moving between the various slides.
.. image:: pics/slidecontroller.png
Theme Manager
-------------
The theme manager is where themes are created and edited. Themes are the text
styles backgrounds that you use to personalize your services.
.. image:: pics/thememanager.png

View File

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

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

View File

@ -1,95 +0,0 @@
.. _plugins-bibles:
:mod:`bibles` Plugin
====================
.. automodule:: openlp.plugins.bibles
:members:
:mod:`BiblePlugin` Class
-------------------------
.. autoclass:: openlp.plugins.bibles.bibleplugin.BiblePlugin
:members:
:mod:`forms` Submodule
----------------------
.. automodule:: openlp.plugins.bibles.forms
:members:
:mod:`BibleImportWizard`
^^^^^^^^^^^^^^^^^^^^^^^^
.. autoclass:: openlp.plugins.bibles.forms.bibleimportwizard.Ui_BibleImportWizard
:members:
.. autoclass:: openlp.plugins.bibles.forms.importwizardform.ImportWizardForm
:members:
:mod:`lib` Submodule
--------------------
.. automodule:: openlp.plugins.bibles.lib
:members:
:mod:`db`
^^^^^^^^^
.. automodule:: openlp.plugins.bibles.lib.db
:members:
.. autoclass:: openlp.plugins.bibles.lib.db.BibleDB
:members:
:mod:`csv`
^^^^^^^^^^
.. automodule:: openlp.plugins.bibles.lib.csvbible
:members:
.. autoclass:: openlp.plugins.bibles.lib.csvbible.CSVBible
:members:
:mod:`http`
^^^^^^^^^^^
.. automodule:: openlp.plugins.bibles.lib.http
:members:
.. autoclass:: openlp.plugins.bibles.lib.http.HTTPBible
:members:
:mod:`bibleOSISimpl`
^^^^^^^^^^^^^^^^^^^^
.. automodule:: openlp.plugins.bibles.lib.osis
:members:
.. autoclass:: openlp.plugins.bibles.lib.osis.OSISBible
:members:
:mod:`biblestab`
^^^^^^^^^^^^^^^^
.. automodule:: openlp.plugins.bibles.lib.biblestab
:members:
:mod:`common`
^^^^^^^^^^^^^
.. automodule:: openlp.plugins.bibles.lib.common
:members:
:mod:`manager`
^^^^^^^^^^^^^^
.. automodule:: openlp.plugins.bibles.lib.manager
:members:
:mod:`mediaitem`
^^^^^^^^^^^^^^^^
.. automodule:: openlp.plugins.bibles.lib.mediaitem
:members:

View File

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

View File

@ -1,46 +0,0 @@
.. _plugins-songs:
:mod:`songs` Plugin
===================
.. automodule:: openlp.plugins.songs
:members:
:mod:`SongsPlugin` Class
------------------------
.. autoclass:: openlp.plugins.songs.songsplugin.SongsPlugin
:members:
:mod:`forms` Submodule
----------------------
.. automodule:: openlp.plugins.songs.forms
:members:
:mod:`AuthorsForm`
^^^^^^^^^^^^^^^^^^
.. autoclass:: openlp.plugins.songs.forms.authorsdialog.Ui_AuthorsDialog
:members:
.. autoclass:: openlp.plugins.songs.forms.authorsform.AuthorsForm
:members:
:mod:`EditSongForm`
^^^^^^^^^^^^^^^^^^^
.. autoclass:: openlp.plugins.songs.forms.editsongdialog.Ui_EditSongDialog
:members:
.. autoclass:: openlp.plugins.songs.forms.editsongform.EditSongForm
:members:
:mod:`EditVerseForm`
^^^^^^^^^^^^^^^^^^^^
.. autoclass:: openlp.plugins.songs.forms.editversedialog.Ui_EditVerseDialog
:members:
.. autoclass:: openlp.plugins.songs.forms.editverseform.EditVerseForm
:members:

View File

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

View File

@ -81,9 +81,6 @@ html_expands.append({u'desc':u'Italics', u'start tag':u'{it}',
u'start html':u'<em>', u'end tag':u'{/it}', u'end html':u'</em>', u'start html':u'<em>', u'end tag':u'{/it}', u'end html':u'</em>',
u'protected':True}) u'protected':True})
# Image image_cache to stop regualar image resizing
image_cache = {}
def translate(context, text, comment=None): def translate(context, text, comment=None):
""" """
A special shortcut method to wrap around the Qt4 translation functions. A special shortcut method to wrap around the Qt4 translation functions.
@ -223,16 +220,13 @@ def image_to_byte(image):
``image`` ``image``
The image to converted. The image to converted.
""" """
log.debug(u'image_to_byte') log.debug(u'image_to_byte - start')
byte_array = QtCore.QByteArray() byte_array = QtCore.QByteArray()
# use buffer to store pixmap into byteArray # use buffer to store pixmap into byteArray
buffie = QtCore.QBuffer(byte_array) buffie = QtCore.QBuffer(byte_array)
buffie.open(QtCore.QIODevice.WriteOnly) buffie.open(QtCore.QIODevice.WriteOnly)
if isinstance(image, QtGui.QImage): image.save(buffie, "PNG")
pixmap = QtGui.QPixmap.fromImage(image) log.debug(u'image_to_byte - end')
else:
pixmap = QtGui.QPixmap(image)
pixmap.save(buffie, "PNG")
# convert to base64 encoding so does not get missed! # convert to base64 encoding so does not get missed!
return byte_array.toBase64() return byte_array.toBase64()
@ -253,26 +247,25 @@ def resize_image(image, width, height, background=QtCore.Qt.black):
The background colour defaults to black. The background colour defaults to black.
""" """
log.debug(u'resize_image') log.debug(u'resize_image - start')
preview = QtGui.QImage(image) if isinstance(image, QtGui.QImage):
preview = image
else:
preview = QtGui.QImage(image)
if not preview.isNull(): if not preview.isNull():
# Only resize if different size # Only resize if different size
if preview.width() == width and preview.height == height: if preview.width() == width and preview.height == height:
return preview return preview
preview = preview.scaled(width, height, QtCore.Qt.KeepAspectRatio, preview = preview.scaled(width, height, QtCore.Qt.KeepAspectRatio,
QtCore.Qt.SmoothTransformation) QtCore.Qt.SmoothTransformation)
image_cache_key = u'%s%s%s' % (image, unicode(width), unicode(height))
if image_cache_key in image_cache:
return image_cache[image_cache_key]
realw = preview.width() realw = preview.width()
realh = preview.height() realh = preview.height()
# and move it to the centre of the preview space # and move it to the centre of the preview space
new_image = QtGui.QImage(width, height, new_image = QtGui.QImage(width, height,
QtGui.QImage.Format_ARGB32_Premultiplied) QtGui.QImage.Format_ARGB32_Premultiplied)
new_image.fill(background)
painter = QtGui.QPainter(new_image) painter = QtGui.QPainter(new_image)
painter.fillRect(new_image.rect(), background)
painter.drawImage((width - realw) / 2, (height - realh) / 2, preview) painter.drawImage((width - realw) / 2, (height - realh) / 2, preview)
image_cache[image_cache_key] = new_image
return new_image return new_image
def check_item_selected(list_widget, message): def check_item_selected(list_widget, message):
@ -312,6 +305,7 @@ def expand_tags(text):
from spelltextedit import SpellTextEdit from spelltextedit import SpellTextEdit
from eventreceiver import Receiver from eventreceiver import Receiver
from imagemanager import ImageManager
from settingsmanager import SettingsManager from settingsmanager import SettingsManager
from plugin import PluginStatus, StringContent, Plugin from plugin import PluginStatus, StringContent, Plugin
from pluginmanager import PluginManager from pluginmanager import PluginManager

View File

@ -246,3 +246,10 @@ class Manager(object):
self.session.rollback() self.session.rollback()
log.exception(u'Failed to delete %s records', object_class.__name__) log.exception(u'Failed to delete %s records', object_class.__name__)
return False return False
def finalise(self):
"""
VACUUM the database on exit.
"""
engine = create_engine(self.db_url)
engine.execute("vacuum")

View File

@ -55,14 +55,17 @@ body {
background-color: black; background-color: black;
display: none; display: none;
} }
#image { #bgimage {
z-index:1; z-index:1;
} }
#video1 { #image {
z-index:2; z-index:2;
} }
#video1 {
z-index:3;
}
#video2 { #video2 {
z-index:2; z-index:3;
} }
#alert { #alert {
position: absolute; position: absolute;
@ -73,7 +76,7 @@ body {
} }
#footer { #footer {
position: absolute; position: absolute;
z-index:5; z-index:6;
%s %s
} }
/* lyric css */ /* lyric css */
@ -87,16 +90,16 @@ body {
var transition = %s; var transition = %s;
function show_video(state, path, volume, loop){ function show_video(state, path, volume, loop){
// Note, the preferred method for looping would be to use the // Note, the preferred method for looping would be to use the
// video tag loop attribute. // video tag loop attribute.
// But QtWebKit doesn't support this. Neither does it support the // But QtWebKit doesn't support this. Neither does it support the
// onended event, hence the setInterval() // onended event, hence the setInterval()
// In addition, setting the currentTime attribute to zero to restart // In addition, setting the currentTime attribute to zero to restart
// the video raises an INDEX_SIZE_ERROR: DOM Exception 1 // the video raises an INDEX_SIZE_ERROR: DOM Exception 1
// To complicate it further, sometimes vid.currentTime stops // To complicate it further, sometimes vid.currentTime stops
// slightly short of vid.duration and vid.ended is intermittent! // slightly short of vid.duration and vid.ended is intermittent!
// //
// Note, currently the background may go black between loops. Not // Note, currently the background may go black between loops. Not
// desirable. Need to investigate using two <video>'s, and hiding/ // desirable. Need to investigate using two <video>'s, and hiding/
// preloading one, and toggle between the two when looping. // preloading one, and toggle between the two when looping.
@ -112,7 +115,7 @@ body {
vid2.volume = volume; vid2.volume = volume;
} }
switch(state){ switch(state){
case 'init': case 'init':
vid.src = path; vid.src = path;
vid2.src = path; vid2.src = path;
if(loop == null) loop = false; if(loop == null) loop = false;
@ -129,8 +132,8 @@ body {
vid.style.visibility = 'visible'; vid.style.visibility = 'visible';
if(vid.looping){ if(vid.looping){
video_timer = setInterval( video_timer = setInterval(
function() { function() {
show_video('poll'); show_video('poll');
}, 200); }, 200);
} }
break; break;
@ -294,7 +297,8 @@ body {
</script> </script>
</head> </head>
<body> <body>
<img id="image" class="size" %s /> <img id="bgimage" class="size" %s />
<img id="image" class="size" style="display:none" />
<video id="video1" class="size" style="visibility:hidden" autobuffer preload> <video id="video1" class="size" style="visibility:hidden" autobuffer preload>
</video> </video>
<video id="video2" class="size" style="visibility:hidden" autobuffer preload> <video id="video2" class="size" style="visibility:hidden" autobuffer preload>
@ -324,6 +328,7 @@ def build_html(item, screen, alert, islive):
height = screen[u'size'].height() height = screen[u'size'].height()
theme = item.themedata theme = item.themedata
webkitvers = webkit_version() webkitvers = webkit_version()
# Image generated and poked in
if item.bg_image_bytes: if item.bg_image_bytes:
image = u'src="data:image/png;base64,%s"' % item.bg_image_bytes image = u'src="data:image/png;base64,%s"' % item.bg_image_bytes
else: else:
@ -397,7 +402,7 @@ def build_lyrics_css(item, webkitvers):
""" """
style = """ style = """
.lyricstable { .lyricstable {
z-index:4; z-index:5;
position: absolute; position: absolute;
display: table; display: table;
%s %s
@ -451,7 +456,7 @@ def build_lyrics_css(item, webkitvers):
if theme.display_outline and webkitvers < 534.3: if theme.display_outline and webkitvers < 534.3:
shadow = u'padding-left: %spx; padding-top: %spx;' % \ shadow = u'padding-left: %spx; padding-top: %spx;' % \
(int(theme.display_shadow_size) + (int(theme.display_shadow_size) +
(int(theme.display_outline_size) * 2), (int(theme.display_outline_size) * 2),
theme.display_shadow_size) theme.display_shadow_size)
shadow += build_lyrics_outline_css(theme, True) shadow += build_lyrics_outline_css(theme, True)
else: else:

View File

@ -0,0 +1,158 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2010 Raoul Snyman #
# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
# Gorven, Scott Guerrieri, Meinert Jordan, Andreas Preikschat, Christian #
# Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon Tibble, #
# Carsten Tinggaard, Frode Woldsund #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
Provides the store and management for Images automatically caching them and
resizing them when needed. Only one copy of each image is needed in the system.
A Thread is used to convert the image to a byte array so the user does not need
to wait for the conversion to happen.
"""
import logging
import os
import time
from PyQt4 import QtCore
from openlp.core.lib import resize_image, image_to_byte
log = logging.getLogger(__name__)
class ImageThread(QtCore.QThread):
"""
A special Qt thread class to speed up the display of text based frames.
This is threaded so it loads the frames in background
"""
def __init__(self, manager):
QtCore.QThread.__init__(self, None)
self.image_mamager = manager
def run(self):
"""
Run the thread.
"""
self.image_mamager.process()
class Image(object):
name = ''
path = ''
dirty = True
image = None
image_bytes = None
class ImageManager(QtCore.QObject):
"""
Image Manager handles the conversion and sizing of images.
"""
log.info(u'Image Manager loaded')
def __init__(self):
self._cache = {}
self._thread_running = False
self._cache_dirty = False
self.image_thread = ImageThread(self)
def update_display(self, width, height):
"""
Screen has changed size so rebuild the cache to new size
"""
log.debug(u'update_display')
self.width = width
self.height = height
# mark the images as dirty for a rebuild
for key in self._cache.keys():
image = self._cache[key]
image.dirty = True
fullpath = os.path.join(image.path, image.name)
image.image = resize_image(fullpath,
self.width, self.height)
self._cache_dirty = True
# only one thread please
if not self._thread_running:
self.image_thread.start()
def get_image(self, name):
"""
Return the Qimage from the cache
"""
log.debug(u'get_image %s' % name)
return self._cache[name].image
def get_image_bytes(self, name):
"""
Returns the byte string for an image
If not present wait for the background thread to process it.
"""
log.debug(u'get_image_bytes %s' % name)
if not self._cache[name].image_bytes:
while self._cache[name].dirty:
log.debug(u'get_image_bytes - waiting')
time.sleep(0.1)
return self._cache[name].image_bytes
def add_image(self, name, path):
"""
Add image to cache if it is not already there
"""
log.debug(u'add_image %s:%s' % (name, path))
if not name in self._cache:
image = Image()
image.name = name
image.path = path
image.image = resize_image(path,
self.width, self.height)
self._cache[name] = image
self._cache_dirty = True
# only one thread please
if not self._thread_running:
self.image_thread.start()
def process(self):
"""
Controls the processing called from a QThread
"""
log.debug(u'process - started')
self._thread_running = True
self.clean_cache()
# data loaded since we started ?
while self._cache_dirty:
log.debug(u'process - recycle')
self.clean_cache()
self._thread_running = False
log.debug(u'process - ended')
def clean_cache(self):
"""
Actually does the work.
"""
log.debug(u'clean_cache')
# we will clean the cache now
self._cache_dirty = False
for key in self._cache.keys():
image = self._cache[key]
if image.dirty:
image.image_bytes = image_to_byte(image.image)
image.dirty = False

View File

@ -51,11 +51,6 @@ class Renderer(object):
self._rect = None self._rect = None
self.theme_name = None self.theme_name = None
self._theme = None self._theme = None
self._bg_image_filename = None
self.frame = None
self.bg_frame = None
self.bg_image = None
self.bg_image_bytes = None
def set_theme(self, theme): def set_theme(self, theme):
""" """
@ -66,14 +61,7 @@ class Renderer(object):
""" """
log.debug(u'set theme') log.debug(u'set theme')
self._theme = theme self._theme = theme
self.bg_frame = None
self.bg_image = None
self.bg_image_bytes = None
self._bg_image_filename = None
self.theme_name = theme.theme_name self.theme_name = theme.theme_name
if theme.background_type == u'image':
if theme.background_filename:
self._bg_image_filename = unicode(theme.background_filename)
def set_text_rectangle(self, rect_main, rect_footer): def set_text_rectangle(self, rect_main, rect_footer):
""" """
@ -105,39 +93,6 @@ class Renderer(object):
(build_lyrics_format_css(self._theme, self.page_width, (build_lyrics_format_css(self._theme, self.page_width,
self.page_height), build_lyrics_outline_css(self._theme)) self.page_height), build_lyrics_outline_css(self._theme))
def set_frame_dest(self, frame_width, frame_height):
"""
Set the size of the slide.
``frame_width``
The width of the slide.
``frame_height``
The height of the slide.
"""
log.debug(u'set frame dest (frame) w %d h %d', frame_width,
frame_height)
self.frame = QtGui.QImage(frame_width, frame_height,
QtGui.QImage.Format_ARGB32_Premultiplied)
if self._bg_image_filename and not self.bg_image:
self.bg_image = resize_image(self._bg_image_filename,
self.frame.width(), self.frame.height())
if self._theme.background_type == u'image':
self.bg_frame = QtGui.QImage(self.frame.width(),
self.frame.height(),
QtGui.QImage.Format_ARGB32_Premultiplied)
painter = QtGui.QPainter()
painter.begin(self.bg_frame)
painter.fillRect(self.frame.rect(), QtCore.Qt.black)
if self.bg_image:
painter.drawImage(0, 0, self.bg_image)
painter.end()
self.bg_image_bytes = image_to_byte(self.bg_frame)
else:
self.bg_frame = None
self.bg_image_bytes = None
def format_slide(self, words, line_break): def format_slide(self, words, line_break):
""" """
Figure out how much text can appear on a slide, using the current Figure out how much text can appear on a slide, using the current

View File

@ -28,7 +28,7 @@ import logging
from PyQt4 import QtCore from PyQt4 import QtCore
from openlp.core.lib import Renderer, ThemeLevel, ServiceItem from openlp.core.lib import Renderer, ThemeLevel, ServiceItem, ImageManager
from openlp.core.ui import MainDisplay from openlp.core.ui import MainDisplay
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -56,7 +56,9 @@ class RenderManager(object):
""" """
log.debug(u'Initilisation started') log.debug(u'Initilisation started')
self.screens = screens self.screens = screens
self.image_manager = ImageManager()
self.display = MainDisplay(self, screens, False) self.display = MainDisplay(self, screens, False)
self.display.imageManager = self.image_manager
self.display.setup() self.display.setup()
self.theme_manager = theme_manager self.theme_manager = theme_manager
self.renderer = Renderer() self.renderer = Renderer()
@ -75,9 +77,11 @@ class RenderManager(object):
log.debug(u'Update Display') log.debug(u'Update Display')
self.calculate_default(self.screens.current[u'size']) self.calculate_default(self.screens.current[u'size'])
self.display = MainDisplay(self, self.screens, False) self.display = MainDisplay(self, self.screens, False)
self.display.imageManager = self.image_manager
self.display.setup() self.display.setup()
self.renderer.bg_frame = None self.renderer.bg_frame = None
self.themedata = None self.themedata = None
self.image_manager.update_display(self.width, self.height)
def set_global_theme(self, global_theme, theme_level=ThemeLevel.Global): def set_global_theme(self, global_theme, theme_level=ThemeLevel.Global):
""" """
@ -153,7 +157,8 @@ class RenderManager(object):
self.calculate_default(self.screens.current[u'size']) self.calculate_default(self.screens.current[u'size'])
self.renderer.set_theme(self.themedata) self.renderer.set_theme(self.themedata)
self.build_text_rectangle(self.themedata) self.build_text_rectangle(self.themedata)
self.renderer.set_frame_dest(self.width, self.height) self.image_manager.add_image(self.themedata.theme_name,
self.themedata.background_filename)
return self.renderer._rect, self.renderer._rect_footer return self.renderer._rect, self.renderer._rect_footer
def build_text_rectangle(self, theme): def build_text_rectangle(self, theme):
@ -211,7 +216,7 @@ class RenderManager(object):
serviceItem.raw_footer = footer serviceItem.raw_footer = footer
serviceItem.render(True) serviceItem.render(True)
self.display.buildHtml(serviceItem) self.display.buildHtml(serviceItem)
raw_html = serviceItem.get_rendered_frame(0)[1] raw_html = serviceItem.get_rendered_frame(0)
preview = self.display.text(raw_html) preview = self.display.text(raw_html)
# Reset the real screen size for subsequent render requests # Reset the real screen size for subsequent render requests
self.calculate_default(self.screens.current[u'size']) self.calculate_default(self.screens.current[u'size'])

View File

@ -30,7 +30,6 @@ type and capability of an item.
import logging import logging
import os import os
import time
import uuid import uuid
from PyQt4 import QtGui from PyQt4 import QtGui
@ -155,17 +154,15 @@ class ServiceItem(object):
line_break = True line_break = True
if self.is_capable(ItemCapabilities.NoLineBreaks): if self.is_capable(ItemCapabilities.NoLineBreaks):
line_break = False line_break = False
theme = None
if self.theme:
theme = self.theme
self.main, self.footer = \
self.render_manager.set_override_theme(theme, useOverride)
self.themedata = self.render_manager.renderer._theme
if self.service_item_type == ServiceItemType.Text: if self.service_item_type == ServiceItemType.Text:
log.debug(u'Formatting slides') log.debug(u'Formatting slides')
theme = None
if self.theme:
theme = self.theme
self.main, self.footer = \
self.render_manager.set_override_theme(theme, useOverride)
self.bg_image_bytes = self.render_manager.renderer.bg_image_bytes
self.themedata = self.render_manager.renderer._theme
for slide in self._raw_frames: for slide in self._raw_frames:
before = time.time()
formatted = self.render_manager \ formatted = self.render_manager \
.format_slide(slide[u'raw_slide'], line_break) .format_slide(slide[u'raw_slide'], line_break)
for page in formatted: for page in formatted:
@ -174,13 +171,8 @@ class ServiceItem(object):
u'text': clean_tags(page.rstrip()), u'text': clean_tags(page.rstrip()),
u'html': expand_tags(page.rstrip()), u'html': expand_tags(page.rstrip()),
u'verseTag': slide[u'verseTag'] }) u'verseTag': slide[u'verseTag'] })
log.log(15, u'Formatting took %4s' % (time.time() - before)) elif self.service_item_type == ServiceItemType.Image or \
elif self.service_item_type == ServiceItemType.Image: self.service_item_type == ServiceItemType.Command:
self.themedata = self.render_manager.global_theme_data
for slide in self._raw_frames:
slide[u'image'] = resize_image(slide[u'image'],
self.render_manager.width, self.render_manager.height)
elif self.service_item_type == ServiceItemType.Command:
pass pass
else: else:
log.error(u'Invalid value renderer :%s' % self.service_item_type) log.error(u'Invalid value renderer :%s' % self.service_item_type)
@ -193,7 +185,7 @@ class ServiceItem(object):
else: else:
self.foot_text = u'%s<br>%s' % (self.foot_text, foot) self.foot_text = u'%s<br>%s' % (self.foot_text, foot)
def add_from_image(self, path, title, image): def add_from_image(self, path, title):
""" """
Add an image slide to the service item. Add an image slide to the service item.
@ -202,13 +194,11 @@ class ServiceItem(object):
``title`` ``title``
A title for the slide in the service item. A title for the slide in the service item.
``image``
The actual image file name.
""" """
self.service_item_type = ServiceItemType.Image self.service_item_type = ServiceItemType.Image
self._raw_frames.append( self._raw_frames.append(
{u'title': title, u'image': image, u'path': path}) {u'title': title, u'path': path})
self.render_manager.image_manager.add_image(title, path)
self._new_item() self._new_item()
def add_from_text(self, title, raw_slide, verse_tag=None): def add_from_text(self, title, raw_slide, verse_tag=None):
@ -242,7 +232,7 @@ class ServiceItem(object):
""" """
self.service_item_type = ServiceItemType.Command self.service_item_type = ServiceItemType.Command
self._raw_frames.append( self._raw_frames.append(
{u'title': file_name, u'image': image, u'path': path}) {u'title': file_name, u'image':image, u'path': path})
self._new_item() self._new_item()
def get_service_repr(self): def get_service_repr(self):
@ -311,8 +301,7 @@ class ServiceItem(object):
elif self.service_item_type == ServiceItemType.Image: elif self.service_item_type == ServiceItemType.Image:
for text_image in serviceitem[u'serviceitem'][u'data']: for text_image in serviceitem[u'serviceitem'][u'data']:
filename = os.path.join(path, text_image) filename = os.path.join(path, text_image)
real_image = QtGui.QImage(unicode(filename)) self.add_from_image(filename, text_image)
self.add_from_image(path, text_image, real_image)
elif self.service_item_type == ServiceItemType.Command: elif self.service_item_type == ServiceItemType.Command:
for text_image in serviceitem[u'serviceitem'][u'data']: for text_image in serviceitem[u'serviceitem'][u'data']:
filename = os.path.join(path, text_image[u'title']) filename = os.path.join(path, text_image[u'title'])
@ -388,9 +377,11 @@ class ServiceItem(object):
renders it if required. renders it if required.
""" """
if self.service_item_type == ServiceItemType.Text: if self.service_item_type == ServiceItemType.Text:
return None, self._display_frames[row][u'html'].split(u'\n')[0] return self._display_frames[row][u'html'].split(u'\n')[0]
elif self.service_item_type == ServiceItemType.Image:
return self._raw_frames[row][u'title']
else: else:
return self._raw_frames[row][u'image'], u'' return self._raw_frames[row][u'image']
def get_frame_title(self, row=0): def get_frame_title(self, row=0):
""" """
@ -400,6 +391,6 @@ class ServiceItem(object):
def get_frame_path(self, row=0): def get_frame_path(self, row=0):
""" """
Returns the title of the raw frame Returns the path of the raw frame
""" """
return self._raw_frames[row][u'path'] return self._raw_frames[row][u'path']

View File

@ -25,7 +25,6 @@
############################################################################### ###############################################################################
import re import re
import sys
try: try:
import enchant import enchant
from enchant import DictNotFoundError from enchant import DictNotFoundError
@ -37,7 +36,7 @@ except ImportError:
# http://john.nachtimwald.com/2009/08/22/qplaintextedit-with-in-line-spell-check/ # http://john.nachtimwald.com/2009/08/22/qplaintextedit-with-in-line-spell-check/
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import html_expands, translate, context_menu_action from openlp.core.lib import html_expands, translate
class SpellTextEdit(QtGui.QPlainTextEdit): class SpellTextEdit(QtGui.QPlainTextEdit):
def __init__(self, *args): def __init__(self, *args):

View File

@ -87,12 +87,12 @@ class ThemeLevel(object):
Service = 2 Service = 2
Song = 3 Song = 3
boolean_list = [u'italics', u'override', u'outline', u'shadow', \ boolean_list = [u'italics', u'override', u'outline', u'shadow',
u'slide_transition'] u'slide_transition']
integer_list =[u'proportion', u'line_adjustment', u'x', u'height', u'y', \ integer_list = [u'proportion', u'line_adjustment', u'x', u'height', u'y',
u'width', u'shadow_size', u'outline_size', u'horizontal_align', \ u'width', u'shadow_size', u'outline_size', u'horizontal_align',
u'vertical_align', u'wrap_style' ] u'vertical_align', u'wrap_style']
class ThemeXML(object): class ThemeXML(object):
""" """

View File

@ -39,7 +39,6 @@ class HideMode(object):
from filerenameform import FileRenameForm from filerenameform import FileRenameForm
from maindisplay import MainDisplay from maindisplay import MainDisplay
from slidecontroller import HideMode
from servicenoteform import ServiceNoteForm from servicenoteform import ServiceNoteForm
from serviceitemeditform import ServiceItemEditForm from serviceitemeditform import ServiceItemEditForm
from screen import ScreenList from screen import ScreenList

View File

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

View File

@ -24,7 +24,7 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################
from PyQt4 import QtCore, QtGui from PyQt4 import QtGui
from exceptiondialog import Ui_ExceptionDialog from exceptiondialog import Ui_ExceptionDialog

View File

@ -27,7 +27,6 @@
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from filerenamedialog import Ui_FileRenameDialog from filerenamedialog import Ui_FileRenameDialog
from openlp.core.lib import translate
class FileRenameForm(QtGui.QDialog, Ui_FileRenameDialog): class FileRenameForm(QtGui.QDialog, Ui_FileRenameDialog):
""" """

View File

@ -90,6 +90,9 @@ class DisplayWidget(QtGui.QGraphicsView):
event.ignore() event.ignore()
class MainDisplay(DisplayWidget): class MainDisplay(DisplayWidget):
"""
This is the display screen.
"""
def __init__(self, parent, screens, live): def __init__(self, parent, screens, live):
DisplayWidget.__init__(self, live, parent=None) DisplayWidget.__init__(self, live, parent=None)
@ -114,21 +117,23 @@ class MainDisplay(DisplayWidget):
""" """
log.debug(u'Setup live = %s for %s ' % (self.isLive, log.debug(u'Setup live = %s for %s ' % (self.isLive,
self.screens.monitor_number)) self.screens.monitor_number))
self.usePhonon = QtCore.QSettings().value(
u'media/use phonon', QtCore.QVariant(True)).toBool()
self.phononActive = False
self.screen = self.screens.current self.screen = self.screens.current
self.setVisible(False) self.setVisible(False)
self.setGeometry(self.screen[u'size']) self.setGeometry(self.screen[u'size'])
try: self.videoWidget = Phonon.VideoWidget(self)
self.webView = QtWebKit.QGraphicsWebView() self.videoWidget.setVisible(False)
self.scene = QtGui.QGraphicsScene(self) self.videoWidget.setGeometry(QtCore.QRect(0, 0,
self.setScene(self.scene) self.screen[u'size'].width(), self.screen[u'size'].height()))
self.scene.addItem(self.webView) self.mediaObject = Phonon.MediaObject(self)
self.webView.setGeometry(QtCore.QRectF(0, 0, self.audio = Phonon.AudioOutput(Phonon.VideoCategory, self.mediaObject)
self.screen[u'size'].width(), self.screen[u'size'].height())) Phonon.createPath(self.mediaObject, self.videoWidget)
except AttributeError: Phonon.createPath(self.mediaObject, self.audio)
# QGraphicsWebView a recent addition, so fall back to QWebView self.webView = QtWebKit.QWebView(self)
self.webView = QtWebKit.QWebView(self) self.webView.setGeometry(0, 0,
self.webView.setGeometry(0, 0, self.screen[u'size'].width(), self.screen[u'size'].height())
self.screen[u'size'].width(), self.screen[u'size'].height())
self.page = self.webView.page() self.page = self.webView.page()
self.frame = self.page.mainFrame() self.frame = self.page.mainFrame()
QtCore.QObject.connect(self.webView, QtCore.QObject.connect(self.webView,
@ -182,7 +187,7 @@ class MainDisplay(DisplayWidget):
`slide` `slide`
The slide text to be displayed The slide text to be displayed
""" """
log.debug(u'text') log.debug(u'text to display')
# Wait for the webview to update before displayiong text. # Wait for the webview to update before displayiong text.
while not self.loaded: while not self.loaded:
Receiver.send_message(u'openlp_process_events') Receiver.send_message(u'openlp_process_events')
@ -197,9 +202,9 @@ class MainDisplay(DisplayWidget):
`slide` `slide`
The slide text to be displayed The slide text to be displayed
""" """
log.debug(u'alert') log.debug(u'alert to display')
if self.height() != self.screen[u'size'].height() \ if self.height() != self.screen[u'size'].height() \
or not self.isVisible(): or not self.isVisible() or self.videoWidget.isVisible():
shrink = True shrink = True
else: else:
shrink = False shrink = False
@ -208,14 +213,26 @@ class MainDisplay(DisplayWidget):
u'top' if shrink else u'') u'top' if shrink else u'')
height = self.frame.evaluateJavaScript(js) height = self.frame.evaluateJavaScript(js)
if shrink: if shrink:
if text: if self.phononActive:
self.resize(self.width(), int(height.toString())) shrinkItem = self.webView
self.setVisible(True)
else: else:
self.setGeometry(self.screen[u'size']) shrinkItem = self
self.setVisible(False) if text:
shrinkItem.resize(self.width(), int(height.toString()))
shrinkItem.setVisible(True)
else:
shrinkItem.setVisible(False)
shrinkItem.resize(self.screen[u'size'].width(),
self.screen[u'size'].height())
def image(self, image): def directImage(self, name, path):
"""
API for replacement backgrounds so Images are added directly to cache
"""
image = self.imageManager.add_image(name, path)
self.image(name)
def image(self, name):
""" """
Add an image as the background. The image is converted to a Add an image as the background. The image is converted to a
bytestream on route. bytestream on route.
@ -223,25 +240,21 @@ class MainDisplay(DisplayWidget):
`Image` `Image`
The Image to be displayed can be QImage or QPixmap The Image to be displayed can be QImage or QPixmap
""" """
log.debug(u'image') log.debug(u'image to display')
image = resize_image(image, self.screen[u'size'].width(), image = self.imageManager.get_image_bytes(name)
self.screen[u'size'].height())
self.resetVideo() self.resetVideo()
self.displayImage(image) self.displayImage(image)
# show screen # show screen
if self.isLive: if self.isLive:
self.setVisible(True) self.setVisible(True)
return self.preview()
def displayImage(self, image): def displayImage(self, image):
""" """
Display an image, as is. Display an image, as is.
""" """
if image: if image:
if isinstance(image, QtGui.QImage): js = u'show_image("data:image/png;base64,%s");' % image
js = u'show_image("data:image/png;base64,%s");' % \
image_to_byte(image)
else:
js = u'show_image("data:image/png;base64,%s");' % image
else: else:
js = u'show_image("");' js = u'show_image("");'
self.frame.evaluateJavaScript(js) self.frame.evaluateJavaScript(js)
@ -259,14 +272,24 @@ class MainDisplay(DisplayWidget):
Used after Video plugin has changed the background Used after Video plugin has changed the background
""" """
log.debug(u'resetVideo') log.debug(u'resetVideo')
self.frame.evaluateJavaScript(u'show_video("close");') if self.phononActive:
self.mediaObject.stop()
self.mediaObject.clearQueue()
self.webView.setVisible(True)
self.videoWidget.setVisible(False)
self.phononActive = False
else:
self.frame.evaluateJavaScript(u'show_video("close");')
def videoPlay(self): def videoPlay(self):
""" """
Responds to the request to play a loaded video Responds to the request to play a loaded video
""" """
log.debug(u'videoPlay') log.debug(u'videoPlay')
self.frame.evaluateJavaScript(u'show_video("play");') if self.phononActive:
self.mediaObject.play()
else:
self.frame.evaluateJavaScript(u'show_video("play");')
# show screen # show screen
if self.isLive: if self.isLive:
self.setVisible(True) self.setVisible(True)
@ -276,32 +299,54 @@ class MainDisplay(DisplayWidget):
Responds to the request to pause a loaded video Responds to the request to pause a loaded video
""" """
log.debug(u'videoPause') log.debug(u'videoPause')
self.frame.evaluateJavaScript(u'show_video("pause");') if self.phononActive:
self.mediaObject.pause()
else:
self.frame.evaluateJavaScript(u'show_video("pause");')
def videoStop(self): def videoStop(self):
""" """
Responds to the request to stop a loaded video Responds to the request to stop a loaded video
""" """
log.debug(u'videoStop') log.debug(u'videoStop')
self.frame.evaluateJavaScript(u'show_video("stop");') if self.phononActive:
self.mediaObject.stop()
else:
self.frame.evaluateJavaScript(u'show_video("stop");')
def videoVolume(self, volume): def videoVolume(self, volume):
""" """
Changes the volume of a running video Changes the volume of a running video
""" """
log.debug(u'videoVolume %d' % volume) log.debug(u'videoVolume %d' % volume)
self.frame.evaluateJavaScript(u'show_video(null, null, %s);' % vol = float(volume)/float(10)
str(float(volume)/float(10))) if self.phononActive:
self.audio.setVolume(vol)
else:
self.frame.evaluateJavaScript(u'show_video(null, null, %s);' %
str(vol))
def video(self, videoPath, volume): def video(self, videoPath, volume, isBackground=False):
""" """
Loads and starts a video to run with the option of sound Loads and starts a video to run with the option of sound
""" """
log.debug(u'video') log.debug(u'video')
self.loaded = True self.loaded = True
js = u'show_video("init", "%s", %s, true); show_video("play");' % \ vol = float(volume)/float(10)
(videoPath.replace(u'\\', u'\\\\'), str(float(volume)/float(10))) if isBackground or not self.usePhonon:
self.frame.evaluateJavaScript(js) js = u'show_video("init", "%s", %s, true); show_video("play");' % \
(videoPath.replace(u'\\', u'\\\\'), \
str(vol))
self.frame.evaluateJavaScript(js)
else:
self.phononActive = True
self.mediaObject.stop()
self.mediaObject.clearQueue()
self.mediaObject.setCurrentSource(Phonon.MediaSource(videoPath))
self.mediaObject.play()
self.webView.setVisible(False)
self.videoWidget.setVisible(True)
self.audio.setVolume(vol)
return self.preview() return self.preview()
def isLoaded(self): def isLoaded(self):
@ -356,6 +401,9 @@ class MainDisplay(DisplayWidget):
self.loaded = False self.loaded = False
self.initialFrame = False self.initialFrame = False
self.serviceItem = serviceItem self.serviceItem = serviceItem
if self.serviceItem.themedata.background_filename:
self.serviceItem.bg_image_bytes = self.imageManager. \
get_image_bytes(self.serviceItem.themedata.theme_name)
html = build_html(self.serviceItem, self.screen, self.parent.alertTab, html = build_html(self.serviceItem, self.screen, self.parent.alertTab,
self.isLive) self.isLive)
log.debug(u'buildHtml - pre setHtml') log.debug(u'buildHtml - pre setHtml')
@ -382,6 +430,8 @@ class MainDisplay(DisplayWidget):
Store the images so they can be replaced when required Store the images so they can be replaced when required
""" """
log.debug(u'hideDisplay mode = %d', mode) log.debug(u'hideDisplay mode = %d', mode)
if self.phononActive:
self.videoPause()
if mode == HideMode.Screen: if mode == HideMode.Screen:
self.frame.evaluateJavaScript(u'show_blank("desktop");') self.frame.evaluateJavaScript(u'show_blank("desktop");')
self.setVisible(False) self.setVisible(False)
@ -389,8 +439,11 @@ class MainDisplay(DisplayWidget):
self.frame.evaluateJavaScript(u'show_blank("black");') self.frame.evaluateJavaScript(u'show_blank("black");')
else: else:
self.frame.evaluateJavaScript(u'show_blank("theme");') self.frame.evaluateJavaScript(u'show_blank("theme");')
if mode != HideMode.Screen and self.isHidden(): if mode != HideMode.Screen:
self.setVisible(True) if self.isHidden():
self.setVisible(True)
if self.phononActive:
self.webView.setVisible(True)
self.hide_mode = mode self.hide_mode = mode
def showDisplay(self): def showDisplay(self):
@ -403,6 +456,9 @@ class MainDisplay(DisplayWidget):
self.frame.evaluateJavaScript('show_blank("show");') self.frame.evaluateJavaScript('show_blank("show");')
if self.isHidden(): if self.isHidden():
self.setVisible(True) self.setVisible(True)
if self.phononActive:
self.webView.setVisible(False)
self.videoPlay()
# Trigger actions when display is active again # Trigger actions when display is active again
Receiver.send_message(u'maindisplay_active') Receiver.send_message(u'maindisplay_active')
self.hide_mode = None self.hide_mode = None
@ -484,3 +540,4 @@ class AudioPlayer(QtCore.QObject):
""" """
log.debug(u'AudioPlayer Reached end of media playlist') log.debug(u'AudioPlayer Reached end of media playlist')
self.mediaObject.clearQueue() self.mediaObject.clearQueue()

View File

@ -824,7 +824,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
QtGui.QMessageBox.Save), QtGui.QMessageBox.Save),
QtGui.QMessageBox.Save) QtGui.QMessageBox.Save)
if ret == QtGui.QMessageBox.Save: if ret == QtGui.QMessageBox.Save:
self.ServiceManagerContents.onSaveService() self.ServiceManagerContents.onSaveService(True)
self.cleanUp() self.cleanUp()
event.accept() event.accept()
elif ret == QtGui.QMessageBox.Discard: elif ret == QtGui.QMessageBox.Discard:

View File

@ -25,6 +25,7 @@
############################################################################### ###############################################################################
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import translate from openlp.core.lib import translate
class Ui_ServiceItemEditDialog(object): class Ui_ServiceItemEditDialog(object):
@ -44,16 +45,26 @@ class Ui_ServiceItemEditDialog(object):
self.topLayout.addWidget(self.listWidget) self.topLayout.addWidget(self.listWidget)
self.buttonLayout = QtGui.QVBoxLayout() self.buttonLayout = QtGui.QVBoxLayout()
self.buttonLayout.setObjectName(u'buttonLayout') self.buttonLayout.setObjectName(u'buttonLayout')
self.upButton = QtGui.QPushButton(self.layoutWidget)
self.upButton.setObjectName(u'upButton')
self.buttonLayout.addWidget(self.upButton)
spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum,
QtGui.QSizePolicy.Expanding)
self.buttonLayout.addItem(spacerItem)
self.deleteButton = QtGui.QPushButton(self.layoutWidget) self.deleteButton = QtGui.QPushButton(self.layoutWidget)
self.deleteButton.setObjectName(u'deleteButton') self.deleteButton.setObjectName(u'deleteButton')
self.buttonLayout.addWidget(self.deleteButton) self.buttonLayout.addWidget(self.deleteButton)
spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum,
QtGui.QSizePolicy.Expanding)
self.buttonLayout.addItem(spacerItem)
self.upButton = QtGui.QPushButton(self.layoutWidget)
self.upButton.setText(u'')
icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap(u':/services/service_up.png'),
QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.upButton.setIcon(icon)
self.upButton.setObjectName(u'upButton')
self.buttonLayout.addWidget(self.upButton)
self.downButton = QtGui.QPushButton(self.layoutWidget) self.downButton = QtGui.QPushButton(self.layoutWidget)
self.downButton.setText(u'')
icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap(u':/services/service_down.png'),
QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.downButton.setIcon(icon)
self.downButton.setObjectName(u'downButton') self.downButton.setObjectName(u'downButton')
self.buttonLayout.addWidget(self.downButton) self.buttonLayout.addWidget(self.downButton)
self.topLayout.addLayout(self.buttonLayout) self.topLayout.addLayout(self.buttonLayout)
@ -70,7 +81,5 @@ class Ui_ServiceItemEditDialog(object):
def retranslateUi(self, serviceItemEditDialog): def retranslateUi(self, serviceItemEditDialog):
serviceItemEditDialog.setWindowTitle( serviceItemEditDialog.setWindowTitle(
translate('OpenLP.ServiceItemEditForm', 'Reorder Service Item')) translate('OpenLP.ServiceItemEditForm', 'Reorder Service Item'))
self.upButton.setText(translate('OpenLP.ServiceItemEditForm', 'Up'))
self.deleteButton.setText(translate('OpenLP.ServiceItemEditForm', self.deleteButton.setText(translate('OpenLP.ServiceItemEditForm',
'Delete')) 'Delete'))
self.downButton.setText(translate('OpenLP.ServiceItemEditForm', 'Down'))

View File

@ -107,6 +107,7 @@ class ServiceManager(QtGui.QWidget):
self.serviceName = u'' self.serviceName = u''
self.suffixes = [] self.suffixes = []
self.droppos = 0 self.droppos = 0
self.expandTabs = False
#is a new service and has not been saved #is a new service and has not been saved
self.isNew = True self.isNew = True
self.serviceNoteForm = ServiceNoteForm(self.parent) self.serviceNoteForm = ServiceNoteForm(self.parent)
@ -199,6 +200,19 @@ class ServiceManager(QtGui.QWidget):
translate('OpenLP.ServiceManager', translate('OpenLP.ServiceManager',
'Delete the selected item from the service.'), 'Delete the selected item from the service.'),
self.onDeleteFromService) self.onDeleteFromService)
self.orderToolbar.addSeparator()
self.orderToolbar.addToolbarButton(
translate('OpenLP.ServiceManager', '&Expand all'),
u':/services/service_top.png',
translate('OpenLP.ServiceManager',
'Expand all the service items.'),
self.onExpandAll)
self.orderToolbar.addToolbarButton(
translate('OpenLP.ServiceManager', '&Collapse all'),
u':/services/service_bottom.png',
translate('OpenLP.ServiceManager',
'Collapse all the service items.'),
self.onCollapseAll)
self.layout.addWidget(self.orderToolbar) self.layout.addWidget(self.orderToolbar)
# Connect up our signals and slots # Connect up our signals and slots
QtCore.QObject.connect(self.themeComboBox, QtCore.QObject.connect(self.themeComboBox,
@ -220,7 +234,7 @@ class ServiceManager(QtGui.QWidget):
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'servicemanager_list_request'), self.listRequest) QtCore.SIGNAL(u'servicemanager_list_request'), self.listRequest)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'config_updated'), self.regenerateServiceItems) QtCore.SIGNAL(u'config_updated'), self.configUpdated)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'theme_update_global'), self.themeChange) QtCore.SIGNAL(u'theme_update_global'), self.themeChange)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.QObject.connect(Receiver.get_receiver(),
@ -265,6 +279,17 @@ class ServiceManager(QtGui.QWidget):
self.themeMenu = QtGui.QMenu( self.themeMenu = QtGui.QMenu(
translate('OpenLP.ServiceManager', '&Change Item Theme')) translate('OpenLP.ServiceManager', '&Change Item Theme'))
self.menu.addMenu(self.themeMenu) self.menu.addMenu(self.themeMenu)
self.configUpdated(True)
def configUpdated(self, firstTime=False):
"""
Triggered when Config dialog is updated.
"""
self.expandTabs = QtCore.QSettings().value(
u'advanced/expand service item',
QtCore.QVariant(u'False')).toBool()
if not firstTime:
self.regenerateServiceItems()
def supportedSuffixes(self, suffix): def supportedSuffixes(self, suffix):
self.suffixes.append(suffix) self.suffixes.append(suffix)
@ -321,7 +346,7 @@ class ServiceManager(QtGui.QWidget):
self.serviceItems[item][u'service_item']) self.serviceItems[item][u'service_item'])
if self.serviceItemEditForm.exec_(): if self.serviceItemEditForm.exec_():
self.addServiceItem(self.serviceItemEditForm.getServiceItem(), self.addServiceItem(self.serviceItemEditForm.getServiceItem(),
replace=True) replace=True, expand=self.serviceItems[item][u'expanded'])
def nextItem(self): def nextItem(self):
""" """
@ -423,6 +448,14 @@ class ServiceManager(QtGui.QWidget):
if setSelected: if setSelected:
firstItem.setSelected(True) firstItem.setSelected(True)
def onCollapseAll(self):
"""
Collapse all the service items
"""
for item in self.serviceItems:
item[u'expanded'] = False
self.regenerateServiceItems()
def collapsed(self, item): def collapsed(self, item):
""" """
Record if an item is collapsed Record if an item is collapsed
@ -431,6 +464,14 @@ class ServiceManager(QtGui.QWidget):
pos = item.data(0, QtCore.Qt.UserRole).toInt()[0] pos = item.data(0, QtCore.Qt.UserRole).toInt()[0]
self.serviceItems[pos -1 ][u'expanded'] = False self.serviceItems[pos -1 ][u'expanded'] = False
def onExpandAll(self):
"""
Collapse all the service items
"""
for item in self.serviceItems:
item[u'expanded'] = True
self.regenerateServiceItems()
def expanded(self, item): def expanded(self, item):
""" """
Record if an item is collapsed Record if an item is collapsed
@ -528,12 +569,12 @@ class ServiceManager(QtGui.QWidget):
Used when moving items as the move takes place in supporting array, Used when moving items as the move takes place in supporting array,
and when regenerating all the items due to theme changes and when regenerating all the items due to theme changes
""" """
#Correct order of items in array # Correct order of items in array
count = 1 count = 1
for item in self.serviceItems: for item in self.serviceItems:
item[u'order'] = count item[u'order'] = count
count += 1 count += 1
#Repaint the screen # Repaint the screen
self.serviceManagerList.clear() self.serviceManagerList.clear()
for itemcount, item in enumerate(self.serviceItems): for itemcount, item in enumerate(self.serviceItems):
serviceitem = item[u'service_item'] serviceitem = item[u'service_item']
@ -609,9 +650,12 @@ class ServiceManager(QtGui.QWidget):
.get_service_repr()}) .get_service_repr()})
if item[u'service_item'].uses_file(): if item[u'service_item'].uses_file():
for frame in item[u'service_item'].get_frames(): for frame in item[u'service_item'].get_frames():
path_from = unicode(os.path.join( if item[u'service_item'].is_image():
frame[u'path'], path_from = frame[u'path']
frame[u'title'])) else:
path_from = unicode(os.path.join(
frame[u'path'],
frame[u'title']))
# On write a file once # On write a file once
if not path_from in write_list: if not path_from in write_list:
write_list.append(path_from) write_list.append(path_from)
@ -805,7 +849,7 @@ class ServiceManager(QtGui.QWidget):
self.isNew = True self.isNew = True
for item in tempServiceItems: for item in tempServiceItems:
self.addServiceItem( self.addServiceItem(
item[u'service_item'], False, item[u'expanded']) item[u'service_item'], False, expand=item[u'expanded'])
# Set to False as items may have changed rendering # Set to False as items may have changed rendering
# does not impact the saved song so True may also be valid # does not impact the saved song so True may also be valid
self.parent.serviceChanged(False, self.serviceName) self.parent.serviceChanged(False, self.serviceName)
@ -834,14 +878,19 @@ class ServiceManager(QtGui.QWidget):
self.parent.LiveController.replaceServiceManagerItem(newItem) self.parent.LiveController.replaceServiceManagerItem(newItem)
self.parent.serviceChanged(False, self.serviceName) self.parent.serviceChanged(False, self.serviceName)
def addServiceItem(self, item, rebuild=False, expand=False, replace=False): def addServiceItem(self, item, rebuild=False, expand=None, replace=False):
""" """
Add a Service item to the list Add a Service item to the list
``item`` ``item``
Service Item to be added Service Item to be added
``expand``
Override the default expand settings. (Tristate)
""" """
log.debug(u'addServiceItem') log.debug(u'addServiceItem')
if expand == None:
expand = self.expandTabs
sitem = self.findServiceItem()[0] sitem = self.findServiceItem()[0]
item.render() item.render()
if replace: if replace:

View File

@ -26,6 +26,7 @@
import logging import logging
import os import os
import time
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from PyQt4.phonon import Phonon from PyQt4.phonon import Phonon
@ -179,23 +180,23 @@ class SlideController(QtGui.QWidget):
self.HideMenu.setMenu(QtGui.QMenu( self.HideMenu.setMenu(QtGui.QMenu(
translate('OpenLP.SlideController', 'Hide'), self.Toolbar)) translate('OpenLP.SlideController', 'Hide'), self.Toolbar))
self.BlankScreen = QtGui.QAction(QtGui.QIcon( self.BlankScreen = QtGui.QAction(QtGui.QIcon(
u':/slides/slide_blank.png'), u':/slides/slide_blank.png'),
translate('OpenLP.SlideController', translate('OpenLP.SlideController',
'Blank Screen'), self.HideMenu) 'Blank Screen'), self.HideMenu)
self.BlankScreen.setCheckable(True) self.BlankScreen.setCheckable(True)
QtCore.QObject.connect(self.BlankScreen, QtCore.QObject.connect(self.BlankScreen,
QtCore.SIGNAL("triggered(bool)"), self.onBlankDisplay) QtCore.SIGNAL("triggered(bool)"), self.onBlankDisplay)
self.ThemeScreen = QtGui.QAction(QtGui.QIcon( self.ThemeScreen = QtGui.QAction(QtGui.QIcon(
u':/slides/slide_theme.png'), u':/slides/slide_theme.png'),
translate('OpenLP.SlideController', translate('OpenLP.SlideController',
'Blank to Theme'), self.HideMenu) 'Blank to Theme'), self.HideMenu)
self.ThemeScreen.setCheckable(True) self.ThemeScreen.setCheckable(True)
QtCore.QObject.connect(self.ThemeScreen, QtCore.QObject.connect(self.ThemeScreen,
QtCore.SIGNAL("triggered(bool)"), self.onThemeDisplay) QtCore.SIGNAL("triggered(bool)"), self.onThemeDisplay)
if self.screens.display_count > 1: if self.screens.display_count > 1:
self.DesktopScreen = QtGui.QAction(QtGui.QIcon( self.DesktopScreen = QtGui.QAction(QtGui.QIcon(
u':/slides/slide_desktop.png'), u':/slides/slide_desktop.png'),
translate('OpenLP.SlideController', translate('OpenLP.SlideController',
'Show Desktop'), self.HideMenu) 'Show Desktop'), self.HideMenu)
self.DesktopScreen.setCheckable(True) self.DesktopScreen.setCheckable(True)
QtCore.QObject.connect(self.DesktopScreen, QtCore.QObject.connect(self.DesktopScreen,
@ -214,7 +215,7 @@ class SlideController(QtGui.QWidget):
self.Toolbar.addToolbarSeparator(u'Close Separator') self.Toolbar.addToolbarSeparator(u'Close Separator')
self.Toolbar.addToolbarButton( self.Toolbar.addToolbarButton(
u'Edit Song', u':/general/general_edit.png', u'Edit Song', u':/general/general_edit.png',
translate('OpenLP.SlideController', translate('OpenLP.SlideController',
'Edit and reload song preview'), 'Edit and reload song preview'),
self.onEditSong) self.onEditSong)
if isLive: if isLive:
@ -400,6 +401,7 @@ class SlideController(QtGui.QWidget):
log.debug(u'screenSizeChanged live = %s' % self.isLive) log.debug(u'screenSizeChanged live = %s' % self.isLive)
# rebuild display as screen size changed # rebuild display as screen size changed
self.display = MainDisplay(self, self.screens, self.isLive) self.display = MainDisplay(self, self.screens, self.isLive)
self.display.imageManager = self.parent.RenderManager.image_manager
self.display.alertTab = self.alertTab self.display.alertTab = self.alertTab
self.ratio = float(self.screens.current[u'size'].width()) / \ self.ratio = float(self.screens.current[u'size'].width()) / \
float(self.screens.current[u'size'].height()) float(self.screens.current[u'size'].height())
@ -543,7 +545,7 @@ class SlideController(QtGui.QWidget):
Receiver.send_message(u'%s_stop' % Receiver.send_message(u'%s_stop' %
self.serviceItem.name.lower(), [serviceItem, self.isLive]) self.serviceItem.name.lower(), [serviceItem, self.isLive])
if self.serviceItem.is_media(): if self.serviceItem.is_media():
self.onMediaStop() self.onMediaClose()
if self.isLive: if self.isLive:
blanked = self.BlankScreen.isChecked() blanked = self.BlankScreen.isChecked()
else: else:
@ -584,11 +586,15 @@ class SlideController(QtGui.QWidget):
else: else:
label = QtGui.QLabel() label = QtGui.QLabel()
label.setMargin(4) label.setMargin(4)
pixmap = resize_image(frame[u'image'],
self.parent.RenderManager.width,
self.parent.RenderManager.height)
label.setScaledContents(True) label.setScaledContents(True)
label.setPixmap(QtGui.QPixmap.fromImage(pixmap)) if self.serviceItem.is_command():
image = resize_image(frame[u'image'],
self.parent.RenderManager.width,
self.parent.RenderManager.height)
else:
image = self.parent.RenderManager.image_manager. \
get_image(frame[u'title'])
label.setPixmap(QtGui.QPixmap.fromImage(image))
self.PreviewListWidget.setCellWidget(framenumber, 0, label) self.PreviewListWidget.setCellWidget(framenumber, 0, label)
slideHeight = width * self.parent.RenderManager.screen_ratio slideHeight = width * self.parent.RenderManager.screen_ratio
row += 1 row += 1
@ -779,15 +785,12 @@ class SlideController(QtGui.QWidget):
[self.serviceItem, self.isLive, row]) [self.serviceItem, self.isLive, row])
self.updatePreview() self.updatePreview()
else: else:
frame, raw_html = self.serviceItem.get_rendered_frame(row) toDisplay = self.serviceItem.get_rendered_frame(row)
if self.serviceItem.is_text(): if self.serviceItem.is_text():
frame = self.display.text(raw_html) frame = self.display.text(toDisplay)
else: else:
self.display.image(frame) frame = self.display.image(toDisplay)
if isinstance(frame, QtGui.QImage): self.SlidePreview.setPixmap(QtGui.QPixmap.fromImage(frame))
self.SlidePreview.setPixmap(QtGui.QPixmap.fromImage(frame))
else:
self.SlidePreview.setPixmap(QtGui.QPixmap(frame))
self.selectedRow = row self.selectedRow = row
Receiver.send_message(u'slidecontroller_%s_changed' % self.typePrefix, Receiver.send_message(u'slidecontroller_%s_changed' % self.typePrefix,
row) row)
@ -931,14 +934,13 @@ class SlideController(QtGui.QWidget):
Respond to the arrival of a media service item Respond to the arrival of a media service item
""" """
log.debug(u'SlideController onMediaStart') log.debug(u'SlideController onMediaStart')
file = os.path.join(item.get_frame_path(), item.get_frame_title())
if self.isLive: if self.isLive:
file = os.path.join(item.get_frame_path(), item.get_frame_title())
self.display.video(file, self.volume) self.display.video(file, self.volume)
self.volumeSlider.setValue(self.volume) self.volumeSlider.setValue(self.volume)
else: else:
self.mediaObject.stop() self.mediaObject.stop()
self.mediaObject.clearQueue() self.mediaObject.clearQueue()
file = os.path.join(item.get_frame_path(), item.get_frame_title())
self.mediaObject.setCurrentSource(Phonon.MediaSource(file)) self.mediaObject.setCurrentSource(Phonon.MediaSource(file))
self.seekSlider.setMediaObject(self.mediaObject) self.seekSlider.setMediaObject(self.mediaObject)
self.seekSlider.show() self.seekSlider.show()
@ -986,3 +988,17 @@ class SlideController(QtGui.QWidget):
self.video.hide() self.video.hide()
self.SlidePreview.clear() self.SlidePreview.clear()
self.SlidePreview.show() self.SlidePreview.show()
def onMediaClose(self):
"""
Respond to a request to close the Video
"""
log.debug(u'SlideController onMediaStop')
if self.isLive:
self.display.resetVideo()
else:
self.mediaObject.stop()
self.mediaObject.clearQueue()
self.video.hide()
self.SlidePreview.clear()
self.SlidePreview.show()

View File

@ -34,9 +34,8 @@ from PyQt4 import QtCore, QtGui
from openlp.core.ui import AmendThemeForm, FileRenameForm from openlp.core.ui import AmendThemeForm, FileRenameForm
from openlp.core.theme import Theme from openlp.core.theme import Theme
from openlp.core.lib import OpenLPToolbar, context_menu_action, \ from openlp.core.lib import OpenLPToolbar, ThemeXML, get_text_file_string, \
ThemeXML, str_to_bool, get_text_file_string, build_icon, Receiver, \ build_icon, Receiver, SettingsManager, translate, check_item_selected
context_menu_separator, SettingsManager, translate, check_item_selected
from openlp.core.utils import AppLocation, get_filesystem_encoding from openlp.core.utils import AppLocation, get_filesystem_encoding
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -267,7 +266,7 @@ class ThemeManager(QtGui.QWidget):
filename = \ filename = \
os.path.split(unicode(oldThemeData.background_filename))[1] os.path.split(unicode(oldThemeData.background_filename))[1]
new_theme.add_background_image(filename) new_theme.add_background_image(filename)
save_to = os.path.join(self.path, theme_name, filename) save_to = os.path.join(self.path, newThemeName, filename)
save_from = oldThemeData.background_filename save_from = oldThemeData.background_filename
new_theme.add_font(unicode(oldThemeData.font_main_name), new_theme.add_font(unicode(oldThemeData.font_main_name),
unicode(oldThemeData.font_main_color), unicode(oldThemeData.font_main_color),

View File

@ -28,7 +28,6 @@ The :mod:`languagemanager` module provides all the translation settings and
language file loading for OpenLP. language file loading for OpenLP.
""" """
import logging import logging
import os
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui

View File

@ -45,13 +45,15 @@ class AlertsPlugin(Plugin):
self.icon = build_icon(u':/plugins/plugin_alerts.png') self.icon = build_icon(u':/plugins/plugin_alerts.png')
self.alertsmanager = AlertsManager(self) self.alertsmanager = AlertsManager(self)
self.manager = Manager(u'alerts', init_schema) self.manager = Manager(u'alerts', init_schema)
self.alertForm = AlertForm(self) visible_name = self.getString(StringContent.VisibleName)
self.alertForm = AlertForm(self, visible_name[u'title'])
def getSettingsTab(self): def getSettingsTab(self):
""" """
Return the settings tab for the Alerts plugin Return the settings tab for the Alerts plugin
""" """
self.alertsTab = AlertsTab(self) visible_name = self.getString(StringContent.VisibleName)
self.alertsTab = AlertsTab(self, visible_name[u'title'])
return self.alertsTab return self.alertsTab
def addToolsMenuItem(self, tools_menu): def addToolsMenuItem(self, tools_menu):
@ -115,4 +117,11 @@ class AlertsPlugin(Plugin):
self.textStrings[StringContent.VisibleName] = { self.textStrings[StringContent.VisibleName] = {
u'title': translate('AlertsPlugin', 'Alerts') u'title': translate('AlertsPlugin', 'Alerts')
} }
def finalise(self):
"""
Time to tidy up on exit
"""
log.info(u'Alerts Finalising')
self.manager.finalise()
Plugin.finalise(self)

View File

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

View File

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

View File

@ -133,42 +133,50 @@ class BiblePlugin(Plugin):
## Import Button ## ## Import Button ##
self.textStrings[StringContent.Import] = { self.textStrings[StringContent.Import] = {
u'title': translate('BiblesPlugin', 'Import'), u'title': translate('BiblesPlugin', 'Import'),
u'tooltip': translate('BiblesPlugin', u'tooltip': translate('BiblesPlugin',
'Import a Bible') 'Import a Bible')
} }
## New Button ## ## New Button ##
self.textStrings[StringContent.New] = { self.textStrings[StringContent.New] = {
u'title': translate('BiblesPlugin', 'Add'), u'title': translate('BiblesPlugin', 'Add'),
u'tooltip': translate('BiblesPlugin', u'tooltip': translate('BiblesPlugin',
'Add a new Bible') 'Add a new Bible')
} }
## Edit Button ## ## Edit Button ##
self.textStrings[StringContent.Edit] = { self.textStrings[StringContent.Edit] = {
u'title': translate('BiblesPlugin', 'Edit'), u'title': translate('BiblesPlugin', 'Edit'),
u'tooltip': translate('BiblesPlugin', u'tooltip': translate('BiblesPlugin',
'Edit the selected Bible') 'Edit the selected Bible')
} }
## Delete Button ## ## Delete Button ##
self.textStrings[StringContent.Delete] = { self.textStrings[StringContent.Delete] = {
u'title': translate('BiblesPlugin', 'Delete'), u'title': translate('BiblesPlugin', 'Delete'),
u'tooltip': translate('BiblesPlugin', u'tooltip': translate('BiblesPlugin',
'Delete the selected Bible') 'Delete the selected Bible')
} }
## Preview ## ## Preview ##
self.textStrings[StringContent.Preview] = { self.textStrings[StringContent.Preview] = {
u'title': translate('BiblesPlugin', 'Preview'), u'title': translate('BiblesPlugin', 'Preview'),
u'tooltip': translate('BiblesPlugin', u'tooltip': translate('BiblesPlugin',
'Preview the selected Bible') 'Preview the selected Bible')
} }
## Live Button ## ## Live Button ##
self.textStrings[StringContent.Live] = { self.textStrings[StringContent.Live] = {
u'title': translate('BiblesPlugin', 'Live'), u'title': translate('BiblesPlugin', 'Live'),
u'tooltip': translate('BiblesPlugin', u'tooltip': translate('BiblesPlugin',
'Send the selected Bible live') 'Send the selected Bible live')
} }
## Add to service Button ## ## Add to service Button ##
self.textStrings[StringContent.Service] = { self.textStrings[StringContent.Service] = {
u'title': translate('BiblesPlugin', 'Service'), u'title': translate('BiblesPlugin', 'Service'),
u'tooltip': translate('BiblesPlugin', u'tooltip': translate('BiblesPlugin',
'Add the selected Bible to the service') 'Add the selected Bible to the service')
} }
def finalise(self):
"""
Time to tidy up on exit
"""
log.info(u'Bible Finalising')
self.manager.finalise()
Plugin.finalise(self)

View File

@ -24,6 +24,33 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################
from importwizardform import ImportWizardForm """
Forms in OpenLP are made up of two classes. One class holds all the graphical
elements, like buttons and lists, and the other class holds all the functional
code, like slots and loading and saving.
__all__ = ['ImportWizardForm'] The first class, commonly known as the **Dialog** class, is typically named
``Ui_<name>Dialog``. It is a slightly modified version of the class that the
``pyuic4`` command produces from Qt4's .ui file. Typical modifications will be
converting most strings from "" to u'' and using OpenLP's ``translate()``
function for translating strings.
The second class, commonly known as the **Form** class, is typically named
``<name>Form``. This class is the one which is instantiated and used. It uses
dual inheritance to inherit from (usually) QtGui.QDialog and the Ui class
mentioned above, like so::
class BibleImportForm(QtGui.QWizard, Ui_BibleImportWizard):
def __init__(self, parent, manager, bibleplugin):
QtGui.QWizard.__init__(self, parent)
self.setupUi(self)
This allows OpenLP to use ``self.object`` for all the GUI elements while keeping
them separate from the functionality, so that it is easier to recreate the GUI
from the .ui files later if necessary.
"""
from bibleimportform import BibleImportForm
__all__ = ['BibleImportForm']

View File

@ -54,7 +54,7 @@ class WebDownload(object):
return cls.Names[name] return cls.Names[name]
class ImportWizardForm(QtGui.QWizard, Ui_BibleImportWizard): class BibleImportForm(QtGui.QWizard, Ui_BibleImportWizard):
""" """
This is the Bible Import Wizard, which allows easy importing of Bibles This is the Bible Import Wizard, which allows easy importing of Bibles
into OpenLP from other formats like OSIS, CSV and OpenSong. into OpenLP from other formats like OSIS, CSV and OpenSong.
@ -282,7 +282,7 @@ class ImportWizardForm(QtGui.QWizard, Ui_BibleImportWizard):
self.LicenseDetailsPage.registerField( self.LicenseDetailsPage.registerField(
u'license_copyright', self.CopyrightEdit) u'license_copyright', self.CopyrightEdit)
self.LicenseDetailsPage.registerField( self.LicenseDetailsPage.registerField(
u'license_permission', self.PermissionEdit) u'license_permissions', self.PermissionsEdit)
def setDefaults(self): def setDefaults(self):
settings = QtCore.QSettings() settings = QtCore.QSettings()
@ -308,8 +308,8 @@ class ImportWizardForm(QtGui.QWizard, Ui_BibleImportWizard):
QtCore.QVariant(self.VersionNameEdit.text())) QtCore.QVariant(self.VersionNameEdit.text()))
self.setField(u'license_copyright', self.setField(u'license_copyright',
QtCore.QVariant(self.CopyrightEdit.text())) QtCore.QVariant(self.CopyrightEdit.text()))
self.setField(u'license_permission', self.setField(u'license_permissions',
QtCore.QVariant(self.PermissionEdit.text())) QtCore.QVariant(self.PermissionsEdit.text()))
self.onLocationComboBoxChanged(WebDownload.Crosswalk) self.onLocationComboBoxChanged(WebDownload.Crosswalk)
settings.endGroup() settings.endGroup()
@ -391,8 +391,8 @@ class ImportWizardForm(QtGui.QWizard, Ui_BibleImportWizard):
bible_type = self.field(u'source_format').toInt()[0] bible_type = self.field(u'source_format').toInt()[0]
license_version = unicode(self.field(u'license_version').toString()) license_version = unicode(self.field(u'license_version').toString())
license_copyright = unicode(self.field(u'license_copyright').toString()) license_copyright = unicode(self.field(u'license_copyright').toString())
license_permission = \ license_permissions = \
unicode(self.field(u'license_permission').toString()) unicode(self.field(u'license_permissions').toString())
importer = None importer = None
if bible_type == BibleFormat.OSIS: if bible_type == BibleFormat.OSIS:
# Import an OSIS bible # Import an OSIS bible
@ -436,7 +436,7 @@ class ImportWizardForm(QtGui.QWizard, Ui_BibleImportWizard):
) )
if importer.do_import(): if importer.do_import():
self.manager.save_meta_data(license_version, license_version, self.manager.save_meta_data(license_version, license_version,
license_copyright, license_permission) license_copyright, license_permissions)
self.manager.reload_bibles() self.manager.reload_bibles()
self.ImportProgressLabel.setText( self.ImportProgressLabel.setText(
translate('BiblesPlugin.ImportWizardForm', 'Finished import.')) translate('BiblesPlugin.ImportWizardForm', 'Finished import.'))

View File

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

View File

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

View File

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

View File

@ -36,7 +36,7 @@ from BeautifulSoup import BeautifulSoup, NavigableString
from openlp.core.lib import Receiver from openlp.core.lib import Receiver
from openlp.core.utils import AppLocation from openlp.core.utils import AppLocation
from openlp.plugins.bibles.lib import SearchResults from openlp.plugins.bibles.lib import SearchResults
from openlp.plugins.bibles.lib.db import BibleDB, Book from openlp.plugins.bibles.lib.db import BibleDB, Book
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -187,16 +187,16 @@ class BGExtract(object):
def get_bible_chapter(self, version, bookname, chapter): def get_bible_chapter(self, version, bookname, chapter):
""" """
Access and decode bibles via the BibleGateway website Access and decode bibles via the BibleGateway website.
``version`` ``version``
The version of the bible like 31 for New International version The version of the bible like 31 for New International version.
``bookname`` ``bookname``
Name of the Book Name of the Book.
``chapter`` ``chapter``
Chapter number Chapter number.
""" """
log.debug(u'get_bible_chapter %s, %s, %s', version, bookname, chapter) log.debug(u'get_bible_chapter %s, %s, %s', version, bookname, chapter)
url_params = urllib.urlencode( url_params = urllib.urlencode(
@ -298,13 +298,13 @@ class CWExtract(object):
versetext = versetext + part versetext = versetext + part
elif part and part.attrMap and \ elif part and part.attrMap and \
(part.attrMap[u'class'] == u'WordsOfChrist' or \ (part.attrMap[u'class'] == u'WordsOfChrist' or \
part.attrMap[u'class'] == u'strongs'): part.attrMap[u'class'] == u'strongs'):
for subpart in part.contents: for subpart in part.contents:
Receiver.send_message(u'openlp_process_events') Receiver.send_message(u'openlp_process_events')
if isinstance(subpart, NavigableString): if isinstance(subpart, NavigableString):
versetext = versetext + subpart versetext = versetext + subpart
elif subpart and subpart.attrMap and \ elif subpart and subpart.attrMap and \
subpart.attrMap[u'class'] == u'strongs': subpart.attrMap[u'class'] == u'strongs':
for subsub in subpart.contents: for subsub in subpart.contents:
Receiver.send_message(u'openlp_process_events') Receiver.send_message(u'openlp_process_events')
if isinstance(subsub, NavigableString): if isinstance(subsub, NavigableString):
@ -428,7 +428,7 @@ class HTTPBible(BibleDB):
def get_chapter(self, book, chapter): def get_chapter(self, book, chapter):
""" """
Receive the request and call the relevant handler methods Receive the request and call the relevant handler methods.
""" """
log.debug(u'get_chapter %s, %s', book, chapter) log.debug(u'get_chapter %s, %s', book, chapter)
log.debug(u'source = %s', self.download_source) log.debug(u'source = %s', self.download_source)

View File

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

View File

@ -31,7 +31,7 @@ from PyQt4 import QtCore, QtGui
from openlp.core.lib import MediaManagerItem, Receiver, BaseListWithDnD, \ from openlp.core.lib import MediaManagerItem, Receiver, BaseListWithDnD, \
ItemCapabilities, translate ItemCapabilities, translate
from openlp.plugins.bibles.forms import ImportWizardForm from openlp.plugins.bibles.forms import BibleImportForm
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -361,7 +361,7 @@ class BibleMediaItem(MediaManagerItem):
def onImportClick(self): def onImportClick(self):
if not hasattr(self, u'import_wizard'): if not hasattr(self, u'import_wizard'):
self.import_wizard = ImportWizardForm(self, self.parent.manager, self.import_wizard = BibleImportForm(self, self.parent.manager,
self.parent) self.parent)
self.import_wizard.exec_() self.import_wizard.exec_()
self.reloadBibles() self.reloadBibles()
@ -374,7 +374,7 @@ class BibleMediaItem(MediaManagerItem):
self.AdvancedSecondBibleComboBox.clear() self.AdvancedSecondBibleComboBox.clear()
self.QuickSecondBibleComboBox.addItem(u'') self.QuickSecondBibleComboBox.addItem(u'')
self.AdvancedSecondBibleComboBox.addItem(u'') self.AdvancedSecondBibleComboBox.addItem(u'')
bibles = self.parent.manager.get_bibles() bibles = self.parent.manager.get_bibles().keys()
# load bibles into the combo boxes # load bibles into the combo boxes
first = True first = True
for bible in bibles: for bible in bibles:
@ -497,6 +497,7 @@ class BibleMediaItem(MediaManagerItem):
def onAdvancedSearchButton(self): def onAdvancedSearchButton(self):
log.debug(u'Advanced Search Button pressed') log.debug(u'Advanced Search Button pressed')
self.AdvancedSearchButton.setEnabled(False)
bible = unicode(self.AdvancedVersionComboBox.currentText()) bible = unicode(self.AdvancedVersionComboBox.currentText())
dual_bible = unicode(self.AdvancedSecondBibleComboBox.currentText()) dual_bible = unicode(self.AdvancedSecondBibleComboBox.currentText())
book = unicode(self.AdvancedBookComboBox.currentText()) book = unicode(self.AdvancedBookComboBox.currentText())
@ -529,16 +530,30 @@ class BibleMediaItem(MediaManagerItem):
self.displayResults(bible, dual_bible) self.displayResults(bible, dual_bible)
else: else:
self.displayResults(bible, dual_bible) self.displayResults(bible, dual_bible)
self.AdvancedSearchButton.setEnabled(True)
def onQuickSearchButton(self): def onQuickSearchButton(self):
log.debug(u'Quick Search Button pressed') log.debug(u'Quick Search Button pressed')
self.QuickSearchButton.setEnabled(False)
bible = unicode(self.QuickVersionComboBox.currentText()) bible = unicode(self.QuickVersionComboBox.currentText())
dual_bible = unicode(self.QuickSecondBibleComboBox.currentText()) dual_bible = unicode(self.QuickSecondBibleComboBox.currentText())
text = unicode(self.QuickSearchEdit.text()) text = unicode(self.QuickSearchEdit.text())
self.search_results = self.parent.manager.get_verses(bible, text) if self.QuickSearchComboBox.currentIndex() == 0:
if dual_bible: # We are doing a 'Verse Search'.
self.dual_search_results = self.parent.manager.get_verses( self.search_results = self.parent.manager.get_verses(bible, text)
dual_bible, text) if dual_bible and self.search_results:
self.dual_search_results = self.parent.manager.get_verses(
dual_bible, text)
else:
# We are doing a ' Text Search'.
bibles = self.parent.manager.get_bibles()
self.search_results = self.parent.manager.verse_search(bible, text)
if dual_bible and self.search_results:
text = []
for verse in self.search_results:
text.append((verse.book.name, verse.chapter, verse.verse,
verse.verse))
self.dual_search_results = bibles[dual_bible].get_verses(text)
if self.ClearQuickSearchComboBox.currentIndex() == 0: if self.ClearQuickSearchComboBox.currentIndex() == 0:
self.listView.clear() self.listView.clear()
if self.listView.count() != 0 and self.search_results: if self.listView.count() != 0 and self.search_results:
@ -558,6 +573,7 @@ class BibleMediaItem(MediaManagerItem):
self.displayResults(bible, dual_bible) self.displayResults(bible, dual_bible)
elif self.search_results: elif self.search_results:
self.displayResults(bible, dual_bible) self.displayResults(bible, dual_bible)
self.QuickSearchButton.setEnabled(True)
def displayResults(self, bible, dual_bible=u''): def displayResults(self, bible, dual_bible=u''):
""" """
@ -566,16 +582,16 @@ class BibleMediaItem(MediaManagerItem):
""" """
version = self.parent.manager.get_meta_data(bible, u'Version') version = self.parent.manager.get_meta_data(bible, u'Version')
copyright = self.parent.manager.get_meta_data(bible, u'Copyright') copyright = self.parent.manager.get_meta_data(bible, u'Copyright')
permission = self.parent.manager.get_meta_data(bible, u'Permissions') permissions = self.parent.manager.get_meta_data(bible, u'Permissions')
if dual_bible: if dual_bible:
dual_version = self.parent.manager.get_meta_data(dual_bible, dual_version = self.parent.manager.get_meta_data(dual_bible,
u'Version') u'Version')
dual_copyright = self.parent.manager.get_meta_data(dual_bible, dual_copyright = self.parent.manager.get_meta_data(dual_bible,
u'Copyright') u'Copyright')
dual_permission = self.parent.manager.get_meta_data(dual_bible, dual_permissions = self.parent.manager.get_meta_data(dual_bible,
u'Permissions') u'Permissions')
if not dual_permission: if not dual_permissions:
dual_permission = u'' dual_permissions = u''
# We count the number of rows which are maybe already present. # We count the number of rows which are maybe already present.
start_count = self.listView.count() start_count = self.listView.count()
for count, verse in enumerate(self.search_results): for count, verse in enumerate(self.search_results):
@ -587,12 +603,12 @@ class BibleMediaItem(MediaManagerItem):
'bible': QtCore.QVariant(bible), 'bible': QtCore.QVariant(bible),
'version': QtCore.QVariant(version.value), 'version': QtCore.QVariant(version.value),
'copyright': QtCore.QVariant(copyright.value), 'copyright': QtCore.QVariant(copyright.value),
'permission': QtCore.QVariant(permission.value), 'permissions': QtCore.QVariant(permissions.value),
'text': QtCore.QVariant(verse.text), 'text': QtCore.QVariant(verse.text),
'dual_bible': QtCore.QVariant(dual_bible), 'dual_bible': QtCore.QVariant(dual_bible),
'dual_version': QtCore.QVariant(dual_version.value), 'dual_version': QtCore.QVariant(dual_version.value),
'dual_copyright': QtCore.QVariant(dual_copyright.value), 'dual_copyright': QtCore.QVariant(dual_copyright.value),
'dual_permission': QtCore.QVariant(dual_permission.value), 'dual_permissions': QtCore.QVariant(dual_permissions.value),
'dual_text': QtCore.QVariant( 'dual_text': QtCore.QVariant(
self.dual_search_results[count].text) self.dual_search_results[count].text)
} }
@ -607,12 +623,12 @@ class BibleMediaItem(MediaManagerItem):
'bible': QtCore.QVariant(bible), 'bible': QtCore.QVariant(bible),
'version': QtCore.QVariant(version.value), 'version': QtCore.QVariant(version.value),
'copyright': QtCore.QVariant(copyright.value), 'copyright': QtCore.QVariant(copyright.value),
'permission': QtCore.QVariant(permission.value), 'permissions': QtCore.QVariant(permissions.value),
'text': QtCore.QVariant(verse.text), 'text': QtCore.QVariant(verse.text),
'dual_bible': QtCore.QVariant(u''), 'dual_bible': QtCore.QVariant(u''),
'dual_version': QtCore.QVariant(u''), 'dual_version': QtCore.QVariant(u''),
'dual_copyright': QtCore.QVariant(u''), 'dual_copyright': QtCore.QVariant(u''),
'dual_permission': QtCore.QVariant(u''), 'dual_permissions': QtCore.QVariant(u''),
'dual_text': QtCore.QVariant(u'') 'dual_text': QtCore.QVariant(u'')
} }
bible_text = u' %s %d:%d (%s)' % (verse.book.name, bible_text = u' %s %d:%d (%s)' % (verse.book.name,
@ -658,20 +674,20 @@ class BibleMediaItem(MediaManagerItem):
bible = self._decodeQtObject(bitem, 'bible') bible = self._decodeQtObject(bitem, 'bible')
version = self._decodeQtObject(bitem, 'version') version = self._decodeQtObject(bitem, 'version')
copyright = self._decodeQtObject(bitem, 'copyright') copyright = self._decodeQtObject(bitem, 'copyright')
permission = self._decodeQtObject(bitem, 'permission') permissions = self._decodeQtObject(bitem, 'permissions')
text = self._decodeQtObject(bitem, 'text') text = self._decodeQtObject(bitem, 'text')
dual_bible = self._decodeQtObject(bitem, 'dual_bible') dual_bible = self._decodeQtObject(bitem, 'dual_bible')
dual_version = self._decodeQtObject(bitem, 'dual_version') dual_version = self._decodeQtObject(bitem, 'dual_version')
dual_copyright = self._decodeQtObject(bitem, 'dual_copyright') dual_copyright = self._decodeQtObject(bitem, 'dual_copyright')
dual_permission = self._decodeQtObject(bitem, 'dual_permission') dual_permissions = self._decodeQtObject(bitem, 'dual_permissions')
dual_text = self._decodeQtObject(bitem, 'dual_text') dual_text = self._decodeQtObject(bitem, 'dual_text')
verse_text = self.formatVerse(old_chapter, chapter, verse) verse_text = self.formatVerse(old_chapter, chapter, verse)
footer = u'%s (%s %s %s)' % (book, version, copyright, permission) footer = u'%s (%s %s %s)' % (book, version, copyright, permissions)
if footer not in raw_footer: if footer not in raw_footer:
raw_footer.append(footer) raw_footer.append(footer)
if dual_bible: if dual_bible:
footer = u'%s (%s %s %s)' % (book, dual_version, dual_copyright, footer = u'%s (%s %s %s)' % (book, dual_version, dual_copyright,
dual_permission) dual_permissions)
if footer not in raw_footer: if footer not in raw_footer:
raw_footer.append(footer) raw_footer.append(footer)
bible_text = u'%s %s\n\n%s %s' % (verse_text, text, verse_text, bible_text = u'%s %s\n\n%s %s' % (verse_text, text, verse_text,

View File

@ -6,8 +6,8 @@ Deut,Deuteronomy,Deut
Josh,Joshua,Josh Josh,Joshua,Josh
Judg,Judges,Judg Judg,Judges,Judg
Ruth,Ruth,Ruth Ruth,Ruth,Ruth
1Sam,1 Samual,1Sam 1Sam,1 Samuel,1Sam
2Sam,2 Samual,2Sam 2Sam,2 Samuel,2Sam
1Kgs,1 Kings,1Kgs 1Kgs,1 Kings,1Kgs
2Kgs,2 Kings,2Kgs 2Kgs,2 Kings,2Kgs
1Chr,1 Chronicles,1Chr 1Chr,1 Chronicles,1Chr

1 Gen Genesis Gen
6 Josh Joshua Josh
7 Judg Judges Judg
8 Ruth Ruth Ruth
9 1Sam 1 Samual 1 Samuel 1Sam
10 2Sam 2 Samual 2 Samuel 2Sam
11 1Kgs 1 Kings 1Kgs
12 2Kgs 2 Kings 2Kgs
13 1Chr 1 Chronicles 1Chr

View File

@ -49,8 +49,8 @@ class CustomPlugin(Plugin):
def __init__(self, plugin_helpers): def __init__(self, plugin_helpers):
Plugin.__init__(self, u'Custom', u'1.9.3', plugin_helpers) Plugin.__init__(self, u'Custom', u'1.9.3', plugin_helpers)
self.weight = -5 self.weight = -5
self.custommanager = Manager(u'custom', init_schema) self.manager = Manager(u'custom', init_schema)
self.edit_custom_form = EditCustomForm(self.custommanager) self.edit_custom_form = EditCustomForm(self.manager)
self.icon_path = u':/plugins/plugin_custom.png' self.icon_path = u':/plugins/plugin_custom.png'
self.icon = build_icon(self.icon_path) self.icon = build_icon(self.icon_path)
@ -115,48 +115,56 @@ class CustomPlugin(Plugin):
## Import Button ## ## Import Button ##
self.textStrings[StringContent.Import] = { self.textStrings[StringContent.Import] = {
u'title': translate('CustomsPlugin', 'Import'), u'title': translate('CustomsPlugin', 'Import'),
u'tooltip': translate('CustomsPlugin', u'tooltip': translate('CustomsPlugin',
'Import a Custom') 'Import a Custom')
} }
## Load Button ## ## Load Button ##
self.textStrings[StringContent.Load] = { self.textStrings[StringContent.Load] = {
u'title': translate('CustomsPlugin', 'Load'), u'title': translate('CustomsPlugin', 'Load'),
u'tooltip': translate('CustomsPlugin', u'tooltip': translate('CustomsPlugin',
'Load a new Custom') 'Load a new Custom')
} }
## New Button ## ## New Button ##
self.textStrings[StringContent.New] = { self.textStrings[StringContent.New] = {
u'title': translate('CustomsPlugin', 'Add'), u'title': translate('CustomsPlugin', 'Add'),
u'tooltip': translate('CustomsPlugin', u'tooltip': translate('CustomsPlugin',
'Add a new Custom') 'Add a new Custom')
} }
## Edit Button ## ## Edit Button ##
self.textStrings[StringContent.Edit] = { self.textStrings[StringContent.Edit] = {
u'title': translate('CustomsPlugin', 'Edit'), u'title': translate('CustomsPlugin', 'Edit'),
u'tooltip': translate('CustomsPlugin', u'tooltip': translate('CustomsPlugin',
'Edit the selected Custom') 'Edit the selected Custom')
} }
## Delete Button ## ## Delete Button ##
self.textStrings[StringContent.Delete] = { self.textStrings[StringContent.Delete] = {
u'title': translate('CustomsPlugin', 'Delete'), u'title': translate('CustomsPlugin', 'Delete'),
u'tooltip': translate('CustomsPlugin', u'tooltip': translate('CustomsPlugin',
'Delete the selected Custom') 'Delete the selected Custom')
} }
## Preview ## ## Preview ##
self.textStrings[StringContent.Preview] = { self.textStrings[StringContent.Preview] = {
u'title': translate('CustomsPlugin', 'Preview'), u'title': translate('CustomsPlugin', 'Preview'),
u'tooltip': translate('CustomsPlugin', u'tooltip': translate('CustomsPlugin',
'Preview the selected Custom') 'Preview the selected Custom')
} }
## Live Button ## ## Live Button ##
self.textStrings[StringContent.Live] = { self.textStrings[StringContent.Live] = {
u'title': translate('CustomsPlugin', 'Live'), u'title': translate('CustomsPlugin', 'Live'),
u'tooltip': translate('CustomsPlugin', u'tooltip': translate('CustomsPlugin',
'Send the selected Custom live') 'Send the selected Custom live')
} }
## Add to service Button ## ## Add to service Button ##
self.textStrings[StringContent.Service] = { self.textStrings[StringContent.Service] = {
u'title': translate('CustomsPlugin', 'Service'), u'title': translate('CustomsPlugin', 'Service'),
u'tooltip': translate('CustomsPlugin', u'tooltip': translate('CustomsPlugin',
'Add the selected Custom to the service') 'Add the selected Custom to the service')
} }
def finalise(self):
"""
Time to tidy up on exit
"""
log.info(u'Custom Finalising')
self.manager.finalise()
Plugin.finalise(self)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -56,6 +56,7 @@ class CustomMediaItem(MediaManagerItem):
# Holds information about whether the edit is remotly triggered and # Holds information about whether the edit is remotly triggered and
# which Custom is required. # which Custom is required.
self.remoteCustom = -1 self.remoteCustom = -1
self.manager = parent.manager
def addEndHeaderBar(self): def addEndHeaderBar(self):
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.QObject.connect(Receiver.get_receiver(),
@ -71,7 +72,7 @@ class CustomMediaItem(MediaManagerItem):
MediaManagerItem.requiredIcons(self) MediaManagerItem.requiredIcons(self)
def initialise(self): def initialise(self):
self.loadCustomListView(self.parent.custommanager.get_all_objects( self.loadCustomListView(self.manager.get_all_objects(
CustomSlide, order_by_ref=CustomSlide.title)) CustomSlide, order_by_ref=CustomSlide.title))
#Called to redisplay the song list screen edith from a search #Called to redisplay the song list screen edith from a search
#or from the exit of the Song edit dialog. If remote editing is active #or from the exit of the Song edit dialog. If remote editing is active
@ -106,7 +107,7 @@ class CustomMediaItem(MediaManagerItem):
type of display is required. type of display is required.
""" """
fields = customid.split(u':') fields = customid.split(u':')
valid = self.parent.custommanager.get_object(CustomSlide, fields[1]) valid = self.manager.get_object(CustomSlide, fields[1])
if valid: if valid:
self.remoteCustom = fields[1] self.remoteCustom = fields[1]
self.remoteTriggered = fields[0] self.remoteTriggered = fields[0]

View File

@ -166,9 +166,8 @@ class ImageMediaItem(MediaManagerItem):
for item in items: for item in items:
bitem = self.listView.item(item.row()) bitem = self.listView.item(item.row())
filename = unicode(bitem.data(QtCore.Qt.UserRole).toString()) filename = unicode(bitem.data(QtCore.Qt.UserRole).toString())
frame = QtGui.QImage(unicode(filename))
(path, name) = os.path.split(filename) (path, name) = os.path.split(filename)
service_item.add_from_image(path, name, frame) service_item.add_from_image(filename, name)
return True return True
else: else:
return False return False
@ -185,7 +184,8 @@ class ImageMediaItem(MediaManagerItem):
for item in items: for item in items:
bitem = self.listView.item(item.row()) bitem = self.listView.item(item.row())
filename = unicode(bitem.data(QtCore.Qt.UserRole).toString()) filename = unicode(bitem.data(QtCore.Qt.UserRole).toString())
self.parent.liveController.display.image(filename) (path, name) = os.path.split(filename)
self.parent.liveController.display.directImage(name, filename)
self.resetButton.setVisible(True) self.resetButton.setVisible(True)
def onPreviewClick(self): def onPreviewClick(self):

View File

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

View File

@ -113,7 +113,7 @@ class MediaMediaItem(MediaManagerItem):
'You must select a media file to replace the background with.')): 'You must select a media file to replace the background with.')):
item = self.listView.currentItem() item = self.listView.currentItem()
filename = unicode(item.data(QtCore.Qt.UserRole).toString()) filename = unicode(item.data(QtCore.Qt.UserRole).toString())
self.parent.liveController.display.video(filename, 0) self.parent.liveController.display.video(filename, 0, True)
self.resetButton.setVisible(True) self.resetButton.setVisible(True)
def generateSlideData(self, service_item, item=None): def generateSlideData(self, service_item, item=None):

View File

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

View File

@ -29,7 +29,7 @@ import logging
from PyQt4.phonon import Phonon from PyQt4.phonon import Phonon
from openlp.core.lib import Plugin, StringContent, build_icon, translate from openlp.core.lib import Plugin, StringContent, build_icon, translate
from openlp.plugins.media.lib import MediaMediaItem from openlp.plugins.media.lib import MediaMediaItem, MediaTab
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -68,6 +68,9 @@ class MediaPlugin(Plugin):
type = u'' type = u''
return list, type return list, type
def getSettingsTab(self):
return MediaTab(self.name)
def getMediaManagerItem(self): def getMediaManagerItem(self):
# Create the MediaManagerItem object # Create the MediaManagerItem object
return MediaMediaItem(self, self, self.icon) return MediaMediaItem(self, self, self.icon)
@ -132,4 +135,4 @@ class MediaPlugin(Plugin):
u'title': translate('MediaPlugin', 'Service'), u'title': translate('MediaPlugin', 'Service'),
u'tooltip': translate('MediaPlugin', u'tooltip': translate('MediaPlugin',
'Add the selected Media to the service') 'Add the selected Media to the service')
} }

View File

@ -169,7 +169,8 @@ class ImpressController(PresentationController):
try: try:
return Dispatch(u'com.sun.star.ServiceManager') return Dispatch(u'com.sun.star.ServiceManager')
except pywintypes.com_error: except pywintypes.com_error:
log.exception(u'Failed to get COM service manager') log.warn(u'Failed to get COM service manager. '
u'Impress Controller has been disabled')
return None return None
def kill(self): def kill(self):

View File

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

View File

@ -37,16 +37,21 @@ log = logging.getLogger(__name__)
class PresentationController(object): class PresentationController(object):
""" """
Base class for presentation controllers to inherit from This class is used to control interactions with presentation applications
Class to control interactions with presentations. by creating a runtime environment. This is a base class for presentation
It creates the runtime environment controllers to inherit from.
To create a new controller, take a copy of this file and name it
so it ends in controller.py, i.e. foobarcontroller.py To create a new controller, take a copy of this file and name it so it ends
Make sure it inherits PresentationController with ``controller.py``, i.e. ``foobarcontroller.py``. Make sure it inherits
Then fill in the blanks. If possible try and make sure it loads :class:`~openlp.plugins.presentations.lib.presentationcontroller.PresentationController`,
on all platforms, using for example os.name checks, although and then fill in the blanks. If possible try to make sure it loads on all
__init__, check_available and presentation_deleted should always work. platforms, usually by using :mod:``os.name`` checks, although
See impresscontroller, powerpointcontroller or pptviewcontroller ``__init__``, ``check_available`` and ``presentation_deleted`` should
always be implemented.
See :class:`~openlp.plugins.presentations.lib.impresscontroller.ImpressController`,
:class:`~openlp.plugins.presentations.lib.powerpointcontroller.PowerpointController` or
:class:`~openlp.plugins.presentations.lib.pptviewcontroller.PptviewController`
for examples. for examples.
**Basic Attributes** **Basic Attributes**
@ -70,7 +75,7 @@ class PresentationController(object):
``alsosupports`` ``alsosupports``
Other file types the application can import, although not necessarily Other file types the application can import, although not necessarily
the first choice due to potential incompatibilities the first choice due to potential incompatibilities
**Hook Functions** **Hook Functions**
``kill()`` ``kill()``
@ -246,7 +251,7 @@ class PresentationDocument(object):
``presentation`` ``presentation``
The file name of the presentations to the run. The file name of the presentations to the run.
Returns False if the file could not be opened Returns False if the file could not be opened
""" """
return False return False
@ -387,7 +392,7 @@ class PresentationDocument(object):
if os.path.isfile(file): if os.path.isfile(file):
img = resize_image(file, 320, 240) img = resize_image(file, 320, 240)
img.save(self.get_thumbnail_path(idx, False)) img.save(self.get_thumbnail_path(idx, False))
def get_thumbnail_path(self, slide_no, check_exists): def get_thumbnail_path(self, slide_no, check_exists):
""" """
Returns an image path containing a preview for the requested slide Returns an image path containing a preview for the requested slide

View File

@ -24,10 +24,37 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################
"""
Forms in OpenLP are made up of two classes. One class holds all the graphical
elements, like buttons and lists, and the other class holds all the functional
code, like slots and loading and saving.
The first class, commonly known as the **Dialog** class, is typically named
``Ui_<name>Dialog``. It is a slightly modified version of the class that the
``pyuic4`` command produces from Qt4's .ui file. Typical modifications will be
converting most strings from "" to u'' and using OpenLP's ``translate()``
function for translating strings.
The second class, commonly known as the **Form** class, is typically named
``<name>Form``. This class is the one which is instantiated and used. It uses
dual inheritance to inherit from (usually) QtGui.QDialog and the Ui class
mentioned above, like so::
class AuthorsForm(QtGui.QDialog, Ui_AuthorsDialog):
def __init__(self, parent=None):
QtGui.QDialog.__init__(self, parent)
self.setupUi(self)
This allows OpenLP to use ``self.object`` for all the GUI elements while keeping
them separate from the functionality, so that it is easier to recreate the GUI
from the .ui files later if necessary.
"""
from authorsform import AuthorsForm from authorsform import AuthorsForm
from topicsform import TopicsForm from topicsform import TopicsForm
from songbookform import SongBookForm from songbookform import SongBookForm
from editverseform import EditVerseForm from editverseform import EditVerseForm
from editsongform import EditSongForm from editsongform import EditSongForm
from songmaintenanceform import SongMaintenanceForm from songmaintenanceform import SongMaintenanceForm
from songimportform import ImportWizardForm from songimportform import SongImportForm

Some files were not shown because too many files have changed in this diff Show More