HEAD
19
OpenLP.spec
@ -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'))
|
@ -17,7 +17,7 @@ import sys
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
sys.path.append(os.path.abspath(os.path.join('..', '..')))
|
||||
sys.path.insert(0, os.path.abspath(os.path.join('..', '..', '..')))
|
||||
|
||||
# -- General configuration -----------------------------------------------------
|
||||
|
||||
@ -39,7 +39,7 @@ master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
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
|
||||
# |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.
|
||||
version = '2.0'
|
||||
# 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
|
||||
# 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
|
||||
# "<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.
|
||||
#html_short_title = None
|
||||
@ -166,7 +166,7 @@ html_static_path = ['_static']
|
||||
#html_file_suffix = ''
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'OpenLPdoc'
|
||||
htmlhelp_basename = 'OpenLP-2.0-api'
|
||||
|
||||
|
||||
# -- Options for LaTeX output --------------------------------------------------
|
||||
@ -180,7 +180,7 @@ htmlhelp_basename = 'OpenLPdoc'
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title, author, documentclass [howto/manual]).
|
||||
latex_documents = [
|
||||
('index', 'OpenLP.tex', u'OpenLP Documentation',
|
||||
('index', 'OpenLP.tex', u'OpenLP 2.0 Developer API',
|
||||
u'Raoul Snyman', 'manual'),
|
||||
]
|
||||
|
@ -3,9 +3,13 @@
|
||||
:mod:`core` Module
|
||||
==================
|
||||
|
||||
.. automodule:: openlp.core
|
||||
:members:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
lib
|
||||
theme
|
||||
|
||||
ui
|
||||
utils
|
@ -1,7 +1,7 @@
|
||||
.. _core-lib:
|
||||
|
||||
:mod:`lib` Module
|
||||
=================
|
||||
Object Library
|
||||
==============
|
||||
|
||||
.. automodule:: openlp.core.lib
|
||||
:members:
|
||||
@ -60,12 +60,6 @@
|
||||
.. autoclass:: openlp.core.lib.settingstab.SettingsTab
|
||||
:members:
|
||||
|
||||
:mod:`ThemeXML`
|
||||
---------------
|
||||
|
||||
.. autoclass:: openlp.core.lib.themexmlhandler.ThemeXML
|
||||
:members:
|
||||
|
||||
:mod:`OpenLPToolbar`
|
||||
--------------------
|
||||
|
27
documentation/api/source/core/ui.rst
Normal 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:
|
7
documentation/api/source/core/utils.rst
Normal file
@ -0,0 +1,7 @@
|
||||
.. _core-utils:
|
||||
|
||||
Utilities
|
||||
=========
|
||||
|
||||
.. automodule:: openlp.core.utils
|
||||
:members:
|
@ -15,7 +15,6 @@ Contents:
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
openlp
|
||||
core/index
|
||||
plugins/index
|
||||
|
31
documentation/api/source/plugins/alerts.rst
Normal 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:
|
55
documentation/api/source/plugins/bibles.rst
Normal 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:
|
34
documentation/api/source/plugins/custom.rst
Normal 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:
|
22
documentation/api/source/plugins/images.rst
Normal 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:
|
20
documentation/api/source/plugins/index.rst
Normal file
@ -0,0 +1,20 @@
|
||||
.. _plugins-index:
|
||||
|
||||
Plugins
|
||||
=======
|
||||
|
||||
.. automodule:: openlp.plugins
|
||||
:members:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
songs
|
||||
bibles
|
||||
presentations
|
||||
media
|
||||
images
|
||||
custom
|
||||
remotes
|
||||
songusage
|
||||
alerts
|
22
documentation/api/source/plugins/media.rst
Normal 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:
|
40
documentation/api/source/plugins/presentations.rst
Normal 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:
|
19
documentation/api/source/plugins/remotes.rst
Normal 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:
|
103
documentation/api/source/plugins/songs.rst
Normal 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:
|
34
documentation/api/source/plugins/songusage.rst
Normal 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:
|
88
documentation/manual/Makefile
Normal file
@ -0,0 +1,88 @@
|
||||
# Makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
PAPER =
|
||||
|
||||
# Internal variables.
|
||||
PAPEROPT_a4 = -D latex_paper_size=a4
|
||||
PAPEROPT_letter = -D latex_paper_size=letter
|
||||
ALLSPHINXOPTS = -d build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
|
||||
|
||||
.PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest
|
||||
|
||||
help:
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
@echo " html to make standalone HTML files"
|
||||
@echo " dirhtml to make HTML files named index.html in directories"
|
||||
@echo " pickle to make pickle files"
|
||||
@echo " json to make JSON files"
|
||||
@echo " htmlhelp to make HTML files and a HTML help project"
|
||||
@echo " qthelp to make HTML files and a qthelp project"
|
||||
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
||||
@echo " changes to make an overview of all changed/added/deprecated items"
|
||||
@echo " linkcheck to check all external links for integrity"
|
||||
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
|
||||
|
||||
clean:
|
||||
-rm -rf build/*
|
||||
|
||||
html:
|
||||
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) build/html
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in build/html."
|
||||
|
||||
dirhtml:
|
||||
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) build/dirhtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in build/dirhtml."
|
||||
|
||||
pickle:
|
||||
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) build/pickle
|
||||
@echo
|
||||
@echo "Build finished; now you can process the pickle files."
|
||||
|
||||
json:
|
||||
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) build/json
|
||||
@echo
|
||||
@echo "Build finished; now you can process the JSON files."
|
||||
|
||||
htmlhelp:
|
||||
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) build/htmlhelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run HTML Help Workshop with the" \
|
||||
".hhp project file in build/htmlhelp."
|
||||
|
||||
qthelp:
|
||||
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) build/qthelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
|
||||
".qhcp project file in build/qthelp, like this:"
|
||||
@echo "# qcollectiongenerator build/qthelp/OpenLP.qhcp"
|
||||
@echo "To view the help file:"
|
||||
@echo "# assistant -collectionFile build/qthelp/OpenLP.qhc"
|
||||
|
||||
latex:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) build/latex
|
||||
@echo
|
||||
@echo "Build finished; the LaTeX files are in build/latex."
|
||||
@echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
|
||||
"run these through (pdf)latex."
|
||||
|
||||
changes:
|
||||
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) build/changes
|
||||
@echo
|
||||
@echo "The overview file is in build/changes."
|
||||
|
||||
linkcheck:
|
||||
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) build/linkcheck
|
||||
@echo
|
||||
@echo "Link check complete; look for any errors in the above output " \
|
||||
"or in build/linkcheck/output.txt."
|
||||
|
||||
doctest:
|
||||
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) build/doctest
|
||||
@echo "Testing of doctests in the sources finished, look at the " \
|
||||
"results in build/doctest/output.txt."
|
112
documentation/manual/make.bat
Normal file
@ -0,0 +1,112 @@
|
||||
@ECHO OFF
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
set SPHINXBUILD=sphinx-build
|
||||
set ALLSPHINXOPTS=-d build/doctrees %SPHINXOPTS% source
|
||||
if NOT "%PAPER%" == "" (
|
||||
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
|
||||
)
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
if "%1" == "help" (
|
||||
:help
|
||||
echo.Please use `make ^<target^>` where ^<target^> is one of
|
||||
echo. html to make standalone HTML files
|
||||
echo. dirhtml to make HTML files named index.html in directories
|
||||
echo. pickle to make pickle files
|
||||
echo. json to make JSON files
|
||||
echo. htmlhelp to make HTML files and a HTML help project
|
||||
echo. qthelp to make HTML files and a qthelp project
|
||||
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
|
||||
echo. changes to make an overview over all changed/added/deprecated items
|
||||
echo. linkcheck to check all external links for integrity
|
||||
echo. doctest to run all doctests embedded in the documentation if enabled
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "clean" (
|
||||
for /d %%i in (build\*) do rmdir /q /s %%i
|
||||
del /q /s build\*
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "html" (
|
||||
%SPHINXBUILD% -b html %ALLSPHINXOPTS% build/html
|
||||
echo.
|
||||
echo.Build finished. The HTML pages are in build/html.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "dirhtml" (
|
||||
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% build/dirhtml
|
||||
echo.
|
||||
echo.Build finished. The HTML pages are in build/dirhtml.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "pickle" (
|
||||
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% build/pickle
|
||||
echo.
|
||||
echo.Build finished; now you can process the pickle files.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "json" (
|
||||
%SPHINXBUILD% -b json %ALLSPHINXOPTS% build/json
|
||||
echo.
|
||||
echo.Build finished; now you can process the JSON files.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "htmlhelp" (
|
||||
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% build/htmlhelp
|
||||
echo.
|
||||
echo.Build finished; now you can run HTML Help Workshop with the ^
|
||||
.hhp project file in build/htmlhelp.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "qthelp" (
|
||||
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% build/qthelp
|
||||
echo.
|
||||
echo.Build finished; now you can run "qcollectiongenerator" with the ^
|
||||
.qhcp project file in build/qthelp, like this:
|
||||
echo.^> qcollectiongenerator build\qthelp\OpenLP.qhcp
|
||||
echo.To view the help file:
|
||||
echo.^> assistant -collectionFile build\qthelp\OpenLP.ghc
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "latex" (
|
||||
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% build/latex
|
||||
echo.
|
||||
echo.Build finished; the LaTeX files are in build/latex.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "changes" (
|
||||
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% build/changes
|
||||
echo.
|
||||
echo.The overview file is in build/changes.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "linkcheck" (
|
||||
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% build/linkcheck
|
||||
echo.
|
||||
echo.Link check complete; look for any errors in the above output ^
|
||||
or in build/linkcheck/output.txt.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "doctest" (
|
||||
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% build/doctest
|
||||
echo.
|
||||
echo.Testing of doctests in the sources finished, look at the ^
|
||||
results in build/doctest/output.txt.
|
||||
goto end
|
||||
)
|
||||
|
||||
:end
|
208
documentation/manual/source/conf.py
Normal 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}'
|
||||
}
|
180
documentation/manual/source/dualmonitors.rst
Normal 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.
|
70
documentation/manual/source/glossary.rst
Normal 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
|
24
documentation/manual/source/index.rst
Normal 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`
|
||||
|
46
documentation/manual/source/introduction.rst
Normal 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
|
BIN
documentation/manual/source/pics/dvi.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
documentation/manual/source/pics/gnome.png
Normal file
After Width: | Height: | Size: 33 KiB |
BIN
documentation/manual/source/pics/kdedisplay.png
Normal file
After Width: | Height: | Size: 64 KiB |
BIN
documentation/manual/source/pics/kdesystemsettings.png
Normal file
After Width: | Height: | Size: 112 KiB |
BIN
documentation/manual/source/pics/mainwindow.png
Normal file
After Width: | Height: | Size: 123 KiB |
BIN
documentation/manual/source/pics/mediamanager.png
Normal file
After Width: | Height: | Size: 104 KiB |
BIN
documentation/manual/source/pics/nvlinux1.png
Normal file
After Width: | Height: | Size: 140 KiB |
BIN
documentation/manual/source/pics/preview.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
documentation/manual/source/pics/servicemanager.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
documentation/manual/source/pics/slidecontroller.png
Normal file
After Width: | Height: | Size: 90 KiB |
BIN
documentation/manual/source/pics/thememanager.png
Normal file
After Width: | Height: | Size: 31 KiB |
BIN
documentation/manual/source/pics/twinview.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
documentation/manual/source/pics/vga.png
Normal file
After Width: | Height: | Size: 7.2 KiB |
BIN
documentation/manual/source/pics/vistadisplaysettings.png
Executable file
After Width: | Height: | Size: 51 KiB |
BIN
documentation/manual/source/pics/vistapersonalize.png
Executable file
After Width: | Height: | Size: 139 KiB |
BIN
documentation/manual/source/pics/winsevendisplay.png
Executable file
After Width: | Height: | Size: 155 KiB |
BIN
documentation/manual/source/pics/winsevenresolution.png
Executable file
After Width: | Height: | Size: 141 KiB |
BIN
documentation/manual/source/pics/xorgwrite.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
documentation/manual/source/pics/xpdisplaysettings.png
Normal file
After Width: | Height: | Size: 35 KiB |
@ -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:
|
||||
|
@ -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:
|
@ -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:
|
116
openlp.pyw
@ -30,6 +30,7 @@ import sys
|
||||
import logging
|
||||
from optparse import OptionParser
|
||||
from traceback import format_exception
|
||||
from subprocess import Popen, PIPE
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
@ -71,6 +72,84 @@ class OpenLP(QtGui.QApplication):
|
||||
"""
|
||||
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):
|
||||
#TODO needed for presentation exceptions
|
||||
return QtGui.QApplication.notify(self, obj, evt)
|
||||
@ -79,39 +158,7 @@ class OpenLP(QtGui.QApplication):
|
||||
"""
|
||||
Run the OpenLP application.
|
||||
"""
|
||||
#Load and store current Application 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()
|
||||
app_version = self._get_version()
|
||||
#provide a listener for widgets to reqest a screen update.
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
QtCore.SIGNAL(u'openlp_process_events'), self.processEvents)
|
||||
@ -172,6 +219,9 @@ def main():
|
||||
parser.add_option('-p', '--portable', dest='portable',
|
||||
action='store_true', help='Specify if this should be run as a '
|
||||
'portable app, off a USB flash drive (not implemented).')
|
||||
parser.add_option('-d', '--dev-version', dest='dev_version',
|
||||
action='store_true', help='Ignore the version file and pull the '
|
||||
'version directly from Bazaar')
|
||||
parser.add_option('-s', '--style', dest='style',
|
||||
help='Set the Qt4 style (passed directly to Qt4).')
|
||||
# Set up logging
|
||||
|
@ -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'protected':True})
|
||||
|
||||
# Image image_cache to stop regualar image resizing
|
||||
image_cache = {}
|
||||
|
||||
def translate(context, text, comment=None):
|
||||
"""
|
||||
A special shortcut method to wrap around the Qt4 translation functions.
|
||||
@ -223,16 +220,13 @@ def image_to_byte(image):
|
||||
``image``
|
||||
The image to converted.
|
||||
"""
|
||||
log.debug(u'image_to_byte')
|
||||
log.debug(u'image_to_byte - start')
|
||||
byte_array = QtCore.QByteArray()
|
||||
# use buffer to store pixmap into byteArray
|
||||
buffie = QtCore.QBuffer(byte_array)
|
||||
buffie.open(QtCore.QIODevice.WriteOnly)
|
||||
if isinstance(image, QtGui.QImage):
|
||||
pixmap = QtGui.QPixmap.fromImage(image)
|
||||
else:
|
||||
pixmap = QtGui.QPixmap(image)
|
||||
pixmap.save(buffie, "PNG")
|
||||
image.save(buffie, "PNG")
|
||||
log.debug(u'image_to_byte - end')
|
||||
# convert to base64 encoding so does not get missed!
|
||||
return byte_array.toBase64()
|
||||
|
||||
@ -253,26 +247,25 @@ def resize_image(image, width, height, background=QtCore.Qt.black):
|
||||
The background colour defaults to black.
|
||||
|
||||
"""
|
||||
log.debug(u'resize_image')
|
||||
preview = QtGui.QImage(image)
|
||||
log.debug(u'resize_image - start')
|
||||
if isinstance(image, QtGui.QImage):
|
||||
preview = image
|
||||
else:
|
||||
preview = QtGui.QImage(image)
|
||||
if not preview.isNull():
|
||||
# Only resize if different size
|
||||
if preview.width() == width and preview.height == height:
|
||||
return preview
|
||||
preview = preview.scaled(width, height, QtCore.Qt.KeepAspectRatio,
|
||||
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()
|
||||
realh = preview.height()
|
||||
# and move it to the centre of the preview space
|
||||
new_image = QtGui.QImage(width, height,
|
||||
QtGui.QImage.Format_ARGB32_Premultiplied)
|
||||
new_image.fill(background)
|
||||
painter = QtGui.QPainter(new_image)
|
||||
painter.fillRect(new_image.rect(), background)
|
||||
painter.drawImage((width - realw) / 2, (height - realh) / 2, preview)
|
||||
image_cache[image_cache_key] = new_image
|
||||
return new_image
|
||||
|
||||
def check_item_selected(list_widget, message):
|
||||
@ -312,6 +305,7 @@ def expand_tags(text):
|
||||
|
||||
from spelltextedit import SpellTextEdit
|
||||
from eventreceiver import Receiver
|
||||
from imagemanager import ImageManager
|
||||
from settingsmanager import SettingsManager
|
||||
from plugin import PluginStatus, StringContent, Plugin
|
||||
from pluginmanager import PluginManager
|
||||
|
@ -246,3 +246,10 @@ class Manager(object):
|
||||
self.session.rollback()
|
||||
log.exception(u'Failed to delete %s records', object_class.__name__)
|
||||
return False
|
||||
|
||||
def finalise(self):
|
||||
"""
|
||||
VACUUM the database on exit.
|
||||
"""
|
||||
engine = create_engine(self.db_url)
|
||||
engine.execute("vacuum")
|
||||
|
@ -55,14 +55,17 @@ body {
|
||||
background-color: black;
|
||||
display: none;
|
||||
}
|
||||
#image {
|
||||
#bgimage {
|
||||
z-index:1;
|
||||
}
|
||||
#video1 {
|
||||
#image {
|
||||
z-index:2;
|
||||
}
|
||||
#video1 {
|
||||
z-index:3;
|
||||
}
|
||||
#video2 {
|
||||
z-index:2;
|
||||
z-index:3;
|
||||
}
|
||||
#alert {
|
||||
position: absolute;
|
||||
@ -73,7 +76,7 @@ body {
|
||||
}
|
||||
#footer {
|
||||
position: absolute;
|
||||
z-index:5;
|
||||
z-index:6;
|
||||
%s
|
||||
}
|
||||
/* lyric css */
|
||||
@ -87,16 +90,16 @@ body {
|
||||
var transition = %s;
|
||||
|
||||
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.
|
||||
// But QtWebKit doesn't support this. Neither does it support the
|
||||
// onended event, hence the setInterval()
|
||||
// In addition, setting the currentTime attribute to zero to restart
|
||||
// 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!
|
||||
//
|
||||
// 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/
|
||||
// preloading one, and toggle between the two when looping.
|
||||
|
||||
@ -112,7 +115,7 @@ body {
|
||||
vid2.volume = volume;
|
||||
}
|
||||
switch(state){
|
||||
case 'init':
|
||||
case 'init':
|
||||
vid.src = path;
|
||||
vid2.src = path;
|
||||
if(loop == null) loop = false;
|
||||
@ -129,8 +132,8 @@ body {
|
||||
vid.style.visibility = 'visible';
|
||||
if(vid.looping){
|
||||
video_timer = setInterval(
|
||||
function() {
|
||||
show_video('poll');
|
||||
function() {
|
||||
show_video('poll');
|
||||
}, 200);
|
||||
}
|
||||
break;
|
||||
@ -294,7 +297,8 @@ body {
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<img id="image" class="size" %s />
|
||||
<img id="bgimage" class="size" %s />
|
||||
<img id="image" class="size" style="display:none" />
|
||||
<video id="video1" class="size" style="visibility:hidden" autobuffer preload>
|
||||
</video>
|
||||
<video id="video2" class="size" style="visibility:hidden" autobuffer preload>
|
||||
@ -324,6 +328,7 @@ def build_html(item, screen, alert, islive):
|
||||
height = screen[u'size'].height()
|
||||
theme = item.themedata
|
||||
webkitvers = webkit_version()
|
||||
# Image generated and poked in
|
||||
if item.bg_image_bytes:
|
||||
image = u'src="data:image/png;base64,%s"' % item.bg_image_bytes
|
||||
else:
|
||||
@ -397,7 +402,7 @@ def build_lyrics_css(item, webkitvers):
|
||||
"""
|
||||
style = """
|
||||
.lyricstable {
|
||||
z-index:4;
|
||||
z-index:5;
|
||||
position: absolute;
|
||||
display: table;
|
||||
%s
|
||||
@ -451,7 +456,7 @@ def build_lyrics_css(item, webkitvers):
|
||||
if theme.display_outline and webkitvers < 534.3:
|
||||
shadow = u'padding-left: %spx; padding-top: %spx;' % \
|
||||
(int(theme.display_shadow_size) +
|
||||
(int(theme.display_outline_size) * 2),
|
||||
(int(theme.display_outline_size) * 2),
|
||||
theme.display_shadow_size)
|
||||
shadow += build_lyrics_outline_css(theme, True)
|
||||
else:
|
||||
|
158
openlp/core/lib/imagemanager.py
Normal 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
|
@ -51,11 +51,6 @@ class Renderer(object):
|
||||
self._rect = None
|
||||
self.theme_name = 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):
|
||||
"""
|
||||
@ -66,14 +61,7 @@ class Renderer(object):
|
||||
"""
|
||||
log.debug(u'set 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
|
||||
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):
|
||||
"""
|
||||
@ -105,39 +93,6 @@ class Renderer(object):
|
||||
(build_lyrics_format_css(self._theme, self.page_width,
|
||||
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):
|
||||
"""
|
||||
Figure out how much text can appear on a slide, using the current
|
||||
|
@ -28,7 +28,7 @@ import logging
|
||||
|
||||
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
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
@ -56,7 +56,9 @@ class RenderManager(object):
|
||||
"""
|
||||
log.debug(u'Initilisation started')
|
||||
self.screens = screens
|
||||
self.image_manager = ImageManager()
|
||||
self.display = MainDisplay(self, screens, False)
|
||||
self.display.imageManager = self.image_manager
|
||||
self.display.setup()
|
||||
self.theme_manager = theme_manager
|
||||
self.renderer = Renderer()
|
||||
@ -75,9 +77,11 @@ class RenderManager(object):
|
||||
log.debug(u'Update Display')
|
||||
self.calculate_default(self.screens.current[u'size'])
|
||||
self.display = MainDisplay(self, self.screens, False)
|
||||
self.display.imageManager = self.image_manager
|
||||
self.display.setup()
|
||||
self.renderer.bg_frame = None
|
||||
self.themedata = None
|
||||
self.image_manager.update_display(self.width, self.height)
|
||||
|
||||
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.renderer.set_theme(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
|
||||
|
||||
def build_text_rectangle(self, theme):
|
||||
@ -211,7 +216,7 @@ class RenderManager(object):
|
||||
serviceItem.raw_footer = footer
|
||||
serviceItem.render(True)
|
||||
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)
|
||||
# Reset the real screen size for subsequent render requests
|
||||
self.calculate_default(self.screens.current[u'size'])
|
||||
|
@ -30,7 +30,6 @@ type and capability of an item.
|
||||
|
||||
import logging
|
||||
import os
|
||||
import time
|
||||
import uuid
|
||||
|
||||
from PyQt4 import QtGui
|
||||
@ -155,17 +154,15 @@ class ServiceItem(object):
|
||||
line_break = True
|
||||
if self.is_capable(ItemCapabilities.NoLineBreaks):
|
||||
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:
|
||||
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:
|
||||
before = time.time()
|
||||
formatted = self.render_manager \
|
||||
.format_slide(slide[u'raw_slide'], line_break)
|
||||
for page in formatted:
|
||||
@ -174,13 +171,8 @@ class ServiceItem(object):
|
||||
u'text': clean_tags(page.rstrip()),
|
||||
u'html': expand_tags(page.rstrip()),
|
||||
u'verseTag': slide[u'verseTag'] })
|
||||
log.log(15, u'Formatting took %4s' % (time.time() - before))
|
||||
elif self.service_item_type == ServiceItemType.Image:
|
||||
self.themedata = self.render_manager.global_theme_data
|
||||
for slide in self._raw_frames:
|
||||
slide[u'image'] = resize_image(slide[u'image'],
|
||||
self.render_manager.width, self.render_manager.height)
|
||||
elif self.service_item_type == ServiceItemType.Command:
|
||||
elif self.service_item_type == ServiceItemType.Image or \
|
||||
self.service_item_type == ServiceItemType.Command:
|
||||
pass
|
||||
else:
|
||||
log.error(u'Invalid value renderer :%s' % self.service_item_type)
|
||||
@ -193,7 +185,7 @@ class ServiceItem(object):
|
||||
else:
|
||||
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.
|
||||
|
||||
@ -202,13 +194,11 @@ class ServiceItem(object):
|
||||
|
||||
``title``
|
||||
A title for the slide in the service item.
|
||||
|
||||
``image``
|
||||
The actual image file name.
|
||||
"""
|
||||
self.service_item_type = ServiceItemType.Image
|
||||
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()
|
||||
|
||||
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._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()
|
||||
|
||||
def get_service_repr(self):
|
||||
@ -311,8 +301,7 @@ class ServiceItem(object):
|
||||
elif self.service_item_type == ServiceItemType.Image:
|
||||
for text_image in serviceitem[u'serviceitem'][u'data']:
|
||||
filename = os.path.join(path, text_image)
|
||||
real_image = QtGui.QImage(unicode(filename))
|
||||
self.add_from_image(path, text_image, real_image)
|
||||
self.add_from_image(filename, text_image)
|
||||
elif self.service_item_type == ServiceItemType.Command:
|
||||
for text_image in serviceitem[u'serviceitem'][u'data']:
|
||||
filename = os.path.join(path, text_image[u'title'])
|
||||
@ -388,9 +377,11 @@ class ServiceItem(object):
|
||||
renders it if required.
|
||||
"""
|
||||
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:
|
||||
return self._raw_frames[row][u'image'], u''
|
||||
return self._raw_frames[row][u'image']
|
||||
|
||||
def get_frame_title(self, row=0):
|
||||
"""
|
||||
@ -400,6 +391,6 @@ class ServiceItem(object):
|
||||
|
||||
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']
|
||||
|
@ -25,7 +25,6 @@
|
||||
###############################################################################
|
||||
|
||||
import re
|
||||
import sys
|
||||
try:
|
||||
import enchant
|
||||
from enchant import DictNotFoundError
|
||||
@ -37,7 +36,7 @@ except ImportError:
|
||||
# http://john.nachtimwald.com/2009/08/22/qplaintextedit-with-in-line-spell-check/
|
||||
|
||||
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):
|
||||
def __init__(self, *args):
|
||||
|
@ -87,12 +87,12 @@ class ThemeLevel(object):
|
||||
Service = 2
|
||||
Song = 3
|
||||
|
||||
boolean_list = [u'italics', u'override', u'outline', u'shadow', \
|
||||
u'slide_transition']
|
||||
boolean_list = [u'italics', u'override', u'outline', u'shadow',
|
||||
u'slide_transition']
|
||||
|
||||
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'vertical_align', u'wrap_style' ]
|
||||
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'vertical_align', u'wrap_style']
|
||||
|
||||
class ThemeXML(object):
|
||||
"""
|
||||
|
@ -39,7 +39,6 @@ class HideMode(object):
|
||||
|
||||
from filerenameform import FileRenameForm
|
||||
from maindisplay import MainDisplay
|
||||
from slidecontroller import HideMode
|
||||
from servicenoteform import ServiceNoteForm
|
||||
from serviceitemeditform import ServiceItemEditForm
|
||||
from screen import ScreenList
|
||||
|
@ -82,6 +82,9 @@ class AdvancedTab(SettingsTab):
|
||||
self.doubleClickLiveCheckBox.setObjectName(u'doubleClickLiveCheckBox')
|
||||
self.uiLayout.addWidget(self.doubleClickLiveCheckBox)
|
||||
self.leftLayout.addWidget(self.uiGroupBox)
|
||||
self.expandServiceItemCheckBox = QtGui.QCheckBox(self.uiGroupBox)
|
||||
self.expandServiceItemCheckBox.setObjectName(u'expandServiceItemCheckBox')
|
||||
self.uiLayout.addWidget(self.expandServiceItemCheckBox)
|
||||
# self.sharedDirGroupBox = QtGui.QGroupBox(self.leftWidget)
|
||||
# self.sharedDirGroupBox.setObjectName(u'sharedDirGroupBox')
|
||||
# self.sharedDirGroupBox.setGeometry(QtCore.QRect(0, 65, 500, 85))
|
||||
@ -140,6 +143,8 @@ class AdvancedTab(SettingsTab):
|
||||
'Remember active media manager tab on startup'))
|
||||
self.doubleClickLiveCheckBox.setText(translate('OpenLP.AdvancedTab',
|
||||
'Double-click to send items straight to live (requires restart)'))
|
||||
self.expandServiceItemCheckBox.setText(translate('OpenLP.AdvancedTab',
|
||||
'Expand new service items on creation'))
|
||||
# self.sharedDirGroupBox.setTitle(
|
||||
# translate('AdvancedTab', 'Central Data Store'))
|
||||
# self.sharedCheckBox.setText(
|
||||
@ -167,6 +172,9 @@ class AdvancedTab(SettingsTab):
|
||||
self.doubleClickLiveCheckBox.setChecked(
|
||||
settings.value(u'double click live',
|
||||
QtCore.QVariant(False)).toBool())
|
||||
self.expandServiceItemCheckBox.setChecked(
|
||||
settings.value(u'expand service item',
|
||||
QtCore.QVariant(False)).toBool())
|
||||
settings.endGroup()
|
||||
|
||||
def save(self):
|
||||
@ -181,6 +189,8 @@ class AdvancedTab(SettingsTab):
|
||||
QtCore.QVariant(self.mediaPluginCheckBox.isChecked()))
|
||||
settings.setValue(u'double click live',
|
||||
QtCore.QVariant(self.doubleClickLiveCheckBox.isChecked()))
|
||||
settings.setValue(u'expand service item',
|
||||
QtCore.QVariant(self.expandServiceItemCheckBox.isChecked()))
|
||||
settings.endGroup()
|
||||
|
||||
def onSharedCheckBoxChanged(self, checked):
|
||||
|
@ -24,7 +24,7 @@
|
||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||
###############################################################################
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
from PyQt4 import QtGui
|
||||
|
||||
from exceptiondialog import Ui_ExceptionDialog
|
||||
|
||||
|
@ -27,7 +27,6 @@
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
from filerenamedialog import Ui_FileRenameDialog
|
||||
from openlp.core.lib import translate
|
||||
|
||||
class FileRenameForm(QtGui.QDialog, Ui_FileRenameDialog):
|
||||
"""
|
||||
|
@ -90,6 +90,9 @@ class DisplayWidget(QtGui.QGraphicsView):
|
||||
event.ignore()
|
||||
|
||||
class MainDisplay(DisplayWidget):
|
||||
"""
|
||||
This is the display screen.
|
||||
"""
|
||||
|
||||
def __init__(self, parent, screens, live):
|
||||
DisplayWidget.__init__(self, live, parent=None)
|
||||
@ -114,21 +117,23 @@ class MainDisplay(DisplayWidget):
|
||||
"""
|
||||
log.debug(u'Setup live = %s for %s ' % (self.isLive,
|
||||
self.screens.monitor_number))
|
||||
self.usePhonon = QtCore.QSettings().value(
|
||||
u'media/use phonon', QtCore.QVariant(True)).toBool()
|
||||
self.phononActive = False
|
||||
self.screen = self.screens.current
|
||||
self.setVisible(False)
|
||||
self.setGeometry(self.screen[u'size'])
|
||||
try:
|
||||
self.webView = QtWebKit.QGraphicsWebView()
|
||||
self.scene = QtGui.QGraphicsScene(self)
|
||||
self.setScene(self.scene)
|
||||
self.scene.addItem(self.webView)
|
||||
self.webView.setGeometry(QtCore.QRectF(0, 0,
|
||||
self.screen[u'size'].width(), self.screen[u'size'].height()))
|
||||
except AttributeError:
|
||||
# QGraphicsWebView a recent addition, so fall back to QWebView
|
||||
self.webView = QtWebKit.QWebView(self)
|
||||
self.webView.setGeometry(0, 0,
|
||||
self.screen[u'size'].width(), self.screen[u'size'].height())
|
||||
self.videoWidget = Phonon.VideoWidget(self)
|
||||
self.videoWidget.setVisible(False)
|
||||
self.videoWidget.setGeometry(QtCore.QRect(0, 0,
|
||||
self.screen[u'size'].width(), self.screen[u'size'].height()))
|
||||
self.mediaObject = Phonon.MediaObject(self)
|
||||
self.audio = Phonon.AudioOutput(Phonon.VideoCategory, self.mediaObject)
|
||||
Phonon.createPath(self.mediaObject, self.videoWidget)
|
||||
Phonon.createPath(self.mediaObject, self.audio)
|
||||
self.webView = QtWebKit.QWebView(self)
|
||||
self.webView.setGeometry(0, 0,
|
||||
self.screen[u'size'].width(), self.screen[u'size'].height())
|
||||
self.page = self.webView.page()
|
||||
self.frame = self.page.mainFrame()
|
||||
QtCore.QObject.connect(self.webView,
|
||||
@ -182,7 +187,7 @@ class MainDisplay(DisplayWidget):
|
||||
`slide`
|
||||
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.
|
||||
while not self.loaded:
|
||||
Receiver.send_message(u'openlp_process_events')
|
||||
@ -197,9 +202,9 @@ class MainDisplay(DisplayWidget):
|
||||
`slide`
|
||||
The slide text to be displayed
|
||||
"""
|
||||
log.debug(u'alert')
|
||||
log.debug(u'alert to display')
|
||||
if self.height() != self.screen[u'size'].height() \
|
||||
or not self.isVisible():
|
||||
or not self.isVisible() or self.videoWidget.isVisible():
|
||||
shrink = True
|
||||
else:
|
||||
shrink = False
|
||||
@ -208,14 +213,26 @@ class MainDisplay(DisplayWidget):
|
||||
u'top' if shrink else u'')
|
||||
height = self.frame.evaluateJavaScript(js)
|
||||
if shrink:
|
||||
if text:
|
||||
self.resize(self.width(), int(height.toString()))
|
||||
self.setVisible(True)
|
||||
if self.phononActive:
|
||||
shrinkItem = self.webView
|
||||
else:
|
||||
self.setGeometry(self.screen[u'size'])
|
||||
self.setVisible(False)
|
||||
shrinkItem = self
|
||||
if text:
|
||||
shrinkItem.resize(self.width(), int(height.toString()))
|
||||
shrinkItem.setVisible(True)
|
||||
else:
|
||||
shrinkItem.setVisible(False)
|
||||
shrinkItem.resize(self.screen[u'size'].width(),
|
||||
self.screen[u'size'].height())
|
||||
|
||||
def image(self, image):
|
||||
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
|
||||
bytestream on route.
|
||||
@ -223,25 +240,21 @@ class MainDisplay(DisplayWidget):
|
||||
`Image`
|
||||
The Image to be displayed can be QImage or QPixmap
|
||||
"""
|
||||
log.debug(u'image')
|
||||
image = resize_image(image, self.screen[u'size'].width(),
|
||||
self.screen[u'size'].height())
|
||||
log.debug(u'image to display')
|
||||
image = self.imageManager.get_image_bytes(name)
|
||||
self.resetVideo()
|
||||
self.displayImage(image)
|
||||
# show screen
|
||||
if self.isLive:
|
||||
self.setVisible(True)
|
||||
return self.preview()
|
||||
|
||||
def displayImage(self, image):
|
||||
"""
|
||||
Display an image, as is.
|
||||
"""
|
||||
if image:
|
||||
if isinstance(image, QtGui.QImage):
|
||||
js = u'show_image("data:image/png;base64,%s");' % \
|
||||
image_to_byte(image)
|
||||
else:
|
||||
js = u'show_image("data:image/png;base64,%s");' % image
|
||||
js = u'show_image("data:image/png;base64,%s");' % image
|
||||
else:
|
||||
js = u'show_image("");'
|
||||
self.frame.evaluateJavaScript(js)
|
||||
@ -259,14 +272,24 @@ class MainDisplay(DisplayWidget):
|
||||
Used after Video plugin has changed the background
|
||||
"""
|
||||
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):
|
||||
"""
|
||||
Responds to the request to play a loaded video
|
||||
"""
|
||||
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
|
||||
if self.isLive:
|
||||
self.setVisible(True)
|
||||
@ -276,32 +299,54 @@ class MainDisplay(DisplayWidget):
|
||||
Responds to the request to pause a loaded video
|
||||
"""
|
||||
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):
|
||||
"""
|
||||
Responds to the request to stop a loaded video
|
||||
"""
|
||||
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):
|
||||
"""
|
||||
Changes the volume of a running video
|
||||
"""
|
||||
log.debug(u'videoVolume %d' % volume)
|
||||
self.frame.evaluateJavaScript(u'show_video(null, null, %s);' %
|
||||
str(float(volume)/float(10)))
|
||||
vol = 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
|
||||
"""
|
||||
log.debug(u'video')
|
||||
self.loaded = True
|
||||
js = u'show_video("init", "%s", %s, true); show_video("play");' % \
|
||||
(videoPath.replace(u'\\', u'\\\\'), str(float(volume)/float(10)))
|
||||
self.frame.evaluateJavaScript(js)
|
||||
vol = float(volume)/float(10)
|
||||
if isBackground or not self.usePhonon:
|
||||
js = u'show_video("init", "%s", %s, true); show_video("play");' % \
|
||||
(videoPath.replace(u'\\', u'\\\\'), \
|
||||
str(vol))
|
||||
self.frame.evaluateJavaScript(js)
|
||||
else:
|
||||
self.phononActive = True
|
||||
self.mediaObject.stop()
|
||||
self.mediaObject.clearQueue()
|
||||
self.mediaObject.setCurrentSource(Phonon.MediaSource(videoPath))
|
||||
self.mediaObject.play()
|
||||
self.webView.setVisible(False)
|
||||
self.videoWidget.setVisible(True)
|
||||
self.audio.setVolume(vol)
|
||||
return self.preview()
|
||||
|
||||
def isLoaded(self):
|
||||
@ -356,6 +401,9 @@ class MainDisplay(DisplayWidget):
|
||||
self.loaded = False
|
||||
self.initialFrame = False
|
||||
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,
|
||||
self.isLive)
|
||||
log.debug(u'buildHtml - pre setHtml')
|
||||
@ -382,6 +430,8 @@ class MainDisplay(DisplayWidget):
|
||||
Store the images so they can be replaced when required
|
||||
"""
|
||||
log.debug(u'hideDisplay mode = %d', mode)
|
||||
if self.phononActive:
|
||||
self.videoPause()
|
||||
if mode == HideMode.Screen:
|
||||
self.frame.evaluateJavaScript(u'show_blank("desktop");')
|
||||
self.setVisible(False)
|
||||
@ -389,8 +439,11 @@ class MainDisplay(DisplayWidget):
|
||||
self.frame.evaluateJavaScript(u'show_blank("black");')
|
||||
else:
|
||||
self.frame.evaluateJavaScript(u'show_blank("theme");')
|
||||
if mode != HideMode.Screen and self.isHidden():
|
||||
self.setVisible(True)
|
||||
if mode != HideMode.Screen:
|
||||
if self.isHidden():
|
||||
self.setVisible(True)
|
||||
if self.phononActive:
|
||||
self.webView.setVisible(True)
|
||||
self.hide_mode = mode
|
||||
|
||||
def showDisplay(self):
|
||||
@ -403,6 +456,9 @@ class MainDisplay(DisplayWidget):
|
||||
self.frame.evaluateJavaScript('show_blank("show");')
|
||||
if self.isHidden():
|
||||
self.setVisible(True)
|
||||
if self.phononActive:
|
||||
self.webView.setVisible(False)
|
||||
self.videoPlay()
|
||||
# Trigger actions when display is active again
|
||||
Receiver.send_message(u'maindisplay_active')
|
||||
self.hide_mode = None
|
||||
@ -484,3 +540,4 @@ class AudioPlayer(QtCore.QObject):
|
||||
"""
|
||||
log.debug(u'AudioPlayer Reached end of media playlist')
|
||||
self.mediaObject.clearQueue()
|
||||
|
||||
|
@ -824,7 +824,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
|
||||
QtGui.QMessageBox.Save),
|
||||
QtGui.QMessageBox.Save)
|
||||
if ret == QtGui.QMessageBox.Save:
|
||||
self.ServiceManagerContents.onSaveService()
|
||||
self.ServiceManagerContents.onSaveService(True)
|
||||
self.cleanUp()
|
||||
event.accept()
|
||||
elif ret == QtGui.QMessageBox.Discard:
|
||||
|
@ -25,6 +25,7 @@
|
||||
###############################################################################
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
from openlp.core.lib import translate
|
||||
|
||||
class Ui_ServiceItemEditDialog(object):
|
||||
@ -44,16 +45,26 @@ class Ui_ServiceItemEditDialog(object):
|
||||
self.topLayout.addWidget(self.listWidget)
|
||||
self.buttonLayout = QtGui.QVBoxLayout()
|
||||
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.setObjectName(u'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.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.buttonLayout.addWidget(self.downButton)
|
||||
self.topLayout.addLayout(self.buttonLayout)
|
||||
@ -70,7 +81,5 @@ class Ui_ServiceItemEditDialog(object):
|
||||
def retranslateUi(self, serviceItemEditDialog):
|
||||
serviceItemEditDialog.setWindowTitle(
|
||||
translate('OpenLP.ServiceItemEditForm', 'Reorder Service Item'))
|
||||
self.upButton.setText(translate('OpenLP.ServiceItemEditForm', 'Up'))
|
||||
self.deleteButton.setText(translate('OpenLP.ServiceItemEditForm',
|
||||
'Delete'))
|
||||
self.downButton.setText(translate('OpenLP.ServiceItemEditForm', 'Down'))
|
||||
|
@ -107,6 +107,7 @@ class ServiceManager(QtGui.QWidget):
|
||||
self.serviceName = u''
|
||||
self.suffixes = []
|
||||
self.droppos = 0
|
||||
self.expandTabs = False
|
||||
#is a new service and has not been saved
|
||||
self.isNew = True
|
||||
self.serviceNoteForm = ServiceNoteForm(self.parent)
|
||||
@ -199,6 +200,19 @@ class ServiceManager(QtGui.QWidget):
|
||||
translate('OpenLP.ServiceManager',
|
||||
'Delete the selected item from the service.'),
|
||||
self.onDeleteFromService)
|
||||
self.orderToolbar.addSeparator()
|
||||
self.orderToolbar.addToolbarButton(
|
||||
translate('OpenLP.ServiceManager', '&Expand all'),
|
||||
u':/services/service_top.png',
|
||||
translate('OpenLP.ServiceManager',
|
||||
'Expand all the service items.'),
|
||||
self.onExpandAll)
|
||||
self.orderToolbar.addToolbarButton(
|
||||
translate('OpenLP.ServiceManager', '&Collapse all'),
|
||||
u':/services/service_bottom.png',
|
||||
translate('OpenLP.ServiceManager',
|
||||
'Collapse all the service items.'),
|
||||
self.onCollapseAll)
|
||||
self.layout.addWidget(self.orderToolbar)
|
||||
# Connect up our signals and slots
|
||||
QtCore.QObject.connect(self.themeComboBox,
|
||||
@ -220,7 +234,7 @@ class ServiceManager(QtGui.QWidget):
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
QtCore.SIGNAL(u'servicemanager_list_request'), self.listRequest)
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
QtCore.SIGNAL(u'config_updated'), self.regenerateServiceItems)
|
||||
QtCore.SIGNAL(u'config_updated'), self.configUpdated)
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
QtCore.SIGNAL(u'theme_update_global'), self.themeChange)
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
@ -265,6 +279,17 @@ class ServiceManager(QtGui.QWidget):
|
||||
self.themeMenu = QtGui.QMenu(
|
||||
translate('OpenLP.ServiceManager', '&Change Item Theme'))
|
||||
self.menu.addMenu(self.themeMenu)
|
||||
self.configUpdated(True)
|
||||
|
||||
def configUpdated(self, firstTime=False):
|
||||
"""
|
||||
Triggered when Config dialog is updated.
|
||||
"""
|
||||
self.expandTabs = QtCore.QSettings().value(
|
||||
u'advanced/expand service item',
|
||||
QtCore.QVariant(u'False')).toBool()
|
||||
if not firstTime:
|
||||
self.regenerateServiceItems()
|
||||
|
||||
def supportedSuffixes(self, suffix):
|
||||
self.suffixes.append(suffix)
|
||||
@ -321,7 +346,7 @@ class ServiceManager(QtGui.QWidget):
|
||||
self.serviceItems[item][u'service_item'])
|
||||
if self.serviceItemEditForm.exec_():
|
||||
self.addServiceItem(self.serviceItemEditForm.getServiceItem(),
|
||||
replace=True)
|
||||
replace=True, expand=self.serviceItems[item][u'expanded'])
|
||||
|
||||
def nextItem(self):
|
||||
"""
|
||||
@ -423,6 +448,14 @@ class ServiceManager(QtGui.QWidget):
|
||||
if setSelected:
|
||||
firstItem.setSelected(True)
|
||||
|
||||
def onCollapseAll(self):
|
||||
"""
|
||||
Collapse all the service items
|
||||
"""
|
||||
for item in self.serviceItems:
|
||||
item[u'expanded'] = False
|
||||
self.regenerateServiceItems()
|
||||
|
||||
def collapsed(self, item):
|
||||
"""
|
||||
Record if an item is collapsed
|
||||
@ -431,6 +464,14 @@ class ServiceManager(QtGui.QWidget):
|
||||
pos = item.data(0, QtCore.Qt.UserRole).toInt()[0]
|
||||
self.serviceItems[pos -1 ][u'expanded'] = False
|
||||
|
||||
def onExpandAll(self):
|
||||
"""
|
||||
Collapse all the service items
|
||||
"""
|
||||
for item in self.serviceItems:
|
||||
item[u'expanded'] = True
|
||||
self.regenerateServiceItems()
|
||||
|
||||
def expanded(self, item):
|
||||
"""
|
||||
Record if an item is collapsed
|
||||
@ -528,12 +569,12 @@ class ServiceManager(QtGui.QWidget):
|
||||
Used when moving items as the move takes place in supporting array,
|
||||
and when regenerating all the items due to theme changes
|
||||
"""
|
||||
#Correct order of items in array
|
||||
# Correct order of items in array
|
||||
count = 1
|
||||
for item in self.serviceItems:
|
||||
item[u'order'] = count
|
||||
count += 1
|
||||
#Repaint the screen
|
||||
# Repaint the screen
|
||||
self.serviceManagerList.clear()
|
||||
for itemcount, item in enumerate(self.serviceItems):
|
||||
serviceitem = item[u'service_item']
|
||||
@ -609,9 +650,12 @@ class ServiceManager(QtGui.QWidget):
|
||||
.get_service_repr()})
|
||||
if item[u'service_item'].uses_file():
|
||||
for frame in item[u'service_item'].get_frames():
|
||||
path_from = unicode(os.path.join(
|
||||
frame[u'path'],
|
||||
frame[u'title']))
|
||||
if item[u'service_item'].is_image():
|
||||
path_from = frame[u'path']
|
||||
else:
|
||||
path_from = unicode(os.path.join(
|
||||
frame[u'path'],
|
||||
frame[u'title']))
|
||||
# On write a file once
|
||||
if not path_from in write_list:
|
||||
write_list.append(path_from)
|
||||
@ -805,7 +849,7 @@ class ServiceManager(QtGui.QWidget):
|
||||
self.isNew = True
|
||||
for item in tempServiceItems:
|
||||
self.addServiceItem(
|
||||
item[u'service_item'], False, item[u'expanded'])
|
||||
item[u'service_item'], False, expand=item[u'expanded'])
|
||||
# Set to False as items may have changed rendering
|
||||
# does not impact the saved song so True may also be valid
|
||||
self.parent.serviceChanged(False, self.serviceName)
|
||||
@ -834,14 +878,19 @@ class ServiceManager(QtGui.QWidget):
|
||||
self.parent.LiveController.replaceServiceManagerItem(newItem)
|
||||
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
|
||||
|
||||
``item``
|
||||
Service Item to be added
|
||||
|
||||
``expand``
|
||||
Override the default expand settings. (Tristate)
|
||||
"""
|
||||
log.debug(u'addServiceItem')
|
||||
if expand == None:
|
||||
expand = self.expandTabs
|
||||
sitem = self.findServiceItem()[0]
|
||||
item.render()
|
||||
if replace:
|
||||
|
@ -26,6 +26,7 @@
|
||||
|
||||
import logging
|
||||
import os
|
||||
import time
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
from PyQt4.phonon import Phonon
|
||||
@ -179,23 +180,23 @@ class SlideController(QtGui.QWidget):
|
||||
self.HideMenu.setMenu(QtGui.QMenu(
|
||||
translate('OpenLP.SlideController', 'Hide'), self.Toolbar))
|
||||
self.BlankScreen = QtGui.QAction(QtGui.QIcon(
|
||||
u':/slides/slide_blank.png'),
|
||||
translate('OpenLP.SlideController',
|
||||
u':/slides/slide_blank.png'),
|
||||
translate('OpenLP.SlideController',
|
||||
'Blank Screen'), self.HideMenu)
|
||||
self.BlankScreen.setCheckable(True)
|
||||
QtCore.QObject.connect(self.BlankScreen,
|
||||
QtCore.SIGNAL("triggered(bool)"), self.onBlankDisplay)
|
||||
self.ThemeScreen = QtGui.QAction(QtGui.QIcon(
|
||||
u':/slides/slide_theme.png'),
|
||||
translate('OpenLP.SlideController',
|
||||
u':/slides/slide_theme.png'),
|
||||
translate('OpenLP.SlideController',
|
||||
'Blank to Theme'), self.HideMenu)
|
||||
self.ThemeScreen.setCheckable(True)
|
||||
QtCore.QObject.connect(self.ThemeScreen,
|
||||
QtCore.SIGNAL("triggered(bool)"), self.onThemeDisplay)
|
||||
if self.screens.display_count > 1:
|
||||
self.DesktopScreen = QtGui.QAction(QtGui.QIcon(
|
||||
u':/slides/slide_desktop.png'),
|
||||
translate('OpenLP.SlideController',
|
||||
u':/slides/slide_desktop.png'),
|
||||
translate('OpenLP.SlideController',
|
||||
'Show Desktop'), self.HideMenu)
|
||||
self.DesktopScreen.setCheckable(True)
|
||||
QtCore.QObject.connect(self.DesktopScreen,
|
||||
@ -214,7 +215,7 @@ class SlideController(QtGui.QWidget):
|
||||
self.Toolbar.addToolbarSeparator(u'Close Separator')
|
||||
self.Toolbar.addToolbarButton(
|
||||
u'Edit Song', u':/general/general_edit.png',
|
||||
translate('OpenLP.SlideController',
|
||||
translate('OpenLP.SlideController',
|
||||
'Edit and reload song preview'),
|
||||
self.onEditSong)
|
||||
if isLive:
|
||||
@ -400,6 +401,7 @@ class SlideController(QtGui.QWidget):
|
||||
log.debug(u'screenSizeChanged live = %s' % self.isLive)
|
||||
# rebuild display as screen size changed
|
||||
self.display = MainDisplay(self, self.screens, self.isLive)
|
||||
self.display.imageManager = self.parent.RenderManager.image_manager
|
||||
self.display.alertTab = self.alertTab
|
||||
self.ratio = float(self.screens.current[u'size'].width()) / \
|
||||
float(self.screens.current[u'size'].height())
|
||||
@ -543,7 +545,7 @@ class SlideController(QtGui.QWidget):
|
||||
Receiver.send_message(u'%s_stop' %
|
||||
self.serviceItem.name.lower(), [serviceItem, self.isLive])
|
||||
if self.serviceItem.is_media():
|
||||
self.onMediaStop()
|
||||
self.onMediaClose()
|
||||
if self.isLive:
|
||||
blanked = self.BlankScreen.isChecked()
|
||||
else:
|
||||
@ -584,11 +586,15 @@ class SlideController(QtGui.QWidget):
|
||||
else:
|
||||
label = QtGui.QLabel()
|
||||
label.setMargin(4)
|
||||
pixmap = resize_image(frame[u'image'],
|
||||
self.parent.RenderManager.width,
|
||||
self.parent.RenderManager.height)
|
||||
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)
|
||||
slideHeight = width * self.parent.RenderManager.screen_ratio
|
||||
row += 1
|
||||
@ -779,15 +785,12 @@ class SlideController(QtGui.QWidget):
|
||||
[self.serviceItem, self.isLive, row])
|
||||
self.updatePreview()
|
||||
else:
|
||||
frame, raw_html = self.serviceItem.get_rendered_frame(row)
|
||||
toDisplay = self.serviceItem.get_rendered_frame(row)
|
||||
if self.serviceItem.is_text():
|
||||
frame = self.display.text(raw_html)
|
||||
frame = self.display.text(toDisplay)
|
||||
else:
|
||||
self.display.image(frame)
|
||||
if isinstance(frame, QtGui.QImage):
|
||||
self.SlidePreview.setPixmap(QtGui.QPixmap.fromImage(frame))
|
||||
else:
|
||||
self.SlidePreview.setPixmap(QtGui.QPixmap(frame))
|
||||
frame = self.display.image(toDisplay)
|
||||
self.SlidePreview.setPixmap(QtGui.QPixmap.fromImage(frame))
|
||||
self.selectedRow = row
|
||||
Receiver.send_message(u'slidecontroller_%s_changed' % self.typePrefix,
|
||||
row)
|
||||
@ -931,14 +934,13 @@ class SlideController(QtGui.QWidget):
|
||||
Respond to the arrival of a media service item
|
||||
"""
|
||||
log.debug(u'SlideController onMediaStart')
|
||||
file = os.path.join(item.get_frame_path(), item.get_frame_title())
|
||||
if self.isLive:
|
||||
file = os.path.join(item.get_frame_path(), item.get_frame_title())
|
||||
self.display.video(file, self.volume)
|
||||
self.volumeSlider.setValue(self.volume)
|
||||
else:
|
||||
self.mediaObject.stop()
|
||||
self.mediaObject.clearQueue()
|
||||
file = os.path.join(item.get_frame_path(), item.get_frame_title())
|
||||
self.mediaObject.setCurrentSource(Phonon.MediaSource(file))
|
||||
self.seekSlider.setMediaObject(self.mediaObject)
|
||||
self.seekSlider.show()
|
||||
@ -986,3 +988,17 @@ class SlideController(QtGui.QWidget):
|
||||
self.video.hide()
|
||||
self.SlidePreview.clear()
|
||||
self.SlidePreview.show()
|
||||
|
||||
def onMediaClose(self):
|
||||
"""
|
||||
Respond to a request to close the Video
|
||||
"""
|
||||
log.debug(u'SlideController onMediaStop')
|
||||
if self.isLive:
|
||||
self.display.resetVideo()
|
||||
else:
|
||||
self.mediaObject.stop()
|
||||
self.mediaObject.clearQueue()
|
||||
self.video.hide()
|
||||
self.SlidePreview.clear()
|
||||
self.SlidePreview.show()
|
||||
|
@ -34,9 +34,8 @@ from PyQt4 import QtCore, QtGui
|
||||
|
||||
from openlp.core.ui import AmendThemeForm, FileRenameForm
|
||||
from openlp.core.theme import Theme
|
||||
from openlp.core.lib import OpenLPToolbar, context_menu_action, \
|
||||
ThemeXML, str_to_bool, get_text_file_string, build_icon, Receiver, \
|
||||
context_menu_separator, SettingsManager, translate, check_item_selected
|
||||
from openlp.core.lib import OpenLPToolbar, ThemeXML, get_text_file_string, \
|
||||
build_icon, Receiver, SettingsManager, translate, check_item_selected
|
||||
from openlp.core.utils import AppLocation, get_filesystem_encoding
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
@ -267,7 +266,7 @@ class ThemeManager(QtGui.QWidget):
|
||||
filename = \
|
||||
os.path.split(unicode(oldThemeData.background_filename))[1]
|
||||
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
|
||||
new_theme.add_font(unicode(oldThemeData.font_main_name),
|
||||
unicode(oldThemeData.font_main_color),
|
||||
|
@ -28,7 +28,6 @@ The :mod:`languagemanager` module provides all the translation settings and
|
||||
language file loading for OpenLP.
|
||||
"""
|
||||
import logging
|
||||
import os
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
|
@ -45,13 +45,15 @@ class AlertsPlugin(Plugin):
|
||||
self.icon = build_icon(u':/plugins/plugin_alerts.png')
|
||||
self.alertsmanager = AlertsManager(self)
|
||||
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):
|
||||
"""
|
||||
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
|
||||
|
||||
def addToolsMenuItem(self, tools_menu):
|
||||
@ -115,4 +117,11 @@ class AlertsPlugin(Plugin):
|
||||
self.textStrings[StringContent.VisibleName] = {
|
||||
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)
|
||||
|
@ -35,7 +35,7 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog):
|
||||
"""
|
||||
Provide UI for the alert system
|
||||
"""
|
||||
def __init__(self, title, visible_title):
|
||||
def __init__(self, plugin, visible_title):
|
||||
"""
|
||||
Initialise the alert form
|
||||
"""
|
||||
|
@ -24,6 +24,6 @@
|
||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||
###############################################################################
|
||||
"""
|
||||
The :mod:`bibles' module provides the Bible plugin to enable OpenLP to display
|
||||
The :mod:`bibles` module provides the Bible plugin to enable OpenLP to display
|
||||
scripture.
|
||||
"""
|
||||
|
@ -133,42 +133,50 @@ class BiblePlugin(Plugin):
|
||||
## Import Button ##
|
||||
self.textStrings[StringContent.Import] = {
|
||||
u'title': translate('BiblesPlugin', 'Import'),
|
||||
u'tooltip': translate('BiblesPlugin',
|
||||
u'tooltip': translate('BiblesPlugin',
|
||||
'Import a Bible')
|
||||
}
|
||||
## New Button ##
|
||||
self.textStrings[StringContent.New] = {
|
||||
u'title': translate('BiblesPlugin', 'Add'),
|
||||
u'tooltip': translate('BiblesPlugin',
|
||||
u'tooltip': translate('BiblesPlugin',
|
||||
'Add a new Bible')
|
||||
}
|
||||
## Edit Button ##
|
||||
self.textStrings[StringContent.Edit] = {
|
||||
u'title': translate('BiblesPlugin', 'Edit'),
|
||||
u'tooltip': translate('BiblesPlugin',
|
||||
u'tooltip': translate('BiblesPlugin',
|
||||
'Edit the selected Bible')
|
||||
}
|
||||
## Delete Button ##
|
||||
self.textStrings[StringContent.Delete] = {
|
||||
u'title': translate('BiblesPlugin', 'Delete'),
|
||||
u'tooltip': translate('BiblesPlugin',
|
||||
u'tooltip': translate('BiblesPlugin',
|
||||
'Delete the selected Bible')
|
||||
}
|
||||
## Preview ##
|
||||
self.textStrings[StringContent.Preview] = {
|
||||
u'title': translate('BiblesPlugin', 'Preview'),
|
||||
u'tooltip': translate('BiblesPlugin',
|
||||
u'tooltip': translate('BiblesPlugin',
|
||||
'Preview the selected Bible')
|
||||
}
|
||||
## Live Button ##
|
||||
self.textStrings[StringContent.Live] = {
|
||||
u'title': translate('BiblesPlugin', 'Live'),
|
||||
u'tooltip': translate('BiblesPlugin',
|
||||
u'tooltip': translate('BiblesPlugin',
|
||||
'Send the selected Bible live')
|
||||
}
|
||||
## Add to service Button ##
|
||||
self.textStrings[StringContent.Service] = {
|
||||
u'title': translate('BiblesPlugin', 'Service'),
|
||||
u'tooltip': translate('BiblesPlugin',
|
||||
u'tooltip': translate('BiblesPlugin',
|
||||
'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)
|
||||
|
@ -24,6 +24,33 @@
|
||||
# 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']
|
||||
|
@ -54,7 +54,7 @@ class WebDownload(object):
|
||||
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
|
||||
into OpenLP from other formats like OSIS, CSV and OpenSong.
|
||||
@ -282,7 +282,7 @@ class ImportWizardForm(QtGui.QWizard, Ui_BibleImportWizard):
|
||||
self.LicenseDetailsPage.registerField(
|
||||
u'license_copyright', self.CopyrightEdit)
|
||||
self.LicenseDetailsPage.registerField(
|
||||
u'license_permission', self.PermissionEdit)
|
||||
u'license_permissions', self.PermissionsEdit)
|
||||
|
||||
def setDefaults(self):
|
||||
settings = QtCore.QSettings()
|
||||
@ -308,8 +308,8 @@ class ImportWizardForm(QtGui.QWizard, Ui_BibleImportWizard):
|
||||
QtCore.QVariant(self.VersionNameEdit.text()))
|
||||
self.setField(u'license_copyright',
|
||||
QtCore.QVariant(self.CopyrightEdit.text()))
|
||||
self.setField(u'license_permission',
|
||||
QtCore.QVariant(self.PermissionEdit.text()))
|
||||
self.setField(u'license_permissions',
|
||||
QtCore.QVariant(self.PermissionsEdit.text()))
|
||||
self.onLocationComboBoxChanged(WebDownload.Crosswalk)
|
||||
settings.endGroup()
|
||||
|
||||
@ -391,8 +391,8 @@ class ImportWizardForm(QtGui.QWizard, Ui_BibleImportWizard):
|
||||
bible_type = self.field(u'source_format').toInt()[0]
|
||||
license_version = unicode(self.field(u'license_version').toString())
|
||||
license_copyright = unicode(self.field(u'license_copyright').toString())
|
||||
license_permission = \
|
||||
unicode(self.field(u'license_permission').toString())
|
||||
license_permissions = \
|
||||
unicode(self.field(u'license_permissions').toString())
|
||||
importer = None
|
||||
if bible_type == BibleFormat.OSIS:
|
||||
# Import an OSIS bible
|
||||
@ -436,7 +436,7 @@ class ImportWizardForm(QtGui.QWizard, Ui_BibleImportWizard):
|
||||
)
|
||||
if importer.do_import():
|
||||
self.manager.save_meta_data(license_version, license_version,
|
||||
license_copyright, license_permission)
|
||||
license_copyright, license_permissions)
|
||||
self.manager.reload_bibles()
|
||||
self.ImportProgressLabel.setText(
|
||||
translate('BiblesPlugin.ImportWizardForm', 'Finished import.'))
|
@ -275,14 +275,14 @@ class Ui_BibleImportWizard(object):
|
||||
self.CopyrightEdit.setObjectName(u'CopyrightEdit')
|
||||
self.LicenseDetailsLayout.setWidget(1, QtGui.QFormLayout.FieldRole,
|
||||
self.CopyrightEdit)
|
||||
self.PermissionLabel = QtGui.QLabel(self.LicenseDetailsPage)
|
||||
self.PermissionLabel.setObjectName(u'PermissionLabel')
|
||||
self.PermissionsLabel = QtGui.QLabel(self.LicenseDetailsPage)
|
||||
self.PermissionsLabel.setObjectName(u'PermissionsLabel')
|
||||
self.LicenseDetailsLayout.setWidget(2, QtGui.QFormLayout.LabelRole,
|
||||
self.PermissionLabel)
|
||||
self.PermissionEdit = QtGui.QLineEdit(self.LicenseDetailsPage)
|
||||
self.PermissionEdit.setObjectName(u'PermissionEdit')
|
||||
self.PermissionsLabel)
|
||||
self.PermissionsEdit = QtGui.QLineEdit(self.LicenseDetailsPage)
|
||||
self.PermissionsEdit.setObjectName(u'PermissionsEdit')
|
||||
self.LicenseDetailsLayout.setWidget(2, QtGui.QFormLayout.FieldRole,
|
||||
self.PermissionEdit)
|
||||
self.PermissionsEdit)
|
||||
BibleImportWizard.addPage(self.LicenseDetailsPage)
|
||||
self.ImportPage = QtGui.QWizardPage()
|
||||
self.ImportPage.setObjectName(u'ImportPage')
|
||||
@ -372,8 +372,8 @@ class Ui_BibleImportWizard(object):
|
||||
translate('BiblesPlugin.ImportWizardForm', 'Version name:'))
|
||||
self.CopyrightLabel.setText(
|
||||
translate('BiblesPlugin.ImportWizardForm', 'Copyright:'))
|
||||
self.PermissionLabel.setText(
|
||||
translate('BiblesPlugin.ImportWizardForm', 'Permission:'))
|
||||
self.PermissionsLabel.setText(
|
||||
translate('BiblesPlugin.ImportWizardForm', 'Permissions:'))
|
||||
self.ImportPage.setTitle(
|
||||
translate('BiblesPlugin.ImportWizardForm', 'Importing'))
|
||||
self.ImportPage.setSubTitle(
|
||||
|
@ -60,22 +60,32 @@ def parse_reference(reference):
|
||||
and converts it to a reference list, a list of references to be queried
|
||||
from the Bible database files.
|
||||
|
||||
BIBLE_REFERENCE regular expression produces the following match groups:
|
||||
0 This is a special group consisting of the whole string that matched.
|
||||
1 [\w ]+ The book the reference is from.
|
||||
2 [0-9]+ The first (or only) chapter in the reference.
|
||||
3 None|[0-9]+ None or the only verse or the first verse in a
|
||||
verse range or the start verse in a chapter range.
|
||||
4 None|[0-9]+|end None or the end verse of the first verse range or
|
||||
the end chapter of a chapter range.
|
||||
5 None|[0-9]+ None or the second chapter in multiple
|
||||
(non-ranged) chapters.
|
||||
6 None|[0-9]+|end None, the start of the second verse range or the
|
||||
end of a chapter range.
|
||||
7 None|[0-9]+|end None or the end of the second verse range.
|
||||
The ``BIBLE_REFERENCE`` constant regular expression produces the following
|
||||
match groups:
|
||||
|
||||
0. (match string)
|
||||
This is a special group consisting of the whole string that matched.
|
||||
1. ``[\w ]+``
|
||||
The book the reference is from.
|
||||
2. ``[0-9]+``
|
||||
The first (or only) chapter in the reference.
|
||||
3. ``None`` or ``[0-9]+``
|
||||
``None``, or the only verse, or the first verse in a verse range or,
|
||||
the start verse in a chapter range.
|
||||
4. ``None`` or ``[0-9]+`` or ``end``
|
||||
``None``, or the end verse of the first verse range, or the end chapter
|
||||
of a chapter range.
|
||||
5. ``None`` or ``[0-9]+``
|
||||
``None``, or the second chapter in multiple (non-ranged) chapters.
|
||||
6. ``None`` or ``[0-9]+`` or ``end``
|
||||
``None``, the start of the second verse range. or the end of a chapter
|
||||
range.
|
||||
7. ``None`` or ``[0-9]+`` or ``end``
|
||||
``None``, or the end of the second verse range.
|
||||
|
||||
The reference list is a list of tuples, with each tuple structured like
|
||||
this::
|
||||
|
||||
(book, chapter, start_verse, end_verse)
|
||||
|
||||
``reference``
|
||||
@ -154,7 +164,7 @@ def parse_reference(reference):
|
||||
|
||||
class SearchResults(object):
|
||||
"""
|
||||
Encapsulate a set of search results. This is Bible-type independant.
|
||||
Encapsulate a set of search results. This is Bible-type independent.
|
||||
"""
|
||||
def __init__(self, book, chapter, verselist):
|
||||
"""
|
||||
|
@ -64,10 +64,10 @@ class Verse(BaseModel):
|
||||
|
||||
def init_schema(url):
|
||||
"""
|
||||
Setup a bible database connection and initialise the database schema
|
||||
Setup a bible database connection and initialise the database schema.
|
||||
|
||||
``url``
|
||||
The database to setup
|
||||
The database to setup.
|
||||
"""
|
||||
session, metadata = init_db(url)
|
||||
|
||||
@ -240,7 +240,7 @@ class BibleDB(QtCore.QObject, Manager):
|
||||
and the value is the verse text.
|
||||
"""
|
||||
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():
|
||||
verse = Verse.populate(
|
||||
book_id = book_id,
|
||||
@ -281,23 +281,23 @@ class BibleDB(QtCore.QObject, Manager):
|
||||
|
||||
def create_meta(self, key, value):
|
||||
"""
|
||||
Utility method to save BibleMeta objects in a Bible database
|
||||
Utility method to save BibleMeta objects in a Bible database.
|
||||
|
||||
``key``
|
||||
The key for this instance
|
||||
The key for this instance.
|
||||
|
||||
``value``
|
||||
The value for this instance
|
||||
The value for this instance.
|
||||
"""
|
||||
log.debug(u'save_meta %s/%s', key, value)
|
||||
self.save_object(BibleMeta.populate(key=key, value=value))
|
||||
|
||||
def get_book(self, book):
|
||||
"""
|
||||
Return a book object from the database
|
||||
Return a book object from the database.
|
||||
|
||||
``book``
|
||||
The name of the book to return
|
||||
The name of the book to return.
|
||||
"""
|
||||
log.debug(u'BibleDb.get_book("%s")', book)
|
||||
db_book = self.get_object_filtered(Book, Book.name.like(book + u'%'))
|
||||
@ -353,9 +353,9 @@ class BibleDB(QtCore.QObject, Manager):
|
||||
QtGui.QMessageBox.information(self.bible_plugin.mediaItem,
|
||||
translate('BiblesPlugin.BibleDB', 'Book not found'),
|
||||
translate('BiblesPlugin.BibleDB', 'The book you requested '
|
||||
'could not be found in this bible. Please check your '
|
||||
'spelling and that this is a complete bible not just '
|
||||
'one testament.'))
|
||||
'could not be found in this Bible. Please check your '
|
||||
'spelling and that this is a complete Bible not just '
|
||||
'one testament.'))
|
||||
return verse_list
|
||||
|
||||
def verse_search(self, text):
|
||||
@ -387,10 +387,10 @@ class BibleDB(QtCore.QObject, Manager):
|
||||
|
||||
def get_chapter_count(self, book):
|
||||
"""
|
||||
Return the number of chapters in a book
|
||||
Return the number of chapters in a book.
|
||||
|
||||
``book``
|
||||
The book to get the chapter count for
|
||||
The book to get the chapter count for.
|
||||
"""
|
||||
log.debug(u'BibleDB.get_chapter_count("%s")', book)
|
||||
count = self.session.query(Verse.chapter).join(Book)\
|
||||
@ -403,13 +403,13 @@ class BibleDB(QtCore.QObject, Manager):
|
||||
|
||||
def get_verse_count(self, book, chapter):
|
||||
"""
|
||||
Return the number of verses in a chapter
|
||||
Return the number of verses in a chapter.
|
||||
|
||||
``book``
|
||||
The book containing the chapter
|
||||
The book containing the chapter.
|
||||
|
||||
``chapter``
|
||||
The chapter to get the verse count for
|
||||
The chapter to get the verse count for.
|
||||
"""
|
||||
log.debug(u'BibleDB.get_verse_count("%s", %s)', book, chapter)
|
||||
count = self.session.query(Verse).join(Book)\
|
||||
@ -423,7 +423,7 @@ class BibleDB(QtCore.QObject, Manager):
|
||||
|
||||
def dump_bible(self):
|
||||
"""
|
||||
Utility debugging method to dump the contents of a bible
|
||||
Utility debugging method to dump the contents of a bible.
|
||||
"""
|
||||
log.debug(u'.........Dumping Bible Database')
|
||||
log.debug('...............................Books ')
|
||||
|
@ -36,7 +36,7 @@ from BeautifulSoup import BeautifulSoup, NavigableString
|
||||
|
||||
from openlp.core.lib import Receiver
|
||||
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
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
@ -187,16 +187,16 @@ class BGExtract(object):
|
||||
|
||||
def get_bible_chapter(self, version, bookname, chapter):
|
||||
"""
|
||||
Access and decode bibles via the BibleGateway website
|
||||
Access and decode bibles via the BibleGateway website.
|
||||
|
||||
``version``
|
||||
The version of the bible like 31 for New International version
|
||||
The version of the bible like 31 for New International version.
|
||||
|
||||
``bookname``
|
||||
Name of the Book
|
||||
Name of the Book.
|
||||
|
||||
``chapter``
|
||||
Chapter number
|
||||
Chapter number.
|
||||
"""
|
||||
log.debug(u'get_bible_chapter %s, %s, %s', version, bookname, chapter)
|
||||
url_params = urllib.urlencode(
|
||||
@ -298,13 +298,13 @@ class CWExtract(object):
|
||||
versetext = versetext + part
|
||||
elif part and part.attrMap and \
|
||||
(part.attrMap[u'class'] == u'WordsOfChrist' or \
|
||||
part.attrMap[u'class'] == u'strongs'):
|
||||
part.attrMap[u'class'] == u'strongs'):
|
||||
for subpart in part.contents:
|
||||
Receiver.send_message(u'openlp_process_events')
|
||||
if isinstance(subpart, NavigableString):
|
||||
versetext = versetext + subpart
|
||||
elif subpart and subpart.attrMap and \
|
||||
subpart.attrMap[u'class'] == u'strongs':
|
||||
subpart.attrMap[u'class'] == u'strongs':
|
||||
for subsub in subpart.contents:
|
||||
Receiver.send_message(u'openlp_process_events')
|
||||
if isinstance(subsub, NavigableString):
|
||||
@ -428,7 +428,7 @@ class HTTPBible(BibleDB):
|
||||
|
||||
def get_chapter(self, book, chapter):
|
||||
"""
|
||||
Receive the request and call the relevant handler methods
|
||||
Receive the request and call the relevant handler methods.
|
||||
"""
|
||||
log.debug(u'get_chapter %s, %s', book, chapter)
|
||||
log.debug(u'source = %s', self.download_source)
|
||||
|
@ -137,7 +137,7 @@ class BibleManager(object):
|
||||
name = bible.get_name()
|
||||
log.debug(u'Bible Name: "%s"', name)
|
||||
self.db_cache[name] = bible
|
||||
# look to see if lazy load bible exists and get create getter.
|
||||
# Look to see if lazy load bible exists and get create getter.
|
||||
source = self.db_cache[name].get_object(BibleMeta,
|
||||
u'download source')
|
||||
if source:
|
||||
@ -181,10 +181,10 @@ class BibleManager(object):
|
||||
|
||||
def get_bibles(self):
|
||||
"""
|
||||
Returns a list of the names of available Bibles.
|
||||
Returns a dict with all available Bibles.
|
||||
"""
|
||||
log.debug(u'get_bibles')
|
||||
return self.db_cache.keys()
|
||||
return self.db_cache
|
||||
|
||||
def get_books(self, bible):
|
||||
"""
|
||||
@ -204,7 +204,7 @@ class BibleManager(object):
|
||||
|
||||
def get_chapter_count(self, bible, book):
|
||||
"""
|
||||
Returns the number of Chapters for a given book
|
||||
Returns the number of Chapters for a given book.
|
||||
"""
|
||||
log.debug(u'get_book_chapter_count %s', book)
|
||||
return self.db_cache[bible].get_chapter_count(book)
|
||||
@ -212,7 +212,7 @@ class BibleManager(object):
|
||||
def get_verse_count(self, bible, book, chapter):
|
||||
"""
|
||||
Returns all the number of verses for a given
|
||||
book and chapterMaxBibleBookVerses
|
||||
book and chapterMaxBibleBookVerses.
|
||||
"""
|
||||
log.debug(u'BibleManager.get_verse_count("%s", "%s", %s)',
|
||||
bible, book, chapter)
|
||||
@ -254,12 +254,35 @@ class BibleManager(object):
|
||||
'Book Chapter:Verse-Verse\n'
|
||||
'Book Chapter:Verse-Verse,Verse-Verse\n'
|
||||
'Book Chapter:Verse-Verse,Chapter:Verse-Verse\n'
|
||||
'Book Chapter:Verse-Chapter:Verse\n'))
|
||||
'Book Chapter:Verse-Chapter:Verse'))
|
||||
return None
|
||||
|
||||
def verse_search(self, bible, text):
|
||||
"""
|
||||
Does a verse search for the given bible and text.
|
||||
|
||||
``bible``
|
||||
The bible to seach in (unicode).
|
||||
|
||||
``text``
|
||||
The text to search for (unicode).
|
||||
"""
|
||||
log.debug(u'BibleManager.verse_search("%s", "%s")', bible, text)
|
||||
if text:
|
||||
return self.db_cache[bible].verse_search(text)
|
||||
else:
|
||||
QtGui.QMessageBox.information(self.parent.mediaItem,
|
||||
translate('BiblesPlugin.BibleManager',
|
||||
'Scripture Reference Error'),
|
||||
translate('BiblesPlugin.BibleManager', 'You did not enter a '
|
||||
'search keyword.\nYou can separate different keywords by a '
|
||||
'space to search for all of your keywords and you can seperate '
|
||||
'them by a comma to search for one of them.'))
|
||||
return None
|
||||
|
||||
def save_meta_data(self, bible, version, copyright, permissions):
|
||||
"""
|
||||
Saves the bibles meta data
|
||||
Saves the bibles meta data.
|
||||
"""
|
||||
log.debug(u'save_meta data %s,%s, %s,%s',
|
||||
bible, version, copyright, permissions)
|
||||
@ -269,14 +292,14 @@ class BibleManager(object):
|
||||
|
||||
def get_meta_data(self, bible, key):
|
||||
"""
|
||||
Returns the meta data for a given key
|
||||
Returns the meta data for a given key.
|
||||
"""
|
||||
log.debug(u'get_meta %s,%s', bible, key)
|
||||
return self.db_cache[bible].get_object(BibleMeta, key)
|
||||
|
||||
def exists(self, name):
|
||||
"""
|
||||
Check cache to see if new bible
|
||||
Check cache to see if new bible.
|
||||
"""
|
||||
if not isinstance(name, unicode):
|
||||
name = unicode(name)
|
||||
@ -287,3 +310,11 @@ class BibleManager(object):
|
||||
if bible == name:
|
||||
return True
|
||||
return False
|
||||
|
||||
def finalise(self):
|
||||
"""
|
||||
Loop through the databases to VACUUM them.
|
||||
"""
|
||||
for bible in self.db_cache:
|
||||
self.db_cache[bible].finalise()
|
||||
|
||||
|
@ -31,7 +31,7 @@ from PyQt4 import QtCore, QtGui
|
||||
|
||||
from openlp.core.lib import MediaManagerItem, Receiver, BaseListWithDnD, \
|
||||
ItemCapabilities, translate
|
||||
from openlp.plugins.bibles.forms import ImportWizardForm
|
||||
from openlp.plugins.bibles.forms import BibleImportForm
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@ -361,7 +361,7 @@ class BibleMediaItem(MediaManagerItem):
|
||||
|
||||
def onImportClick(self):
|
||||
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.import_wizard.exec_()
|
||||
self.reloadBibles()
|
||||
@ -374,7 +374,7 @@ class BibleMediaItem(MediaManagerItem):
|
||||
self.AdvancedSecondBibleComboBox.clear()
|
||||
self.QuickSecondBibleComboBox.addItem(u'')
|
||||
self.AdvancedSecondBibleComboBox.addItem(u'')
|
||||
bibles = self.parent.manager.get_bibles()
|
||||
bibles = self.parent.manager.get_bibles().keys()
|
||||
# load bibles into the combo boxes
|
||||
first = True
|
||||
for bible in bibles:
|
||||
@ -497,6 +497,7 @@ class BibleMediaItem(MediaManagerItem):
|
||||
|
||||
def onAdvancedSearchButton(self):
|
||||
log.debug(u'Advanced Search Button pressed')
|
||||
self.AdvancedSearchButton.setEnabled(False)
|
||||
bible = unicode(self.AdvancedVersionComboBox.currentText())
|
||||
dual_bible = unicode(self.AdvancedSecondBibleComboBox.currentText())
|
||||
book = unicode(self.AdvancedBookComboBox.currentText())
|
||||
@ -529,16 +530,30 @@ class BibleMediaItem(MediaManagerItem):
|
||||
self.displayResults(bible, dual_bible)
|
||||
else:
|
||||
self.displayResults(bible, dual_bible)
|
||||
self.AdvancedSearchButton.setEnabled(True)
|
||||
|
||||
def onQuickSearchButton(self):
|
||||
log.debug(u'Quick Search Button pressed')
|
||||
self.QuickSearchButton.setEnabled(False)
|
||||
bible = unicode(self.QuickVersionComboBox.currentText())
|
||||
dual_bible = unicode(self.QuickSecondBibleComboBox.currentText())
|
||||
text = unicode(self.QuickSearchEdit.text())
|
||||
self.search_results = self.parent.manager.get_verses(bible, text)
|
||||
if dual_bible:
|
||||
self.dual_search_results = self.parent.manager.get_verses(
|
||||
dual_bible, text)
|
||||
if self.QuickSearchComboBox.currentIndex() == 0:
|
||||
# We are doing a 'Verse Search'.
|
||||
self.search_results = self.parent.manager.get_verses(bible, text)
|
||||
if dual_bible and self.search_results:
|
||||
self.dual_search_results = self.parent.manager.get_verses(
|
||||
dual_bible, text)
|
||||
else:
|
||||
# We are doing a ' Text Search'.
|
||||
bibles = self.parent.manager.get_bibles()
|
||||
self.search_results = self.parent.manager.verse_search(bible, text)
|
||||
if dual_bible and self.search_results:
|
||||
text = []
|
||||
for verse in self.search_results:
|
||||
text.append((verse.book.name, verse.chapter, verse.verse,
|
||||
verse.verse))
|
||||
self.dual_search_results = bibles[dual_bible].get_verses(text)
|
||||
if self.ClearQuickSearchComboBox.currentIndex() == 0:
|
||||
self.listView.clear()
|
||||
if self.listView.count() != 0 and self.search_results:
|
||||
@ -558,6 +573,7 @@ class BibleMediaItem(MediaManagerItem):
|
||||
self.displayResults(bible, dual_bible)
|
||||
elif self.search_results:
|
||||
self.displayResults(bible, dual_bible)
|
||||
self.QuickSearchButton.setEnabled(True)
|
||||
|
||||
def displayResults(self, bible, dual_bible=u''):
|
||||
"""
|
||||
@ -566,16 +582,16 @@ class BibleMediaItem(MediaManagerItem):
|
||||
"""
|
||||
version = self.parent.manager.get_meta_data(bible, u'Version')
|
||||
copyright = self.parent.manager.get_meta_data(bible, u'Copyright')
|
||||
permission = self.parent.manager.get_meta_data(bible, u'Permissions')
|
||||
permissions = self.parent.manager.get_meta_data(bible, u'Permissions')
|
||||
if dual_bible:
|
||||
dual_version = self.parent.manager.get_meta_data(dual_bible,
|
||||
u'Version')
|
||||
dual_copyright = self.parent.manager.get_meta_data(dual_bible,
|
||||
u'Copyright')
|
||||
dual_permission = self.parent.manager.get_meta_data(dual_bible,
|
||||
dual_permissions = self.parent.manager.get_meta_data(dual_bible,
|
||||
u'Permissions')
|
||||
if not dual_permission:
|
||||
dual_permission = u''
|
||||
if not dual_permissions:
|
||||
dual_permissions = u''
|
||||
# We count the number of rows which are maybe already present.
|
||||
start_count = self.listView.count()
|
||||
for count, verse in enumerate(self.search_results):
|
||||
@ -587,12 +603,12 @@ class BibleMediaItem(MediaManagerItem):
|
||||
'bible': QtCore.QVariant(bible),
|
||||
'version': QtCore.QVariant(version.value),
|
||||
'copyright': QtCore.QVariant(copyright.value),
|
||||
'permission': QtCore.QVariant(permission.value),
|
||||
'permissions': QtCore.QVariant(permissions.value),
|
||||
'text': QtCore.QVariant(verse.text),
|
||||
'dual_bible': QtCore.QVariant(dual_bible),
|
||||
'dual_version': QtCore.QVariant(dual_version.value),
|
||||
'dual_copyright': QtCore.QVariant(dual_copyright.value),
|
||||
'dual_permission': QtCore.QVariant(dual_permission.value),
|
||||
'dual_permissions': QtCore.QVariant(dual_permissions.value),
|
||||
'dual_text': QtCore.QVariant(
|
||||
self.dual_search_results[count].text)
|
||||
}
|
||||
@ -607,12 +623,12 @@ class BibleMediaItem(MediaManagerItem):
|
||||
'bible': QtCore.QVariant(bible),
|
||||
'version': QtCore.QVariant(version.value),
|
||||
'copyright': QtCore.QVariant(copyright.value),
|
||||
'permission': QtCore.QVariant(permission.value),
|
||||
'permissions': QtCore.QVariant(permissions.value),
|
||||
'text': QtCore.QVariant(verse.text),
|
||||
'dual_bible': QtCore.QVariant(u''),
|
||||
'dual_version': QtCore.QVariant(u''),
|
||||
'dual_copyright': QtCore.QVariant(u''),
|
||||
'dual_permission': QtCore.QVariant(u''),
|
||||
'dual_permissions': QtCore.QVariant(u''),
|
||||
'dual_text': QtCore.QVariant(u'')
|
||||
}
|
||||
bible_text = u' %s %d:%d (%s)' % (verse.book.name,
|
||||
@ -658,20 +674,20 @@ class BibleMediaItem(MediaManagerItem):
|
||||
bible = self._decodeQtObject(bitem, 'bible')
|
||||
version = self._decodeQtObject(bitem, 'version')
|
||||
copyright = self._decodeQtObject(bitem, 'copyright')
|
||||
permission = self._decodeQtObject(bitem, 'permission')
|
||||
permissions = self._decodeQtObject(bitem, 'permissions')
|
||||
text = self._decodeQtObject(bitem, 'text')
|
||||
dual_bible = self._decodeQtObject(bitem, 'dual_bible')
|
||||
dual_version = self._decodeQtObject(bitem, 'dual_version')
|
||||
dual_copyright = self._decodeQtObject(bitem, 'dual_copyright')
|
||||
dual_permission = self._decodeQtObject(bitem, 'dual_permission')
|
||||
dual_permissions = self._decodeQtObject(bitem, 'dual_permissions')
|
||||
dual_text = self._decodeQtObject(bitem, 'dual_text')
|
||||
verse_text = self.formatVerse(old_chapter, chapter, verse)
|
||||
footer = u'%s (%s %s %s)' % (book, version, copyright, permission)
|
||||
footer = u'%s (%s %s %s)' % (book, version, copyright, permissions)
|
||||
if footer not in raw_footer:
|
||||
raw_footer.append(footer)
|
||||
if dual_bible:
|
||||
footer = u'%s (%s %s %s)' % (book, dual_version, dual_copyright,
|
||||
dual_permission)
|
||||
dual_permissions)
|
||||
if footer not in raw_footer:
|
||||
raw_footer.append(footer)
|
||||
bible_text = u'%s %s\n\n%s %s' % (verse_text, text, verse_text,
|
||||
|
@ -6,8 +6,8 @@ Deut,Deuteronomy,Deut
|
||||
Josh,Joshua,Josh
|
||||
Judg,Judges,Judg
|
||||
Ruth,Ruth,Ruth
|
||||
1Sam,1 Samual,1Sam
|
||||
2Sam,2 Samual,2Sam
|
||||
1Sam,1 Samuel,1Sam
|
||||
2Sam,2 Samuel,2Sam
|
||||
1Kgs,1 Kings,1Kgs
|
||||
2Kgs,2 Kings,2Kgs
|
||||
1Chr,1 Chronicles,1Chr
|
||||
|
|
@ -49,8 +49,8 @@ class CustomPlugin(Plugin):
|
||||
def __init__(self, plugin_helpers):
|
||||
Plugin.__init__(self, u'Custom', u'1.9.3', plugin_helpers)
|
||||
self.weight = -5
|
||||
self.custommanager = Manager(u'custom', init_schema)
|
||||
self.edit_custom_form = EditCustomForm(self.custommanager)
|
||||
self.manager = Manager(u'custom', init_schema)
|
||||
self.edit_custom_form = EditCustomForm(self.manager)
|
||||
self.icon_path = u':/plugins/plugin_custom.png'
|
||||
self.icon = build_icon(self.icon_path)
|
||||
|
||||
@ -115,48 +115,56 @@ class CustomPlugin(Plugin):
|
||||
## Import Button ##
|
||||
self.textStrings[StringContent.Import] = {
|
||||
u'title': translate('CustomsPlugin', 'Import'),
|
||||
u'tooltip': translate('CustomsPlugin',
|
||||
u'tooltip': translate('CustomsPlugin',
|
||||
'Import a Custom')
|
||||
}
|
||||
## Load Button ##
|
||||
self.textStrings[StringContent.Load] = {
|
||||
u'title': translate('CustomsPlugin', 'Load'),
|
||||
u'tooltip': translate('CustomsPlugin',
|
||||
u'tooltip': translate('CustomsPlugin',
|
||||
'Load a new Custom')
|
||||
}
|
||||
## New Button ##
|
||||
self.textStrings[StringContent.New] = {
|
||||
u'title': translate('CustomsPlugin', 'Add'),
|
||||
u'tooltip': translate('CustomsPlugin',
|
||||
u'tooltip': translate('CustomsPlugin',
|
||||
'Add a new Custom')
|
||||
}
|
||||
## Edit Button ##
|
||||
self.textStrings[StringContent.Edit] = {
|
||||
u'title': translate('CustomsPlugin', 'Edit'),
|
||||
u'tooltip': translate('CustomsPlugin',
|
||||
u'tooltip': translate('CustomsPlugin',
|
||||
'Edit the selected Custom')
|
||||
}
|
||||
## Delete Button ##
|
||||
self.textStrings[StringContent.Delete] = {
|
||||
u'title': translate('CustomsPlugin', 'Delete'),
|
||||
u'tooltip': translate('CustomsPlugin',
|
||||
u'tooltip': translate('CustomsPlugin',
|
||||
'Delete the selected Custom')
|
||||
}
|
||||
## Preview ##
|
||||
self.textStrings[StringContent.Preview] = {
|
||||
u'title': translate('CustomsPlugin', 'Preview'),
|
||||
u'tooltip': translate('CustomsPlugin',
|
||||
u'tooltip': translate('CustomsPlugin',
|
||||
'Preview the selected Custom')
|
||||
}
|
||||
## Live Button ##
|
||||
self.textStrings[StringContent.Live] = {
|
||||
u'title': translate('CustomsPlugin', 'Live'),
|
||||
u'tooltip': translate('CustomsPlugin',
|
||||
u'tooltip': translate('CustomsPlugin',
|
||||
'Send the selected Custom live')
|
||||
}
|
||||
## Add to service Button ##
|
||||
self.textStrings[StringContent.Service] = {
|
||||
u'title': translate('CustomsPlugin', 'Service'),
|
||||
u'tooltip': translate('CustomsPlugin',
|
||||
u'tooltip': translate('CustomsPlugin',
|
||||
'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)
|
||||
|
@ -25,3 +25,4 @@
|
||||
###############################################################################
|
||||
|
||||
from editcustomform import EditCustomForm
|
||||
from editcustomslideform import EditCustomSlideForm
|
||||
|
@ -26,7 +26,7 @@
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
from openlp.core.lib import build_icon, translate, SpellTextEdit
|
||||
from openlp.core.lib import build_icon, translate
|
||||
|
||||
class Ui_CustomEditDialog(object):
|
||||
def setupUi(self, customEditDialog):
|
||||
@ -36,6 +36,70 @@ class Ui_CustomEditDialog(object):
|
||||
build_icon(u':/icon/openlp.org-icon-32.bmp'))
|
||||
self.gridLayout = QtGui.QGridLayout(customEditDialog)
|
||||
self.gridLayout.setObjectName(u'gridLayout')
|
||||
self.horizontalLayout3 = QtGui.QHBoxLayout()
|
||||
self.horizontalLayout3.setObjectName(u'horizontalLayout3')
|
||||
self.themeLabel = QtGui.QLabel(customEditDialog)
|
||||
self.themeLabel.setObjectName(u'themeLabel')
|
||||
self.horizontalLayout3.addWidget(self.themeLabel)
|
||||
self.themeComboBox = QtGui.QComboBox(customEditDialog)
|
||||
self.themeLabel.setBuddy(self.themeComboBox)
|
||||
self.themeComboBox.setObjectName(u'themeComboBox')
|
||||
self.horizontalLayout3.addWidget(self.themeComboBox)
|
||||
self.gridLayout.addLayout(self.horizontalLayout3, 2, 0, 1, 1)
|
||||
self.horizontalLayout2 = QtGui.QHBoxLayout()
|
||||
self.horizontalLayout2.setObjectName(u'horizontalLayout2')
|
||||
self.creditLabel = QtGui.QLabel(customEditDialog)
|
||||
self.creditLabel.setObjectName(u'creditLabel')
|
||||
self.horizontalLayout2.addWidget(self.creditLabel)
|
||||
self.creditEdit = QtGui.QLineEdit(customEditDialog)
|
||||
self.creditLabel.setBuddy(self.creditEdit)
|
||||
self.creditEdit.setObjectName(u'creditEdit')
|
||||
self.horizontalLayout2.addWidget(self.creditEdit)
|
||||
self.gridLayout.addLayout(self.horizontalLayout2, 3, 0, 1, 1)
|
||||
self.buttonBox = QtGui.QDialogButtonBox(customEditDialog)
|
||||
self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel |
|
||||
QtGui.QDialogButtonBox.Save)
|
||||
self.buttonBox.setObjectName(u'buttonBox')
|
||||
self.gridLayout.addWidget(self.buttonBox, 4, 0, 1, 1)
|
||||
self.horizontalLayout4 = QtGui.QHBoxLayout()
|
||||
self.horizontalLayout4.setObjectName(u'horizontalLayout4')
|
||||
self.slideListView = QtGui.QListWidget(customEditDialog)
|
||||
self.slideListView.setAlternatingRowColors(True)
|
||||
self.slideListView.setObjectName(u'slideListView')
|
||||
self.horizontalLayout4.addWidget(self.slideListView)
|
||||
self.verticalLayout = QtGui.QVBoxLayout()
|
||||
self.verticalLayout.setObjectName(u'verticalLayout')
|
||||
self.addButton = QtGui.QPushButton(customEditDialog)
|
||||
self.addButton.setObjectName(u'addButton')
|
||||
self.verticalLayout.addWidget(self.addButton)
|
||||
self.editButton = QtGui.QPushButton(customEditDialog)
|
||||
self.editButton.setObjectName(u'editButton')
|
||||
self.verticalLayout.addWidget(self.editButton)
|
||||
self.editAllButton = QtGui.QPushButton(customEditDialog)
|
||||
self.editAllButton.setObjectName(u'editAllButton')
|
||||
self.verticalLayout.addWidget(self.editAllButton)
|
||||
self.deleteButton = QtGui.QPushButton(customEditDialog)
|
||||
self.deleteButton.setObjectName(u'deleteButton')
|
||||
self.verticalLayout.addWidget(self.deleteButton)
|
||||
spacerItem = QtGui.QSpacerItem(20, 128, QtGui.QSizePolicy.Minimum,
|
||||
QtGui.QSizePolicy.Expanding)
|
||||
self.verticalLayout.addItem(spacerItem)
|
||||
self.upButton = QtGui.QPushButton(customEditDialog)
|
||||
icon1 = QtGui.QIcon()
|
||||
icon1.addPixmap(QtGui.QPixmap(u':/services/service_up.png'),
|
||||
QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||
self.upButton.setIcon(icon1)
|
||||
self.upButton.setObjectName(u'upButton')
|
||||
self.verticalLayout.addWidget(self.upButton)
|
||||
self.downButton = QtGui.QPushButton(customEditDialog)
|
||||
icon2 = QtGui.QIcon()
|
||||
icon2.addPixmap(QtGui.QPixmap(u':/services/service_down.png'),
|
||||
QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||
self.downButton.setIcon(icon2)
|
||||
self.downButton.setObjectName(u'downButton')
|
||||
self.verticalLayout.addWidget(self.downButton)
|
||||
self.horizontalLayout4.addLayout(self.verticalLayout)
|
||||
self.gridLayout.addLayout(self.horizontalLayout4, 1, 0, 1, 1)
|
||||
self.horizontalLayout = QtGui.QHBoxLayout()
|
||||
self.horizontalLayout.setObjectName(u'horizontalLayout')
|
||||
self.titleLabel = QtGui.QLabel(customEditDialog)
|
||||
@ -46,91 +110,7 @@ class Ui_CustomEditDialog(object):
|
||||
self.titleEdit.setObjectName(u'titleEdit')
|
||||
self.horizontalLayout.addWidget(self.titleEdit)
|
||||
self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 1)
|
||||
self.horizontalLayout4 = QtGui.QHBoxLayout()
|
||||
self.horizontalLayout4.setObjectName(u'horizontalLayout4')
|
||||
self.verseListView = QtGui.QListWidget(customEditDialog)
|
||||
self.verseListView.setAlternatingRowColors(True)
|
||||
self.verseListView.setObjectName(u'verseListView')
|
||||
self.horizontalLayout4.addWidget(self.verseListView)
|
||||
self.verticalLayout = QtGui.QVBoxLayout()
|
||||
self.verticalLayout.setObjectName(u'verticalLayout')
|
||||
self.upButton = QtGui.QPushButton(customEditDialog)
|
||||
self.upButton.setIcon(build_icon(u':/services/service_up.png'))
|
||||
self.upButton.setObjectName(u'upButton')
|
||||
self.verticalLayout.addWidget(self.upButton)
|
||||
spacerItem = QtGui.QSpacerItem(20, 128, QtGui.QSizePolicy.Minimum,
|
||||
QtGui.QSizePolicy.Expanding)
|
||||
self.verticalLayout.addItem(spacerItem)
|
||||
self.downButton = QtGui.QPushButton(customEditDialog)
|
||||
self.downButton.setIcon(build_icon(u':/services/service_down.png'))
|
||||
self.downButton.setObjectName(u'downButton')
|
||||
self.verticalLayout.addWidget(self.downButton)
|
||||
self.horizontalLayout4.addLayout(self.verticalLayout)
|
||||
self.gridLayout.addLayout(self.horizontalLayout4, 1, 0, 1, 1)
|
||||
self.editWidget = QtGui.QWidget(customEditDialog)
|
||||
self.editWidget.setObjectName(u'editWidget')
|
||||
self.editLayout3 = QtGui.QHBoxLayout(self.editWidget)
|
||||
self.editLayout3.setSpacing(8)
|
||||
self.editLayout3.setMargin(0)
|
||||
self.editLayout3.setObjectName(u'editLayout3')
|
||||
self.verseTextEdit = SpellTextEdit(self)
|
||||
self.verseTextEdit.setObjectName(u'verseTextEdit')
|
||||
self.editLayout3.addWidget(self.verseTextEdit)
|
||||
self.buttonWidget = QtGui.QWidget(self.editWidget)
|
||||
self.buttonWidget.setObjectName(u'buttonWidget')
|
||||
self.verticalLayout2 = QtGui.QVBoxLayout(self.buttonWidget)
|
||||
self.verticalLayout2.setObjectName(u'verticalLayout2')
|
||||
self.addButton = QtGui.QPushButton(self.buttonWidget)
|
||||
self.addButton.setObjectName(u'addButton')
|
||||
self.verticalLayout2.addWidget(self.addButton)
|
||||
self.editButton = QtGui.QPushButton(self.buttonWidget)
|
||||
self.editButton.setObjectName(u'editButton')
|
||||
self.verticalLayout2.addWidget(self.editButton)
|
||||
self.editAllButton = QtGui.QPushButton(self.buttonWidget)
|
||||
self.editAllButton.setObjectName(u'editAllButton')
|
||||
self.verticalLayout2.addWidget(self.editAllButton)
|
||||
self.saveButton = QtGui.QPushButton(self.buttonWidget)
|
||||
self.saveButton.setObjectName(u'saveButton')
|
||||
self.verticalLayout2.addWidget(self.saveButton)
|
||||
self.deleteButton = QtGui.QPushButton(self.buttonWidget)
|
||||
self.deleteButton.setObjectName(u'deleteButton')
|
||||
self.verticalLayout2.addWidget(self.deleteButton)
|
||||
self.clearButton = QtGui.QPushButton(self.buttonWidget)
|
||||
self.clearButton.setObjectName(u'clearButton')
|
||||
self.verticalLayout2.addWidget(self.clearButton)
|
||||
self.splitButton = QtGui.QPushButton(self.buttonWidget)
|
||||
self.splitButton.setObjectName(u'splitButton')
|
||||
self.verticalLayout2.addWidget(self.splitButton)
|
||||
spacerItem1 = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum,
|
||||
QtGui.QSizePolicy.Expanding)
|
||||
self.verticalLayout2.addItem(spacerItem1)
|
||||
self.editLayout3.addWidget(self.buttonWidget)
|
||||
self.gridLayout.addWidget(self.editWidget, 2, 0, 1, 1)
|
||||
self.horizontalLayout3 = QtGui.QHBoxLayout()
|
||||
self.horizontalLayout3.setObjectName(u'horizontalLayout3')
|
||||
self.themeLabel = QtGui.QLabel(customEditDialog)
|
||||
self.themeLabel.setObjectName(u'themeLabel')
|
||||
self.horizontalLayout3.addWidget(self.themeLabel)
|
||||
self.themeComboBox = QtGui.QComboBox(customEditDialog)
|
||||
self.themeLabel.setBuddy(self.themeComboBox)
|
||||
self.themeComboBox.setObjectName(u'themeComboBox')
|
||||
self.horizontalLayout3.addWidget(self.themeComboBox)
|
||||
self.gridLayout.addLayout(self.horizontalLayout3, 3, 0, 1, 1)
|
||||
self.horizontalLayout2 = QtGui.QHBoxLayout()
|
||||
self.horizontalLayout2.setObjectName(u'horizontalLayout2')
|
||||
self.creditLabel = QtGui.QLabel(customEditDialog)
|
||||
self.creditLabel.setObjectName(u'creditLabel')
|
||||
self.horizontalLayout2.addWidget(self.creditLabel)
|
||||
self.creditEdit = QtGui.QLineEdit(customEditDialog)
|
||||
self.creditLabel.setBuddy(self.creditEdit)
|
||||
self.creditEdit.setObjectName(u'creditEdit')
|
||||
self.horizontalLayout2.addWidget(self.creditEdit)
|
||||
self.gridLayout.addLayout(self.horizontalLayout2, 4, 0, 1, 1)
|
||||
self.buttonBox = QtGui.QDialogButtonBox(customEditDialog)
|
||||
self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel |
|
||||
QtGui.QDialogButtonBox.Save)
|
||||
self.buttonBox.setObjectName(u'buttonBox')
|
||||
self.gridLayout.addWidget(self.buttonBox, 5, 0, 1, 1)
|
||||
|
||||
self.retranslateUi(customEditDialog)
|
||||
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(u'accepted()'),
|
||||
customEditDialog.accept)
|
||||
@ -143,46 +123,32 @@ class Ui_CustomEditDialog(object):
|
||||
translate('CustomPlugin.EditCustomForm', 'Edit Custom Slides'))
|
||||
self.upButton.setToolTip(
|
||||
translate('CustomPlugin.EditCustomForm', 'Move slide up one '
|
||||
'position.'))
|
||||
'position.'))
|
||||
self.downButton.setToolTip(
|
||||
translate('CustomPlugin.EditCustomForm', 'Move slide down one '
|
||||
'position.'))
|
||||
'position.'))
|
||||
self.titleLabel.setText(
|
||||
translate('CustomPlugin.EditCustomForm', '&Title:'))
|
||||
self.addButton.setText(
|
||||
translate('CustomPlugin.EditCustomForm', 'Add New'))
|
||||
translate('CustomPlugin.EditCustomForm', '&Add'))
|
||||
self.addButton.setToolTip(
|
||||
translate('CustomPlugin.EditCustomForm', 'Add a new slide at '
|
||||
'bottom.'))
|
||||
'bottom.'))
|
||||
self.editButton.setText(
|
||||
translate('CustomPlugin.EditCustomForm', 'Edit'))
|
||||
translate('CustomPlugin.EditCustomForm', '&Edit'))
|
||||
self.editButton.setToolTip(
|
||||
translate('CustomPlugin.EditCustomForm', 'Edit the selected '
|
||||
'slide.'))
|
||||
'slide.'))
|
||||
self.editAllButton.setText(
|
||||
translate('CustomPlugin.EditCustomForm', 'Edit All'))
|
||||
translate('CustomPlugin.EditCustomForm', 'Ed&it All'))
|
||||
self.editAllButton.setToolTip(
|
||||
translate('CustomPlugin.EditCustomForm', 'Edit all the slides at '
|
||||
'once.'))
|
||||
self.saveButton.setText(
|
||||
translate('CustomPlugin.EditCustomForm', 'Save'))
|
||||
self.saveButton.setToolTip(
|
||||
translate('CustomPlugin.EditCustomForm', 'Save the slide currently '
|
||||
'being edited.'))
|
||||
'once.'))
|
||||
self.deleteButton.setText(
|
||||
translate('CustomPlugin.EditCustomForm', 'Delete'))
|
||||
translate('CustomPlugin.EditCustomForm', '&Delete'))
|
||||
self.deleteButton.setToolTip(
|
||||
translate('CustomPlugin.EditCustomForm', 'Delete the selected '
|
||||
'slide.'))
|
||||
self.clearButton.setText(
|
||||
translate('CustomPlugin.EditCustomForm', 'Clear'))
|
||||
self.clearButton.setToolTip(
|
||||
translate('CustomPlugin.EditCustomForm', 'Clear edit area'))
|
||||
self.splitButton.setText(
|
||||
translate('CustomPlugin.EditCustomForm', 'Split Slide'))
|
||||
self.splitButton.setToolTip(
|
||||
translate('CustomPlugin.EditCustomForm', 'Split a slide into two '
|
||||
'by inserting a slide splitter.'))
|
||||
'slide.'))
|
||||
self.themeLabel.setText(
|
||||
translate('CustomPlugin.EditCustomForm', 'The&me:'))
|
||||
self.creditLabel.setText(
|
||||
|
@ -32,6 +32,7 @@ from openlp.core.lib import Receiver, translate
|
||||
from openlp.plugins.custom.lib import CustomXMLBuilder, CustomXMLParser
|
||||
from openlp.plugins.custom.lib.db import CustomSlide
|
||||
from editcustomdialog import Ui_CustomEditDialog
|
||||
from editcustomslideform import EditCustomSlideForm
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@ -40,7 +41,7 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
|
||||
Class documentation goes here.
|
||||
"""
|
||||
log.info(u'Custom Editor loaded')
|
||||
def __init__(self, custommanager, parent = None):
|
||||
def __init__(self, manager, parent=None):
|
||||
"""
|
||||
Constructor
|
||||
"""
|
||||
@ -61,28 +62,20 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
|
||||
QtCore.SIGNAL(u'pressed()'), self.onEditButtonPressed)
|
||||
QtCore.QObject.connect(self.editAllButton,
|
||||
QtCore.SIGNAL(u'pressed()'), self.onEditAllButtonPressed)
|
||||
QtCore.QObject.connect(self.saveButton,
|
||||
QtCore.SIGNAL(u'pressed()'), self.onSaveButtonPressed)
|
||||
QtCore.QObject.connect(self.deleteButton,
|
||||
QtCore.SIGNAL(u'pressed()'), self.onDeleteButtonPressed)
|
||||
QtCore.QObject.connect(self.clearButton,
|
||||
QtCore.SIGNAL(u'pressed()'), self.onClearButtonPressed)
|
||||
QtCore.QObject.connect(self.upButton,
|
||||
QtCore.SIGNAL(u'pressed()'), self.onUpButtonPressed)
|
||||
QtCore.QObject.connect(self.downButton,
|
||||
QtCore.SIGNAL(u'pressed()'), self.onDownButtonPressed)
|
||||
QtCore.QObject.connect(self.splitButton,
|
||||
QtCore.SIGNAL(u'pressed()'), self.onSplitButtonPressed)
|
||||
QtCore.QObject.connect(self.verseListView,
|
||||
QtCore.SIGNAL(u'itemDoubleClicked(QListWidgetItem*)'),
|
||||
self.onVerseListViewSelected)
|
||||
QtCore.QObject.connect(self.verseListView,
|
||||
QtCore.QObject.connect(self.slideListView,
|
||||
QtCore.SIGNAL(u'itemClicked(QListWidgetItem*)'),
|
||||
self.onVerseListViewPressed)
|
||||
self.onSlideListViewPressed)
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
QtCore.SIGNAL(u'theme_update_list'), self.loadThemes)
|
||||
# Create other objects and forms
|
||||
self.custommanager = custommanager
|
||||
# Create other objects and forms.
|
||||
self.manager = manager
|
||||
self.editSlideForm = EditCustomSlideForm(self)
|
||||
self.initialise()
|
||||
|
||||
def onPreview(self, button):
|
||||
@ -92,21 +85,15 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
|
||||
Receiver.send_message(u'custom_preview')
|
||||
|
||||
def initialise(self):
|
||||
self.editAll = False
|
||||
self.addButton.setEnabled(True)
|
||||
self.deleteButton.setEnabled(False)
|
||||
self.editButton.setEnabled(False)
|
||||
self.editAllButton.setEnabled(True)
|
||||
self.saveButton.setEnabled(False)
|
||||
self.clearButton.setEnabled(False)
|
||||
self.splitButton.setEnabled(False)
|
||||
self.titleEdit.setText(u'')
|
||||
self.creditEdit.setText(u'')
|
||||
self.verseTextEdit.clear()
|
||||
self.verseListView.clear()
|
||||
#make sure we have a new item
|
||||
self.slideListView.clear()
|
||||
# Make sure we have a new item.
|
||||
self.customSlide = CustomSlide()
|
||||
self.themeComboBox.addItem(u'')
|
||||
|
||||
def loadThemes(self, themelist):
|
||||
self.themeComboBox.clear()
|
||||
@ -115,16 +102,26 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
|
||||
self.themeComboBox.addItem(themename)
|
||||
|
||||
def loadCustom(self, id, preview=False):
|
||||
"""
|
||||
Called when editing or creating a new custom.
|
||||
|
||||
``id``
|
||||
The cutom's id. If zero, then a new custom is created.
|
||||
|
||||
``preview``
|
||||
States whether the custom is edited while being previewed in the
|
||||
preview panel.
|
||||
"""
|
||||
self.customSlide = CustomSlide()
|
||||
self.initialise()
|
||||
if id != 0:
|
||||
self.customSlide = self.custommanager.get_object(CustomSlide, id)
|
||||
self.customSlide = self.manager.get_object(CustomSlide, id)
|
||||
self.titleEdit.setText(self.customSlide.title)
|
||||
self.creditEdit.setText(self.customSlide.credits)
|
||||
customXML = CustomXMLParser(self.customSlide.text)
|
||||
verseList = customXML.get_verses()
|
||||
for verse in verseList:
|
||||
self.verseListView.addItem(verse[1])
|
||||
slideList = customXML.get_verses()
|
||||
for slide in slideList:
|
||||
self.slideListView.addItem(slide[1])
|
||||
theme = self.customSlide.theme_name
|
||||
id = self.themeComboBox.findText(theme, QtCore.Qt.MatchExactly)
|
||||
if id == -1:
|
||||
@ -132,7 +129,8 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
|
||||
self.themeComboBox.setCurrentIndex(id)
|
||||
else:
|
||||
self.themeComboBox.setCurrentIndex(0)
|
||||
#if not preview hide the preview button
|
||||
self.editAllButton.setEnabled(False)
|
||||
# If not preview hide the preview button.
|
||||
self.previewButton.setVisible(False)
|
||||
if preview:
|
||||
self.previewButton.setVisible(True)
|
||||
@ -148,6 +146,9 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
|
||||
self.close()
|
||||
|
||||
def saveCustom(self):
|
||||
"""
|
||||
Saves the custom.
|
||||
"""
|
||||
valid, message = self._validate()
|
||||
if not valid:
|
||||
QtGui.QMessageBox.critical(self,
|
||||
@ -157,9 +158,9 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
|
||||
sxml.new_document()
|
||||
sxml.add_lyrics_to_song()
|
||||
count = 1
|
||||
for i in range(0, self.verseListView.count()):
|
||||
for i in range(0, self.slideListView.count()):
|
||||
sxml.add_verse_to_lyrics(u'custom', unicode(count),
|
||||
unicode(self.verseListView.item(i).text()))
|
||||
unicode(self.slideListView.item(i).text()))
|
||||
count += 1
|
||||
self.customSlide.title = unicode(self.titleEdit.displayText(), u'utf-8')
|
||||
self.customSlide.text = unicode(sxml.extract_xml(), u'utf-8')
|
||||
@ -167,117 +168,106 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
|
||||
u'utf-8')
|
||||
self.customSlide.theme_name = unicode(self.themeComboBox.currentText(),
|
||||
u'utf-8')
|
||||
return self.custommanager.save_object(self.customSlide)
|
||||
return self.manager.save_object(self.customSlide)
|
||||
|
||||
def onUpButtonPressed(self):
|
||||
selectedRow = self.verseListView.currentRow()
|
||||
selectedRow = self.slideListView.currentRow()
|
||||
if selectedRow != 0:
|
||||
qw = self.verseListView.takeItem(selectedRow)
|
||||
self.verseListView.insertItem(selectedRow - 1, qw)
|
||||
self.verseListView.setCurrentRow(selectedRow - 1)
|
||||
qw = self.slideListView.takeItem(selectedRow)
|
||||
self.slideListView.insertItem(selectedRow - 1, qw)
|
||||
self.slideListView.setCurrentRow(selectedRow - 1)
|
||||
|
||||
def onDownButtonPressed(self):
|
||||
selectedRow = self.verseListView.currentRow()
|
||||
selectedRow = self.slideListView.currentRow()
|
||||
# zero base arrays
|
||||
if selectedRow != self.verseListView.count() - 1:
|
||||
qw = self.verseListView.takeItem(selectedRow)
|
||||
self.verseListView.insertItem(selectedRow + 1, qw)
|
||||
self.verseListView.setCurrentRow(selectedRow + 1)
|
||||
if selectedRow != self.slideListView.count() - 1:
|
||||
qw = self.slideListView.takeItem(selectedRow)
|
||||
self.slideListView.insertItem(selectedRow + 1, qw)
|
||||
self.slideListView.setCurrentRow(selectedRow + 1)
|
||||
|
||||
def onClearButtonPressed(self):
|
||||
self.verseTextEdit.clear()
|
||||
self.editAll = False
|
||||
self.addButton.setEnabled(True)
|
||||
self.editAllButton.setEnabled(True)
|
||||
self.saveButton.setEnabled(False)
|
||||
|
||||
def onVerseListViewPressed(self, item):
|
||||
def onSlideListViewPressed(self, item):
|
||||
self.deleteButton.setEnabled(True)
|
||||
self.editButton.setEnabled(True)
|
||||
|
||||
def onVerseListViewSelected(self, item):
|
||||
self.editText(item.text())
|
||||
|
||||
def onAddButtonPressed(self):
|
||||
self.verseListView.addItem(self.verseTextEdit.toPlainText())
|
||||
self.deleteButton.setEnabled(False)
|
||||
self.verseTextEdit.clear()
|
||||
self.editSlideForm.setText(u'')
|
||||
if self.editSlideForm.exec_():
|
||||
for slide in self.editSlideForm.getText():
|
||||
self.slideListView.addItem(slide)
|
||||
self.editAllButton.setEnabled(True)
|
||||
|
||||
def onEditButtonPressed(self):
|
||||
self.editText(self.verseListView.currentItem().text())
|
||||
self.editSlideForm.setText(self.slideListView.currentItem().text())
|
||||
if self.editSlideForm.exec_():
|
||||
self.updateSlideList(self.editSlideForm.getText())
|
||||
|
||||
def onEditAllButtonPressed(self):
|
||||
self.editAll = True
|
||||
self.addButton.setEnabled(False)
|
||||
self.splitButton.setEnabled(True)
|
||||
if self.verseListView.count() > 0:
|
||||
verse_list = u''
|
||||
for row in range(0, self.verseListView.count()):
|
||||
item = self.verseListView.item(row)
|
||||
verse_list += item.text()
|
||||
if row != self.verseListView.count() - 1:
|
||||
verse_list += u'\n[---]\n'
|
||||
self.editText(verse_list)
|
||||
"""
|
||||
Edits all slides.
|
||||
"""
|
||||
if self.slideListView.count() > 0:
|
||||
slide_list = u''
|
||||
for row in range(0, self.slideListView.count()):
|
||||
item = self.slideListView.item(row)
|
||||
slide_list += item.text()
|
||||
if row != self.slideListView.count() - 1:
|
||||
slide_list += u'\n[---]\n'
|
||||
self.editSlideForm.setText(slide_list)
|
||||
if self.editSlideForm.exec_():
|
||||
self.updateSlideList(self.editSlideForm.getText(), True)
|
||||
|
||||
def editText(self, text):
|
||||
self.beforeText = text
|
||||
self.verseTextEdit.setPlainText(text)
|
||||
self.deleteButton.setEnabled(False)
|
||||
self.editButton.setEnabled(False)
|
||||
self.editAllButton.setEnabled(False)
|
||||
self.saveButton.setEnabled(True)
|
||||
self.clearButton.setEnabled(True)
|
||||
def updateSlideList(self, slides, edit_all=False):
|
||||
"""
|
||||
Updates the slide list after editing slides.
|
||||
|
||||
def onSaveButtonPressed(self):
|
||||
if self.editAll:
|
||||
self.verseListView.clear()
|
||||
for row in unicode(self.verseTextEdit.toPlainText()).split(
|
||||
u'\n[---]\n'):
|
||||
self.verseListView.addItem(row)
|
||||
``slides``
|
||||
A list of all slides which have been edited.
|
||||
|
||||
``edit_all``
|
||||
Indicates if all slides or only one slide has been edited.
|
||||
"""
|
||||
if len(slides) == 1:
|
||||
self.slideListView.currentItem().setText(slides[0])
|
||||
else:
|
||||
self.verseListView.currentItem().setText(
|
||||
self.verseTextEdit.toPlainText())
|
||||
#number of lines has change
|
||||
if len(self.beforeText.split(u'\n')) != \
|
||||
len(self.verseTextEdit.toPlainText().split(u'\n')):
|
||||
tempList = {}
|
||||
for row in range(0, self.verseListView.count()):
|
||||
tempList[row] = self.verseListView.item(row).text()
|
||||
self.verseListView.clear()
|
||||
for row in range (0, len(tempList)):
|
||||
self.verseListView.addItem(tempList[row])
|
||||
self.verseListView.repaint()
|
||||
self.addButton.setEnabled(True)
|
||||
self.saveButton.setEnabled(False)
|
||||
self.editButton.setEnabled(False)
|
||||
self.editAllButton.setEnabled(True)
|
||||
self.splitButton.setEnabled(False)
|
||||
self.verseTextEdit.clear()
|
||||
|
||||
def onSplitButtonPressed(self):
|
||||
if self.verseTextEdit.textCursor().columnNumber() != 0:
|
||||
self.verseTextEdit.insertPlainText(u'\n')
|
||||
self.verseTextEdit.insertPlainText(u'[---]\n' )
|
||||
self.verseTextEdit.setFocus()
|
||||
if edit_all:
|
||||
self.slideListView.clear()
|
||||
for slide in slides:
|
||||
self.slideListView.addItem(slide)
|
||||
else:
|
||||
old_slides = []
|
||||
old_row = self.slideListView.currentRow()
|
||||
# Create a list with all (old/unedited) slides.
|
||||
old_slides = [self.slideListView.item(row).text() for row in \
|
||||
range(0, self.slideListView.count())]
|
||||
self.slideListView.clear()
|
||||
old_slides.pop(old_row)
|
||||
# Insert all slides to make the old_slides list complete.
|
||||
for slide in slides:
|
||||
old_slides.insert(old_row, slide)
|
||||
for slide in old_slides:
|
||||
self.slideListView.addItem(slide)
|
||||
self.slideListView.repaint()
|
||||
|
||||
def onDeleteButtonPressed(self):
|
||||
self.verseListView.takeItem(self.verseListView.currentRow())
|
||||
self.editButton.setEnabled(False)
|
||||
self.slideListView.takeItem(self.slideListView.currentRow())
|
||||
self.editButton.setEnabled(True)
|
||||
self.editAllButton.setEnabled(True)
|
||||
if self.slideListView.count() == 0:
|
||||
self.deleteButton.setEnabled(False)
|
||||
self.editButton.setEnabled(False)
|
||||
self.editAllButton.setEnabled(False)
|
||||
|
||||
def _validate(self):
|
||||
"""
|
||||
Checks whether a custom is valid or not.
|
||||
"""
|
||||
# We must have a title.
|
||||
if len(self.titleEdit.displayText()) == 0:
|
||||
self.titleEdit.setFocus()
|
||||
return False, translate('CustomPlugin.EditCustomForm',
|
||||
'You need to type in a title.')
|
||||
# must have 1 slide
|
||||
if self.verseListView.count() == 0:
|
||||
self.verseTextEdit.setFocus()
|
||||
# We must have one slide.
|
||||
if self.slideListView.count() == 0:
|
||||
return False, translate('CustomPlugin.EditCustomForm',
|
||||
'You need to add at least one slide')
|
||||
if self.verseTextEdit.toPlainText():
|
||||
self.verseTextEdit.setFocus()
|
||||
return False, translate('CustomPlugin.EditCustomForm',
|
||||
'You have one or more unsaved slides, please either save your '
|
||||
'slide(s) or clear your changes.')
|
||||
return True, u''
|
||||
|
59
openlp/plugins/custom/forms/editcustomslidedialog.py
Normal 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.'))
|
75
openlp/plugins/custom/forms/editcustomslideform.py
Normal 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()
|
@ -56,6 +56,7 @@ class CustomMediaItem(MediaManagerItem):
|
||||
# Holds information about whether the edit is remotly triggered and
|
||||
# which Custom is required.
|
||||
self.remoteCustom = -1
|
||||
self.manager = parent.manager
|
||||
|
||||
def addEndHeaderBar(self):
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
@ -71,7 +72,7 @@ class CustomMediaItem(MediaManagerItem):
|
||||
MediaManagerItem.requiredIcons(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))
|
||||
#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
|
||||
@ -106,7 +107,7 @@ class CustomMediaItem(MediaManagerItem):
|
||||
type of display is required.
|
||||
"""
|
||||
fields = customid.split(u':')
|
||||
valid = self.parent.custommanager.get_object(CustomSlide, fields[1])
|
||||
valid = self.manager.get_object(CustomSlide, fields[1])
|
||||
if valid:
|
||||
self.remoteCustom = fields[1]
|
||||
self.remoteTriggered = fields[0]
|
||||
|
@ -166,9 +166,8 @@ class ImageMediaItem(MediaManagerItem):
|
||||
for item in items:
|
||||
bitem = self.listView.item(item.row())
|
||||
filename = unicode(bitem.data(QtCore.Qt.UserRole).toString())
|
||||
frame = QtGui.QImage(unicode(filename))
|
||||
(path, name) = os.path.split(filename)
|
||||
service_item.add_from_image(path, name, frame)
|
||||
service_item.add_from_image(filename, name)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
@ -185,7 +184,8 @@ class ImageMediaItem(MediaManagerItem):
|
||||
for item in items:
|
||||
bitem = self.listView.item(item.row())
|
||||
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)
|
||||
|
||||
def onPreviewClick(self):
|
||||
|
@ -25,5 +25,6 @@
|
||||
###############################################################################
|
||||
|
||||
from mediaitem import MediaMediaItem
|
||||
from mediatab import MediaTab
|
||||
|
||||
__all__ = ['MediaMediaItem']
|
||||
|
@ -113,7 +113,7 @@ class MediaMediaItem(MediaManagerItem):
|
||||
'You must select a media file to replace the background with.')):
|
||||
item = self.listView.currentItem()
|
||||
filename = unicode(item.data(QtCore.Qt.UserRole).toString())
|
||||
self.parent.liveController.display.video(filename, 0)
|
||||
self.parent.liveController.display.video(filename, 0, True)
|
||||
self.resetButton.setVisible(True)
|
||||
|
||||
def generateSlideData(self, service_item, item=None):
|
||||
|
84
openlp/plugins/media/lib/mediatab.py
Normal 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')
|
||||
|
||||
|
@ -29,7 +29,7 @@ import logging
|
||||
from PyQt4.phonon import Phonon
|
||||
|
||||
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__)
|
||||
|
||||
@ -68,6 +68,9 @@ class MediaPlugin(Plugin):
|
||||
type = u''
|
||||
return list, type
|
||||
|
||||
def getSettingsTab(self):
|
||||
return MediaTab(self.name)
|
||||
|
||||
def getMediaManagerItem(self):
|
||||
# Create the MediaManagerItem object
|
||||
return MediaMediaItem(self, self, self.icon)
|
||||
@ -132,4 +135,4 @@ class MediaPlugin(Plugin):
|
||||
u'title': translate('MediaPlugin', 'Service'),
|
||||
u'tooltip': translate('MediaPlugin',
|
||||
'Add the selected Media to the service')
|
||||
}
|
||||
}
|
||||
|
@ -169,7 +169,8 @@ class ImpressController(PresentationController):
|
||||
try:
|
||||
return Dispatch(u'com.sun.star.ServiceManager')
|
||||
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
|
||||
|
||||
def kill(self):
|
||||
|
@ -110,10 +110,10 @@ class PowerpointDocument(PresentationDocument):
|
||||
"""
|
||||
Class which holds information and controls a single 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')
|
||||
PresentationDocument.__init__(self, controller, presentation)
|
||||
@ -125,13 +125,13 @@ class PowerpointDocument(PresentationDocument):
|
||||
Opens the PowerPoint file using the process created earlier
|
||||
|
||||
``presentation``
|
||||
The file name of the presentations to run.
|
||||
The file name of the presentations to run.
|
||||
"""
|
||||
log.debug(u'LoadPresentation')
|
||||
if not self.controller.process or not self.controller.process.Visible:
|
||||
self.controller.start_process()
|
||||
try:
|
||||
self.controller.process.Presentations.Open(self.filepath, False,
|
||||
self.controller.process.Presentations.Open(self.filepath, False,
|
||||
False, True)
|
||||
except pywintypes.com_error:
|
||||
return False
|
||||
@ -143,22 +143,24 @@ class PowerpointDocument(PresentationDocument):
|
||||
def create_thumbnails(self):
|
||||
"""
|
||||
Create the thumbnail images for the current presentation.
|
||||
Note an alternative and quicker method would be do
|
||||
|
||||
Note an alternative and quicker method would be do::
|
||||
|
||||
self.presentation.Slides[n].Copy()
|
||||
thumbnail = QApplication.clipboard.image()
|
||||
But for now we want a physical file since it makes
|
||||
life easier elsewhere
|
||||
|
||||
However, for the moment, we want a physical file since it makes life
|
||||
easier elsewhere.
|
||||
"""
|
||||
if self.check_thumbnails():
|
||||
return
|
||||
self.presentation.Export(os.path.join(self.get_thumbnail_folder(), ''),
|
||||
self.presentation.Export(os.path.join(self.get_thumbnail_folder(), ''),
|
||||
'png', 320, 240)
|
||||
|
||||
def close_presentation(self):
|
||||
"""
|
||||
Close presentation and clean up objects
|
||||
Triggerent by new object being added to SlideController orOpenLP
|
||||
being shut down
|
||||
Close presentation and clean up objects. This is triggered by a new
|
||||
object being added to SlideController or OpenLP being shut down.
|
||||
"""
|
||||
log.debug(u'ClosePresentation')
|
||||
if self.presentation:
|
||||
@ -171,7 +173,7 @@ class PowerpointDocument(PresentationDocument):
|
||||
|
||||
def is_loaded(self):
|
||||
"""
|
||||
Returns true if a presentation is loaded
|
||||
Returns ``True`` if a presentation is loaded.
|
||||
"""
|
||||
try:
|
||||
if not self.controller.process.Visible:
|
||||
@ -187,7 +189,7 @@ class PowerpointDocument(PresentationDocument):
|
||||
|
||||
def is_active(self):
|
||||
"""
|
||||
Returns true if a presentation is currently active
|
||||
Returns ``True`` if a presentation is currently active.
|
||||
"""
|
||||
if not self.is_loaded():
|
||||
return False
|
||||
@ -202,7 +204,7 @@ class PowerpointDocument(PresentationDocument):
|
||||
|
||||
def unblank_screen(self):
|
||||
"""
|
||||
Unblanks (restores) the presentationn
|
||||
Unblanks (restores) the presentation.
|
||||
"""
|
||||
self.presentation.SlideShowSettings.Run()
|
||||
self.presentation.SlideShowWindow.View.State = 1
|
||||
@ -210,13 +212,13 @@ class PowerpointDocument(PresentationDocument):
|
||||
|
||||
def blank_screen(self):
|
||||
"""
|
||||
Blanks the screen
|
||||
Blanks the screen.
|
||||
"""
|
||||
self.presentation.SlideShowWindow.View.State = 3
|
||||
|
||||
def is_blank(self):
|
||||
"""
|
||||
Returns true if screen is blank
|
||||
Returns ``True`` if screen is blank.
|
||||
"""
|
||||
if self.is_active():
|
||||
return self.presentation.SlideShowWindow.View.State == 3
|
||||
@ -225,14 +227,14 @@ class PowerpointDocument(PresentationDocument):
|
||||
|
||||
def stop_presentation(self):
|
||||
"""
|
||||
Stops the current presentation and hides the output
|
||||
Stops the current presentation and hides the output.
|
||||
"""
|
||||
self.presentation.SlideShowWindow.View.Exit()
|
||||
|
||||
if os.name == u'nt':
|
||||
def start_presentation(self):
|
||||
"""
|
||||
Starts a presentation from the beginning
|
||||
Starts a presentation from the beginning.
|
||||
"""
|
||||
#SlideShowWindow measures its size/position by points, not pixels
|
||||
try:
|
||||
@ -254,40 +256,40 @@ class PowerpointDocument(PresentationDocument):
|
||||
|
||||
def get_slide_number(self):
|
||||
"""
|
||||
Returns the current slide number
|
||||
Returns the current slide number.
|
||||
"""
|
||||
return self.presentation.SlideShowWindow.View.CurrentShowPosition
|
||||
|
||||
def get_slide_count(self):
|
||||
"""
|
||||
Returns total number of slides
|
||||
Returns total number of slides.
|
||||
"""
|
||||
return self.presentation.Slides.Count
|
||||
|
||||
def goto_slide(self, slideno):
|
||||
"""
|
||||
Moves to a specific slide in the presentation
|
||||
Moves to a specific slide in the presentation.
|
||||
"""
|
||||
self.presentation.SlideShowWindow.View.GotoSlide(slideno)
|
||||
|
||||
def next_step(self):
|
||||
"""
|
||||
Triggers the next effect of slide on the running presentation
|
||||
Triggers the next effect of slide on the running presentation.
|
||||
"""
|
||||
self.presentation.SlideShowWindow.View.Next()
|
||||
|
||||
def previous_step(self):
|
||||
"""
|
||||
Triggers the previous slide on the running presentation
|
||||
Triggers the previous slide on the running presentation.
|
||||
"""
|
||||
self.presentation.SlideShowWindow.View.Previous()
|
||||
|
||||
def get_slide_text(self, slide_no):
|
||||
"""
|
||||
Returns the text on the slide
|
||||
Returns the text on the slide.
|
||||
|
||||
``slide_no``
|
||||
The slide the text is required for, starting at 1
|
||||
The slide the text is required for, starting at 1.
|
||||
"""
|
||||
text = ''
|
||||
shapes = self.presentation.Slides(slide_no).Shapes
|
||||
@ -299,10 +301,10 @@ class PowerpointDocument(PresentationDocument):
|
||||
|
||||
def get_slide_notes(self, slide_no):
|
||||
"""
|
||||
Returns the text on the slide
|
||||
Returns the text on the slide.
|
||||
|
||||
``slide_no``
|
||||
The slide the notes are required for, starting at 1
|
||||
The slide the notes are required for, starting at 1.
|
||||
"""
|
||||
text = ''
|
||||
shapes = self.presentation.Slides(slide_no).NotesPage.Shapes
|
||||
|
@ -37,16 +37,21 @@ log = logging.getLogger(__name__)
|
||||
|
||||
class PresentationController(object):
|
||||
"""
|
||||
Base class for presentation controllers to inherit from
|
||||
Class to control interactions with presentations.
|
||||
It creates the runtime environment
|
||||
To create a new controller, take a copy of this file and name it
|
||||
so it ends in controller.py, i.e. foobarcontroller.py
|
||||
Make sure it inherits PresentationController
|
||||
Then fill in the blanks. If possible try and make sure it loads
|
||||
on all platforms, using for example os.name checks, although
|
||||
__init__, check_available and presentation_deleted should always work.
|
||||
See impresscontroller, powerpointcontroller or pptviewcontroller
|
||||
This class is used to control interactions with presentation applications
|
||||
by creating a runtime environment. This is a base class for presentation
|
||||
controllers to inherit from.
|
||||
|
||||
To create a new controller, take a copy of this file and name it so it ends
|
||||
with ``controller.py``, i.e. ``foobarcontroller.py``. Make sure it inherits
|
||||
:class:`~openlp.plugins.presentations.lib.presentationcontroller.PresentationController`,
|
||||
and then fill in the blanks. If possible try to make sure it loads on all
|
||||
platforms, usually by using :mod:``os.name`` checks, although
|
||||
``__init__``, ``check_available`` and ``presentation_deleted`` should
|
||||
always be implemented.
|
||||
|
||||
See :class:`~openlp.plugins.presentations.lib.impresscontroller.ImpressController`,
|
||||
:class:`~openlp.plugins.presentations.lib.powerpointcontroller.PowerpointController` or
|
||||
:class:`~openlp.plugins.presentations.lib.pptviewcontroller.PptviewController`
|
||||
for examples.
|
||||
|
||||
**Basic Attributes**
|
||||
@ -70,7 +75,7 @@ class PresentationController(object):
|
||||
``alsosupports``
|
||||
Other file types the application can import, although not necessarily
|
||||
the first choice due to potential incompatibilities
|
||||
|
||||
|
||||
**Hook Functions**
|
||||
|
||||
``kill()``
|
||||
@ -246,7 +251,7 @@ class PresentationDocument(object):
|
||||
|
||||
``presentation``
|
||||
The file name of the presentations to the run.
|
||||
|
||||
|
||||
Returns False if the file could not be opened
|
||||
"""
|
||||
return False
|
||||
@ -387,7 +392,7 @@ class PresentationDocument(object):
|
||||
if os.path.isfile(file):
|
||||
img = resize_image(file, 320, 240)
|
||||
img.save(self.get_thumbnail_path(idx, False))
|
||||
|
||||
|
||||
def get_thumbnail_path(self, slide_no, check_exists):
|
||||
"""
|
||||
Returns an image path containing a preview for the requested slide
|
||||
|
@ -24,10 +24,37 @@
|
||||
# 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 topicsform import TopicsForm
|
||||
from songbookform import SongBookForm
|
||||
from editverseform import EditVerseForm
|
||||
from editsongform import EditSongForm
|
||||
from songmaintenanceform import SongMaintenanceForm
|
||||
from songimportform import ImportWizardForm
|
||||
from songimportform import SongImportForm
|
||||
|