trunk r1129

This commit is contained in:
Andreas Preikschat 2010-12-03 21:54:28 +01:00
commit 59fc6f7b3f
110 changed files with 4566 additions and 83250 deletions

View File

@ -48,7 +48,7 @@ Service Manger
-------------- --------------
The service manager contains the media items in your service file. This is the 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 area from which your media items go live, and you can also save, open, and edit
services files. services files.
.. image:: pics/servicemanager.png .. image:: pics/servicemanager.png

View File

@ -14,6 +14,8 @@ Contents:
introduction introduction
glossary glossary
dualmonitors dualmonitors
mediamanager
songs
Indices and tables Indices and tables
================== ==================

View File

@ -0,0 +1,26 @@
=============
Media Manager
=============
Once you get your system set up for OpenLP you will be ready to add content to
your setup. This will all happen through the **Media Manager**. The
`Media Manager` contains all the bibles, songs, presentations, media, and
everything else that you will project through OpenLP.
Enabling the Plugins
--------------------
You may need to enable the plugins that came with OpenLP. As you can see below
this is what the `Media Manager` looks like with all the plugins enabled.
.. image:: pics/mediamanager.png
To enable the plugins navigate to :menuselection:`Settings --> Plugins` or
press `F7`. You will then want to click on the plugin to the left that you want
to enable and select **active** from the drop down box to the right.
.. image:: pics/plugins.png
Now you should be ready to add content to OpenLP check out the section of this
guide on the individual plugins.

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

View File

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 51 KiB

0
documentation/manual/source/pics/vistapersonalize.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 139 KiB

After

Width:  |  Height:  |  Size: 139 KiB

0
documentation/manual/source/pics/winsevendisplay.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 155 KiB

After

Width:  |  Height:  |  Size: 155 KiB

View File

Before

Width:  |  Height:  |  Size: 141 KiB

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View File

@ -0,0 +1,100 @@
=====
Songs
=====
Managing your songs in OpenLP is a relatively simple process. There are also
converters provided to get data from other formats into OpenLP.
Song Importer
=============
If you are using an earlier version of OpenLP or come from another software
package, you may be able to convert your existing database to work in OpenLP
2.0. To access the Song Importer :menuselection:`File --> Import --> Song`.
You will then see the Song Importer window, then click :guilabel:`Next`.
.. image:: pics/songimporter.png
After choosing :guilabel:`Next` you can then select from the various types of
software that OpenLP will convert songs from.
.. image:: pics/songimporterchoices.png
Then click on the file folder icon to choose the file of the song database you
want to import. See the following sections for information on the different
formats that OpenLP will import.
Importing from OpenLP Version 1
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Converting from OpenLP Version 1 is a pretty simple process. You will first
need to locate your version 1 database file.
Windows XP::
C:\Documents and Settings\All Users\Application Data\openlp.org\Data\songs.olp
Windows Vista / Windows 7::
C:\ProgramData\openlp.org\Data\songs.olp
After clicking :guilabel:`Next` your conversion should be complete.
.. image:: pics/finishedimport.png
Then press :guilabel:`Finish` and you should now be ready to use your OpenLP
version one songs.
Importing from OpenSong
^^^^^^^^^^^^^^^^^^^^^^^
Converting from OpenSong you will need to locate your songs database. In the
later versions of OpenSong you are asked to define the location of this. The
songs will be located in a folder named :guilabel:`Songs`. This folder should
contain files with all your songs in them without a file extension. (file.xxx).
When you have located this folder you will then need to select the songs from
the folder.
.. image:: pics/selectsongs.png
On most operating systems to select all the songs, first select the first song
in the lest then press shift and select the last song in the list. After this
press :guilabel:`Next` and you should see that your import has been successful.
.. image:: pics/finishedimport.png
Press :guilabel:`Finish` and you will now be ready to use your songs imported
from OpenSong.
Importing from CCLI Song Select
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
To import from CCLI Song Select you must be a CCLI Subscriber and also a
subscriber of the Song Select service. For info on that go to:
http://www.ccli.com
The first step for importing from CCLI Song Select is to log into your account.
Then search for your desired song. For this example we will be adding the song
"Amazing Grace".
.. image:: pics/songselectsongsearch.png
For the song you are searching for select `lyrics` This should take you to a
page displaying the lyrics and copyright info for your song.
.. image:: pics/songselectlyrics.png
Next, hover over the :guilabel:`Lyrics` menu from the upper right corner. Then
choose either the .txt or .usr file. You will then be asked to chose a download
location if your browser does not automatically select that for you. Select
this file from the OpenLP import window and then click :guilabel:`Next` You can
also select multiple songs for import at once on most operating systems by
selecting the first item in the list then holding shift select the last item in
the list. When finished you should see that your import has completed.
.. image:: pics/finishedimport.png
Press :guilabel:`Finish` and you will now be ready to use your songs imported
from CCLI SongSelect.

View File

@ -38,48 +38,51 @@ log = logging.getLogger(__name__)
# TODO make external and configurable in alpha 4 via a settings dialog # TODO make external and configurable in alpha 4 via a settings dialog
html_expands = [] html_expands = []
html_expands.append({u'desc':u'Red', u'start tag':u'{r}', html_expands.append({u'desc': u'Red', u'start tag': u'{r}',
u'start html':u'<span style="-webkit-text-fill-color:red">', u'start html': u'<span style="-webkit-text-fill-color:red">',
u'end tag':u'{/r}', u'end html':u'</span>', u'protected':False}) u'end tag': u'{/r}', u'end html': u'</span>', u'protected': False})
html_expands.append({u'desc':u'Black', u'start tag':u'{b}', html_expands.append({u'desc': u'Black', u'start tag': u'{b}',
u'start html':u'<span style="-webkit-text-fill-color:black">', u'start html': u'<span style="-webkit-text-fill-color:black">',
u'end tag':u'{/b}', u'end html':u'</span>', u'protected':False}) u'end tag': u'{/b}', u'end html': u'</span>', u'protected': False})
html_expands.append({u'desc':u'Blue', u'start tag':u'{bl}', html_expands.append({u'desc': u'Blue', u'start tag': u'{bl}',
u'start html':u'<span style="-webkit-text-fill-color:blue">', u'start html': u'<span style="-webkit-text-fill-color:blue">',
u'end tag':u'{/bl}', u'end html':u'</span>', u'protected':False}) u'end tag': u'{/bl}', u'end html': u'</span>', u'protected': False})
html_expands.append({u'desc':u'Yellow', u'start tag':u'{y}', html_expands.append({u'desc': u'Yellow', u'start tag': u'{y}',
u'start html':u'<span style="-webkit-text-fill-color:yellow">', u'start html': u'<span style="-webkit-text-fill-color:yellow">',
u'end tag':u'{/y}', u'end html':u'</span>', u'protected':False}) u'end tag': u'{/y}', u'end html': u'</span>', u'protected': False})
html_expands.append({u'desc':u'Green', u'start tag':u'{g}', html_expands.append({u'desc': u'Green', u'start tag': u'{g}',
u'start html':u'<span style="-webkit-text-fill-color:green">', u'start html': u'<span style="-webkit-text-fill-color:green">',
u'end tag':u'{/g}', u'end html':u'</span>', u'protected':False}) u'end tag': u'{/g}', u'end html': u'</span>', u'protected': False})
html_expands.append({u'desc':u'Pink', u'start tag':u'{pk}', html_expands.append({u'desc': u'Pink', u'start tag': u'{pk}',
u'start html':u'<span style="-webkit-text-fill-color:#CC33CC">', u'start html': u'<span style="-webkit-text-fill-color:#CC33CC">',
u'end tag':u'{/pk}', u'end html':u'</span>', u'protected':False}) u'end tag': u'{/pk}', u'end html': u'</span>', u'protected': False})
html_expands.append({u'desc':u'Orange', u'start tag':u'{o}', html_expands.append({u'desc': u'Orange', u'start tag': u'{o}',
u'start html':u'<span style="-webkit-text-fill-color:#CC0033">', u'start html': u'<span style="-webkit-text-fill-color:#CC0033">',
u'end tag':u'{/o}', u'end html':u'</span>', u'protected':False}) u'end tag': u'{/o}', u'end html': u'</span>', u'protected': False})
html_expands.append({u'desc':u'Purple', u'start tag':u'{pp}', html_expands.append({u'desc': u'Purple', u'start tag': u'{pp}',
u'start html':u'<span style="-webkit-text-fill-color:#9900FF">', u'start html': u'<span style="-webkit-text-fill-color:#9900FF">',
u'end tag':u'{/pp}', u'end html':u'</span>', u'protected':False}) u'end tag': u'{/pp}', u'end html': u'</span>', u'protected': False})
html_expands.append({u'desc':u'White', u'start tag':u'{w}', html_expands.append({u'desc': u'White', u'start tag': u'{w}',
u'start html':u'<span style="-webkit-text-fill-color:white">', u'start html': u'<span style="-webkit-text-fill-color:white">',
u'end tag':u'{/w}', u'end html':u'</span>', u'protected':False}) u'end tag': u'{/w}', u'end html': u'</span>', u'protected': False})
html_expands.append({u'desc':u'Superscript', u'start tag':u'{su}', html_expands.append({u'desc': u'Superscript', u'start tag': u'{su}',
u'start html':u'<sup>', u'end tag':u'{/su}', u'end html':u'</sup>', u'start html': u'<sup>', u'end tag': u'{/su}', u'end html': u'</sup>',
u'protected':True}) u'protected': True})
html_expands.append({u'desc':u'Subscript', u'start tag':u'{sb}', html_expands.append({u'desc': u'Subscript', u'start tag': u'{sb}',
u'start html':u'<sub>', u'end tag':u'{/sb}', u'end html':u'</sub>', u'start html': u'<sub>', u'end tag': u'{/sb}', u'end html': u'</sub>',
u'protected':True}) u'protected': True})
html_expands.append({u'desc':u'Paragraph', u'start tag':u'{p}', html_expands.append({u'desc': u'Paragraph', u'start tag': u'{p}',
u'start html':u'<p>', u'end tag':u'{/p}', u'end html':u'</p>', u'start html': u'<p>', u'end tag': u'{/p}', u'end html': u'</p>',
u'protected':True}) u'protected': True})
html_expands.append({u'desc':u'Bold', u'start tag':u'{st}', html_expands.append({u'desc': u'Bold', u'start tag': u'{st}',
u'start html':u'<strong>', u'end tag':u'{/st}', u'end html':u'</strong>', u'start html': u'<strong>', u'end tag': u'{/st}', u'end html': u'</strong>',
u'protected':True}) u'protected': True})
html_expands.append({u'desc':u'Italics', u'start tag':u'{it}', html_expands.append({u'desc': u'Italics', u'start tag': u'{it}',
u'start html':u'<em>', u'end tag':u'{/it}', u'end html':u'</em>', u'start html': u'<em>', u'end tag': u'{/it}', u'end html': u'</em>',
u'protected':True}) u'protected': True})
html_expands.append({u'desc': u'Underline', u'start tag': u'{u}',
u'start html': u'<span style="text-decoration: underline;">',
u'end tag': u'{/u}', u'end html': u'</span>', u'protected': True})
def translate(context, text, comment=None): def translate(context, text, comment=None):
""" """
@ -303,6 +306,8 @@ def expand_tags(text):
text = text.replace(tag[u'end tag'], tag[u'end html']) text = text.replace(tag[u'end tag'], tag[u'end html'])
return text return text
from theme import ThemeLevel, ThemeXML, BackgroundGradientType, BackgroundType, \
HorizontalType, VerticalType
from spelltextedit import SpellTextEdit from spelltextedit import SpellTextEdit
from eventreceiver import Receiver from eventreceiver import Receiver
from imagemanager import ImageManager from imagemanager import ImageManager
@ -317,7 +322,6 @@ from htmlbuilder import build_html, build_lyrics_format_css, \
build_lyrics_outline_css build_lyrics_outline_css
from toolbar import OpenLPToolbar from toolbar import OpenLPToolbar
from dockwidget import OpenLPDockWidget from dockwidget import OpenLPDockWidget
from theme import ThemeLevel, ThemeXML
from renderer import Renderer from renderer import Renderer
from rendermanager import RenderManager from rendermanager import RenderManager
from mediamanageritem import MediaManagerItem from mediamanageritem import MediaManagerItem

View File

@ -117,6 +117,7 @@ class Manager(object):
settings = QtCore.QSettings() settings = QtCore.QSettings()
settings.beginGroup(plugin_name) settings.beginGroup(plugin_name)
self.db_url = u'' self.db_url = u''
self.is_dirty = False
db_type = unicode( db_type = unicode(
settings.value(u'db type', QtCore.QVariant(u'sqlite')).toString()) settings.value(u'db type', QtCore.QVariant(u'sqlite')).toString())
if db_type == u'sqlite': if db_type == u'sqlite':
@ -150,12 +151,34 @@ class Manager(object):
self.session.add(object_instance) self.session.add(object_instance)
if commit: if commit:
self.session.commit() self.session.commit()
self.is_dirty = True
return True return True
except InvalidRequestError: except InvalidRequestError:
self.session.rollback() self.session.rollback()
log.exception(u'Object save failed') log.exception(u'Object save failed')
return False return False
def save_objects(self, object_list, commit=True):
"""
Save a list of objects to the database
``object_list``
The list of objects to save
``commit``
Commit the session with this object
"""
try:
self.session.add_all(object_list)
if commit:
self.session.commit()
self.is_dirty = True
return True
except InvalidRequestError:
self.session.rollback()
log.exception(u'Object list save failed')
return False
def get_object(self, object_class, key=None): def get_object(self, object_class, key=None):
""" """
Return the details of an object Return the details of an object
@ -205,6 +228,22 @@ class Manager(object):
return query.order_by(order_by_ref).all() return query.order_by(order_by_ref).all()
return query.all() return query.all()
def get_object_count(self, object_class, filter_clause=None):
"""
Returns a count of the number of objects in the database.
``object_class``
The type of objects to return.
``filter_clause``
The filter governing selection of objects to return. Defaults to
None.
"""
query = self.session.query(object_class)
if filter_clause is not None:
query = query.filter(filter_clause)
return query.count()
def delete_object(self, object_class, key): def delete_object(self, object_class, key):
""" """
Delete an object from the database Delete an object from the database
@ -220,6 +259,7 @@ class Manager(object):
try: try:
self.session.delete(object_instance) self.session.delete(object_instance)
self.session.commit() self.session.commit()
self.is_dirty = True
return True return True
except InvalidRequestError: except InvalidRequestError:
self.session.rollback() self.session.rollback()
@ -241,6 +281,7 @@ class Manager(object):
query = query.filter(filter_clause) query = query.filter(filter_clause)
query.delete(synchronize_session=False) query.delete(synchronize_session=False)
self.session.commit() self.session.commit()
self.is_dirty = True
return True return True
except InvalidRequestError: except InvalidRequestError:
self.session.rollback() self.session.rollback()
@ -251,5 +292,7 @@ class Manager(object):
""" """
VACUUM the database on exit. VACUUM the database on exit.
""" """
engine = create_engine(self.db_url) if self.is_dirty:
engine.execute("vacuum") engine = create_engine(self.db_url)
if self.db_url.startswith(u'sqlite'):
engine.execute("vacuum")

View File

@ -25,8 +25,11 @@
############################################################################### ###############################################################################
import logging import logging
from PyQt4 import QtWebKit from PyQt4 import QtWebKit
from openlp.core.lib import BackgroundType, BackgroundGradientType
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
HTMLSRC = u""" HTMLSRC = u"""
@ -368,16 +371,32 @@ def build_background_css(item, width, height):
theme = item.themedata theme = item.themedata
background = u'background-color: black' background = u'background-color: black'
if theme: if theme:
if theme.background_type == u'solid': if theme.background_type == BackgroundType.to_string(BackgroundType.Solid):
background = u'background-color: %s' % theme.background_color background = u'background-color: %s' % theme.background_color
else: else:
if theme.background_direction == u'horizontal': if theme.background_direction == BackgroundGradientType.to_string \
(BackgroundGradientType.Horizontal):
background = \ background = \
u'background: ' \ u'background: ' \
u'-webkit-gradient(linear, left top, left bottom, ' \ u'-webkit-gradient(linear, left top, left bottom, ' \
'from(%s), to(%s))' % (theme.background_start_color, 'from(%s), to(%s))' % (theme.background_start_color,
theme.background_end_color) theme.background_end_color)
elif theme.background_direction == u'vertical': elif theme.background_direction == BackgroundGradientType.to_string \
(BackgroundGradientType.LeftTop):
background = \
u'background: ' \
u'-webkit-gradient(linear, left top, right bottom, ' \
'from(%s), to(%s))' % (theme.background_start_color,
theme.background_end_color)
elif theme.background_direction == BackgroundGradientType.to_string \
(BackgroundGradientType.LeftBottom):
background = \
u'background: ' \
u'-webkit-gradient(linear, left bottom, right top, ' \
'from(%s), to(%s))' % (theme.background_start_color,
theme.background_end_color)
elif theme.background_direction == BackgroundGradientType.to_string \
(BackgroundGradientType.Vertical):
background = \ background = \
u'background: -webkit-gradient(linear, left top, ' \ u'background: -webkit-gradient(linear, left top, ' \
u'right top, from(%s), to(%s))' % \ u'right top, from(%s), to(%s))' % \
@ -452,17 +471,17 @@ def build_lyrics_css(item, webkitvers):
lyricsmain += build_lyrics_outline_css(theme) lyricsmain += build_lyrics_outline_css(theme)
else: else:
outline = build_lyrics_outline_css(theme) outline = build_lyrics_outline_css(theme)
if theme.display_shadow: if theme.font_main_shadow:
if theme.display_outline and webkitvers < 534.3: if theme.font_main_outline and webkitvers < 534.3:
shadow = u'padding-left: %spx; padding-top: %spx;' % \ shadow = u'padding-left: %spx; padding-top: %spx;' % \
(int(theme.display_shadow_size) + (int(theme.font_main_shadow_size) +
(int(theme.display_outline_size) * 2), (int(theme.font_main_outline_size) * 2),
theme.display_shadow_size) theme.font_main_shadow_size)
shadow += build_lyrics_outline_css(theme, True) shadow += build_lyrics_outline_css(theme, True)
else: else:
lyricsmain += u' text-shadow: %s %spx %spx;' % \ lyricsmain += u' text-shadow: %s %spx %spx;' % \
(theme.display_shadow_color, theme.display_shadow_size, (theme.font_main_shadow_color, theme.font_main_shadow_size,
theme.display_shadow_size) theme.font_main_shadow_size)
lyrics_css = style % (lyricstable, lyrics, lyricsmain, outline, shadow) lyrics_css = style % (lyricstable, lyrics, lyricsmain, outline, shadow)
return lyrics_css return lyrics_css
@ -477,14 +496,14 @@ def build_lyrics_outline_css(theme, is_shadow=False):
`is_shadow` `is_shadow`
If true, use the shadow colors instead If true, use the shadow colors instead
""" """
if theme.display_outline: if theme.font_main_outline:
size = float(theme.display_outline_size) / 16 size = float(theme.font_main_outline_size) / 16
if is_shadow: if is_shadow:
fill_color = theme.display_shadow_color fill_color = theme.font_main_shadow_color
outline_color = theme.display_shadow_color outline_color = theme.font_main_shadow_color
else: else:
fill_color = theme.font_main_color fill_color = theme.font_main_color
outline_color = theme.display_outline_color outline_color = theme.font_main_outline_color
return u' -webkit-text-stroke: %sem %s; ' \ return u' -webkit-text-stroke: %sem %s; ' \
u'-webkit-text-fill-color: %s; ' % (size, outline_color, fill_color) u'-webkit-text-fill-color: %s; ' % (size, outline_color, fill_color)
else: else:
@ -517,23 +536,23 @@ def build_lyrics_format_css(theme, width, height):
valign = u'middle' valign = u'middle'
else: else:
valign = u'top' valign = u'top'
if theme.display_outline: if theme.font_main_outline:
left_margin = int(theme.display_outline_size) * 2 left_margin = int(theme.font_main_outline_size) * 2
else: else:
left_margin = 0 left_margin = 0
lyrics = u'white-space:pre-wrap; word-wrap: break-word; ' \ lyrics = u'white-space:pre-wrap; word-wrap: break-word; ' \
'text-align: %s; vertical-align: %s; font-family: %s; ' \ 'text-align: %s; vertical-align: %s; font-family: %s; ' \
'font-size: %spt; color: %s; line-height: %d%%; margin:0;' \ 'font-size: %spt; color: %s; line-height: %d%%; margin:0;' \
'padding:0; padding-left:%spx; width: %spx; height: %spx; ' % \ 'padding:0; padding-left:%spx; width: %spx; height: %spx; ' % \
(align, valign, theme.font_main_name, theme.font_main_proportion, (align, valign, theme.font_main_name, theme.font_main_size,
theme.font_main_color, 100 + int(theme.font_main_line_adjustment), theme.font_main_color, 100 + int(theme.font_main_line_adjustment),
left_margin, width, height) left_margin, width, height)
if theme.display_outline: if theme.font_main_outline:
if webkit_version() < 534.3: if webkit_version() < 534.3:
lyrics += u' letter-spacing: 1px;' lyrics += u' letter-spacing: 1px;'
if theme.font_main_italics: if theme.font_main_italics:
lyrics += u' font-style:italic; ' lyrics += u' font-style:italic; '
if theme.font_main_weight == u'Bold': if theme.font_main_bold:
lyrics += u' font-weight:bold; ' lyrics += u' font-weight:bold; '
return lyrics return lyrics
@ -553,7 +572,7 @@ def build_lyrics_html(item, webkitvers):
# display:table/display:table-cell are required for each lyric block. # display:table/display:table-cell are required for each lyric block.
lyrics = u'' lyrics = u''
theme = item.themedata theme = item.themedata
if webkitvers < 534.4 and theme and theme.display_outline: if webkitvers < 534.4 and theme and theme.font_main_outline:
lyrics += u'<div class="lyricstable">' \ lyrics += u'<div class="lyricstable">' \
u'<div id="lyricsshadow" style="opacity:1" ' \ u'<div id="lyricsshadow" style="opacity:1" ' \
u'class="lyricscell lyricsshadow"></div></div>' u'class="lyricscell lyricsshadow"></div></div>'
@ -589,7 +608,7 @@ def build_footer_css(item, height):
bottom = height - int(item.footer.y()) - int(item.footer.height()) bottom = height - int(item.footer.y()) - int(item.footer.height())
lyrics_html = style % (item.footer.x(), bottom, lyrics_html = style % (item.footer.x(), bottom,
item.footer.width(), theme.font_footer_name, item.footer.width(), theme.font_footer_name,
theme.font_footer_proportion, theme.font_footer_color) theme.font_footer_size, theme.font_footer_color)
return lyrics_html return lyrics_html
def build_alert_css(alertTab, width): def build_alert_css(alertTab, width):

View File

@ -320,15 +320,9 @@ class MediaManagerItem(QtGui.QWidget):
translate('OpenLP.MediaManagerItem', translate('OpenLP.MediaManagerItem',
'&Add to selected Service Item'), '&Add to selected Service Item'),
self.onAddEditClick)) self.onAddEditClick))
if QtCore.QSettings().value(u'advanced/double click live', QtCore.QObject.connect(self.listView,
QtCore.QVariant(False)).toBool(): QtCore.SIGNAL(u'doubleClicked(QModelIndex)'),
QtCore.QObject.connect(self.listView, self.onClickPressed)
QtCore.SIGNAL(u'doubleClicked(QModelIndex)'),
self.onLiveClick)
else:
QtCore.QObject.connect(self.listView,
QtCore.SIGNAL(u'doubleClicked(QModelIndex)'),
self.onPreviewClick)
def initialise(self): def initialise(self):
""" """
@ -426,10 +420,20 @@ class MediaManagerItem(QtGui.QWidget):
raise NotImplementedError(u'MediaManagerItem.onDeleteClick needs to ' raise NotImplementedError(u'MediaManagerItem.onDeleteClick needs to '
u'be defined by the plugin') u'be defined by the plugin')
def generateSlideData(self, service_item, item=None): def generateSlideData(self, serviceItem, item=None, xmlVersion=False):
raise NotImplementedError(u'MediaManagerItem.generateSlideData needs ' raise NotImplementedError(u'MediaManagerItem.generateSlideData needs '
u'to be defined by the plugin') u'to be defined by the plugin')
def onClickPressed(self):
"""
Allows the list click action to be determined dynamically
"""
if QtCore.QSettings().value(u'advanced/double click live',
QtCore.QVariant(False)).toBool():
self.onLiveClick()
else:
self.onPreviewClick()
def onPreviewClick(self): def onPreviewClick(self):
""" """
Preview an item by building a service item then adding that service Preview an item by building a service item then adding that service
@ -442,10 +446,10 @@ class MediaManagerItem(QtGui.QWidget):
'You must select one or more items to preview.')) 'You must select one or more items to preview.'))
else: else:
log.debug(self.plugin.name + u' Preview requested') log.debug(self.plugin.name + u' Preview requested')
service_item = self.buildServiceItem() serviceItem = self.buildServiceItem()
if service_item: if serviceItem:
service_item.from_plugin = True serviceItem.from_plugin = True
self.parent.previewController.addServiceItem(service_item) self.parent.previewController.addServiceItem(serviceItem)
def onLiveClick(self): def onLiveClick(self):
""" """
@ -459,10 +463,10 @@ class MediaManagerItem(QtGui.QWidget):
'You must select one or more items to send live.')) 'You must select one or more items to send live.'))
else: else:
log.debug(self.plugin.name + u' Live requested') log.debug(self.plugin.name + u' Live requested')
service_item = self.buildServiceItem() serviceItem = self.buildServiceItem()
if service_item: if serviceItem:
service_item.from_plugin = True serviceItem.from_plugin = True
self.parent.liveController.addServiceItem(service_item) self.parent.liveController.addServiceItem(serviceItem)
def onAddClick(self): def onAddClick(self):
""" """
@ -474,22 +478,22 @@ class MediaManagerItem(QtGui.QWidget):
translate('OpenLP.MediaManagerItem', translate('OpenLP.MediaManagerItem',
'You must select one or more items.')) 'You must select one or more items.'))
else: else:
# Is it posssible to process multiple list items to generate multiple # Is it posssible to process multiple list items to generate
# service items? # multiple service items?
if self.singleServiceItem or self.remoteTriggered: if self.singleServiceItem or self.remoteTriggered:
log.debug(self.plugin.name + u' Add requested') log.debug(self.plugin.name + u' Add requested')
service_item = self.buildServiceItem() serviceItem = self.buildServiceItem(None, True)
if service_item: if serviceItem:
service_item.from_plugin = False serviceItem.from_plugin = False
self.parent.serviceManager.addServiceItem(service_item, self.parent.serviceManager.addServiceItem(serviceItem,
replace=self.remoteTriggered) replace=self.remoteTriggered)
else: else:
items = self.listView.selectedIndexes() items = self.listView.selectedIndexes()
for item in items: for item in items:
service_item = self.buildServiceItem(item) serviceItem = self.buildServiceItem(item, True)
if service_item: if serviceItem:
service_item.from_plugin = False serviceItem.from_plugin = False
self.parent.serviceManager.addServiceItem(service_item) self.parent.serviceManager.addServiceItem(serviceItem)
def onAddEditClick(self): def onAddEditClick(self):
""" """
@ -502,36 +506,36 @@ class MediaManagerItem(QtGui.QWidget):
'You must select one or more items')) 'You must select one or more items'))
else: else:
log.debug(self.plugin.name + u' Add requested') log.debug(self.plugin.name + u' Add requested')
service_item = self.parent.serviceManager.getServiceItem() serviceItem = self.parent.serviceManager.getServiceItem()
if not service_item: if not serviceItem:
QtGui.QMessageBox.information(self, QtGui.QMessageBox.information(self,
translate('OpenLP.MediaManagerItem', translate('OpenLP.MediaManagerItem',
'No Service Item Selected'), 'No Service Item Selected'),
translate('OpenLP.MediaManagerItem', translate('OpenLP.MediaManagerItem',
'You must select an existing service item to add to.')) 'You must select an existing service item to add to.'))
elif self.title.lower() == service_item.name.lower(): elif self.title.lower() == serviceItem.name.lower():
self.generateSlideData(service_item) self.generateSlideData(serviceItem)
self.parent.serviceManager.addServiceItem(service_item, self.parent.serviceManager.addServiceItem(serviceItem,
replace=True) replace=True)
else: else:
#Turn off the remote edit update message indicator # Turn off the remote edit update message indicator
QtGui.QMessageBox.information(self, QtGui.QMessageBox.information(self,
translate('OpenLP.MediaManagerItem', translate('OpenLP.MediaManagerItem',
'Invalid Service Item'), 'Invalid Service Item'),
unicode(translate('OpenLP.MediaManagerItem', unicode(translate('OpenLP.MediaManagerItem',
'You must select a %s service item.')) % self.title) 'You must select a %s service item.')) % self.title)
def buildServiceItem(self, item=None): def buildServiceItem(self, item=None, xmlVersion=False):
""" """
Common method for generating a service item Common method for generating a service item
""" """
service_item = ServiceItem(self.parent) serviceItem = ServiceItem(self.parent)
if self.serviceItemIconName: if self.serviceItemIconName:
service_item.add_icon(self.serviceItemIconName) serviceItem.add_icon(self.serviceItemIconName)
else: else:
service_item.add_icon(self.parent.icon_path) serviceItem.add_icon(self.parent.icon_path)
if self.generateSlideData(service_item, item): if self.generateSlideData(serviceItem, item, xmlVersion):
return service_item return serviceItem
else: else:
return None return None
@ -541,4 +545,3 @@ class MediaManagerItem(QtGui.QWidget):
individual service items need to be processed by the plugins individual service items need to be processed by the plugins
""" """
pass pass

View File

@ -156,9 +156,11 @@ class PluginManager(object):
if plugin.settings_tab: if plugin.settings_tab:
log.debug(u'Inserting settings tab item from %s' % log.debug(u'Inserting settings tab item from %s' %
visible_title[u'title']) visible_title[u'title'])
settingsform.addTab(visible_title[u'title'], plugin.settings_tab) settingsform.addTab(visible_title[u'title'],
plugin.settings_tab)
else: else:
log.debug(u'No tab settings in %s' % visible_title[u'title']) log.debug(
u'No tab settings in %s' % visible_title[u'title'])
def hook_import_menu(self, import_menu): def hook_import_menu(self, import_menu):
""" """

View File

@ -29,11 +29,10 @@ format it for the output display.
""" """
import logging import logging
from PyQt4 import QtGui, QtCore, QtWebKit from PyQt4 import QtWebKit
from openlp.core.lib import resize_image, expand_tags, \
build_lyrics_format_css, build_lyrics_outline_css, image_to_byte
from openlp.core.lib import expand_tags, build_lyrics_format_css, \
build_lyrics_outline_css, Receiver
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -78,9 +77,9 @@ class Renderer(object):
self._rect_footer = rect_footer self._rect_footer = rect_footer
self.page_width = self._rect.width() self.page_width = self._rect.width()
self.page_height = self._rect.height() self.page_height = self._rect.height()
if self._theme.display_shadow: if self._theme.font_main_shadow:
self.page_width -= int(self._theme.display_shadow_size) self.page_width -= int(self._theme.font_main_shadow_size)
self.page_height -= int(self._theme.display_shadow_size) self.page_height -= int(self._theme.font_main_shadow_size)
self.web = QtWebKit.QWebView() self.web = QtWebKit.QWebView()
self.web.setVisible(False) self.web.setVisible(False)
self.web.resize(self.page_width, self.page_height) self.web.resize(self.page_width, self.page_height)
@ -93,13 +92,20 @@ class Renderer(object):
(build_lyrics_format_css(self._theme, self.page_width, (build_lyrics_format_css(self._theme, self.page_width,
self.page_height), build_lyrics_outline_css(self._theme)) self.page_height), build_lyrics_outline_css(self._theme))
def format_slide(self, words, line_break): def format_slide(self, words, line_break, force_page=False):
""" """
Figure out how much text can appear on a slide, using the current Figure out how much text can appear on a slide, using the current
theme settings. theme settings.
``words`` ``words``
The words to be fitted on the slide. The words to be fitted on the slide.
``line_break``
Add line endings after each line of text used for bibles.
``force_page``
Flag to tell message lines in page.
""" """
log.debug(u'format_slide - Start') log.debug(u'format_slide - Start')
line_end = u'' line_end = u''
@ -115,19 +121,26 @@ class Renderer(object):
formatted = [] formatted = []
html_text = u'' html_text = u''
styled_text = u'' styled_text = u''
line_count = 0
for line in text: for line in text:
styled_line = expand_tags(line) if line_count != -1:
if styled_text: line_count += 1
styled_text += line_end + styled_line styled_line = expand_tags(line) + line_end
styled_text += styled_line
html = self.page_shell + styled_text + u'</div></body></html>' html = self.page_shell + styled_text + u'</div></body></html>'
self.web.setHtml(html) self.web.setHtml(html)
# Text too long so go to next page # Text too long so go to next page
if self.web_frame.contentsSize().height() > self.page_height: if self.web_frame.contentsSize().height() > self.page_height:
if force_page and line_count > 0:
Receiver.send_message(u'theme_line_count', line_count)
line_count = -1
if html_text.endswith(u'<br>'):
html_text = html_text[:len(html_text)-4]
formatted.append(html_text) formatted.append(html_text)
html_text = u'' html_text = u''
styled_text = styled_line styled_text = styled_line
html_text += line + line_end html_text += line + line_end
if line_break: if html_text.endswith(u'<br>'):
html_text = html_text[:len(html_text)-4] html_text = html_text[:len(html_text)-4]
formatted.append(html_text) formatted.append(html_text)
log.debug(u'format_slide - End') log.debug(u'format_slide - End')

View File

@ -67,8 +67,9 @@ class RenderManager(object):
self.service_theme = u'' self.service_theme = u''
self.theme_level = u'' self.theme_level = u''
self.override_background = None self.override_background = None
self.themedata = None self.theme_data = None
self.alertTab = None self.alertTab = None
self.force_page = False
def update_display(self): def update_display(self):
""" """
@ -80,7 +81,7 @@ class RenderManager(object):
self.display.imageManager = self.image_manager self.display.imageManager = self.image_manager
self.display.setup() self.display.setup()
self.renderer.bg_frame = None self.renderer.bg_frame = None
self.themedata = None self.theme_data = None
self.image_manager.update_display(self.width, self.height) self.image_manager.update_display(self.width, self.height)
def set_global_theme(self, global_theme, theme_level=ThemeLevel.Global): def set_global_theme(self, global_theme, theme_level=ThemeLevel.Global):
@ -99,7 +100,7 @@ class RenderManager(object):
self.theme_level = theme_level self.theme_level = theme_level
self.global_theme_data = \ self.global_theme_data = \
self.theme_manager.getThemeData(self.global_theme) self.theme_manager.getThemeData(self.global_theme)
self.themedata = None self.theme_data = None
def set_service_theme(self, service_theme): def set_service_theme(self, service_theme):
""" """
@ -109,7 +110,7 @@ class RenderManager(object):
The service-level theme to be set. The service-level theme to be set.
""" """
self.service_theme = service_theme self.service_theme = service_theme
self.themedata = None self.theme_data = None
def set_override_theme(self, theme, overrideLevels=False): def set_override_theme(self, theme, overrideLevels=False):
""" """
@ -146,19 +147,19 @@ class RenderManager(object):
self.theme = self.service_theme self.theme = self.service_theme
else: else:
self.theme = self.global_theme self.theme = self.global_theme
if self.theme != self.renderer.theme_name or self.themedata is None \ if self.theme != self.renderer.theme_name or self.theme_data is None \
or overrideLevels: or overrideLevels:
log.debug(u'theme is now %s', self.theme) log.debug(u'theme is now %s', self.theme)
# Force the theme to be the one passed in. # Force the theme to be the one passed in.
if overrideLevels: if overrideLevels:
self.themedata = theme self.theme_data = theme
else: else:
self.themedata = self.theme_manager.getThemeData(self.theme) self.theme_data = self.theme_manager.getThemeData(self.theme)
self.calculate_default(self.screens.current[u'size']) self.calculate_default(self.screens.current[u'size'])
self.renderer.set_theme(self.themedata) self.renderer.set_theme(self.theme_data)
self.build_text_rectangle(self.themedata) self.build_text_rectangle(self.theme_data)
self.image_manager.add_image(self.themedata.theme_name, self.image_manager.add_image(self.theme_data.theme_name,
self.themedata.background_filename) self.theme_data.background_filename)
return self.renderer._rect, self.renderer._rect_footer return self.renderer._rect, self.renderer._rect_footer
def build_text_rectangle(self, theme): def build_text_rectangle(self, theme):
@ -187,14 +188,19 @@ class RenderManager(object):
theme.font_footer_height - 1) theme.font_footer_height - 1)
self.renderer.set_text_rectangle(main_rect, footer_rect) self.renderer.set_text_rectangle(main_rect, footer_rect)
def generate_preview(self, themedata): def generate_preview(self, theme_data, force_page=False):
""" """
Generate a preview of a theme. Generate a preview of a theme.
``themedata`` ``theme_data``
The theme to generated a preview for. The theme to generated a preview for.
``force_page``
Flag to tell message lines per page need to be generated.
""" """
log.debug(u'generate preview') log.debug(u'generate preview')
# save value for use in format_slide
self.force_page = force_page
# set the default image size for previews # set the default image size for previews
self.calculate_default(self.screens.preview[u'size']) self.calculate_default(self.screens.preview[u'size'])
verse = u'The Lord said to {r}Noah{/r}: \n' \ verse = u'The Lord said to {r}Noah{/r}: \n' \
@ -204,23 +210,27 @@ class RenderManager(object):
'Get those children out of the muddy, muddy \n' \ 'Get those children out of the muddy, muddy \n' \
'{r}C{/r}{b}h{/b}{bl}i{/bl}{y}l{/y}{g}d{/g}{pk}' \ '{r}C{/r}{b}h{/b}{bl}i{/bl}{y}l{/y}{g}d{/g}{pk}' \
'r{/pk}{o}e{/o}{pp}n{/pp} of the Lord\n' 'r{/pk}{o}e{/o}{pp}n{/pp} of the Lord\n'
# make big page for theme edit dialog to get line count
if self.force_page:
verse = verse + verse + verse
footer = [] footer = []
footer.append(u'Arky Arky (Unknown)' ) footer.append(u'Arky Arky (Unknown)' )
footer.append(u'Public Domain') footer.append(u'Public Domain')
footer.append(u'CCLI 123456') footer.append(u'CCLI 123456')
# build a service item to generate preview # build a service item to generate preview
serviceItem = ServiceItem() serviceItem = ServiceItem()
serviceItem.theme = themedata serviceItem.theme = theme_data
serviceItem.add_from_text(u'', verse, footer) serviceItem.add_from_text(u'', verse, footer)
serviceItem.render_manager = self serviceItem.render_manager = self
serviceItem.raw_footer = footer serviceItem.raw_footer = footer
serviceItem.render(True) serviceItem.render(True)
self.display.buildHtml(serviceItem) if not self.force_page:
raw_html = serviceItem.get_rendered_frame(0) self.display.buildHtml(serviceItem)
preview = self.display.text(raw_html) raw_html = serviceItem.get_rendered_frame(0)
# Reset the real screen size for subsequent render requests preview = self.display.text(raw_html)
self.calculate_default(self.screens.current[u'size']) # Reset the real screen size for subsequent render requests
return preview self.calculate_default(self.screens.current[u'size'])
return preview
def format_slide(self, words, line_break): def format_slide(self, words, line_break):
""" """
@ -228,9 +238,12 @@ class RenderManager(object):
``words`` ``words``
The words to go on the slides. The words to go on the slides.
``line_break``
Add line endings after each line of text used for bibles.
""" """
log.debug(u'format slide') log.debug(u'format slide')
return self.renderer.format_slide(words, line_break) return self.renderer.format_slide(words, line_break, self.force_page)
def calculate_default(self, screen): def calculate_default(self, screen):
""" """

View File

@ -32,9 +32,7 @@ import logging
import os import os
import uuid import uuid
from PyQt4 import QtGui from openlp.core.lib import build_icon, clean_tags, expand_tags
from openlp.core.lib import build_icon, resize_image, clean_tags, expand_tags
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -102,6 +100,8 @@ class ServiceItem(object):
self.bg_image_bytes = None self.bg_image_bytes = None
self.search_string = u'' self.search_string = u''
self.data_string = u'' self.data_string = u''
self.edit_id = None
self.xml_version = None
self._new_item() self._new_item()
def _new_item(self): def _new_item(self):
@ -214,7 +214,7 @@ class ServiceItem(object):
self.service_item_type = ServiceItemType.Text self.service_item_type = ServiceItemType.Text
title = title.split(u'\n')[0] title = title.split(u'\n')[0]
self._raw_frames.append( self._raw_frames.append(
{u'title': title, u'raw_slide': raw_slide, u'verseTag':verse_tag}) {u'title': title, u'raw_slide': raw_slide, u'verseTag': verse_tag})
self._new_item() self._new_item()
def add_from_command(self, path, file_name, image): def add_from_command(self, path, file_name, image):
@ -232,7 +232,7 @@ class ServiceItem(object):
""" """
self.service_item_type = ServiceItemType.Command self.service_item_type = ServiceItemType.Command
self._raw_frames.append( self._raw_frames.append(
{u'title': file_name, u'image':image, u'path': path}) {u'title': file_name, u'image': image, u'path': path})
self._new_item() self._new_item()
def get_service_repr(self): def get_service_repr(self):
@ -243,17 +243,18 @@ class ServiceItem(object):
service_header = { service_header = {
u'name': self.name.lower(), u'name': self.name.lower(),
u'plugin': self.name, u'plugin': self.name,
u'theme':self.theme, u'theme': self.theme,
u'title':self.title, u'title': self.title,
u'icon':self.icon, u'icon': self.icon,
u'footer':self.raw_footer, u'footer': self.raw_footer,
u'type':self.service_item_type, u'type': self.service_item_type,
u'audit':self.audit, u'audit': self.audit,
u'notes':self.notes, u'notes': self.notes,
u'from_plugin':self.from_plugin, u'from_plugin': self.from_plugin,
u'capabilities':self.capabilities, u'capabilities': self.capabilities,
u'search':self.search_string, u'search': self.search_string,
u'data':self.data_string u'data': self.data_string,
u'xml_version': self.xml_version
} }
service_data = [] service_data = []
if self.service_item_type == ServiceItemType.Text: if self.service_item_type == ServiceItemType.Text:
@ -265,7 +266,7 @@ class ServiceItem(object):
elif self.service_item_type == ServiceItemType.Command: elif self.service_item_type == ServiceItemType.Command:
for slide in self._raw_frames: for slide in self._raw_frames:
service_data.append( service_data.append(
{u'title':slide[u'title'], u'image':slide[u'image']}) {u'title': slide[u'title'], u'image': slide[u'image']})
return {u'header': service_header, u'data': service_data} return {u'header': service_header, u'data': service_data}
def set_from_service(self, serviceitem, path=None): def set_from_service(self, serviceitem, path=None):
@ -295,6 +296,8 @@ class ServiceItem(object):
if u'search' in header: if u'search' in header:
self.search_string = header[u'search'] self.search_string = header[u'search']
self.data_string = header[u'data'] self.data_string = header[u'data']
if u'xml_version' in header:
self.xml_version = header[u'xml_version']
if self.service_item_type == ServiceItemType.Text: if self.service_item_type == ServiceItemType.Text:
for slide in serviceitem[u'serviceitem'][u'data']: for slide in serviceitem[u'serviceitem'][u'data']:
self._raw_frames.append(slide) self._raw_frames.append(slide)

View File

@ -28,52 +28,56 @@ Provide the theme XML and handling functions for OpenLP v2 themes.
""" """
import os import os
import re import re
import logging
from xml.dom.minidom import Document from xml.dom.minidom import Document
from xml.etree.ElementTree import ElementTree, XML from xml.etree.ElementTree import ElementTree, XML
from lxml import etree, objectify
from openlp.core.lib import str_to_bool from openlp.core.lib import str_to_bool
log = logging.getLogger(__name__)
BLANK_THEME_XML = \ BLANK_THEME_XML = \
'''<?xml version="1.0" encoding="utf-8"?> '''<?xml version="1.0" encoding="utf-8"?>
<theme version="1.0"> <theme version="1.0">
<name>BlankStyle</name> <name> </name>
<background mode="transparent"/> <background type="image">
<background type="solid" mode="opaque"> <filename></filename>
<color>#000000</color>
</background> </background>
<background type="gradient" mode="opaque"> <background type="gradient">
<startColor>#000000</startColor> <startColor>#000000</startColor>
<endColor>#000000</endColor> <endColor>#000000</endColor>
<direction>vertical</direction> <direction>vertical</direction>
</background> </background>
<background type="image" mode="opaque"> <background type="solid">
<filename></filename> <color>#000000</color>
</background> </background>
<font type="main"> <font type="main">
<name>Arial</name> <name>Arial</name>
<color>#000000</color> <color>#FFFFFF</color>
<proportion>30</proportion> <size>30</size>
<weight>Normal</weight> <bold>False</bold>
<italics>False</italics> <italics>False</italics>
<line_adjustment>0</line_adjustment> <line_adjustment>0</line_adjustment>
<shadow shadowColor="#000000" shadowSize="5">True</shadow>
<outline outlineColor="#000000" outlineSize="2">False</outline>
<location override="False" x="10" y="10" width="1004" height="690"/> <location override="False" x="10" y="10" width="1004" height="690"/>
</font> </font>
<font type="footer"> <font type="footer">
<name>Arial</name> <name>Arial</name>
<color>#000000</color> <color>#FFFFFF</color>
<proportion>12</proportion> <size>12</size>
<weight>Normal</weight> <bold>False</bold>
<italics>False</italics> <italics>False</italics>
<line_adjustment>0</line_adjustment> <line_adjustment>0</line_adjustment>
<shadow shadowColor="#000000" shadowSize="5">True</shadow>
<outline outlineColor="#000000" outlineSize="2">False</outline>
<location override="False" x="10" y="690" width="1004" height="78"/> <location override="False" x="10" y="690" width="1004" height="78"/>
</font> </font>
<display> <display>
<shadow color="#000000" size="5">True</shadow>
<outline color="#000000" size="2">False</outline>
<horizontalAlign>0</horizontalAlign> <horizontalAlign>0</horizontalAlign>
<verticalAlign>0</verticalAlign> <verticalAlign>0</verticalAlign>
<wrapStyle>0</wrapStyle>
<slideTransition>False</slideTransition> <slideTransition>False</slideTransition>
</display> </display>
</theme> </theme>
@ -87,10 +91,76 @@ class ThemeLevel(object):
Service = 2 Service = 2
Song = 3 Song = 3
class BackgroundType(object):
Solid = 0
Gradient = 1
Image = 2
@staticmethod
def to_string(type):
if type == BackgroundType.Solid:
return u'solid'
elif type == BackgroundType.Gradient:
return u'gradient'
elif type == BackgroundType.Image:
return u'image'
@staticmethod
def from_string(type_string):
if type_string == u'solid':
return BackgroundType.Solid
elif type_string == u'gradient':
return BackgroundType.Gradient
elif type_string == u'image':
return BackgroundType.Image
class BackgroundGradientType(object):
Horizontal = 0
Vertical = 1
Circular = 2
LeftTop = 3
LeftBottom = 4
@staticmethod
def to_string(type):
if type == BackgroundGradientType.Horizontal:
return u'horizontal'
elif type == BackgroundGradientType.Vertical:
return u'vertical'
elif type == BackgroundGradientType.Circular:
return u'circular'
elif type == BackgroundGradientType.LeftTop:
return u'leftTop'
elif type == BackgroundGradientType.LeftBottom:
return u'leftBottom'
@staticmethod
def from_string(type_string):
if type_string == u'horizontal':
return BackgroundGradientType.Horizontal
elif type_string == u'vertical':
return BackgroundGradientType.Vertical
elif type_string == u'circular':
return BackgroundGradientType.Circular
elif type_string == u'leftTop':
return BackgroundGradientType.LeftTop
elif type_string == u'leftBottom':
return BackgroundGradientType.LeftBottom
class HorizontalType(object):
Left = 0
Center = 1
Right = 2
class VerticalType(object):
Top = 0
Middle = 1
Bottom = 2
boolean_list = [u'italics', u'override', u'outline', u'shadow', boolean_list = [u'italics', u'override', u'outline', u'shadow',
u'slide_transition'] u'slide_transition']
integer_list = [u'proportion', u'line_adjustment', u'x', u'height', u'y', integer_list = [u'size', u'line_adjustment', u'x', u'height', u'y',
u'width', u'shadow_size', u'outline_size', u'horizontal_align', u'width', u'shadow_size', u'outline_size', u'horizontal_align',
u'vertical_align', u'wrap_style'] u'vertical_align', u'wrap_style']
@ -104,6 +174,7 @@ class ThemeXML(object):
""" """
# Create the minidom document # Create the minidom document
self.theme_xml = Document() self.theme_xml = Document()
self.parse_xml(BLANK_THEME_XML)
def extend_image_filename(self, path): def extend_image_filename(self, path):
""" """
@ -112,19 +183,21 @@ class ThemeXML(object):
``path`` ``path``
The path name to be added. The path name to be added.
""" """
if self.background_filename and path: if self.background_type == u'image':
self.theme_name = self.theme_name.strip() if self.background_filename and path:
self.background_filename = self.background_filename.strip() self.theme_name = self.theme_name.strip()
self.background_filename = os.path.join(path, self.theme_name, self.background_filename = self.background_filename.strip()
self.background_filename) self.background_filename = os.path.join(path, self.theme_name,
self.background_filename)
def new_document(self, name): def _new_document(self, name):
""" """
Create a new theme XML document. Create a new theme XML document.
""" """
self.theme_xml = Document()
self.theme = self.theme_xml.createElement(u'theme') self.theme = self.theme_xml.createElement(u'theme')
self.theme_xml.appendChild(self.theme) self.theme_xml.appendChild(self.theme)
self.theme.setAttribute(u'version', u'1.0') self.theme.setAttribute(u'version', u'2.0')
self.name = self.theme_xml.createElement(u'name') self.name = self.theme_xml.createElement(u'name')
text_node = self.theme_xml.createTextNode(name) text_node = self.theme_xml.createTextNode(name)
self.name.appendChild(text_node) self.name.appendChild(text_node)
@ -146,10 +219,9 @@ class ThemeXML(object):
The color of the background. The color of the background.
""" """
background = self.theme_xml.createElement(u'background') background = self.theme_xml.createElement(u'background')
background.setAttribute(u'mode', u'opaque')
background.setAttribute(u'type', u'solid') background.setAttribute(u'type', u'solid')
self.theme.appendChild(background) self.theme.appendChild(background)
self.child_element(background, u'color', bkcolor) self.child_element(background, u'color', unicode(bkcolor))
def add_background_gradient(self, startcolor, endcolor, direction): def add_background_gradient(self, startcolor, endcolor, direction):
""" """
@ -165,15 +237,14 @@ class ThemeXML(object):
The direction of the gradient. The direction of the gradient.
""" """
background = self.theme_xml.createElement(u'background') background = self.theme_xml.createElement(u'background')
background.setAttribute(u'mode', u'opaque')
background.setAttribute(u'type', u'gradient') background.setAttribute(u'type', u'gradient')
self.theme.appendChild(background) self.theme.appendChild(background)
# Create startColor element # Create startColor element
self.child_element(background, u'startColor', startcolor) self.child_element(background, u'startColor', unicode(startcolor))
# Create endColor element # Create endColor element
self.child_element(background, u'endColor', endcolor) self.child_element(background, u'endColor', unicode(endcolor))
# Create direction element # Create direction element
self.child_element(background, u'direction', direction) self.child_element(background, u'direction', unicode(direction))
def add_background_image(self, filename): def add_background_image(self, filename):
""" """
@ -183,15 +254,15 @@ class ThemeXML(object):
The file name of the image. The file name of the image.
""" """
background = self.theme_xml.createElement(u'background') background = self.theme_xml.createElement(u'background')
background.setAttribute(u'mode', u'opaque')
background.setAttribute(u'type', u'image') background.setAttribute(u'type', u'image')
self.theme.appendChild(background) self.theme.appendChild(background)
#Create Filename element # Create Filename element
self.child_element(background, u'filename', filename) self.child_element(background, u'filename', filename)
def add_font(self, name, color, proportion, override, fonttype=u'main', def add_font(self, name, color, size, override, fonttype=u'main',
weight=u'Normal', italics=u'False', line_adjustment=0, bold=u'False', italics=u'False', line_adjustment=0,
xpos=0, ypos=0, width=0, height=0): xpos=0, ypos=0, width=0, height=0 , outline=u'False', outline_color=u'#ffffff',
outline_pixel=2, shadow=u'False', shadow_color=u'#ffffff', shadow_pixel=5):
""" """
Add a Font. Add a Font.
@ -201,7 +272,7 @@ class ThemeXML(object):
``color`` ``color``
The colour of the font. The colour of the font.
``proportion`` ``size``
The size of the font. The size of the font.
``override`` ``override``
@ -227,45 +298,6 @@ class ThemeXML(object):
``height`` ``height``
The height of the text block. The height of the text block.
"""
background = self.theme_xml.createElement(u'font')
background.setAttribute(u'type', fonttype)
self.theme.appendChild(background)
#Create Font name element
self.child_element(background, u'name', name)
#Create Font color element
self.child_element(background, u'color', color)
#Create Proportion name element
self.child_element(background, u'proportion', proportion)
#Create weight name element
self.child_element(background, u'weight', weight)
#Create italics name element
self.child_element(background, u'italics', italics)
#Create indentation name element
self.child_element(
background, u'line_adjustment', unicode(line_adjustment))
#Create Location element
element = self.theme_xml.createElement(u'location')
element.setAttribute(u'override', override)
if override == u'True':
element.setAttribute(u'x', xpos)
element.setAttribute(u'y', ypos)
element.setAttribute(u'width', width)
element.setAttribute(u'height', height)
background.appendChild(element)
def add_display(self, shadow, shadow_color, outline, outline_color,
horizontal, vertical, wrap, transition, shadow_pixel=5,
outline_pixel=2):
"""
Add a Display options.
``shadow``
Whether or not to show a shadow.
``shadow_color``
The colour of the shadow.
``outline`` ``outline``
Whether or not to show an outline. Whether or not to show an outline.
@ -273,53 +305,88 @@ class ThemeXML(object):
``outline_color`` ``outline_color``
The colour of the outline. The colour of the outline.
``outline_size``
How big the Shadow is
``shadow``
Whether or not to show a shadow.
``shadow_color``
The colour of the shadow.
``shadow_size``
How big the Shadow is
"""
background = self.theme_xml.createElement(u'font')
background.setAttribute(u'type', fonttype)
self.theme.appendChild(background)
# Create Font name element
self.child_element(background, u'name', name)
# Create Font color element
self.child_element(background, u'color', color)
# Create Proportion name element
self.child_element(background, u'size', unicode(size))
# Create weight name element
self.child_element(background, u'bold', unicode(bold))
# Create italics name element
self.child_element(background, u'italics', unicode(italics))
# Create indentation name element
self.child_element(
background, u'line_adjustment', unicode(line_adjustment))
# Create Location element
element = self.theme_xml.createElement(u'location')
element.setAttribute(u'override', unicode(override))
element.setAttribute(u'x', unicode(xpos))
element.setAttribute(u'y', unicode(ypos))
element.setAttribute(u'width', unicode(width))
element.setAttribute(u'height', unicode(height))
background.appendChild(element)
# Shadow
element = self.theme_xml.createElement(u'shadow')
element.setAttribute(u'shadowColor', unicode(shadow_color))
element.setAttribute(u'shadowSize', unicode(shadow_pixel))
value = self.theme_xml.createTextNode(unicode(shadow))
element.appendChild(value)
background.appendChild(element)
# Outline
element = self.theme_xml.createElement(u'outline')
element.setAttribute(u'outlineColor', unicode(outline_color))
element.setAttribute(u'outlineSize', unicode(outline_pixel))
value = self.theme_xml.createTextNode(unicode(outline))
element.appendChild(value)
background.appendChild(element)
def add_display(self, horizontal, vertical, transition):
"""
Add a Display options.
``horizontal`` ``horizontal``
The horizontal alignment of the text. The horizontal alignment of the text.
``vertical`` ``vertical``
The vertical alignment of the text. The vertical alignment of the text.
``wrap``
Wrap style.
``transition`` ``transition``
Whether the slide transition is active. Whether the slide transition is active.
""" """
background = self.theme_xml.createElement(u'display') background = self.theme_xml.createElement(u'display')
self.theme.appendChild(background) self.theme.appendChild(background)
# Shadow
element = self.theme_xml.createElement(u'shadow')
element.setAttribute(u'color', shadow_color)
element.setAttribute(u'size', unicode(shadow_pixel))
value = self.theme_xml.createTextNode(shadow)
element.appendChild(value)
background.appendChild(element)
# Outline
element = self.theme_xml.createElement(u'outline')
element.setAttribute(u'color', outline_color)
element.setAttribute(u'size', unicode(outline_pixel))
value = self.theme_xml.createTextNode(outline)
element.appendChild(value)
background.appendChild(element)
# Horizontal alignment # Horizontal alignment
element = self.theme_xml.createElement(u'horizontalAlign') element = self.theme_xml.createElement(u'horizontalAlign')
value = self.theme_xml.createTextNode(horizontal) value = self.theme_xml.createTextNode(unicode(horizontal))
element.appendChild(value) element.appendChild(value)
background.appendChild(element) background.appendChild(element)
# Vertical alignment # Vertical alignment
element = self.theme_xml.createElement(u'verticalAlign') element = self.theme_xml.createElement(u'verticalAlign')
value = self.theme_xml.createTextNode(vertical) value = self.theme_xml.createTextNode(unicode(vertical))
element.appendChild(value)
background.appendChild(element)
# Wrap style
element = self.theme_xml.createElement(u'wrapStyle')
value = self.theme_xml.createTextNode(wrap)
element.appendChild(value) element.appendChild(value)
background.appendChild(element) background.appendChild(element)
# Slide Transition # Slide Transition
element = self.theme_xml.createElement(u'slideTransition') element = self.theme_xml.createElement(u'slideTransition')
value = self.theme_xml.createTextNode(transition) value = self.theme_xml.createTextNode(unicode(transition))
element.appendChild(value) element.appendChild(value)
background.appendChild(element) background.appendChild(element)
@ -342,12 +409,14 @@ class ThemeXML(object):
""" """
Print out the XML string. Print out the XML string.
""" """
self._build_xml_from_attrs()
return self.theme_xml.toxml(u'utf-8').decode(u'utf-8') return self.theme_xml.toxml(u'utf-8').decode(u'utf-8')
def extract_formatted_xml(self): def extract_formatted_xml(self):
""" """
Pull out the XML string formatted for human consumption Pull out the XML string formatted for human consumption
""" """
self._build_xml_from_attrs()
return self.theme_xml.toprettyxml(indent=u' ', newl=u'\n', return self.theme_xml.toprettyxml(indent=u' ', newl=u'\n',
encoding=u'utf-8') encoding=u'utf-8')
@ -358,8 +427,7 @@ class ThemeXML(object):
``xml`` ``xml``
The XML string to parse. The XML string to parse.
""" """
self.parse_xml(BLANK_THEME_XML) self.parse_xml(unicode(xml))
self.parse_xml(xml)
def parse_xml(self, xml): def parse_xml(self, xml):
""" """
@ -368,47 +436,95 @@ class ThemeXML(object):
``xml`` ``xml``
The XML string to parse. The XML string to parse.
""" """
theme_xml = ElementTree(element=XML(xml.encode(u'ascii', # remove encoding string
u'xmlcharrefreplace'))) line = xml.find(u'?>')
if line:
xml = xml[line + 2:]
try:
theme_xml = objectify.fromstring(xml)
except etree.XMLSyntaxError:
log.exception(u'Invalid xml %s', xml)
return
xml_iter = theme_xml.getiterator() xml_iter = theme_xml.getiterator()
master = u''
for element in xml_iter: for element in xml_iter:
if not isinstance(element.text, unicode): parent = element.getparent()
element.text = unicode(str(element.text), u'utf-8') master = u''
if element.getchildren(): if parent is not None:
master = element.tag + u'_' if element.getparent().tag == u'font':
master = element.getparent().tag + u'_' + \
element.getparent().attrib[u'type']
# set up Outline and Shadow Tags and move to font_main
if element.getparent().tag == u'display':
if element.tag.startswith(u'shadow') or \
element.tag.startswith(u'outline'):
self._create_attr(u'font_main', element.tag, element.text)
master = element.getparent().tag
if element.getparent().tag == u'background':
master = element.getparent().tag
if element.getparent().attrib:
for attr in element.getparent().attrib:
self._create_attr(master, attr, \
element.getparent().attrib[attr])
if master:
self._create_attr(master, element.tag, element.text)
if element.attrib:
for attr in element.attrib:
base_element = attr
# correction for the shadow and outline tags
if element.tag == u'shadow' or element.tag == u'outline':
if not attr.startswith(element.tag):
base_element = element.tag + u'_' + attr
self._create_attr(master, base_element,
element.attrib[attr])
else: else:
# background transparent tags have no children so special case if element.tag == u'name':
if element.tag == u'background': self._create_attr(u'theme', element.tag, element.text)
for e in element.attrib.iteritems():
self._create_attr(element.tag , e[0], e[1]) def _translate_tags(self, master, element, value):
if element.attrib: """
for e in element.attrib.iteritems(): Clean up XML removing and redefining tags
if master == u'font_' and e[0] == u'type': """
master += e[1] + u'_' master = master.strip().lstrip()
elif master == u'display_' and (element.tag == u'shadow' \ element = element.strip().lstrip()
or element.tag == u'outline' ): value = unicode(value).strip().lstrip()
self._create_attr(master, element.tag, element.text) if master == u'display':
self._create_attr(master, element.tag + u'_'+ e[0], e[1]) if element == u'wrapStyle':
else: return True, None, None, None
field = master + e[0] if element.startswith(u'shadow') or element.startswith(u'outline'):
self._create_attr(master, e[0], e[1]) master = u'font_main'
# fix bold font
if element == u'weight':
element = u'bold'
if value == u'Normal':
value = False
else: else:
if element.tag: value = True
element.text = element.text.strip().lstrip() if element == u'proportion':
self._create_attr(master , element.tag, element.text) element = u'size'
return False, master, element, value
def _create_attr(self, master , element, value): def _create_attr(self, master , element, value):
""" """
Create the attributes with the correct data types and name format Create the attributes with the correct data types and name format
""" """
reject, master, element, value = \
self._translate_tags(master, element, value)
if reject:
return
field = self._de_hump(element) field = self._de_hump(element)
tag = master + u'_' + field
if field in boolean_list: if field in boolean_list:
setattr(self, master + field, str_to_bool(value)) setattr(self, tag, str_to_bool(value))
elif field in integer_list: elif field in integer_list:
setattr(self, master + field, int(value)) setattr(self, tag, int(value))
else: else:
setattr(self, master + field, unicode(value)) # make string value unicode
if not isinstance(value, unicode):
value = unicode(str(value), u'utf-8')
# None means an empty string so lets have one.
if value == u'None':
value = u''
setattr(self, tag, unicode(value).strip().lstrip())
def __str__(self): def __str__(self):
""" """
@ -427,3 +543,58 @@ class ThemeXML(object):
s1 = re.sub(u'(.)([A-Z][a-z]+)', r'\1_\2', name) s1 = re.sub(u'(.)([A-Z][a-z]+)', r'\1_\2', name)
return re.sub(u'([a-z0-9])([A-Z])', r'\1_\2', s1).lower() return re.sub(u'([a-z0-9])([A-Z])', r'\1_\2', s1).lower()
def _build_xml_from_attrs(self):
"""
Build the XML from the varables in the object
"""
self._new_document(self.theme_name)
if self.background_type == \
BackgroundType.to_string(BackgroundType.Solid):
self.add_background_solid(self.background_color)
elif self.background_type == \
BackgroundType.to_string(BackgroundType.Gradient):
self.add_background_gradient(
self.background_start_color,
self.background_end_color,
self.background_direction)
else:
filename = \
os.path.split(self.background_filename)[1]
self.add_background_image(filename)
self.add_font(self.font_main_name,
self.font_main_color,
self.font_main_size,
self.font_main_override, u'main',
self.font_main_bold,
self.font_main_italics,
self.font_main_line_adjustment,
self.font_main_x,
self.font_main_y,
self.font_main_width,
self.font_main_height,
self.font_main_outline,
self.font_main_outline_color,
self.font_main_outline_size,
self.font_main_shadow,
self.font_main_shadow_color,
self.font_main_shadow_size)
self.add_font(self.font_footer_name,
self.font_footer_color,
self.font_footer_size,
self.font_footer_override, u'footer',
self.font_footer_bold,
self.font_footer_italics,
0, # line adjustment
self.font_footer_x,
self.font_footer_y,
self.font_footer_width,
self.font_footer_height,
self.font_footer_outline,
self.font_footer_outline_color,
self.font_footer_outline_size,
self.font_footer_shadow,
self.font_footer_shadow_color,
self.font_footer_shadow_size)
self.add_display(self.display_horizontal_align,
self.display_vertical_align,
self.display_slide_transition)

View File

@ -37,12 +37,12 @@ class HideMode(object):
Theme = 2 Theme = 2
Screen = 3 Screen = 3
from themeform import ThemeForm
from filerenameform import FileRenameForm from filerenameform import FileRenameForm
from maindisplay import MainDisplay from maindisplay import MainDisplay
from servicenoteform import ServiceNoteForm from servicenoteform import ServiceNoteForm
from serviceitemeditform import ServiceItemEditForm from serviceitemeditform import ServiceItemEditForm
from screen import ScreenList from screen import ScreenList
from amendthemeform import AmendThemeForm
from slidecontroller import SlideController from slidecontroller import SlideController
from splashscreen import SplashScreen from splashscreen import SplashScreen
from generaltab import GeneralTab from generaltab import GeneralTab
@ -51,10 +51,11 @@ from advancedtab import AdvancedTab
from aboutform import AboutForm from aboutform import AboutForm
from pluginform import PluginForm from pluginform import PluginForm
from settingsform import SettingsForm from settingsform import SettingsForm
from shortcutlistform import ShortcutListForm
from mediadockmanager import MediaDockManager from mediadockmanager import MediaDockManager
from servicemanager import ServiceManager from servicemanager import ServiceManager
from thememanager import ThemeManager from thememanager import ThemeManager
__all__ = ['SplashScreen', 'AboutForm', 'SettingsForm', __all__ = ['SplashScreen', 'AboutForm', 'SettingsForm',
'MainDisplay', 'SlideController', 'ServiceManager', 'ThemeManager', 'MainDisplay', 'SlideController', 'ServiceManager', 'ThemeManager',
'AmendThemeForm', 'MediaDockManager', 'ServiceItemEditForm'] 'MediaDockManager', 'ServiceItemEditForm']

View File

@ -81,9 +81,13 @@ class AdvancedTab(SettingsTab):
self.doubleClickLiveCheckBox = QtGui.QCheckBox(self.uiGroupBox) self.doubleClickLiveCheckBox = QtGui.QCheckBox(self.uiGroupBox)
self.doubleClickLiveCheckBox.setObjectName(u'doubleClickLiveCheckBox') self.doubleClickLiveCheckBox.setObjectName(u'doubleClickLiveCheckBox')
self.uiLayout.addWidget(self.doubleClickLiveCheckBox) self.uiLayout.addWidget(self.doubleClickLiveCheckBox)
# self.expandServiceItemCheckBox = QtGui.QCheckBox(self.uiGroupBox)
# self.expandServiceItemCheckBox.setObjectName(u'expandServiceItemCheckBox')
# self.uiLayout.addWidget(self.expandServiceItemCheckBox)
self.leftLayout.addWidget(self.uiGroupBox) self.leftLayout.addWidget(self.uiGroupBox)
self.expandServiceItemCheckBox = QtGui.QCheckBox(self.uiGroupBox) self.expandServiceItemCheckBox = QtGui.QCheckBox(self.uiGroupBox)
self.expandServiceItemCheckBox.setObjectName(u'expandServiceItemCheckBox') self.expandServiceItemCheckBox.setObjectName(
u'expandServiceItemCheckBox')
self.uiLayout.addWidget(self.expandServiceItemCheckBox) self.uiLayout.addWidget(self.expandServiceItemCheckBox)
# self.sharedDirGroupBox = QtGui.QGroupBox(self.leftWidget) # self.sharedDirGroupBox = QtGui.QGroupBox(self.leftWidget)
# self.sharedDirGroupBox.setObjectName(u'sharedDirGroupBox') # self.sharedDirGroupBox.setObjectName(u'sharedDirGroupBox')
@ -142,7 +146,7 @@ class AdvancedTab(SettingsTab):
self.mediaPluginCheckBox.setText(translate('OpenLP.AdvancedTab', self.mediaPluginCheckBox.setText(translate('OpenLP.AdvancedTab',
'Remember active media manager tab on startup')) 'Remember active media manager tab on startup'))
self.doubleClickLiveCheckBox.setText(translate('OpenLP.AdvancedTab', self.doubleClickLiveCheckBox.setText(translate('OpenLP.AdvancedTab',
'Double-click to send items straight to live (requires restart)')) 'Double-click to send items straight to live'))
self.expandServiceItemCheckBox.setText(translate('OpenLP.AdvancedTab', self.expandServiceItemCheckBox.setText(translate('OpenLP.AdvancedTab',
'Expand new service items on creation')) 'Expand new service items on creation'))
# self.sharedDirGroupBox.setTitle( # self.sharedDirGroupBox.setTitle(

View File

@ -90,6 +90,16 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
QtCore.QObject.connect(self.fontMainSizeSpinBox, QtCore.QObject.connect(self.fontMainSizeSpinBox,
QtCore.SIGNAL(u'editingFinished()'), QtCore.SIGNAL(u'editingFinished()'),
self.onFontMainSizeSpinBoxChanged) self.onFontMainSizeSpinBoxChanged)
QtCore.QObject.connect(self.fontMainLineAdjustmentSpinBox,
QtCore.SIGNAL(u'editingFinished()'),
self.onFontMainLineAdjustmentSpinBoxChanged)
QtCore.QObject.connect(self.shadowSpinBox,
QtCore.SIGNAL(u'editingFinished()'),
self.onShadowSpinBoxChanged)
QtCore.QObject.connect(self.outlineSpinBox,
QtCore.SIGNAL(u'editingFinished()'),
self.onOutlineSpinBoxChanged)
QtCore.QObject.connect(self.fontFooterSizeSpinBox, QtCore.QObject.connect(self.fontFooterSizeSpinBox,
QtCore.SIGNAL(u'editingFinished()'), QtCore.SIGNAL(u'editingFinished()'),
self.onFontFooterSizeSpinBoxChanged) self.onFontFooterSizeSpinBoxChanged)
@ -118,12 +128,7 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
QtCore.QObject.connect(self.fontFooterHeightSpinBox, QtCore.QObject.connect(self.fontFooterHeightSpinBox,
QtCore.SIGNAL(u'editingFinished()'), QtCore.SIGNAL(u'editingFinished()'),
self.onFontFooterHeightSpinBoxChanged) self.onFontFooterHeightSpinBoxChanged)
QtCore.QObject.connect(self.shadowSpinBox,
QtCore.SIGNAL(u'editingFinished()'),
self.onShadowSpinBoxChanged)
QtCore.QObject.connect(self.outlineSpinBox,
QtCore.SIGNAL(u'editingFinished()'),
self.onOutlineSpinBoxChanged)
# CheckBoxes # CheckBoxes
QtCore.QObject.connect(self.fontMainDefaultCheckBox, QtCore.QObject.connect(self.fontMainDefaultCheckBox,
QtCore.SIGNAL(u'stateChanged(int)'), QtCore.SIGNAL(u'stateChanged(int)'),
@ -525,7 +530,7 @@ class AmendThemeForm(QtGui.QDialog, Ui_AmendThemeDialog):
else: else:
self.gradientComboBox.setCurrentIndex(2) self.gradientComboBox.setCurrentIndex(2)
# Font Main Tab # Font Main Tab
self.fontMainComboBox.setCurrentFont( self.mainFontComboBox.setCurrentFont(
QtGui.QFont(self.theme.font_main_name)) QtGui.QFont(self.theme.font_main_name))
self.fontMainSizeSpinBox.setValue(self.theme.font_main_proportion) self.fontMainSizeSpinBox.setValue(self.theme.font_main_proportion)
if not self.theme.font_main_italics and \ if not self.theme.font_main_italics and \

View File

@ -34,7 +34,8 @@ class Ui_FileRenameDialog(object):
FileRenameDialog.resize(400, 87) FileRenameDialog.resize(400, 87)
self.buttonBox = QtGui.QDialogButtonBox(FileRenameDialog) self.buttonBox = QtGui.QDialogButtonBox(FileRenameDialog)
self.buttonBox.setGeometry(QtCore.QRect(210, 50, 171, 25)) self.buttonBox.setGeometry(QtCore.QRect(210, 50, 171, 25))
self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok) self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel |
QtGui.QDialogButtonBox.Ok)
self.buttonBox.setObjectName("buttonBox") self.buttonBox.setObjectName("buttonBox")
self.widget = QtGui.QWidget(FileRenameDialog) self.widget = QtGui.QWidget(FileRenameDialog)
self.widget.setGeometry(QtCore.QRect(10, 10, 381, 35)) self.widget.setGeometry(QtCore.QRect(10, 10, 381, 35))

View File

@ -30,13 +30,13 @@ import os
from PyQt4 import QtCore, QtGui, QtWebKit from PyQt4 import QtCore, QtGui, QtWebKit
from PyQt4.phonon import Phonon from PyQt4.phonon import Phonon
from openlp.core.lib import Receiver, resize_image, build_html, ServiceItem, \ from openlp.core.lib import Receiver, build_html, ServiceItem, image_to_byte
image_to_byte
from openlp.core.ui import HideMode from openlp.core.ui import HideMode
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
#http://www.steveheffernan.com/html5-video-player/demo-video-player.html #http://www.steveheffernan.com/html5-video-player/demo-video-player.html
#http://html5demos.com/two-videos
class DisplayWidget(QtGui.QGraphicsView): class DisplayWidget(QtGui.QGraphicsView):
""" """
@ -100,7 +100,7 @@ class MainDisplay(DisplayWidget):
self.screens = screens self.screens = screens
self.isLive = live self.isLive = live
self.alertTab = None self.alertTab = None
self.hide_mode = None self.hideMode = None
self.setWindowTitle(u'OpenLP Display') self.setWindowTitle(u'OpenLP Display')
self.setStyleSheet(u'border: 0px; margin: 0px; padding: 0px;') self.setStyleSheet(u'border: 0px; margin: 0px; padding: 0px;')
self.setWindowFlags(QtCore.Qt.FramelessWindowHint | self.setWindowFlags(QtCore.Qt.FramelessWindowHint |
@ -381,8 +381,8 @@ class MainDisplay(DisplayWidget):
if self.isLive: if self.isLive:
self.setVisible(True) self.setVisible(True)
# if was hidden keep it hidden # if was hidden keep it hidden
if self.hide_mode and self.isLive: if self.hideMode and self.isLive:
self.hideDisplay(self.hide_mode) self.hideDisplay(self.hideMode)
preview = QtGui.QImage(self.screen[u'size'].width(), preview = QtGui.QImage(self.screen[u'size'].width(),
self.screen[u'size'].height(), self.screen[u'size'].height(),
QtGui.QImage.Format_ARGB32_Premultiplied) QtGui.QImage.Format_ARGB32_Premultiplied)
@ -412,8 +412,8 @@ class MainDisplay(DisplayWidget):
if serviceItem.foot_text and serviceItem.foot_text: if serviceItem.foot_text and serviceItem.foot_text:
self.footer(serviceItem.foot_text) self.footer(serviceItem.foot_text)
# if was hidden keep it hidden # if was hidden keep it hidden
if self.hide_mode and self.isLive: if self.hideMode and self.isLive:
self.hideDisplay(self.hide_mode) self.hideDisplay(self.hideMode)
def footer(self, text): def footer(self, text):
""" """
@ -444,7 +444,7 @@ class MainDisplay(DisplayWidget):
self.setVisible(True) self.setVisible(True)
if self.phononActive: if self.phononActive:
self.webView.setVisible(True) self.webView.setVisible(True)
self.hide_mode = mode self.hideMode = mode
def showDisplay(self): def showDisplay(self):
""" """
@ -459,9 +459,9 @@ class MainDisplay(DisplayWidget):
if self.phononActive: if self.phononActive:
self.webView.setVisible(False) self.webView.setVisible(False)
self.videoPlay() self.videoPlay()
self.hideMode = None
# Trigger actions when display is active again # Trigger actions when display is active again
Receiver.send_message(u'maindisplay_active') Receiver.send_message(u'maindisplay_active')
self.hide_mode = None
class AudioPlayer(QtCore.QObject): class AudioPlayer(QtCore.QObject):
""" """

View File

@ -29,10 +29,12 @@ import logging
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.ui import AboutForm, SettingsForm, ServiceManager, \ from openlp.core.ui import AboutForm, SettingsForm, ServiceManager, \
ThemeManager, SlideController, PluginForm, MediaDockManager ThemeManager, SlideController, PluginForm, MediaDockManager, \
ShortcutListForm
from openlp.core.lib import RenderManager, build_icon, OpenLPDockWidget, \ from openlp.core.lib import RenderManager, build_icon, OpenLPDockWidget, \
SettingsManager, PluginManager, Receiver, translate SettingsManager, PluginManager, Receiver, translate
from openlp.core.utils import AppLocation, add_actions, LanguageManager from openlp.core.utils import AppLocation, add_actions, LanguageManager, \
ActionList
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -73,6 +75,7 @@ class Ui_MainWindow(object):
MainWindow.setSizePolicy(sizePolicy) MainWindow.setSizePolicy(sizePolicy)
MainIcon = build_icon(u':/icon/openlp-logo-16x16.png') MainIcon = build_icon(u':/icon/openlp-logo-16x16.png')
MainWindow.setWindowIcon(MainIcon) MainWindow.setWindowIcon(MainIcon)
self.setDockNestingEnabled(True)
# Set up the main container, which contains all the other form widgets # Set up the main container, which contains all the other form widgets
self.MainContent = QtGui.QWidget(MainWindow) self.MainContent = QtGui.QWidget(MainWindow)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding,
@ -98,6 +101,12 @@ class Ui_MainWindow(object):
self.screens) self.screens)
self.LiveController = SlideController(self, self.settingsmanager, self.LiveController = SlideController(self, self.settingsmanager,
self.screens, True) self.screens, True)
previewVisible = QtCore.QSettings().value(
u'user interface/preview panel', QtCore.QVariant(True)).toBool()
self.PreviewController.Panel.setVisible(previewVisible)
liveVisible = QtCore.QSettings().value(u'user interface/live panel',
QtCore.QVariant(True)).toBool()
self.LiveController.Panel.setVisible(liveVisible)
# Create menu # Create menu
self.MenuBar = QtGui.QMenuBar(MainWindow) self.MenuBar = QtGui.QMenuBar(MainWindow)
self.MenuBar.setGeometry(QtCore.QRect(0, 0, 1087, 27)) self.MenuBar.setGeometry(QtCore.QRect(0, 0, 1087, 27))
@ -177,29 +186,34 @@ class Ui_MainWindow(object):
self.FileNewItem = QtGui.QAction(MainWindow) self.FileNewItem = QtGui.QAction(MainWindow)
self.FileNewItem.setIcon(build_icon(u':/general/general_new.png')) self.FileNewItem.setIcon(build_icon(u':/general/general_new.png'))
self.FileNewItem.setObjectName(u'FileNewItem') self.FileNewItem.setObjectName(u'FileNewItem')
MainWindow.actionList.add_action(self.FileNewItem, u'File')
self.FileOpenItem = QtGui.QAction(MainWindow) self.FileOpenItem = QtGui.QAction(MainWindow)
self.FileOpenItem.setIcon(build_icon(u':/general/general_open.png')) self.FileOpenItem.setIcon(build_icon(u':/general/general_open.png'))
self.FileOpenItem.setObjectName(u'FileOpenItem') self.FileOpenItem.setObjectName(u'FileOpenItem')
MainWindow.actionList.add_action(self.FileOpenItem, u'File')
self.FileSaveItem = QtGui.QAction(MainWindow) self.FileSaveItem = QtGui.QAction(MainWindow)
self.FileSaveItem.setIcon(build_icon(u':/general/general_save.png')) self.FileSaveItem.setIcon(build_icon(u':/general/general_save.png'))
self.FileSaveItem.setObjectName(u'FileSaveItem') self.FileSaveItem.setObjectName(u'FileSaveItem')
MainWindow.actionList.add_action(self.FileSaveItem, u'File')
self.FileSaveAsItem = QtGui.QAction(MainWindow) self.FileSaveAsItem = QtGui.QAction(MainWindow)
self.FileSaveAsItem.setObjectName(u'FileSaveAsItem') self.FileSaveAsItem.setObjectName(u'FileSaveAsItem')
MainWindow.actionList.add_action(self.FileSaveAsItem, u'File')
self.FileExitItem = QtGui.QAction(MainWindow) self.FileExitItem = QtGui.QAction(MainWindow)
self.FileExitItem.setIcon(build_icon(u':/system/system_exit.png')) self.FileExitItem.setIcon(build_icon(u':/system/system_exit.png'))
self.FileExitItem.setObjectName(u'FileExitItem') self.FileExitItem.setObjectName(u'FileExitItem')
MainWindow.actionList.add_action(self.FileExitItem, u'File')
self.ImportThemeItem = QtGui.QAction(MainWindow) self.ImportThemeItem = QtGui.QAction(MainWindow)
self.ImportThemeItem.setObjectName(u'ImportThemeItem') self.ImportThemeItem.setObjectName(u'ImportThemeItem')
MainWindow.actionList.add_action(self.ImportThemeItem, u'Import')
self.ImportLanguageItem = QtGui.QAction(MainWindow) self.ImportLanguageItem = QtGui.QAction(MainWindow)
self.ImportLanguageItem.setObjectName(u'ImportLanguageItem') self.ImportLanguageItem.setObjectName(u'ImportLanguageItem')
MainWindow.actionList.add_action(self.ImportLanguageItem, u'Import')
self.ExportThemeItem = QtGui.QAction(MainWindow) self.ExportThemeItem = QtGui.QAction(MainWindow)
self.ExportThemeItem.setObjectName(u'ExportThemeItem') self.ExportThemeItem.setObjectName(u'ExportThemeItem')
MainWindow.actionList.add_action(self.ExportThemeItem, u'Export')
self.ExportLanguageItem = QtGui.QAction(MainWindow) self.ExportLanguageItem = QtGui.QAction(MainWindow)
self.ExportLanguageItem.setObjectName(u'ExportLanguageItem') self.ExportLanguageItem.setObjectName(u'ExportLanguageItem')
self.SettingsConfigureItem = QtGui.QAction(MainWindow) MainWindow.actionList.add_action(self.ExportLanguageItem, u'Export')
self.SettingsConfigureItem.setIcon(
build_icon(u':/system/system_settings.png'))
self.SettingsConfigureItem.setObjectName(u'SettingsConfigureItem')
self.ViewMediaManagerItem = QtGui.QAction(MainWindow) self.ViewMediaManagerItem = QtGui.QAction(MainWindow)
self.ViewMediaManagerItem.setCheckable(True) self.ViewMediaManagerItem.setCheckable(True)
self.ViewMediaManagerItem.setChecked(self.MediaManagerDock.isVisible()) self.ViewMediaManagerItem.setChecked(self.MediaManagerDock.isVisible())
@ -212,6 +226,7 @@ class Ui_MainWindow(object):
self.ViewThemeManagerItem.setIcon( self.ViewThemeManagerItem.setIcon(
build_icon(u':/system/system_thememanager.png')) build_icon(u':/system/system_thememanager.png'))
self.ViewThemeManagerItem.setObjectName(u'ViewThemeManagerItem') self.ViewThemeManagerItem.setObjectName(u'ViewThemeManagerItem')
MainWindow.actionList.add_action(self.ViewMediaManagerItem, u'View')
self.ViewServiceManagerItem = QtGui.QAction(MainWindow) self.ViewServiceManagerItem = QtGui.QAction(MainWindow)
self.ViewServiceManagerItem.setCheckable(True) self.ViewServiceManagerItem.setCheckable(True)
self.ViewServiceManagerItem.setChecked( self.ViewServiceManagerItem.setChecked(
@ -219,28 +234,49 @@ class Ui_MainWindow(object):
self.ViewServiceManagerItem.setIcon( self.ViewServiceManagerItem.setIcon(
build_icon(u':/system/system_servicemanager.png')) build_icon(u':/system/system_servicemanager.png'))
self.ViewServiceManagerItem.setObjectName(u'ViewServiceManagerItem') self.ViewServiceManagerItem.setObjectName(u'ViewServiceManagerItem')
MainWindow.actionList.add_action(self.ViewServiceManagerItem, u'View')
self.ViewPreviewPanel = QtGui.QAction(MainWindow)
self.ViewPreviewPanel.setCheckable(True)
self.ViewPreviewPanel.setChecked(previewVisible)
self.ViewPreviewPanel.setObjectName(u'ViewPreviewPanel')
MainWindow.actionList.add_action(self.ViewPreviewPanel, u'View')
self.ViewLivePanel = QtGui.QAction(MainWindow)
self.ViewLivePanel.setCheckable(True)
self.ViewLivePanel.setChecked(liveVisible)
self.ViewLivePanel.setObjectName(u'ViewLivePanel')
MainWindow.actionList.add_action(self.ViewLivePanel, u'View')
self.ModeDefaultItem = QtGui.QAction(MainWindow)
self.ModeDefaultItem.setCheckable(True)
self.ModeDefaultItem.setObjectName(u'ModeDefaultItem')
MainWindow.actionList.add_action(self.ModeDefaultItem, u'View Mode')
self.ModeSetupItem = QtGui.QAction(MainWindow)
self.ModeSetupItem.setCheckable(True)
self.ModeSetupItem.setObjectName(u'ModeLiveItem')
MainWindow.actionList.add_action(self.ModeSetupItem, u'View Mode')
self.ModeLiveItem = QtGui.QAction(MainWindow)
self.ModeLiveItem.setCheckable(True)
self.ModeLiveItem.setObjectName(u'ModeLiveItem')
MainWindow.actionList.add_action(self.ModeLiveItem, u'View Mode')
self.ModeGroup = QtGui.QActionGroup(MainWindow)
self.ModeGroup.addAction(self.ModeDefaultItem)
self.ModeGroup.addAction(self.ModeSetupItem)
self.ModeGroup.addAction(self.ModeLiveItem)
self.ModeDefaultItem.setChecked(True)
self.ToolsAddToolItem = QtGui.QAction(MainWindow)
self.ToolsAddToolItem.setIcon(build_icon(u':/tools/tools_add.png'))
self.ToolsAddToolItem.setObjectName(u'ToolsAddToolItem')
MainWindow.actionList.add_action(self.ToolsAddToolItem, u'Tools')
self.SettingsPluginListItem = QtGui.QAction(MainWindow) self.SettingsPluginListItem = QtGui.QAction(MainWindow)
self.SettingsPluginListItem.setIcon( self.SettingsPluginListItem.setIcon(
build_icon(u':/system/settings_plugin_list.png')) build_icon(u':/system/settings_plugin_list.png'))
self.SettingsPluginListItem.setObjectName(u'SettingsPluginListItem') self.SettingsPluginListItem.setObjectName(u'SettingsPluginListItem')
self.HelpDocumentationItem = QtGui.QAction(MainWindow) MainWindow.actionList.add_action(self.SettingsPluginListItem,
self.HelpDocumentationItem.setIcon( u'Settings')
build_icon(u':/system/system_help_contents.png'))
self.HelpDocumentationItem.setObjectName(u'HelpDocumentationItem')
self.HelpDocumentationItem.setEnabled(False)
self.HelpAboutItem = QtGui.QAction(MainWindow)
self.HelpAboutItem.setIcon(
build_icon(u':/system/system_about.png'))
self.HelpAboutItem.setObjectName(u'HelpAboutItem')
self.HelpOnlineHelpItem = QtGui.QAction(MainWindow)
self.HelpOnlineHelpItem.setObjectName(u'HelpOnlineHelpItem')
self.HelpOnlineHelpItem.setEnabled(False)
self.HelpWebSiteItem = QtGui.QAction(MainWindow)
self.HelpWebSiteItem.setObjectName(u'HelpWebSiteItem')
#i18n Language Items #i18n Language Items
self.AutoLanguageItem = QtGui.QAction(MainWindow) self.AutoLanguageItem = QtGui.QAction(MainWindow)
self.AutoLanguageItem.setObjectName(u'AutoLanguageItem') self.AutoLanguageItem.setObjectName(u'AutoLanguageItem')
self.AutoLanguageItem.setCheckable(True) self.AutoLanguageItem.setCheckable(True)
MainWindow.actionList.add_action(self.AutoLanguageItem, u'Settings')
self.LanguageGroup = QtGui.QActionGroup(MainWindow) self.LanguageGroup = QtGui.QActionGroup(MainWindow)
qmList = LanguageManager.get_qm_list() qmList = LanguageManager.get_qm_list()
savedLanguage = LanguageManager.get_language() savedLanguage = LanguageManager.get_language()
@ -253,37 +289,34 @@ class Ui_MainWindow(object):
languageItem.setChecked(True) languageItem.setChecked(True)
add_actions(self.LanguageGroup, [languageItem]) add_actions(self.LanguageGroup, [languageItem])
self.LanguageGroup.setDisabled(LanguageManager.auto_language) self.LanguageGroup.setDisabled(LanguageManager.auto_language)
self.ToolsAddToolItem = QtGui.QAction(MainWindow) self.SettingsShortcutsItem = QtGui.QAction(MainWindow)
self.ToolsAddToolItem.setIcon(build_icon(u':/tools/tools_add.png')) self.SettingsShortcutsItem.setIcon(
self.ToolsAddToolItem.setObjectName(u'ToolsAddToolItem') build_icon(u':/system/system_configure_shortcuts.png'))
self.ViewPreviewPanel = QtGui.QAction(MainWindow) self.SettingsShortcutsItem.setObjectName(u'SettingsShortcutsItem')
self.ViewPreviewPanel.setCheckable(True) self.SettingsConfigureItem = QtGui.QAction(MainWindow)
previewVisible = QtCore.QSettings().value( self.SettingsConfigureItem.setIcon(
u'user interface/preview panel', QtCore.QVariant(True)).toBool() build_icon(u':/system/system_settings.png'))
self.ViewPreviewPanel.setChecked(previewVisible) self.SettingsConfigureItem.setObjectName(u'SettingsConfigureItem')
self.ViewPreviewPanel.setObjectName(u'ViewPreviewPanel') MainWindow.actionList.add_action(self.SettingsShortcutsItem,
self.PreviewController.Panel.setVisible(previewVisible) u'Settings')
self.ViewLivePanel = QtGui.QAction(MainWindow) self.HelpDocumentationItem = QtGui.QAction(MainWindow)
self.ViewLivePanel.setCheckable(True) self.HelpDocumentationItem.setIcon(
liveVisible = QtCore.QSettings().value(u'user interface/live panel', build_icon(u':/system/system_help_contents.png'))
QtCore.QVariant(True)).toBool() self.HelpDocumentationItem.setObjectName(u'HelpDocumentationItem')
self.ViewLivePanel.setChecked(liveVisible) self.HelpDocumentationItem.setEnabled(False)
self.ViewLivePanel.setObjectName(u'ViewLivePanel') MainWindow.actionList.add_action(self.HelpDocumentationItem, u'Help')
self.LiveController.Panel.setVisible(liveVisible) self.HelpAboutItem = QtGui.QAction(MainWindow)
self.ModeDefaultItem = QtGui.QAction(MainWindow) self.HelpAboutItem.setIcon(
self.ModeDefaultItem.setCheckable(True) build_icon(u':/system/system_about.png'))
self.ModeDefaultItem.setObjectName(u'ModeDefaultItem') self.HelpAboutItem.setObjectName(u'HelpAboutItem')
self.ModeSetupItem = QtGui.QAction(MainWindow) MainWindow.actionList.add_action(self.HelpAboutItem, u'Help')
self.ModeSetupItem.setCheckable(True) self.HelpOnlineHelpItem = QtGui.QAction(MainWindow)
self.ModeSetupItem.setObjectName(u'ModeLiveItem') self.HelpOnlineHelpItem.setObjectName(u'HelpOnlineHelpItem')
self.ModeLiveItem = QtGui.QAction(MainWindow) self.HelpOnlineHelpItem.setEnabled(False)
self.ModeLiveItem.setCheckable(True) MainWindow.actionList.add_action(self.HelpOnlineHelpItem, u'Help')
self.ModeLiveItem.setObjectName(u'ModeLiveItem') self.HelpWebSiteItem = QtGui.QAction(MainWindow)
self.ModeGroup = QtGui.QActionGroup(MainWindow) self.HelpWebSiteItem.setObjectName(u'HelpWebSiteItem')
self.ModeGroup.addAction(self.ModeDefaultItem) MainWindow.actionList.add_action(self.HelpWebSiteItem, u'Help')
self.ModeGroup.addAction(self.ModeSetupItem)
self.ModeGroup.addAction(self.ModeLiveItem)
self.ModeDefaultItem.setChecked(True)
add_actions(self.FileImportMenu, add_actions(self.FileImportMenu,
(self.ImportThemeItem, self.ImportLanguageItem)) (self.ImportThemeItem, self.ImportLanguageItem))
add_actions(self.FileExportMenu, add_actions(self.FileExportMenu,
@ -303,7 +336,7 @@ class Ui_MainWindow(object):
add_actions(self.SettingsLanguageMenu, self.LanguageGroup.actions()) add_actions(self.SettingsLanguageMenu, self.LanguageGroup.actions())
add_actions(self.SettingsMenu, (self.SettingsPluginListItem, add_actions(self.SettingsMenu, (self.SettingsPluginListItem,
self.SettingsLanguageMenu.menuAction(), None, self.SettingsLanguageMenu.menuAction(), None,
self.SettingsConfigureItem)) self.SettingsShortcutsItem, self.SettingsConfigureItem))
add_actions(self.ToolsMenu, add_actions(self.ToolsMenu,
(self.ToolsAddToolItem, None)) (self.ToolsAddToolItem, None))
add_actions(self.HelpMenu, add_actions(self.HelpMenu,
@ -394,6 +427,8 @@ class Ui_MainWindow(object):
translate('OpenLP.MainWindow', '&Theme')) translate('OpenLP.MainWindow', '&Theme'))
self.ExportLanguageItem.setText( self.ExportLanguageItem.setText(
translate('OpenLP.MainWindow', '&Language')) translate('OpenLP.MainWindow', '&Language'))
self.SettingsShortcutsItem.setText(
translate('OpenLP.MainWindow', 'Configure &Shortcuts...'))
self.SettingsConfigureItem.setText( self.SettingsConfigureItem.setText(
translate('OpenLP.MainWindow', '&Configure OpenLP...')) translate('OpenLP.MainWindow', '&Configure OpenLP...'))
self.ViewMediaManagerItem.setText( self.ViewMediaManagerItem.setText(
@ -488,6 +523,8 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
""" """
log.info(u'MainWindow loaded') log.info(u'MainWindow loaded')
actionList = ActionList()
def __init__(self, screens, applicationVersion): def __init__(self, screens, applicationVersion):
""" """
This constructor sets up the interface, the various managers, and the This constructor sets up the interface, the various managers, and the
@ -495,6 +532,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
""" """
QtGui.QMainWindow.__init__(self) QtGui.QMainWindow.__init__(self)
self.screens = screens self.screens = screens
self.actionList = ActionList()
self.applicationVersion = applicationVersion self.applicationVersion = applicationVersion
# Set up settings sections for the main application # Set up settings sections for the main application
# (not for use by plugins) # (not for use by plugins)
@ -506,6 +544,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.settingsmanager = SettingsManager(screens) self.settingsmanager = SettingsManager(screens)
self.aboutForm = AboutForm(self, applicationVersion) self.aboutForm = AboutForm(self, applicationVersion)
self.settingsForm = SettingsForm(self.screens, self, self) self.settingsForm = SettingsForm(self.screens, self, self)
self.shortcutForm = ShortcutListForm(self)
self.recentFiles = QtCore.QStringList() self.recentFiles = QtCore.QStringList()
# Set up the path with plugins # Set up the path with plugins
pluginpath = AppLocation.get_directory(AppLocation.PluginsDir) pluginpath = AppLocation.get_directory(AppLocation.PluginsDir)
@ -551,7 +590,9 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
QtCore.QObject.connect(self.SettingsPluginListItem, QtCore.QObject.connect(self.SettingsPluginListItem,
QtCore.SIGNAL(u'triggered()'), self.onPluginItemClicked) QtCore.SIGNAL(u'triggered()'), self.onPluginItemClicked)
QtCore.QObject.connect(self.SettingsConfigureItem, QtCore.QObject.connect(self.SettingsConfigureItem,
QtCore.SIGNAL(u'triggered()'), self.onOptionsSettingsItemClicked) QtCore.SIGNAL(u'triggered()'), self.onSettingsConfigureItemClicked)
QtCore.QObject.connect(self.SettingsShortcutsItem,
QtCore.SIGNAL(u'triggered()'), self.onSettingsShortcutsItemClicked)
QtCore.QObject.connect(self.FileNewItem, QtCore.SIGNAL(u'triggered()'), QtCore.QObject.connect(self.FileNewItem, QtCore.SIGNAL(u'triggered()'),
self.ServiceManagerContents.onNewService) self.ServiceManagerContents.onNewService)
QtCore.QObject.connect(self.FileOpenItem, QtCore.QObject.connect(self.FileOpenItem,
@ -563,7 +604,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
QtCore.QObject.connect(self.FileSaveAsItem, QtCore.QObject.connect(self.FileSaveAsItem,
QtCore.SIGNAL(u'triggered()'), QtCore.SIGNAL(u'triggered()'),
self.ServiceManagerContents.onSaveService) self.ServiceManagerContents.onSaveService)
#i18n set signals for languages # i18n set signals for languages
QtCore.QObject.connect(self.AutoLanguageItem, QtCore.QObject.connect(self.AutoLanguageItem,
QtCore.SIGNAL(u'toggled(bool)'), self.setAutoLanguage) QtCore.SIGNAL(u'toggled(bool)'), self.setAutoLanguage)
self.LanguageGroup.triggered.connect(LanguageManager.set_language) self.LanguageGroup.triggered.connect(LanguageManager.set_language)
@ -583,15 +624,15 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
QtCore.SIGNAL(u'config_screen_changed'), self.screenChanged) QtCore.SIGNAL(u'config_screen_changed'), self.screenChanged)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'maindisplay_status_text'), self.showStatusMessage) QtCore.SIGNAL(u'maindisplay_status_text'), self.showStatusMessage)
#warning cyclic dependency # warning cyclic dependency
#RenderManager needs to call ThemeManager and # RenderManager needs to call ThemeManager and
#ThemeManager needs to call RenderManager # ThemeManager needs to call RenderManager
self.RenderManager = RenderManager( self.RenderManager = RenderManager(
self.ThemeManagerContents, self.screens) self.ThemeManagerContents, self.screens)
#Define the media Dock Manager # Define the media Dock Manager
self.mediaDockManager = MediaDockManager(self.MediaToolBox) self.mediaDockManager = MediaDockManager(self.MediaToolBox)
log.info(u'Load Plugins') log.info(u'Load Plugins')
#make the controllers available to the plugins # make the controllers available to the plugins
self.plugin_helpers[u'preview'] = self.PreviewController self.plugin_helpers[u'preview'] = self.PreviewController
self.plugin_helpers[u'live'] = self.LiveController self.plugin_helpers[u'live'] = self.LiveController
self.plugin_helpers[u'render'] = self.RenderManager self.plugin_helpers[u'render'] = self.RenderManager
@ -712,12 +753,18 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.pluginForm.load() self.pluginForm.load()
self.pluginForm.exec_() self.pluginForm.exec_()
def onOptionsSettingsItemClicked(self): def onSettingsConfigureItemClicked(self):
""" """
Show the Settings dialog Show the Settings dialog
""" """
self.settingsForm.exec_() self.settingsForm.exec_()
def onSettingsShortcutsItemClicked(self):
"""
Show the shortcuts dialog
"""
self.shortcutForm.exec_(self.actionList)
def onModeDefaultItemClicked(self): def onModeDefaultItemClicked(self):
""" """
Put OpenLP into "Default" view mode. Put OpenLP into "Default" view mode.
@ -808,7 +855,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.plugin_manager.finalise_plugins() self.plugin_manager.finalise_plugins()
# Save settings # Save settings
self.saveSettings() self.saveSettings()
#Close down the display # Close down the display
self.LiveController.display.close() self.LiveController.display.close()
def serviceChanged(self, reset=False, serviceName=None): def serviceChanged(self, reset=False, serviceName=None):

View File

@ -107,7 +107,8 @@ class PluginForm(QtGui.QDialog, Ui_PluginViewDialog):
if self.pluginListWidget.currentItem() is None: if self.pluginListWidget.currentItem() is None:
self._clearDetails() self._clearDetails()
return return
plugin_name_plural = self.pluginListWidget.currentItem().text().split(u' ')[0] plugin_name_plural = \
self.pluginListWidget.currentItem().text().split(u' ')[0]
self.activePlugin = None self.activePlugin = None
for plugin in self.parent.plugin_manager.plugins: for plugin in self.parent.plugin_manager.plugins:
name_string = plugin.getString(StringContent.Name) name_string = plugin.getString(StringContent.Name)

View File

@ -116,6 +116,7 @@ class ServiceManager(QtGui.QWidget):
self.layout = QtGui.QVBoxLayout(self) self.layout = QtGui.QVBoxLayout(self)
self.layout.setSpacing(0) self.layout.setSpacing(0)
self.layout.setMargin(0) self.layout.setMargin(0)
self.expandTabs = False
# Create the top toolbar # Create the top toolbar
self.toolbar = OpenLPToolbar(self) self.toolbar = OpenLPToolbar(self)
self.toolbar.addToolbarButton( self.toolbar.addToolbarButton(
@ -203,13 +204,13 @@ class ServiceManager(QtGui.QWidget):
self.orderToolbar.addSeparator() self.orderToolbar.addSeparator()
self.orderToolbar.addToolbarButton( self.orderToolbar.addToolbarButton(
translate('OpenLP.ServiceManager', '&Expand all'), translate('OpenLP.ServiceManager', '&Expand all'),
u':/services/service_top.png', u':/services/service_expand_all.png',
translate('OpenLP.ServiceManager', translate('OpenLP.ServiceManager',
'Expand all the service items.'), 'Expand all the service items.'),
self.onExpandAll) self.onExpandAll)
self.orderToolbar.addToolbarButton( self.orderToolbar.addToolbarButton(
translate('OpenLP.ServiceManager', '&Collapse all'), translate('OpenLP.ServiceManager', '&Collapse all'),
u':/services/service_bottom.png', u':/services/service_collapse_all.png',
translate('OpenLP.ServiceManager', translate('OpenLP.ServiceManager',
'Collapse all the service items.'), 'Collapse all the service items.'),
self.onCollapseAll) self.onCollapseAll)
@ -306,8 +307,8 @@ class ServiceManager(QtGui.QWidget):
self.editAction.setVisible(False) self.editAction.setVisible(False)
self.maintainAction.setVisible(False) self.maintainAction.setVisible(False)
self.notesAction.setVisible(False) self.notesAction.setVisible(False)
if serviceItem[u'service_item'].is_capable(ItemCapabilities.AllowsEdit) \ if serviceItem[u'service_item'].is_capable(ItemCapabilities.AllowsEdit)\
and hasattr(serviceItem[u'service_item'], u'editId'): and serviceItem[u'service_item'].edit_id:
self.editAction.setVisible(True) self.editAction.setVisible(True)
if serviceItem[u'service_item']\ if serviceItem[u'service_item']\
.is_capable(ItemCapabilities.AllowsMaintain): .is_capable(ItemCapabilities.AllowsMaintain):
@ -441,7 +442,8 @@ class ServiceManager(QtGui.QWidget):
if setSelected: if setSelected:
setSelected = False setSelected = False
serviceIterator.value().setSelected(True) serviceIterator.value().setSelected(True)
elif serviceIterator.value() and serviceIterator.value().isSelected(): elif serviceIterator.value() and \
serviceIterator.value().isSelected():
serviceIterator.value().setSelected(False) serviceIterator.value().setSelected(False)
setSelected = True setSelected = True
serviceIterator += 1 serviceIterator += 1
@ -761,7 +763,8 @@ class ServiceManager(QtGui.QWidget):
serviceitem.set_from_service(item, self.servicePath) serviceitem.set_from_service(item, self.servicePath)
self.validateItem(serviceitem) self.validateItem(serviceitem)
self.addServiceItem(serviceitem) self.addServiceItem(serviceitem)
if serviceitem.is_capable(ItemCapabilities.OnLoadUpdate): if serviceitem.is_capable(
ItemCapabilities.OnLoadUpdate):
Receiver.send_message(u'%s_service_load' % Receiver.send_message(u'%s_service_load' %
serviceitem.name.lower(), serviceitem) serviceitem.name.lower(), serviceitem)
try: try:
@ -786,6 +789,8 @@ class ServiceManager(QtGui.QWidget):
self.serviceName = name[len(name) - 1] self.serviceName = name[len(name) - 1]
self.parent.addRecentFile(filename) self.parent.addRecentFile(filename)
self.parent.serviceChanged(True, self.serviceName) self.parent.serviceChanged(True, self.serviceName)
# Refresh Plugin lists
Receiver.send_message(u'plugin_list_refresh')
def validateItem(self, serviceItem): def validateItem(self, serviceItem):
""" """
@ -861,7 +866,7 @@ class ServiceManager(QtGui.QWidget):
editId, uuid = message.split(u':') editId, uuid = message.split(u':')
for item in self.serviceItems: for item in self.serviceItems:
if item[u'service_item']._uuid == uuid: if item[u'service_item']._uuid == uuid:
item[u'service_item'].editId = editId item[u'service_item'].edit_id = editId
def replaceServiceItem(self, newItem): def replaceServiceItem(self, newItem):
""" """
@ -870,7 +875,7 @@ class ServiceManager(QtGui.QWidget):
""" """
newItem.render() newItem.render()
for itemcount, item in enumerate(self.serviceItems): for itemcount, item in enumerate(self.serviceItems):
if item[u'service_item'].editId == newItem.editId and \ if item[u'service_item'].edit_id == newItem.edit_id and \
item[u'service_item'].name == newItem.name: item[u'service_item'].name == newItem.name:
newItem.merge(item[u'service_item']) newItem.merge(item[u'service_item'])
item[u'service_item'] = newItem item[u'service_item'] = newItem
@ -888,8 +893,8 @@ class ServiceManager(QtGui.QWidget):
``expand`` ``expand``
Override the default expand settings. (Tristate) Override the default expand settings. (Tristate)
""" """
log.debug(u'addServiceItem') # if not passed set to config value
if expand == None: if expand is None:
expand = self.expandTabs expand = self.expandTabs
sitem = self.findServiceItem()[0] sitem = self.findServiceItem()[0]
item.render() item.render()
@ -980,7 +985,7 @@ class ServiceManager(QtGui.QWidget):
.is_capable(ItemCapabilities.AllowsEdit): .is_capable(ItemCapabilities.AllowsEdit):
Receiver.send_message(u'%s_edit' % Receiver.send_message(u'%s_edit' %
self.serviceItems[item][u'service_item'].name.lower(), u'L:%s' % self.serviceItems[item][u'service_item'].name.lower(), u'L:%s' %
self.serviceItems[item][u'service_item'].editId ) self.serviceItems[item][u'service_item'].edit_id )
def findServiceItem(self): def findServiceItem(self):
""" """
@ -1025,6 +1030,9 @@ class ServiceManager(QtGui.QWidget):
# ServiceManager started the drag and drop # ServiceManager started the drag and drop
if plugin == u'ServiceManager': if plugin == u'ServiceManager':
startpos, startCount = self.findServiceItem() startpos, startCount = self.findServiceItem()
# If no items selected
if startpos == -1:
return
if item is None: if item is None:
endpos = len(self.serviceItems) endpos = len(self.serviceItems)
else: else:

View File

@ -0,0 +1,114 @@
# -*- 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, build_icon
class Ui_ShortcutListDialog(object):
def setupUi(self, shortcutListDialog):
shortcutListDialog.setObjectName(u'shortcutListDialog')
shortcutListDialog.resize(500, 438)
self.shortcutListLayout = QtGui.QVBoxLayout(shortcutListDialog)
self.shortcutListLayout.setSpacing(8)
self.shortcutListLayout.setMargin(8)
self.shortcutListLayout.setObjectName(u'shortcutListLayout')
self.shortcutListTreeWidget = QtGui.QTreeWidget(shortcutListDialog)
self.shortcutListTreeWidget.setAlternatingRowColors(True)
self.shortcutListTreeWidget.setObjectName(u'shortcutListTreeWidget')
self.shortcutListTreeWidget.setColumnCount(2)
self.shortcutListTreeWidget.setSelectionBehavior(
QtGui.QAbstractItemView.SelectRows)
self.shortcutListLayout.addWidget(self.shortcutListTreeWidget)
self.shortcutLayout = QtGui.QVBoxLayout()
self.shortcutLayout.setSpacing(8)
self.shortcutLayout.setContentsMargins(0, -1, -1, -1)
self.shortcutLayout.setObjectName(u'shortcutLayout')
self.defaultRadioButton = QtGui.QRadioButton(shortcutListDialog)
self.defaultRadioButton.setChecked(True)
self.defaultRadioButton.setObjectName(u'defaultRadioButton')
self.shortcutLayout.addWidget(self.defaultRadioButton)
self.customShortcutLayout = QtGui.QHBoxLayout()
self.customShortcutLayout.setSpacing(8)
self.customShortcutLayout.setObjectName(u'customShortcutLayout')
self.customRadioButton = QtGui.QRadioButton(shortcutListDialog)
self.customRadioButton.setObjectName(u'customRadioButton')
self.customShortcutLayout.addWidget(self.customRadioButton)
self.shortcutPushButton = QtGui.QPushButton(shortcutListDialog)
self.shortcutPushButton.setMinimumSize(QtCore.QSize(84, 0))
self.shortcutPushButton.setIcon(
build_icon(u':/system/system_configure_shortcuts.png'))
self.shortcutPushButton.setCheckable(True)
self.shortcutPushButton.setChecked(False)
self.shortcutPushButton.setObjectName(u'shortcutPushButton')
self.customShortcutLayout.addWidget(self.shortcutPushButton)
self.clearShortcutToolButton = QtGui.QToolButton(shortcutListDialog)
self.clearShortcutToolButton.setMinimumSize(QtCore.QSize(0, 16))
self.clearShortcutToolButton.setText(u'')
self.clearShortcutToolButton.setIcon(
build_icon(u':/system/clear_shortcut.png'))
self.clearShortcutToolButton.setObjectName(u'clearShortcutToolButton')
self.customShortcutLayout.addWidget(self.clearShortcutToolButton)
self.customShortcutSpacer = QtGui.QSpacerItem(40, 20,
QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.customShortcutLayout.addItem(self.customShortcutSpacer)
self.shortcutLayout.addLayout(self.customShortcutLayout)
self.shortcutListLayout.addLayout(self.shortcutLayout)
self.shortcutListButtonBox = QtGui.QDialogButtonBox(shortcutListDialog)
self.shortcutListButtonBox.setOrientation(QtCore.Qt.Horizontal)
self.shortcutListButtonBox.setStandardButtons(
QtGui.QDialogButtonBox.Cancel | QtGui.QDialogButtonBox.Ok |
QtGui.QDialogButtonBox.Reset)
self.shortcutListButtonBox.setObjectName(u'shortcutListButtonBox')
self.shortcutListLayout.addWidget(self.shortcutListButtonBox)
self.retranslateUi(shortcutListDialog)
QtCore.QObject.connect(
self.shortcutListButtonBox,
QtCore.SIGNAL(u'accepted()'),
shortcutListDialog.accept
)
QtCore.QObject.connect(
self.shortcutListButtonBox,
QtCore.SIGNAL(u'rejected()'),
shortcutListDialog.reject
)
QtCore.QMetaObject.connectSlotsByName(shortcutListDialog)
def retranslateUi(self, shortcutListDialog):
shortcutListDialog.setWindowTitle(
translate('OpenLP.ShortcutListDialog', 'Customize Shortcuts'))
self.shortcutListTreeWidget.setHeaderLabels([
translate('OpenLP.ShortcutListDialog', 'Action'),
translate('OpenLP.ShortcutListDialog', 'Shortcut')
])
self.defaultRadioButton.setText(
translate('OpenLP.ShortcutListDialog', 'Default: %s'))
self.customRadioButton.setText(
translate('OpenLP.ShortcutListDialog', 'Custom:'))
self.shortcutPushButton.setText(
translate('OpenLP.ShortcutListDialog', 'None'))

View File

@ -0,0 +1,110 @@
# -*- 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
import re
from PyQt4 import QtCore, QtGui
from openlp.core.utils import translate
from shortcutlistdialog import Ui_ShortcutListDialog
REMOVE_AMPERSAND = re.compile(r'&{1}')
log = logging.getLogger(__name__)
class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
"""
The shortcut list dialog
"""
def __init__(self, parent):
"""
Do some initialisation stuff
"""
QtGui.QDialog.__init__(self, parent)
self.setupUi(self)
self.actionList = None
self.captureShortcut = False
QtCore.QObject.connect(
self.shortcutPushButton,
QtCore.SIGNAL(u'toggled(bool)'),
self.onShortcutPushButtonClicked
)
def keyReleaseEvent(self, event):
Qt = QtCore.Qt
if not self.captureShortcut:
return
key = event.key()
if key == Qt.Key_Shift or key == Qt.Key_Control or \
key == Qt.Key_Meta or key == Qt.Key_Alt:
return
key_string = QtGui.QKeySequence(key).toString()
if event.modifiers() & Qt.ControlModifier == Qt.ControlModifier:
key_string = u'Ctrl+' + key_string
if event.modifiers() & Qt.AltModifier == Qt.AltModifier:
key_string = u'Alt+' + key_string
if event.modifiers() & Qt.ShiftModifier == Qt.ShiftModifier:
key_string = u'Shift+' + key_string
key_sequence = QtGui.QKeySequence(key_string)
existing_key = QtGui.QKeySequence("Ctrl+Shift+F8")
if key_sequence == existing_key:
QtGui.QMessageBox.warning(
self,
translate('OpenLP.ShortcutListDialog', 'Duplicate Shortcut'),
unicode(translate('OpenLP.ShortcutListDialog', 'The shortcut '
'"%s" is already assigned to another action, please '
'use a different shortcut.')) % key_sequence.toString(),
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok),
QtGui.QMessageBox.Ok
)
else:
self.shortcutPushButton.setText(key_sequence.toString())
self.shortcutPushButton.setChecked(False)
self.captureShortcut = False
def exec_(self, actionList):
self.actionList = actionList
self.refreshActions()
return QtGui.QDialog.exec_(self)
def refreshActions(self):
self.shortcutListTreeWidget.clear()
for category in self.actionList.categories:
item = QtGui.QTreeWidgetItem([category.name])
for action in category.actions:
actionText = REMOVE_AMPERSAND.sub('', unicode(action.text()))
shortcutText = action.shortcut().toString()
actionItem = QtGui.QTreeWidgetItem([actionText, shortcutText])
actionItem.setIcon(0, action.icon())
item.addChild(actionItem)
item.setExpanded(True)
self.shortcutListTreeWidget.addTopLevelItem(item)
def onShortcutPushButtonClicked(self, toggled):
self.captureShortcut = toggled

View File

@ -26,7 +26,6 @@
import logging import logging
import os import os
import time
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from PyQt4.phonon import Phonon from PyQt4.phonon import Phonon
@ -332,10 +331,8 @@ class SlideController(QtGui.QWidget):
QtCore.QObject.connect(self.PreviewListWidget, QtCore.QObject.connect(self.PreviewListWidget,
QtCore.SIGNAL(u'clicked(QModelIndex)'), self.onSlideSelected) QtCore.SIGNAL(u'clicked(QModelIndex)'), self.onSlideSelected)
if not self.isLive: if not self.isLive:
if QtCore.QSettings().value(u'advanced/double click live', QtCore.QObject.connect(self.PreviewListWidget,
QtCore.QVariant(False)).toBool(): QtCore.SIGNAL(u'doubleClicked(QModelIndex)'), self.onGoLiveClick)
QtCore.QObject.connect(self.PreviewListWidget,
QtCore.SIGNAL(u'doubleClicked(QModelIndex)'), self.onGoLive)
if isLive: if isLive:
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'slidecontroller_live_spin_delay'), QtCore.SIGNAL(u'slidecontroller_live_spin_delay'),
@ -392,6 +389,8 @@ class SlideController(QtGui.QWidget):
if self.isLive: if self.isLive:
QtCore.QObject.connect(self.volumeSlider, QtCore.QObject.connect(self.volumeSlider,
QtCore.SIGNAL(u'sliderReleased()'), self.mediaVolume) QtCore.SIGNAL(u'sliderReleased()'), self.mediaVolume)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'maindisplay_active'), self.updatePreview)
def screenSizeChanged(self): def screenSizeChanged(self):
""" """
@ -434,8 +433,12 @@ class SlideController(QtGui.QWidget):
request = unicode(self.sender().text()) request = unicode(self.sender().text())
slideno = self.slideList[request] slideno = self.slideList[request]
if slideno > self.PreviewListWidget.rowCount(): if slideno > self.PreviewListWidget.rowCount():
self.PreviewListWidget.selectRow(self.PreviewListWidget.rowCount()) self.PreviewListWidget.selectRow(
self.PreviewListWidget.rowCount() - 1)
else: else:
if slideno + 1 < self.PreviewListWidget.rowCount():
self.PreviewListWidget.scrollToItem(
self.PreviewListWidget.item(slideno + 1, 0))
self.PreviewListWidget.selectRow(slideno) self.PreviewListWidget.selectRow(slideno)
self.onSlideSelected() self.onSlideSelected()
@ -527,6 +530,9 @@ class SlideController(QtGui.QWidget):
log.debug(u'addServiceManagerItem live = %s' % self.isLive) log.debug(u'addServiceManagerItem live = %s' % self.isLive)
# If service item is the same as the current on only change slide # If service item is the same as the current on only change slide
if item.__eq__(self.serviceItem): if item.__eq__(self.serviceItem):
if slideno + 1 < self.PreviewListWidget.rowCount():
self.PreviewListWidget.scrollToItem(
self.PreviewListWidget.item(slideno + 1, 0))
self.PreviewListWidget.selectRow(slideno) self.PreviewListWidget.selectRow(slideno)
self.onSlideSelected() self.onSlideSelected()
return return
@ -608,8 +614,12 @@ class SlideController(QtGui.QWidget):
self.PreviewListWidget.setColumnWidth(0, self.PreviewListWidget.setColumnWidth(0,
self.PreviewListWidget.viewport().size().width()) self.PreviewListWidget.viewport().size().width())
if slideno > self.PreviewListWidget.rowCount(): if slideno > self.PreviewListWidget.rowCount():
self.PreviewListWidget.selectRow(self.PreviewListWidget.rowCount()) self.PreviewListWidget.selectRow(
self.PreviewListWidget.rowCount() - 1)
else: else:
if slideno + 1 < self.PreviewListWidget.rowCount():
self.PreviewListWidget.scrollToItem(
self.PreviewListWidget.item(slideno + 1, 0))
self.PreviewListWidget.selectRow(slideno) self.PreviewListWidget.selectRow(slideno)
self.enableToolBar(serviceItem) self.enableToolBar(serviceItem)
# Pass to display for viewing # Pass to display for viewing
@ -668,6 +678,9 @@ class SlideController(QtGui.QWidget):
[self.serviceItem, self.isLive, index]) [self.serviceItem, self.isLive, index])
self.updatePreview() self.updatePreview()
else: else:
if index + 1 < self.PreviewListWidget.rowCount():
self.PreviewListWidget.scrollToItem(
self.PreviewListWidget.item(index + 1, 0))
self.PreviewListWidget.selectRow(index) self.PreviewListWidget.selectRow(index)
self.onSlideSelected() self.onSlideSelected()
@ -780,9 +793,11 @@ class SlideController(QtGui.QWidget):
row = self.PreviewListWidget.currentRow() row = self.PreviewListWidget.currentRow()
self.selectedRow = 0 self.selectedRow = 0
if row > -1 and row < self.PreviewListWidget.rowCount(): if row > -1 and row < self.PreviewListWidget.rowCount():
if self.serviceItem.is_command() and self.isLive: if self.serviceItem.is_command():
Receiver.send_message(u'%s_slide' % self.serviceItem.name.lower(), if self.isLive:
[self.serviceItem, self.isLive, row]) Receiver.send_message(
u'%s_slide' % self.serviceItem.name.lower(),
[self.serviceItem, self.isLive, row])
self.updatePreview() self.updatePreview()
else: else:
toDisplay = self.serviceItem.get_rendered_frame(row) toDisplay = self.serviceItem.get_rendered_frame(row)
@ -799,22 +814,24 @@ class SlideController(QtGui.QWidget):
""" """
The slide has been changed. Update the slidecontroller accordingly The slide has been changed. Update the slidecontroller accordingly
""" """
if row + 1 < self.PreviewListWidget.rowCount():
self.PreviewListWidget.scrollToItem(
self.PreviewListWidget.item(row + 1, 0))
self.PreviewListWidget.selectRow(row) self.PreviewListWidget.selectRow(row)
self.updatePreview() self.updatePreview()
Receiver.send_message(u'slidecontroller_%s_changed' % self.typePrefix, Receiver.send_message(u'slidecontroller_%s_changed' % self.typePrefix,
row) row)
def updatePreview(self): def updatePreview(self):
log.debug(u'updatePreview %s ' %self.screens.current[u'primary'])
if not self.screens.current[u'primary']: if not self.screens.current[u'primary']:
# Grab now, but try again in a couple of seconds if slide change # Grab now, but try again in a couple of seconds if slide change
# is slow # is slow
QtCore.QTimer.singleShot(0.5, self.grabMainDisplay) QtCore.QTimer.singleShot(0.5, self.grabMainDisplay)
QtCore.QTimer.singleShot(2.5, self.grabMainDisplay) QtCore.QTimer.singleShot(2.5, self.grabMainDisplay)
else: else:
label = self.PreviewListWidget.cellWidget( self.SlidePreview.setPixmap(
self.PreviewListWidget.currentRow(), 1) QtGui.QPixmap.fromImage(self.display.preview()))
if label:
self.SlidePreview.setPixmap(label.pixmap())
def grabMainDisplay(self): def grabMainDisplay(self):
winid = QtGui.QApplication.desktop().winId() winid = QtGui.QApplication.desktop().winId()
@ -844,6 +861,9 @@ class SlideController(QtGui.QWidget):
else: else:
Receiver.send_message('servicemanager_next_item') Receiver.send_message('servicemanager_next_item')
return return
if row + 1 < self.PreviewListWidget.rowCount():
self.PreviewListWidget.scrollToItem(
self.PreviewListWidget.item(row + 1, 0))
self.PreviewListWidget.selectRow(row) self.PreviewListWidget.selectRow(row)
self.onSlideSelected() self.onSlideSelected()
@ -867,6 +887,9 @@ class SlideController(QtGui.QWidget):
row = self.PreviewListWidget.rowCount() - 1 row = self.PreviewListWidget.rowCount() - 1
else: else:
row = 0 row = 0
if row + 1 < self.PreviewListWidget.rowCount():
self.PreviewListWidget.scrollToItem(
self.PreviewListWidget.item(row + 1, 0))
self.PreviewListWidget.selectRow(row) self.PreviewListWidget.selectRow(row)
self.onSlideSelected() self.onSlideSelected()
@ -918,7 +941,15 @@ class SlideController(QtGui.QWidget):
""" """
self.songEdit = True self.songEdit = True
Receiver.send_message(u'%s_edit' % self.serviceItem.name.lower(), Receiver.send_message(u'%s_edit' % self.serviceItem.name.lower(),
u'P:%s' % self.serviceItem.editId) u'P:%s' % self.serviceItem.edit_id)
def onGoLiveClick(self):
"""
triggered by clicking the Preview slide items
"""
if QtCore.QSettings().value(u'advanced/double click live',
QtCore.QVariant(False)).toBool():
self.onGoLive()
def onGoLive(self): def onGoLive(self):
""" """

650
openlp/core/ui/themeform.py Normal file
View File

@ -0,0 +1,650 @@
# -*- 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
import os
from PyQt4 import QtCore, QtGui
from openlp.core.lib import translate, BackgroundType, BackgroundGradientType, \
Receiver
from openlp.core.utils import get_images_filter
from themewizard import Ui_ThemeWizard
log = logging.getLogger(__name__)
class ThemeForm(QtGui.QWizard, Ui_ThemeWizard):
"""
This is the Bible Import Wizard, which allows easy importing of Bibles
into OpenLP from other formats like OSIS, CSV and OpenSong.
"""
log.info(u'ThemeWizardForm loaded')
def __init__(self, parent):
"""
Instantiate the wizard, and run any extra setup we need to.
``parent``
The QWidget-derived parent of the wizard.
"""
QtGui.QWizard.__init__(self, parent)
self.thememanager = parent
self.setupUi(self)
self.registerFields()
self.accepted = False
QtCore.QObject.connect(self.backgroundTypeComboBox,
QtCore.SIGNAL(u'currentIndexChanged(int)'),
self.onBackgroundComboBox)
QtCore.QObject.connect(self.gradientComboBox,
QtCore.SIGNAL(u'currentIndexChanged(int)'),
self.onGradientComboBox)
QtCore.QObject.connect(self.color1PushButton,
QtCore.SIGNAL(u'pressed()'),
self.onColor1PushButtonClicked)
QtCore.QObject.connect(self.color2PushButton,
QtCore.SIGNAL(u'pressed()'),
self.onColor2PushButtonClicked)
QtCore.QObject.connect(self.imageBrowseButton,
QtCore.SIGNAL(u'pressed()'),
self.onImageBrowseButtonClicked)
QtCore.QObject.connect(self.mainColorPushButton,
QtCore.SIGNAL(u'pressed()'),
self.onMainColourPushButtonClicked)
QtCore.QObject.connect(self.outlineColorPushButton,
QtCore.SIGNAL(u'pressed()'),
self.onOutlineColourPushButtonClicked)
QtCore.QObject.connect(self.shadowColorPushButton,
QtCore.SIGNAL(u'pressed()'),
self.onShadowColourPushButtonClicked)
QtCore.QObject.connect(self.outlineCheckBox,
QtCore.SIGNAL(u'stateChanged(int)'),
self.onOutlineCheckCheckBoxChanged)
QtCore.QObject.connect(self.shadowCheckBox,
QtCore.SIGNAL(u'stateChanged(int)'),
self.onShadowCheckCheckBoxChanged)
QtCore.QObject.connect(self.footerColorPushButton,
QtCore.SIGNAL(u'pressed()'),
self.onFooterColourPushButtonClicked)
QtCore.QObject.connect(self.mainDefaultPositionCheckBox,
QtCore.SIGNAL(u'stateChanged(int)'),
self.onMainDefaultPositionCheckBox)
QtCore.QObject.connect(self.footerDefaultPositionCheckBox,
QtCore.SIGNAL(u'stateChanged(int)'),
self.onFooterDefaultPositionCheckBox)
QtCore.QObject.connect(self,
QtCore.SIGNAL(u'currentIdChanged(int)'),
self.pageChanged)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'theme_line_count'),
self.updateLinesText)
QtCore.QObject.connect(self.mainSizeSpinBox,
QtCore.SIGNAL(u'valueChanged(int)'),
self.calculateLines)
QtCore.QObject.connect(self.mainSizeSpinBox,
QtCore.SIGNAL(u'editingFinished()'),
self.calculateLines)
QtCore.QObject.connect(self.lineSpacingSpinBox,
QtCore.SIGNAL(u'valueChanged(int)'),
self.calculateLines)
QtCore.QObject.connect(self.lineSpacingSpinBox,
QtCore.SIGNAL(u'editingFinished()'),
self.calculateLines)
QtCore.QObject.connect(self.outlineSizeSpinBox,
QtCore.SIGNAL(u'valueChanged(int)'),
self.calculateLines)
QtCore.QObject.connect(self.outlineSizeSpinBox,
QtCore.SIGNAL(u'editingFinished()'),
self.calculateLines)
QtCore.QObject.connect(self.shadowSizeSpinBox,
QtCore.SIGNAL(u'valueChanged(int)'),
self.calculateLines)
QtCore.QObject.connect(self.shadowSizeSpinBox,
QtCore.SIGNAL(u'editingFinished()'),
self.calculateLines)
QtCore.QObject.connect(self.mainFontComboBox,
QtCore.SIGNAL(u'activated(int)'),
self.calculateLines)
def pageChanged(self, pageId):
"""
Detects Page changes and updates as approprate.
"""
if pageId == 6:
self.updateTheme()
frame = self.thememanager.generateImage(self.theme)
self.previewBoxLabel.setPixmap(QtGui.QPixmap.fromImage(frame))
def setDefaults(self):
"""
Set up display at start of theme edit.
"""
self.restart()
self.accepted = False
self.setBackgroundTabValues()
self.setMainAreaTabValues()
self.setFooterAreaTabValues()
self.setAlignmentTabValues()
self.setPositionTabValues()
self.setPreviewTabValues()
def registerFields(self):
"""
Map field names to screen names,
"""
self.backgroundPage.registerField(
u'background_type', self.backgroundTypeComboBox)
self.backgroundPage.registerField(
u'color_1', self.color1PushButton)
self.backgroundPage.registerField(
u'color_2', self.color2PushButton)
self.backgroundPage.registerField(
u'background_image', self.imageLineEdit)
self.backgroundPage.registerField(
u'gradient', self.gradientComboBox)
self.mainAreaPage.registerField(
u'mainFontComboBox', self.mainFontComboBox)
self.mainAreaPage.registerField(
u'mainColorPushButton', self.mainColorPushButton)
self.mainAreaPage.registerField(
u'mainSizeSpinBox', self.mainSizeSpinBox)
self.mainAreaPage.registerField(
u'lineSpacingSpinBox', self.lineSpacingSpinBox)
self.mainAreaPage.registerField(
u'outlineCheckBox', self.outlineCheckBox)
self.mainAreaPage.registerField(
u'outlineColorPushButton', self.outlineColorPushButton)
self.mainAreaPage.registerField(
u'outlineSizeSpinBox', self.outlineSizeSpinBox)
self.mainAreaPage.registerField(
u'shadowCheckBox', self.shadowCheckBox)
self.mainAreaPage.registerField(
u'boldCheckBox', self.boldCheckBox)
self.mainAreaPage.registerField(
u'italicsCheckBox', self.italicsCheckBox)
self.mainAreaPage.registerField(
u'shadowColorPushButton', self.shadowColorPushButton)
self.mainAreaPage.registerField(
u'shadowSizeSpinBox', self.shadowSizeSpinBox)
self.mainAreaPage.registerField(
u'footerSizeSpinBox', self.footerSizeSpinBox)
self.areaPositionPage.registerField(
u'mainPositionX', self.mainXSpinBox)
self.areaPositionPage.registerField(
u'mainPositionY', self.mainYSpinBox)
self.areaPositionPage.registerField(
u'mainPositionWidth', self.mainWidthSpinBox)
self.areaPositionPage.registerField(
u'mainPositionHeight', self.mainHeightSpinBox)
self.areaPositionPage.registerField(
u'footerPositionX', self.footerXSpinBox)
self.areaPositionPage.registerField(
u'footerPositionY', self.footerYSpinBox)
self.areaPositionPage.registerField(
u'footerPositionWidth', self.footerWidthSpinBox)
self.areaPositionPage.registerField(
u'footerPositionHeight', self.footerHeightSpinBox)
self.backgroundPage.registerField(
u'horizontal', self.horizontalComboBox)
self.backgroundPage.registerField(
u'vertical', self.verticalComboBox)
self.backgroundPage.registerField(
u'slideTransition', self.transitionsCheckBox)
self.backgroundPage.registerField(
u'name', self.themeNameEdit)
def calculateLines(self):
"""
Calculate the number of lines on a page by rendering text
"""
# Do not trigger on start up
if self.page != 0:
self.updateTheme()
frame = self.thememanager.generateImage(self.theme, True)
def updateLinesText(self, lines):
"""
Updates the lines on a page on the wizard
"""
self.mainLineCountLabel.setText(unicode(translate('OpenLP.ThemeForm', \
'(%d lines per slide)' % int(lines))))
def onOutlineCheckCheckBoxChanged(self, state):
"""
Change state as Outline check box changed
"""
if state == QtCore.Qt.Checked:
self.theme.font_main_outline = True
else:
self.theme.font_main_outline = False
self.outlineColorPushButton.setEnabled(self.theme.font_main_outline)
self.outlineSizeSpinBox.setEnabled(self.theme.font_main_outline)
self.calculateLines()
def onShadowCheckCheckBoxChanged(self, state):
"""
Change state as Shadow check box changed
"""
if state == QtCore.Qt.Checked:
self.theme.font_main_shadow = True
else:
self.theme.font_main_shadow = False
self.shadowColorPushButton.setEnabled(self.theme.font_main_shadow)
self.shadowSizeSpinBox.setEnabled(self.theme.font_main_shadow)
self.calculateLines()
def onMainDefaultPositionCheckBox(self, value):
"""
Change state as Main Area Position check box changed
"""
if value == QtCore.Qt.Checked:
self.theme.font_main_override = False
else:
self.theme.font_main_override = True
self.mainXSpinBox.setEnabled(self.theme.font_main_override)
self.mainYSpinBox.setEnabled(self.theme.font_main_override)
self.mainHeightSpinBox.setEnabled(self.theme.font_main_override)
self.mainWidthSpinBox.setEnabled(self.theme.font_main_override)
def onFooterDefaultPositionCheckBox(self, value):
"""
Change state as Footer Area Position check box changed
"""
if value == QtCore.Qt.Checked:
self.theme.font_footer_override = False
else:
self.theme.font_footer_override = True
self.footerXSpinBox.setEnabled(self.theme.font_footer_override)
self.footerYSpinBox.setEnabled(self.theme.font_footer_override)
self.footerHeightSpinBox.setEnabled(self.theme.font_footer_override)
self.footerWidthSpinBox.setEnabled(self.theme.font_footer_override)
def exec_(self):
"""
Run the wizard.
"""
self.setDefaults()
return QtGui.QWizard.exec_(self)
def initializePage(self, id):
"""
Set up the pages for Initial run through dialog
"""
log.debug(u'initializePage %s' % id)
self.page = id
if id == 1:
self.setBackgroundTabValues()
elif id == 2:
self.setMainAreaTabValues()
elif id == 3:
self.setFooterAreaTabValues()
elif id == 4:
self.setAlignmentTabValues()
elif id == 5:
self.setPositionTabValues()
def setBackgroundTabValues(self):
"""
Handle the display and State of the background display tab.
"""
if self.theme.background_type == \
BackgroundType.to_string(BackgroundType.Solid):
self.setField(u'background_type', QtCore.QVariant(0))
self.color1PushButton.setVisible(True)
self.color1Label.setVisible(True)
self.color1PushButton.setStyleSheet(u'background-color: %s' %
self.theme.background_color)
self.color1Label.setText(
translate('OpenLP.ThemeForm', 'Color:'))
self.color2PushButton.setVisible(False)
self.color2Label.setVisible(False)
self.gradientLabel.setVisible(False)
self.gradientComboBox.setVisible(False)
self.imageLabel.setVisible(False)
self.imageLineEdit.setVisible(False)
self.imageBrowseButton.setVisible(False)
self.imageLineEdit.setText(u'')
elif self.theme.background_type == \
BackgroundType.to_string(BackgroundType.Gradient):
self.setField(u'background_type', QtCore.QVariant(1))
self.color1PushButton.setVisible(True)
self.color1Label.setVisible(True)
self.color1PushButton.setStyleSheet(u'background-color: %s' %
self.theme.background_start_color)
self.color1Label.setText(
translate('OpenLP.ThemeForm', 'First color:'))
self.color2PushButton.setVisible(True)
self.color2Label.setVisible(True)
self.color2PushButton.setStyleSheet(u'background-color: %s' %
self.theme.background_end_color)
self.color2Label.setText(
translate('OpenLP.ThemeForm', 'Second color:'))
self.gradientLabel.setVisible(True)
self.gradientComboBox.setVisible(True)
self.imageLabel.setVisible(False)
self.imageLineEdit.setVisible(False)
self.imageBrowseButton.setVisible(False)
self.imageLineEdit.setText(u'')
else:
self.setField(u'background_type', QtCore.QVariant(2))
self.color1PushButton.setVisible(False)
self.color1Label.setVisible(False)
self.color2PushButton.setVisible(False)
self.color2Label.setVisible(False)
self.gradientLabel.setVisible(False)
self.gradientComboBox.setVisible(False)
self.imageLineEdit.setVisible(True)
self.imageLabel.setVisible(True)
self.imageBrowseButton.setVisible(True)
self.imageLineEdit.setText(self.theme.background_filename)
if self.theme.background_direction == \
BackgroundGradientType.to_string(BackgroundGradientType.Horizontal):
self.setField(u'gradient', QtCore.QVariant(0))
elif self.theme.background_direction == \
BackgroundGradientType.to_string(BackgroundGradientType.Vertical):
self.setField(u'gradient', QtCore.QVariant(1))
elif self.theme.background_direction == \
BackgroundGradientType.to_string(BackgroundGradientType.Circular):
self.setField(u'gradient', QtCore.QVariant(2))
elif self.theme.background_direction == \
BackgroundGradientType.to_string(BackgroundGradientType.LeftTop):
self.setField(u'gradient', QtCore.QVariant(3))
else:
self.setField(u'gradient', QtCore.QVariant(4))
def setMainAreaTabValues(self):
"""
Handle the display and State of the Main Area tab.
"""
self.mainFontComboBox.setCurrentFont(
QtGui.QFont(self.theme.font_main_name))
self.mainColorPushButton.setStyleSheet(u'background-color: %s' %
self.theme.font_main_color)
self.setField(u'mainSizeSpinBox', \
QtCore.QVariant(self.theme.font_main_size))
self.setField(u'lineSpacingSpinBox', \
QtCore.QVariant(self.theme.font_main_line_adjustment))
self.setField(u'outlineCheckBox', \
QtCore.QVariant(self.theme.font_main_outline))
self.outlineColorPushButton.setStyleSheet(u'background-color: %s' %
self.theme.font_main_outline_color)
self.setField(u'outlineSizeSpinBox', \
QtCore.QVariant(self.theme.font_main_outline_size))
self.setField(u'shadowCheckBox', \
QtCore.QVariant(self.theme.font_main_shadow))
self.shadowColorPushButton.setStyleSheet(u'background-color: %s' %
self.theme.font_main_shadow_color)
self.setField(u'shadowSizeSpinBox', \
QtCore.QVariant(self.theme.font_main_shadow_size))
self.setField(u'boldCheckBox', \
QtCore.QVariant(self.theme.font_main_bold))
self.setField(u'italicsCheckBox', \
QtCore.QVariant(self.theme.font_main_italics))
# Set up field states
if self.theme.font_main_outline:
self.setField(u'outlineCheckBox', QtCore.QVariant(False))
else:
self.setField(u'outlineCheckBox', QtCore.QVariant(True))
self.outlineColorPushButton.setEnabled(self.theme.font_main_outline)
self.outlineSizeSpinBox.setEnabled(self.theme.font_main_outline)
if self.theme.font_main_shadow:
self.setField(u'shadowCheckBox', QtCore.QVariant(False))
else:
self.setField(u'shadowCheckBox', QtCore.QVariant(True))
self.shadowColorPushButton.setEnabled(self.theme.font_main_shadow)
self.shadowSizeSpinBox.setEnabled(self.theme.font_main_shadow)
def setFooterAreaTabValues(self):
"""
Handle the display and State of the Footer Area tab.
"""
self.footerFontComboBox.setCurrentFont(
QtGui.QFont(self.theme.font_main_name))
self.footerColorPushButton.setStyleSheet(u'background-color: %s' %
self.theme.font_footer_color)
self.setField(u'footerSizeSpinBox', \
QtCore.QVariant(self.theme.font_footer_size))
def setPositionTabValues(self):
"""
Handle the display and State of the Position tab.
"""
# Main Area
if self.theme.font_main_override:
self.mainDefaultPositionCheckBox.setChecked(False)
else:
self.mainDefaultPositionCheckBox.setChecked(True)
self.setField(u'mainPositionX', \
QtCore.QVariant(self.theme.font_main_x))
self.setField(u'mainPositionY', \
QtCore.QVariant(self.theme.font_main_y))
self.setField(u'mainPositionHeight', \
QtCore.QVariant(self.theme.font_main_height))
self.setField(u'mainPositionWidth', \
QtCore.QVariant(self.theme.font_main_width))
# Footer
if self.theme.font_footer_override:
self.footerDefaultPositionCheckBox.setChecked(False)
else:
self.footerDefaultPositionCheckBox.setChecked(True)
self.setField(u'footerPositionX', \
QtCore.QVariant(self.theme.font_footer_x))
self.setField(u'footerPositionY', \
QtCore.QVariant(self.theme.font_footer_y))
self.setField(u'footerPositionHeight', \
QtCore.QVariant(self.theme.font_footer_height))
self.setField(u'footerPositionWidth', \
QtCore.QVariant(self.theme.font_footer_width))
def setAlignmentTabValues(self):
"""
Define the Tab Alignments Page
"""
self.setField(u'horizontal', \
QtCore.QVariant(self.theme.display_horizontal_align))
self.setField(u'vertical', \
QtCore.QVariant(self.theme.display_vertical_align))
self.setField(u'slideTransition', \
QtCore.QVariant(self.theme.display_slide_transition))
def setPreviewTabValues(self):
self.setField(u'name', QtCore.QVariant(self.theme.theme_name))
if len(self.theme.theme_name) > 1:
self.themeNameEdit.setEnabled(False)
else:
self.themeNameEdit.setEnabled(True)
def onBackgroundComboBox(self, index):
"""
Background style Combo box has changed.
"""
self.theme.background_type = BackgroundType.to_string(index)
self.setBackgroundTabValues()
def onGradientComboBox(self, index):
"""
Background gradient Combo box has changed.
"""
self.theme.background_direction = \
BackgroundGradientType.to_string(index)
self.setBackgroundTabValues()
def onColor1PushButtonClicked(self):
"""
Background / Gradient 1 Color button pushed.
"""
if self.theme.background_type == \
BackgroundType.to_string(BackgroundType.Solid):
self.theme.background_color = \
self._colorButton(self.theme.background_color)
else:
self.theme.background_start_color = \
self._colorButton(self.theme.background_start_color)
self.setBackgroundTabValues()
def onColor2PushButtonClicked(self):
"""
Gradient 2 Color button pushed.
"""
self.theme.background_end_color = \
self._colorButton(self.theme.background_end_color)
self.setBackgroundTabValues()
def onImageBrowseButtonClicked(self):
"""
Background Image button pushed.
"""
images_filter = get_images_filter()
images_filter = '%s;;%s (*.*) (*)' % (images_filter,
translate('OpenLP.ThemeForm', 'All Files'))
filename = QtGui.QFileDialog.getOpenFileName(self,
translate('OpenLP.ThemeForm', 'Select Image'), u'',
images_filter)
if filename:
self.theme.background_filename = unicode(filename)
self.setBackgroundTabValues()
def onMainFontComboBox(self):
"""
Main Font Combo box changed
"""
self.theme.font_main_name = self.mainFontComboBox.currentFont().family()
def onMainColourPushButtonClicked(self):
self.theme.font_main_color = \
self._colorButton(self.theme.font_main_color)
self.setMainAreaTabValues()
def onOutlineColourPushButtonClicked(self):
self.theme.font_main_outline_color = \
self._colorButton(self.theme.font_main_outline_color)
self.setMainAreaTabValues()
def onShadowColourPushButtonClicked(self):
self.theme.font_main_shadow_color = \
self._colorButton(self.theme.font_main_shadow_color)
self.setMainAreaTabValues()
def onFooterColourPushButtonClicked(self):
self.theme.font_footer_color = \
self._colorButton(self.theme.font_footer_color)
self.setFooterAreaTabValues()
def updateTheme(self):
"""
Update the theme object from the UI for fields not already updated
when the are changed.
"""
log.debug(u'updateTheme')
# main page
self.theme.font_main_name = \
unicode(self.mainFontComboBox.currentFont().family())
self.theme.font_main_size = \
self.field(u'mainSizeSpinBox').toInt()[0]
self.theme.font_main_line_adjustment = \
self.field(u'lineSpacingSpinBox').toInt()[0]
self.theme.font_main_outline_size = \
self.field(u'outlineSizeSpinBox').toInt()[0]
self.theme.font_main_shadow_size = \
self.field(u'shadowSizeSpinBox').toInt()[0]
self.theme.font_main_bold = \
self.field(u'boldCheckBox').toBool()
self.theme.font_main_italics = \
self.field(u'italicsCheckBox').toBool()
# footer page
self.theme.font_footer_name = \
unicode(self.footerFontComboBox.currentFont().family())
self.theme.font_footer_size = \
self.field(u'footerSizeSpinBox').toInt()[0]
# position page
self.theme.font_main_x = self.field(u'mainPositionX').toInt()[0]
self.theme.font_main_y = self.field(u'mainPositionY').toInt()[0]
self.theme.font_main_height = \
self.field(u'mainPositionHeight').toInt()[0]
self.theme.font_main_width = self.field(u'mainPositionWidth').toInt()[0]
self.theme.font_footer_x = self.field(u'footerPositionX').toInt()[0]
self.theme.font_footer_y = self.field(u'footerPositionY').toInt()[0]
self.theme.font_footer_height = \
self.field(u'footerPositionHeight').toInt()[0]
self.theme.font_footer_width = \
self.field(u'footerPositionWidth').toInt()[0]
# position page
self.theme.display_horizontal_align = \
self.horizontalComboBox.currentIndex()
self.theme.display_vertical_align = \
self.verticalComboBox.currentIndex()
self.theme.display_slide_transition = \
self.field(u'slideTransition').toBool()
def accept(self):
"""
Lets save the them as Finish has been pressed
"""
# Some reason getting double submission.
# Hack to stop it for now.
if self.accepted:
return
self.accepted = True
# Save the theme name
self.theme.theme_name = \
unicode(self.field(u'name').toString())
if not self.theme.theme_name:
QtGui.QMessageBox.critical(self,
translate('OpenLP.ThemeForm', 'Theme Name Missing'),
translate('OpenLP.ThemeForm',
'There is no name for this theme. '
'Please enter one.'),
(QtGui.QMessageBox.Ok),
QtGui.QMessageBox.Ok)
return
if self.theme.theme_name == u'-1' or self.theme.theme_name == u'None':
QtGui.QMessageBox.critical(self,
translate('OpenLP.ThemeForm', 'Theme Name Invalid'),
translate('OpenLP.ThemeForm',
'Invalid theme name. '
'Please enter one.'),
(QtGui.QMessageBox.Ok),
QtGui.QMessageBox.Ok)
return
saveFrom = None
saveTo = None
if self.theme.background_type == \
BackgroundType.to_string(BackgroundType.Image):
filename = \
os.path.split(unicode(self.theme.background_filename))[1]
saveTo = os.path.join(self.path, self.theme.theme_name, filename)
saveFrom = self.theme.background_filename
if self.thememanager.saveTheme(self.theme, saveFrom, saveTo):
return QtGui.QDialog.accept(self)
def _colorButton(self, field):
"""
Handle Color buttons
"""
new_color = QtGui.QColorDialog.getColor(
QtGui.QColor(field), self)
if new_color.isValid():
field = new_color.name()
return field

View File

@ -32,10 +32,11 @@ import logging
from xml.etree.ElementTree import ElementTree, XML from xml.etree.ElementTree import ElementTree, XML
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.ui import AmendThemeForm, FileRenameForm from openlp.core.ui import FileRenameForm, ThemeForm
from openlp.core.theme import Theme from openlp.core.theme import Theme
from openlp.core.lib import OpenLPToolbar, ThemeXML, get_text_file_string, \ from openlp.core.lib import OpenLPToolbar, ThemeXML, get_text_file_string, \
build_icon, Receiver, SettingsManager, translate, check_item_selected build_icon, Receiver, SettingsManager, translate, check_item_selected, \
BackgroundType, BackgroundGradientType
from openlp.core.utils import AppLocation, get_filesystem_encoding from openlp.core.utils import AppLocation, get_filesystem_encoding
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -52,7 +53,7 @@ class ThemeManager(QtGui.QWidget):
self.layout = QtGui.QVBoxLayout(self) self.layout = QtGui.QVBoxLayout(self)
self.layout.setSpacing(0) self.layout.setSpacing(0)
self.layout.setMargin(0) self.layout.setMargin(0)
self.amendThemeForm = AmendThemeForm(self) self.themeForm = ThemeForm(self)
self.fileRenameForm = FileRenameForm(self) self.fileRenameForm = FileRenameForm(self)
self.toolbar = OpenLPToolbar(self) self.toolbar = OpenLPToolbar(self)
self.toolbar.addToolbarButton( self.toolbar.addToolbarButton(
@ -125,7 +126,7 @@ class ThemeManager(QtGui.QWidget):
self.checkThemesExists(self.path) self.checkThemesExists(self.path)
self.thumbPath = os.path.join(self.path, u'thumbnails') self.thumbPath = os.path.join(self.path, u'thumbnails')
self.checkThemesExists(self.thumbPath) self.checkThemesExists(self.thumbPath)
self.amendThemeForm.path = self.path self.themeForm.path = self.path
self.oldBackgroundImage = None self.oldBackgroundImage = None
self.editingDefault = False self.editingDefault = False
# Last little bits of setting up # Last little bits of setting up
@ -180,7 +181,7 @@ class ThemeManager(QtGui.QWidget):
'%s (default)')) % newName '%s (default)')) % newName
self.themeListWidget.item(count).setText(name) self.themeListWidget.item(count).setText(name)
def changeGlobalFromScreen(self, index = -1): def changeGlobalFromScreen(self, index=-1):
""" """
Change the global theme when a theme is double clicked upon in the Change the global theme when a theme is double clicked upon in the
Theme Manager list Theme Manager list
@ -213,10 +214,10 @@ class ThemeManager(QtGui.QWidget):
Loads a new theme with the default settings and then launches the theme Loads a new theme with the default settings and then launches the theme
editing form for the user to make their customisations. editing form for the user to make their customisations.
""" """
theme = self.createThemeFromXml(self.baseTheme(), self.path) theme = ThemeXML()
self.amendThemeForm.loadTheme(theme)
self.saveThemeName = u'' self.saveThemeName = u''
self.amendThemeForm.exec_() self.themeForm.theme = theme
self.themeForm.exec_()
def onRenameTheme(self): def onRenameTheme(self):
""" """
@ -242,67 +243,23 @@ class ThemeManager(QtGui.QWidget):
self.saveThemeName = u'' self.saveThemeName = u''
if self.fileRenameForm.exec_(): if self.fileRenameForm.exec_():
newThemeName = unicode(self.fileRenameForm.FileNameEdit.text()) newThemeName = unicode(self.fileRenameForm.FileNameEdit.text())
oldThemeData = self.getThemeData(oldThemeName) themeData = self.getThemeData(oldThemeName)
self.cloneThemeData(oldThemeData, newThemeName) self.cloneThemeData(themeData, newThemeName)
self.loadThemes() self.loadThemes()
def cloneThemeData(self, oldThemeData, newThemeName): def cloneThemeData(self, themeData, newThemeName):
""" """
Takes a theme and makes a new copy of it as well as saving it.
""" """
log.debug(u'cloneThemeData') log.debug(u'cloneThemeData')
new_theme = ThemeXML() saveTo = None
new_theme.new_document(newThemeName) saveFrom = None
save_from = None if themeData.background_type == u'image':
save_to = None saveTo = os.path.join(self.path, newThemeName,
if oldThemeData.background_type == u'solid': os.path.split(unicode(themeData.background_filename))[1])
new_theme.add_background_solid( saveFrom = themeData.background_filename
unicode(oldThemeData.background_color)) themeData.theme_name = newThemeName
elif oldThemeData.background_type == u'gradient': self.saveTheme(themeData, saveFrom, saveTo)
new_theme.add_background_gradient(
unicode(oldThemeData.background_start_color),
unicode(oldThemeData.background_end_color),
oldThemeData.background_direction)
else:
filename = \
os.path.split(unicode(oldThemeData.background_filename))[1]
new_theme.add_background_image(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),
unicode(oldThemeData.font_main_proportion),
unicode(oldThemeData.font_main_override), u'main',
unicode(oldThemeData.font_main_weight),
unicode(oldThemeData.font_main_italics),
unicode(oldThemeData.font_main_line_adjustment),
unicode(oldThemeData.font_main_x),
unicode(oldThemeData.font_main_y),
unicode(oldThemeData.font_main_width),
unicode(oldThemeData.font_main_height))
new_theme.add_font(unicode(oldThemeData.font_footer_name),
unicode(oldThemeData.font_footer_color),
unicode(oldThemeData.font_footer_proportion),
unicode(oldThemeData.font_footer_override), u'footer',
unicode(oldThemeData.font_footer_weight),
unicode(oldThemeData.font_footer_italics),
0, # line adjustment
unicode(oldThemeData.font_footer_x),
unicode(oldThemeData.font_footer_y),
unicode(oldThemeData.font_footer_width),
unicode(oldThemeData.font_footer_height))
new_theme.add_display(unicode(oldThemeData.display_shadow),
unicode(oldThemeData.display_shadow_color),
unicode(oldThemeData.display_outline),
unicode(oldThemeData.display_outline_color),
unicode(oldThemeData.display_horizontal_align),
unicode(oldThemeData.display_vertical_align),
unicode(oldThemeData.display_wrap_style),
unicode(oldThemeData.display_slide_transition),
unicode(oldThemeData.display_shadow_size),
unicode(oldThemeData.display_outline_size))
theme = new_theme.extract_xml()
pretty_theme = new_theme.extract_formatted_xml()
self.saveTheme(newThemeName, theme, pretty_theme, save_from, save_to)
def onEditTheme(self): def onEditTheme(self):
""" """
@ -320,10 +277,10 @@ class ThemeManager(QtGui.QWidget):
unicode(item.data(QtCore.Qt.UserRole).toString())) unicode(item.data(QtCore.Qt.UserRole).toString()))
if theme.background_type == u'image': if theme.background_type == u'image':
self.oldBackgroundImage = theme.background_filename self.oldBackgroundImage = theme.background_filename
self.amendThemeForm.loadTheme(theme)
self.saveThemeName = unicode( self.saveThemeName = unicode(
item.data(QtCore.Qt.UserRole).toString()) item.data(QtCore.Qt.UserRole).toString())
self.amendThemeForm.exec_() self.themeForm.theme = theme
self.themeForm.exec_()
def onDeleteTheme(self): def onDeleteTheme(self):
""" """
@ -340,7 +297,8 @@ class ThemeManager(QtGui.QWidget):
# confirm deletion # confirm deletion
answer = QtGui.QMessageBox.question(self, answer = QtGui.QMessageBox.question(self,
translate('OpenLP.ThemeManager', 'Delete Confirmation'), translate('OpenLP.ThemeManager', 'Delete Confirmation'),
translate('OpenLP.ThemeManager', 'Delete theme?'), unicode(translate('OpenLP.ThemeManager', 'Delete %s theme?'))
% theme,
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes |
QtGui.QMessageBox.No), QtGui.QMessageBox.No) QtGui.QMessageBox.No), QtGui.QMessageBox.No)
if answer == QtGui.QMessageBox.No: if answer == QtGui.QMessageBox.No:
@ -462,6 +420,7 @@ class ThemeManager(QtGui.QWidget):
self.themelist = [] self.themelist = []
self.themeListWidget.clear() self.themeListWidget.clear()
dirList = os.listdir(self.path) dirList = os.listdir(self.path)
dirList.sort()
for name in dirList: for name in dirList:
if name.endswith(u'.png'): if name.endswith(u'.png'):
# check to see file is in theme root directory # check to see file is in theme root directory
@ -500,20 +459,21 @@ class ThemeManager(QtGui.QWidget):
""" """
return self.themelist return self.themelist
def getThemeData(self, themename): def getThemeData(self, themeName):
""" """
Returns a theme object from an XML file Returns a theme object from an XML file
``themename`` ``themeName``
Name of the theme to load from file Name of the theme to load from file
""" """
log.debug(u'getthemedata for theme %s', themename) log.debug(u'getthemedata for theme %s', themeName)
xml_file = os.path.join(self.path, unicode(themename), xmlFile = os.path.join(self.path, unicode(themeName),
unicode(themename) + u'.xml') unicode(themeName) + u'.xml')
xml = get_text_file_string(xml_file) xml = get_text_file_string(xmlFile)
if not xml: if not xml:
xml = self.baseTheme() return self.baseTheme()
return self.createThemeFromXml(xml, self.path) else:
return self.createThemeFromXml(xml, self.path)
def checkThemesExists(self, dir): def checkThemesExists(self, dir):
""" """
@ -584,7 +544,8 @@ class ThemeManager(QtGui.QWidget):
outfile = open(fullpath, u'wb') outfile = open(fullpath, u'wb')
outfile.write(zip.read(file)) outfile.write(zip.read(file))
if filexml: if filexml:
self.generateAndSaveImage(dir, themename, filexml) theme = self.createThemeFromXml(filexml, self.path)
self.generateAndSaveImage(dir, themename, theme)
else: else:
QtGui.QMessageBox.critical(self, QtGui.QMessageBox.critical(self,
translate('OpenLP.ThemeManager', 'Error'), translate('OpenLP.ThemeManager', 'Error'),
@ -631,50 +592,59 @@ class ThemeManager(QtGui.QWidget):
""" """
theme = Theme(xml_data) theme = Theme(xml_data)
newtheme = ThemeXML() newtheme = ThemeXML()
newtheme.new_document(theme.Name) newtheme.theme_name = theme.Name
if theme.BackgroundType == 0: if theme.BackgroundType == 0:
newtheme.add_background_solid(unicode( newtheme.background_type = \
theme.BackgroundParameter1.name())) BackgroundType.to_string(BackgroundType.Solid)
newtheme.background_color = \
unicode(theme.BackgroundParameter1.name())
elif theme.BackgroundType == 1: elif theme.BackgroundType == 1:
direction = u'vertical' newtheme.background_type = \
BackgroundType.to_string(BackgroundType.Gradient)
newtheme.background_direction = \
BackgroundGradientType. \
to_string(BackgroundGradientType.Horizontal)
if theme.BackgroundParameter3.name() == 1: if theme.BackgroundParameter3.name() == 1:
direction = u'horizontal' newtheme.background_direction = \
newtheme.add_background_gradient( BackgroundGradientType. \
unicode(theme.BackgroundParameter1.name()), to_string(BackgroundGradientType.Horizontal)
unicode(theme.BackgroundParameter2.name()), direction) newtheme.background_start_color = \
unicode(theme.BackgroundParameter1.name())
newtheme.background_end_color = \
unicode(theme.BackgroundParameter2.name())
else: else:
newtheme.add_background_image(unicode(theme.BackgroundParameter1)) newtheme.background_type = \
newtheme.add_font(unicode(theme.FontName), BackgroundType.to_string(BackgroundType.Image)
unicode(theme.FontColor.name()), newtheme.background_filename = unicode(theme.BackgroundParameter1)
unicode(theme.FontProportion * 3), u'False') newtheme.font_main_name = theme.FontName
newtheme.add_font(unicode(theme.FontName), newtheme.font_main_color = unicode(theme.FontColor.name())
unicode(theme.FontColor.name()), newtheme.font_main_size = theme.FontProportion * 3
unicode(12), u'False', u'footer') newtheme.font_footer_name = theme.FontName
outline = False newtheme.font_footer_color = unicode(theme.FontColor.name())
shadow = False newtheme.font_main_shadow = False
if theme.Shadow == 1: if theme.Shadow == 1:
shadow = True newtheme.font_main_shadow = True
newtheme.font_main_shadow_color = unicode(theme.ShadowColor.name())
if theme.Outline == 1: if theme.Outline == 1:
outline = True newtheme.font_main_outline = True
newtheme.font_main_outline_color = unicode(theme.OutlineColor.name())
vAlignCorrection = 0 vAlignCorrection = 0
if theme.VerticalAlign == 2: if theme.VerticalAlign == 2:
vAlignCorrection = 1 vAlignCorrection = 1
elif theme.VerticalAlign == 1: elif theme.VerticalAlign == 1:
vAlignCorrection = 2 vAlignCorrection = 2
newtheme.add_display(unicode(shadow), newtheme.display_horizontal_align = theme.HorizontalAlign
unicode(theme.ShadowColor.name()), newtheme.display_vertical_align = vAlignCorrection
unicode(outline), unicode(theme.OutlineColor.name()),
unicode(theme.HorizontalAlign), unicode(vAlignCorrection),
unicode(theme.WrapStyle), unicode(0))
return newtheme.extract_xml() return newtheme.extract_xml()
def saveTheme(self, name, theme_xml, theme_pretty_xml, image_from, def saveTheme(self, theme, imageFrom, imageTo):
image_to):
""" """
Called by thememaintenance Dialog to save the theme Called by thememaintenance Dialog to save the theme
and to trigger the reload of the theme list and to trigger the reload of the theme list
""" """
log.debug(u'saveTheme %s %s', name, theme_xml) name = theme.theme_name
theme_pretty_xml = theme.extract_formatted_xml()
log.debug(u'saveTheme %s %s', name, theme_pretty_xml)
theme_dir = os.path.join(self.path, name) theme_dir = os.path.join(self.path, name)
if not os.path.exists(theme_dir): if not os.path.exists(theme_dir):
os.mkdir(os.path.join(self.path, name)) os.mkdir(os.path.join(self.path, name))
@ -700,8 +670,8 @@ class ThemeManager(QtGui.QWidget):
self.deleteTheme(self.saveThemeName) self.deleteTheme(self.saveThemeName)
if result == QtGui.QMessageBox.Yes: if result == QtGui.QMessageBox.Yes:
# Save the theme, overwriting the existing theme if necessary. # Save the theme, overwriting the existing theme if necessary.
if image_to and self.oldBackgroundImage and \ if imageTo and self.oldBackgroundImage and \
image_to != self.oldBackgroundImage: imageTo != self.oldBackgroundImage:
try: try:
os.remove(self.oldBackgroundImage) os.remove(self.oldBackgroundImage)
except OSError: except OSError:
@ -715,15 +685,15 @@ class ThemeManager(QtGui.QWidget):
finally: finally:
if outfile: if outfile:
outfile.close() outfile.close()
if image_from and image_from != image_to: if imageFrom and imageFrom != imageTo:
try: try:
encoding = get_filesystem_encoding() encoding = get_filesystem_encoding()
shutil.copyfile( shutil.copyfile(
unicode(image_from).encode(encoding), unicode(imageFrom).encode(encoding),
unicode(image_to).encode(encoding)) unicode(imageTo).encode(encoding))
except IOError: except IOError:
log.exception(u'Failed to save theme image') log.exception(u'Failed to save theme image')
self.generateAndSaveImage(self.path, name, theme_xml) self.generateAndSaveImage(self.path, name, theme)
self.loadThemes() self.loadThemes()
# Check if we need to set a new service theme # Check if we need to set a new service theme
if editedServiceTheme: if editedServiceTheme:
@ -748,14 +718,15 @@ class ThemeManager(QtGui.QWidget):
self.global_theme) self.global_theme)
self.editingDefault = False self.editingDefault = False
self.pushThemes() self.pushThemes()
return True
else: else:
# Don't close the dialog - allow the user to change the name of # Don't close the dialog - allow the user to change the name of
# the theme or to cancel the theme dialog completely. # the theme or to cancel the theme dialog completely.
return False return False
def generateAndSaveImage(self, dir, name, theme_xml): def generateAndSaveImage(self, dir, name, theme):
log.debug(u'generateAndSaveImage %s %s %s', dir, name, theme_xml) log.debug(u'generateAndSaveImage %s %s', dir, name)
theme = self.createThemeFromXml(theme_xml, dir) theme_xml = theme.extract_xml()
frame = self.generateImage(theme) frame = self.generateImage(theme)
samplepathname = os.path.join(self.path, name + u'.png') samplepathname = os.path.join(self.path, name + u'.png')
if os.path.exists(samplepathname): if os.path.exists(samplepathname):
@ -767,12 +738,18 @@ class ThemeManager(QtGui.QWidget):
pixmap.save(thumb, u'png') pixmap.save(thumb, u'png')
log.debug(u'Theme image written to %s', samplepathname) log.debug(u'Theme image written to %s', samplepathname)
def generateImage(self, themedata): def generateImage(self, themeData, forcePage=False):
""" """
Call the RenderManager to build a Sample Image Call the RenderManager to build a Sample Image
``themeData``
The theme to generated a preview for.
``forcePage``
Flag to tell message lines per page need to be generated.
""" """
log.debug(u'generateImage \n%s ', themedata) log.debug(u'generateImage \n%s ', themeData)
return self.parent.RenderManager.generate_preview(themedata) return self.parent.RenderManager.generate_preview(themeData, forcePage)
def getPreviewImage(self, theme): def getPreviewImage(self, theme):
""" """
@ -791,25 +768,16 @@ class ThemeManager(QtGui.QWidget):
""" """
log.debug(u'base theme created') log.debug(u'base theme created')
newtheme = ThemeXML() newtheme = ThemeXML()
newtheme.new_document( return newtheme
unicode(translate('OpenLP.ThemeManager', 'New Theme')))
newtheme.add_background_solid(u'#000000')
newtheme.add_font(unicode(QtGui.QFont().family()), u'#FFFFFF',
u'30', u'False')
newtheme.add_font(unicode(QtGui.QFont().family()), u'#FFFFFF',
u'12', u'False', u'footer')
newtheme.add_display(u'False', u'#FFFFFF', u'False',
unicode(u'#FFFFFF'), u'0', u'0', u'0', u'False')
return newtheme.extract_xml()
def createThemeFromXml(self, theme_xml, path): def createThemeFromXml(self, themeXml, path):
""" """
Return a theme object using information parsed from XML Return a theme object using information parsed from XML
``theme_xml`` ``themeXml``
The XML data to load into the theme The XML data to load into the theme
""" """
theme = ThemeXML() theme = ThemeXML()
theme.parse(theme_xml) theme.parse(themeXml)
theme.extend_image_filename(path) theme.extend_image_filename(path)
return theme return theme

View File

@ -183,9 +183,14 @@ class ThemesTab(SettingsTab):
def updateThemeList(self, theme_list): def updateThemeList(self, theme_list):
""" """
Called from ThemeManager when the Themes have changed Called from ThemeManager when the Themes have changed.
``theme_list``
The list of available themes::
[u'Bible Theme', u'Song Theme']
""" """
#reload as may have been triggered by the ThemeManager # Reload as may have been triggered by the ThemeManager.
self.global_theme = unicode(QtCore.QSettings().value( self.global_theme = unicode(QtCore.QSettings().value(
self.settingsSection + u'/global theme', self.settingsSection + u'/global theme',
QtCore.QVariant(u'')).toString()) QtCore.QVariant(u'')).toString())

View File

@ -0,0 +1,547 @@
# -*- 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, build_icon
class Ui_ThemeWizard(object):
def setupUi(self, ThemeWizard):
ThemeWizard.setObjectName(u'ThemeWizard')
ThemeWizard.resize(550, 386)
ThemeWizard.setModal(True)
ThemeWizard.setWizardStyle(QtGui.QWizard.ModernStyle)
ThemeWizard.setOptions(QtGui.QWizard.IndependentPages|QtGui.QWizard.NoBackButtonOnStartPage)
self.welcomePage = QtGui.QWizardPage()
self.welcomePage.setTitle(u'')
self.welcomePage.setSubTitle(u'')
self.welcomePage.setObjectName(u'welcomePage')
self.welcomeLayout = QtGui.QHBoxLayout(self.welcomePage)
self.welcomeLayout.setSpacing(8)
self.welcomeLayout.setMargin(0)
self.welcomeLayout.setObjectName(u'welcomeLayout')
self.importBibleImage = QtGui.QLabel(self.welcomePage)
self.importBibleImage.setMinimumSize(QtCore.QSize(163, 0))
self.importBibleImage.setMaximumSize(QtCore.QSize(163, 16777215))
self.importBibleImage.setLineWidth(0)
self.importBibleImage.setText(u'')
self.importBibleImage.setPixmap(QtGui.QPixmap(u':/wizards/wizard_importbible.bmp'))
self.importBibleImage.setIndent(0)
self.importBibleImage.setObjectName(u'importBibleImage')
self.welcomeLayout.addWidget(self.importBibleImage)
self.welcomePageLayout = QtGui.QVBoxLayout()
self.welcomePageLayout.setSpacing(8)
self.welcomePageLayout.setObjectName(u'welcomePageLayout')
self.titleLabel = QtGui.QLabel(self.welcomePage)
self.titleLabel.setObjectName(u'titleLabel')
self.welcomePageLayout.addWidget(self.titleLabel)
spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Fixed)
self.welcomePageLayout.addItem(spacerItem)
self.informationLabel = QtGui.QLabel(self.welcomePage)
self.informationLabel.setWordWrap(True)
self.informationLabel.setMargin(10)
self.informationLabel.setObjectName(u'informationLabel')
self.welcomePageLayout.addWidget(self.informationLabel)
spacerItem1 = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
self.welcomePageLayout.addItem(spacerItem1)
self.welcomeLayout.addLayout(self.welcomePageLayout)
ThemeWizard.addPage(self.welcomePage)
self.backgroundPage = QtGui.QWizardPage()
self.backgroundPage.setObjectName(u'backgroundPage')
self.backgroundLayout = QtGui.QFormLayout(self.backgroundPage)
self.backgroundLayout.setFieldGrowthPolicy(QtGui.QFormLayout.ExpandingFieldsGrow)
self.backgroundLayout.setLabelAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
self.backgroundLayout.setMargin(20)
self.backgroundLayout.setSpacing(8)
self.backgroundLayout.setObjectName(u'backgroundLayout')
self.backgroundTypeLabel = QtGui.QLabel(self.backgroundPage)
self.backgroundTypeLabel.setObjectName(u'backgroundTypeLabel')
self.backgroundLayout.setWidget(0, QtGui.QFormLayout.LabelRole, self.backgroundTypeLabel)
self.backgroundTypeComboBox = QtGui.QComboBox(self.backgroundPage)
self.backgroundTypeComboBox.setObjectName(u'backgroundTypeComboBox')
self.backgroundTypeComboBox.addItem(u'')
self.backgroundTypeComboBox.addItem(u'')
self.backgroundTypeComboBox.addItem(u'')
self.backgroundLayout.setWidget(0, QtGui.QFormLayout.FieldRole, self.backgroundTypeComboBox)
self.color1Label = QtGui.QLabel(self.backgroundPage)
self.color1Label.setObjectName(u'color1Label')
self.backgroundLayout.setWidget(1, QtGui.QFormLayout.LabelRole, self.color1Label)
self.color1PushButton = QtGui.QPushButton(self.backgroundPage)
self.color1PushButton.setText(u'')
self.color1PushButton.setObjectName(u'color1PushButton')
self.backgroundLayout.setWidget(1, QtGui.QFormLayout.FieldRole, self.color1PushButton)
self.color2Label = QtGui.QLabel(self.backgroundPage)
self.color2Label.setObjectName(u'color2Label')
self.backgroundLayout.setWidget(2, QtGui.QFormLayout.LabelRole, self.color2Label)
self.color2PushButton = QtGui.QPushButton(self.backgroundPage)
self.color2PushButton.setText(u'')
self.color2PushButton.setObjectName(u'color2PushButton')
self.backgroundLayout.setWidget(2, QtGui.QFormLayout.FieldRole, self.color2PushButton)
self.imageLabel = QtGui.QLabel(self.backgroundPage)
self.imageLabel.setObjectName(u'imageLabel')
self.backgroundLayout.setWidget(3, QtGui.QFormLayout.LabelRole, self.imageLabel)
self.imageLayout = QtGui.QHBoxLayout()
self.imageLayout.setSpacing(8)
self.imageLayout.setObjectName(u'imageLayout')
self.imageLineEdit = QtGui.QLineEdit(self.backgroundPage)
self.imageLineEdit.setObjectName(u'imageLineEdit')
self.imageLayout.addWidget(self.imageLineEdit)
self.imageBrowseButton = QtGui.QToolButton(self.backgroundPage)
self.imageBrowseButton.setText(u'')
self.imageBrowseButton.setIcon(build_icon(u':/general/general_open.png'))
self.imageBrowseButton.setObjectName(u'imageBrowseButton')
self.imageLayout.addWidget(self.imageBrowseButton)
self.backgroundLayout.setLayout(3, QtGui.QFormLayout.FieldRole, self.imageLayout)
self.gradientLabel = QtGui.QLabel(self.backgroundPage)
self.gradientLabel.setObjectName(u'gradientLabel')
self.backgroundLayout.setWidget(4, QtGui.QFormLayout.LabelRole, self.gradientLabel)
self.gradientComboBox = QtGui.QComboBox(self.backgroundPage)
self.gradientComboBox.setObjectName(u'gradientComboBox')
self.gradientComboBox.addItem(u'')
self.gradientComboBox.addItem(u'')
self.gradientComboBox.addItem(u'')
self.gradientComboBox.addItem(u'')
self.gradientComboBox.addItem(u'')
self.backgroundLayout.setWidget(4, QtGui.QFormLayout.FieldRole, self.gradientComboBox)
ThemeWizard.addPage(self.backgroundPage)
self.mainAreaPage = QtGui.QWizardPage()
self.mainAreaPage.setObjectName(u'mainAreaPage')
self.formLayout = QtGui.QFormLayout(self.mainAreaPage)
self.formLayout.setFormAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop)
self.formLayout.setContentsMargins(-1, 20, 20, 20)
self.formLayout.setSpacing(8)
self.formLayout.setObjectName(u'formLayout')
self.mainFontLabel = QtGui.QLabel(self.mainAreaPage)
self.mainFontLabel.setObjectName(u'mainFontLabel')
self.formLayout.setWidget(0, QtGui.QFormLayout.LabelRole, self.mainFontLabel)
self.mainFontComboBox = QtGui.QFontComboBox(self.mainAreaPage)
self.mainFontComboBox.setObjectName(u'mainFontComboBox')
self.formLayout.setWidget(0, QtGui.QFormLayout.FieldRole, self.mainFontComboBox)
self.mainColorLabel = QtGui.QLabel(self.mainAreaPage)
self.mainColorLabel.setObjectName(u'mainColorLabel')
self.formLayout.setWidget(1, QtGui.QFormLayout.LabelRole, self.mainColorLabel)
self.mainColorPushButton = QtGui.QPushButton(self.mainAreaPage)
self.mainColorPushButton.setText(u'')
self.mainColorPushButton.setObjectName(u'mainColorPushButton')
self.formLayout.setWidget(1, QtGui.QFormLayout.FieldRole, self.mainColorPushButton)
self.mainSizeLabel = QtGui.QLabel(self.mainAreaPage)
self.mainSizeLabel.setObjectName(u'mainSizeLabel')
self.formLayout.setWidget(2, QtGui.QFormLayout.LabelRole, self.mainSizeLabel)
self.mainSizeLayout = QtGui.QHBoxLayout()
self.mainSizeLayout.setSpacing(8)
self.mainSizeLayout.setMargin(0)
self.mainSizeLayout.setObjectName(u'mainSizeLayout')
self.mainSizeSpinBox = QtGui.QSpinBox(self.mainAreaPage)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.mainSizeSpinBox.sizePolicy().hasHeightForWidth())
self.mainSizeSpinBox.setSizePolicy(sizePolicy)
self.mainSizeSpinBox.setMinimumSize(QtCore.QSize(70, 0))
self.mainSizeSpinBox.setMaximum(999)
self.mainSizeSpinBox.setProperty(u'value', 16)
self.mainSizeSpinBox.setObjectName(u'mainSizeSpinBox')
self.mainSizeLayout.addWidget(self.mainSizeSpinBox)
self.mainLineCountLabel = QtGui.QLabel(self.mainAreaPage)
self.mainLineCountLabel.setObjectName(u'mainLineCountLabel')
self.mainSizeLayout.addWidget(self.mainLineCountLabel)
self.formLayout.setLayout(2, QtGui.QFormLayout.FieldRole, self.mainSizeLayout)
self.lineSpacingLabel = QtGui.QLabel(self.mainAreaPage)
self.lineSpacingLabel.setObjectName(u'lineSpacingLabel')
self.formLayout.setWidget(3, QtGui.QFormLayout.LabelRole, self.lineSpacingLabel)
self.lineSpacingSpinBox = QtGui.QSpinBox(self.mainAreaPage)
self.lineSpacingSpinBox.setMinimum(-50)
self.lineSpacingSpinBox.setMaximum(50)
self.lineSpacingSpinBox.setObjectName(u'lineSpacingSpinBox')
self.formLayout.setWidget(3, QtGui.QFormLayout.FieldRole, self.lineSpacingSpinBox)
self.outlineCheckBox = QtGui.QCheckBox(self.mainAreaPage)
self.outlineCheckBox.setObjectName(u'outlineCheckBox')
self.formLayout.setWidget(4, QtGui.QFormLayout.LabelRole, self.outlineCheckBox)
self.outlineLayout = QtGui.QHBoxLayout()
self.outlineLayout.setObjectName(u'outlineLayout')
self.outlineColorPushButton = QtGui.QPushButton(self.mainAreaPage)
self.outlineColorPushButton.setEnabled(True)
self.outlineColorPushButton.setText(u'')
self.outlineColorPushButton.setObjectName(u'outlineColorPushButton')
self.outlineLayout.addWidget(self.outlineColorPushButton)
self.outlineSizeLabel = QtGui.QLabel(self.mainAreaPage)
self.outlineSizeLabel.setObjectName(u'outlineSizeLabel')
self.outlineLayout.addWidget(self.outlineSizeLabel)
self.outlineSizeSpinBox = QtGui.QSpinBox(self.mainAreaPage)
self.outlineSizeSpinBox.setObjectName(u'outlineSizeSpinBox')
self.outlineLayout.addWidget(self.outlineSizeSpinBox)
self.formLayout.setLayout(4, QtGui.QFormLayout.FieldRole, self.outlineLayout)
self.shadowCheckBox = QtGui.QCheckBox(self.mainAreaPage)
self.shadowCheckBox.setObjectName(u'shadowCheckBox')
self.formLayout.setWidget(5, QtGui.QFormLayout.LabelRole, self.shadowCheckBox)
self.shadowLayout = QtGui.QHBoxLayout()
self.shadowLayout.setObjectName(u'shadowLayout')
self.shadowColorPushButton = QtGui.QPushButton(self.mainAreaPage)
self.shadowColorPushButton.setEnabled(True)
self.shadowColorPushButton.setText(u'')
self.shadowColorPushButton.setObjectName(u'shadowColorPushButton')
self.shadowLayout.addWidget(self.shadowColorPushButton)
self.shadowSizeLabel = QtGui.QLabel(self.mainAreaPage)
self.shadowSizeLabel.setObjectName(u'shadowSizeLabel')
self.shadowLayout.addWidget(self.shadowSizeLabel)
self.shadowSizeSpinBox = QtGui.QSpinBox(self.mainAreaPage)
self.shadowSizeSpinBox.setObjectName(u'shadowSizeSpinBox')
self.shadowLayout.addWidget(self.shadowSizeSpinBox)
self.formLayout.setLayout(5, QtGui.QFormLayout.FieldRole, self.shadowLayout)
self.boldCheckBox = QtGui.QCheckBox(self.mainAreaPage)
self.boldCheckBox.setObjectName(u'boldCheckBox')
self.formLayout.setWidget(6, QtGui.QFormLayout.FieldRole, self.boldCheckBox)
self.italicsCheckBox = QtGui.QCheckBox(self.mainAreaPage)
self.italicsCheckBox.setObjectName(u'italicsCheckBox')
self.formLayout.setWidget(7, QtGui.QFormLayout.FieldRole, self.italicsCheckBox)
ThemeWizard.addPage(self.mainAreaPage)
self.footerAreaPage = QtGui.QWizardPage()
self.footerAreaPage.setObjectName(u'footerAreaPage')
self.footerLayout = QtGui.QFormLayout(self.footerAreaPage)
self.footerLayout.setFieldGrowthPolicy(QtGui.QFormLayout.ExpandingFieldsGrow)
self.footerLayout.setContentsMargins(50, 20, 20, 20)
self.footerLayout.setSpacing(8)
self.footerLayout.setObjectName(u'footerLayout')
self.footerFontLabel = QtGui.QLabel(self.footerAreaPage)
self.footerFontLabel.setObjectName(u'footerFontLabel')
self.footerLayout.setWidget(0, QtGui.QFormLayout.LabelRole, self.footerFontLabel)
self.footerFontComboBox = QtGui.QFontComboBox(self.footerAreaPage)
self.footerFontComboBox.setObjectName(u'footerFontComboBox')
self.footerLayout.setWidget(0, QtGui.QFormLayout.FieldRole, self.footerFontComboBox)
self.footerColorLabel = QtGui.QLabel(self.footerAreaPage)
self.footerColorLabel.setObjectName(u'footerColorLabel')
self.footerLayout.setWidget(1, QtGui.QFormLayout.LabelRole, self.footerColorLabel)
self.footerColorPushButton = QtGui.QPushButton(self.footerAreaPage)
self.footerColorPushButton.setText(u'')
self.footerColorPushButton.setObjectName(u'footerColorPushButton')
self.footerLayout.setWidget(1, QtGui.QFormLayout.FieldRole, self.footerColorPushButton)
self.footerSizeLabel = QtGui.QLabel(self.footerAreaPage)
self.footerSizeLabel.setObjectName(u'footerSizeLabel')
self.footerLayout.setWidget(2, QtGui.QFormLayout.LabelRole, self.footerSizeLabel)
self.footerSizeSpinBox = QtGui.QSpinBox(self.footerAreaPage)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.footerSizeSpinBox.sizePolicy().hasHeightForWidth())
self.footerSizeSpinBox.setSizePolicy(sizePolicy)
self.footerSizeSpinBox.setMinimumSize(QtCore.QSize(70, 0))
self.footerSizeSpinBox.setMaximum(999)
self.footerSizeSpinBox.setProperty(u'value', 10)
self.footerSizeSpinBox.setObjectName(u'footerSizeSpinBox')
self.footerLayout.setWidget(2, QtGui.QFormLayout.FieldRole, self.footerSizeSpinBox)
ThemeWizard.addPage(self.footerAreaPage)
self.alignmentPage = QtGui.QWizardPage()
self.alignmentPage.setObjectName(u'alignmentPage')
self.formLayout_2 = QtGui.QFormLayout(self.alignmentPage)
self.formLayout_2.setMargin(20)
self.formLayout_2.setObjectName(u'formLayout_2')
self.horizontalLabel = QtGui.QLabel(self.alignmentPage)
self.horizontalLabel.setObjectName(u'horizontalLabel')
self.formLayout_2.setWidget(0, QtGui.QFormLayout.LabelRole, self.horizontalLabel)
self.horizontalComboBox = QtGui.QComboBox(self.alignmentPage)
self.horizontalComboBox.setEditable(False)
self.horizontalComboBox.setObjectName(u'horizontalComboBox')
self.horizontalComboBox.addItem(u'')
self.horizontalComboBox.addItem(u'')
self.horizontalComboBox.addItem(u'')
self.formLayout_2.setWidget(0, QtGui.QFormLayout.FieldRole, self.horizontalComboBox)
self.verticalLabel = QtGui.QLabel(self.alignmentPage)
self.verticalLabel.setObjectName(u'verticalLabel')
self.formLayout_2.setWidget(1, QtGui.QFormLayout.LabelRole, self.verticalLabel)
self.verticalComboBox = QtGui.QComboBox(self.alignmentPage)
self.verticalComboBox.setObjectName(u'verticalComboBox')
self.verticalComboBox.addItem(u'')
self.verticalComboBox.addItem(u'')
self.verticalComboBox.addItem(u'')
self.formLayout_2.setWidget(1, QtGui.QFormLayout.FieldRole, self.verticalComboBox)
self.transitionsCheckBox = QtGui.QCheckBox(self.alignmentPage)
self.transitionsCheckBox.setObjectName(u'transitionsCheckBox')
self.formLayout_2.setWidget(2, QtGui.QFormLayout.FieldRole, self.transitionsCheckBox)
ThemeWizard.addPage(self.alignmentPage)
self.areaPositionPage = QtGui.QWizardPage()
self.areaPositionPage.setObjectName(u'areaPositionPage')
self.gridLayout_2 = QtGui.QGridLayout(self.areaPositionPage)
self.gridLayout_2.setMargin(20)
self.gridLayout_2.setSpacing(8)
self.gridLayout_2.setObjectName(u'gridLayout_2')
self.mainPositionGroupBox = QtGui.QGroupBox(self.areaPositionPage)
self.mainPositionGroupBox.setMinimumSize(QtCore.QSize(248, 0))
self.mainPositionGroupBox.setObjectName(u'mainPositionGroupBox')
self.mainPositionLayout = QtGui.QFormLayout(self.mainPositionGroupBox)
self.mainPositionLayout.setMargin(8)
self.mainPositionLayout.setSpacing(8)
self.mainPositionLayout.setObjectName(u'mainPositionLayout')
self.mainDefaultPositionCheckBox = QtGui.QCheckBox(self.mainPositionGroupBox)
self.mainDefaultPositionCheckBox.setChecked(True)
self.mainDefaultPositionCheckBox.setTristate(False)
self.mainDefaultPositionCheckBox.setObjectName(u'mainDefaultPositionCheckBox')
self.mainPositionLayout.setWidget(0, QtGui.QFormLayout.FieldRole, self.mainDefaultPositionCheckBox)
self.nainXLabel = QtGui.QLabel(self.mainPositionGroupBox)
self.nainXLabel.setObjectName(u'nainXLabel')
self.mainPositionLayout.setWidget(1, QtGui.QFormLayout.LabelRole, self.nainXLabel)
self.mainXSpinBox = QtGui.QSpinBox(self.mainPositionGroupBox)
self.mainXSpinBox.setEnabled(False)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.mainXSpinBox.sizePolicy().hasHeightForWidth())
self.mainXSpinBox.setSizePolicy(sizePolicy)
self.mainXSpinBox.setMinimumSize(QtCore.QSize(78, 0))
self.mainXSpinBox.setMaximum(9999)
self.mainXSpinBox.setProperty(u'value', 0)
self.mainXSpinBox.setObjectName(u'mainXSpinBox')
self.mainPositionLayout.setWidget(1, QtGui.QFormLayout.FieldRole, self.mainXSpinBox)
self.mainYSpinBox = QtGui.QSpinBox(self.mainPositionGroupBox)
self.mainYSpinBox.setEnabled(False)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.mainYSpinBox.sizePolicy().hasHeightForWidth())
self.mainYSpinBox.setSizePolicy(sizePolicy)
self.mainYSpinBox.setMinimumSize(QtCore.QSize(78, 0))
self.mainYSpinBox.setMaximum(9999)
self.mainYSpinBox.setObjectName(u'mainYSpinBox')
self.mainPositionLayout.setWidget(2, QtGui.QFormLayout.FieldRole, self.mainYSpinBox)
self.mainYLabel = QtGui.QLabel(self.mainPositionGroupBox)
self.mainYLabel.setObjectName(u'mainYLabel')
self.mainPositionLayout.setWidget(2, QtGui.QFormLayout.LabelRole, self.mainYLabel)
self.mainWidthSpinBox = QtGui.QSpinBox(self.mainPositionGroupBox)
self.mainWidthSpinBox.setEnabled(False)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.mainWidthSpinBox.sizePolicy().hasHeightForWidth())
self.mainWidthSpinBox.setSizePolicy(sizePolicy)
self.mainWidthSpinBox.setMinimumSize(QtCore.QSize(78, 0))
self.mainWidthSpinBox.setMaximum(9999)
self.mainWidthSpinBox.setObjectName(u'mainWidthSpinBox')
self.mainPositionLayout.setWidget(3, QtGui.QFormLayout.FieldRole, self.mainWidthSpinBox)
self.mainWidthLabel = QtGui.QLabel(self.mainPositionGroupBox)
self.mainWidthLabel.setObjectName(u'mainWidthLabel')
self.mainPositionLayout.setWidget(3, QtGui.QFormLayout.LabelRole, self.mainWidthLabel)
self.mainHeightSpinBox = QtGui.QSpinBox(self.mainPositionGroupBox)
self.mainHeightSpinBox.setEnabled(False)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.mainHeightSpinBox.sizePolicy().hasHeightForWidth())
self.mainHeightSpinBox.setSizePolicy(sizePolicy)
self.mainHeightSpinBox.setMinimumSize(QtCore.QSize(78, 0))
self.mainHeightSpinBox.setMaximum(9999)
self.mainHeightSpinBox.setObjectName(u'mainHeightSpinBox')
self.mainPositionLayout.setWidget(4, QtGui.QFormLayout.FieldRole, self.mainHeightSpinBox)
self.mainHeightLabel = QtGui.QLabel(self.mainPositionGroupBox)
self.mainHeightLabel.setObjectName(u'mainHeightLabel')
self.mainPositionLayout.setWidget(4, QtGui.QFormLayout.LabelRole, self.mainHeightLabel)
self.gridLayout_2.addWidget(self.mainPositionGroupBox, 1, 0, 1, 1)
self.footerPositionGroupBox = QtGui.QGroupBox(self.areaPositionPage)
self.footerPositionGroupBox.setMinimumSize(QtCore.QSize(248, 0))
self.footerPositionGroupBox.setObjectName(u'footerPositionGroupBox')
self.footerPositionLayout = QtGui.QFormLayout(self.footerPositionGroupBox)
self.footerPositionLayout.setMargin(8)
self.footerPositionLayout.setSpacing(8)
self.footerPositionLayout.setObjectName(u'footerPositionLayout')
self.footerXLabel = QtGui.QLabel(self.footerPositionGroupBox)
self.footerXLabel.setObjectName(u'footerXLabel')
self.footerPositionLayout.setWidget(1, QtGui.QFormLayout.LabelRole, self.footerXLabel)
self.footerXSpinBox = QtGui.QSpinBox(self.footerPositionGroupBox)
self.footerXSpinBox.setEnabled(False)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.footerXSpinBox.sizePolicy().hasHeightForWidth())
self.footerXSpinBox.setSizePolicy(sizePolicy)
self.footerXSpinBox.setMinimumSize(QtCore.QSize(78, 0))
self.footerXSpinBox.setMaximum(9999)
self.footerXSpinBox.setProperty(u'value', 0)
self.footerXSpinBox.setObjectName(u'footerXSpinBox')
self.footerPositionLayout.setWidget(1, QtGui.QFormLayout.FieldRole, self.footerXSpinBox)
self.footerYLabel = QtGui.QLabel(self.footerPositionGroupBox)
self.footerYLabel.setObjectName(u'footerYLabel')
self.footerPositionLayout.setWidget(2, QtGui.QFormLayout.LabelRole, self.footerYLabel)
self.footerYSpinBox = QtGui.QSpinBox(self.footerPositionGroupBox)
self.footerYSpinBox.setEnabled(False)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.footerYSpinBox.sizePolicy().hasHeightForWidth())
self.footerYSpinBox.setSizePolicy(sizePolicy)
self.footerYSpinBox.setMinimumSize(QtCore.QSize(78, 0))
self.footerYSpinBox.setMaximum(9999)
self.footerYSpinBox.setProperty(u'value', 0)
self.footerYSpinBox.setObjectName(u'footerYSpinBox')
self.footerPositionLayout.setWidget(2, QtGui.QFormLayout.FieldRole, self.footerYSpinBox)
self.footerWidthLabel = QtGui.QLabel(self.footerPositionGroupBox)
self.footerWidthLabel.setObjectName(u'footerWidthLabel')
self.footerPositionLayout.setWidget(3, QtGui.QFormLayout.LabelRole, self.footerWidthLabel)
self.footerWidthSpinBox = QtGui.QSpinBox(self.footerPositionGroupBox)
self.footerWidthSpinBox.setEnabled(False)
self.footerWidthSpinBox.setMinimumSize(QtCore.QSize(78, 0))
self.footerWidthSpinBox.setMaximum(9999)
self.footerWidthSpinBox.setObjectName(u'footerWidthSpinBox')
self.footerPositionLayout.setWidget(3, QtGui.QFormLayout.FieldRole, self.footerWidthSpinBox)
self.footerHeightLabel = QtGui.QLabel(self.footerPositionGroupBox)
self.footerHeightLabel.setObjectName(u'footerHeightLabel')
self.footerPositionLayout.setWidget(4, QtGui.QFormLayout.LabelRole, self.footerHeightLabel)
self.footerHeightSpinBox = QtGui.QSpinBox(self.footerPositionGroupBox)
self.footerHeightSpinBox.setEnabled(False)
self.footerHeightSpinBox.setMinimumSize(QtCore.QSize(78, 0))
self.footerHeightSpinBox.setMaximum(9999)
self.footerHeightSpinBox.setObjectName(u'footerHeightSpinBox')
self.footerPositionLayout.setWidget(4, QtGui.QFormLayout.FieldRole, self.footerHeightSpinBox)
self.footerDefaultPositionCheckBox = QtGui.QCheckBox(self.footerPositionGroupBox)
self.footerDefaultPositionCheckBox.setChecked(True)
self.footerDefaultPositionCheckBox.setObjectName(u'footerDefaultPositionCheckBox')
self.footerPositionLayout.setWidget(0, QtGui.QFormLayout.FieldRole, self.footerDefaultPositionCheckBox)
self.gridLayout_2.addWidget(self.footerPositionGroupBox, 1, 1, 1, 1)
ThemeWizard.addPage(self.areaPositionPage)
self.previewPage = QtGui.QWizardPage()
self.previewPage.setObjectName(u'previewPage')
self.themeNameLabel = QtGui.QLabel(self.previewPage)
self.themeNameLabel.setGeometry(QtCore.QRect(20, 10, 82, 16))
self.themeNameLabel.setTextFormat(QtCore.Qt.PlainText)
self.themeNameLabel.setObjectName(u'themeNameLabel')
self.previewLabel = QtGui.QLabel(self.previewPage)
self.previewLabel.setGeometry(QtCore.QRect(250, 60, 48, 16))
self.previewLabel.setAlignment(QtCore.Qt.AlignCenter)
self.previewLabel.setObjectName(u'previewLabel')
self.themeNameEdit = QtGui.QLineEdit(self.previewPage)
self.themeNameEdit.setGeometry(QtCore.QRect(117, 4, 351, 23))
self.themeNameEdit.setObjectName(u'themeNameEdit')
self.groupBox = QtGui.QGroupBox(self.previewPage)
self.groupBox.setGeometry(QtCore.QRect(40, 80, 464, 214))
self.groupBox.setTitle(u'')
self.groupBox.setObjectName(u'groupBox')
self.horizontalLayout = QtGui.QHBoxLayout(self.groupBox)
self.horizontalLayout.setObjectName(u'horizontalLayout')
spacerItem2 = QtGui.QSpacerItem(58, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem2)
self.previewBoxLabel = QtGui.QLabel(self.groupBox)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.previewBoxLabel.sizePolicy().hasHeightForWidth())
self.previewBoxLabel.setSizePolicy(sizePolicy)
self.previewBoxLabel.setMinimumSize(QtCore.QSize(300, 200))
self.previewBoxLabel.setFrameShape(QtGui.QFrame.WinPanel)
self.previewBoxLabel.setFrameShadow(QtGui.QFrame.Sunken)
self.previewBoxLabel.setLineWidth(1)
self.previewBoxLabel.setText(u'')
self.previewBoxLabel.setScaledContents(True)
self.previewBoxLabel.setObjectName(u'previewBoxLabel')
self.horizontalLayout.addWidget(self.previewBoxLabel)
spacerItem3 = QtGui.QSpacerItem(78, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem3)
ThemeWizard.addPage(self.previewPage)
self.themeNameLabel.setBuddy(self.themeNameEdit)
self.retranslateUi(ThemeWizard)
QtCore.QObject.connect(ThemeWizard, QtCore.SIGNAL(u'accepted()'), ThemeWizard.accept)
QtCore.QMetaObject.connectSlotsByName(ThemeWizard)
def retranslateUi(self, ThemeWizard):
ThemeWizard.setWindowTitle(translate('OpenLP.ThemeForm', 'Theme Wizard'))
self.titleLabel.setText(translate('OpenLP.ThemeForm', '<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n'
'<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n'
'p, li { white-space: pre-wrap; }\n'
'</style></head><body style=\" font-family:\'Sans Serif\'; font-size:9pt; font-weight:400; font-style:normal;\">\n'
'<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-size:14pt; font-weight:600;\">Welcome to the Theme Wizard</span></p></body></html>'))
self.informationLabel.setText(translate('OpenLP.ThemeForm', 'This wizard will help you to maintain Themes . Click the next button below to start the process by setting up your background.'))
self.backgroundPage.setTitle(translate('OpenLP.ThemeForm', 'Set Up Background'))
self.backgroundPage.setSubTitle(translate('OpenLP.ThemeForm', 'Set up your theme\'s background according to the parameters below.'))
self.backgroundTypeLabel.setText(translate('OpenLP.ThemeForm', 'Background type:'))
self.backgroundTypeComboBox.setItemText(0, translate('OpenLP.ThemeForm', 'Solid Color'))
self.backgroundTypeComboBox.setItemText(1, translate('OpenLP.ThemeForm', 'Gradient'))
self.backgroundTypeComboBox.setItemText(2, translate('OpenLP.ThemeForm', 'Image'))
self.color1Label.setText(translate('OpenLP.ThemeForm', '<Color1>'))
self.color2Label.setText(translate('OpenLP.ThemeForm', '<Color2>'))
self.imageLabel.setText(translate('OpenLP.ThemeForm', 'Image:'))
self.gradientLabel.setText(translate('OpenLP.ThemeForm', 'Gradient:'))
self.gradientComboBox.setItemText(0, translate('OpenLP.ThemeForm', 'Horizontal'))
self.gradientComboBox.setItemText(1, translate('OpenLP.ThemeForm', 'Vertical'))
self.gradientComboBox.setItemText(2, translate('OpenLP.ThemeForm', 'Circular'))
self.gradientComboBox.setItemText(3, translate('OpenLP.ThemeForm', 'Top Left - Bottom Right'))
self.gradientComboBox.setItemText(4, translate('OpenLP.ThemeForm', 'Bottom Left - Top Right'))
self.mainAreaPage.setTitle(translate('OpenLP.ThemeForm', 'Main Area Font Details'))
self.mainAreaPage.setSubTitle(translate('OpenLP.ThemeForm', 'Define the font and display characteristics for the Display text'))
self.mainFontLabel.setText(translate('OpenLP.ThemeForm', 'Font:'))
self.mainColorLabel.setText(translate('OpenLP.ThemeForm', 'Color:'))
self.mainSizeLabel.setText(translate('OpenLP.ThemeForm', 'Size:'))
self.mainSizeSpinBox.setSuffix(translate('OpenLP.ThemeForm', 'pt'))
self.mainLineCountLabel.setText(translate('OpenLP.ThemeForm', '(%d lines per slide)'))
self.lineSpacingLabel.setText(translate('OpenLP.ThemeForm', 'Line Spacing:'))
self.lineSpacingSpinBox.setSuffix(translate('OpenLP.ThemeForm', 'pt'))
self.outlineCheckBox.setText(translate('OpenLP.ThemeForm', '&Outline:'))
self.outlineSizeLabel.setText(translate('OpenLP.ThemeForm', 'Size:'))
self.outlineSizeSpinBox.setSuffix(translate('OpenLP.ThemeForm', 'pt'))
self.shadowCheckBox.setText(translate('OpenLP.ThemeForm', '&Shadow:'))
self.shadowSizeLabel.setText(translate('OpenLP.ThemeForm', 'Size:'))
self.shadowSizeSpinBox.setSuffix(translate('OpenLP.ThemeForm', 'pt'))
self.boldCheckBox.setText(translate('OpenLP.ThemeForm', 'Bold Display'))
self.italicsCheckBox.setText(translate('OpenLP.ThemeForm', 'Italic Display'))
self.footerAreaPage.setTitle(translate('OpenLP.ThemeForm', 'Footer Area Font Details'))
self.footerAreaPage.setSubTitle(translate('OpenLP.ThemeForm', 'Define the font and display characteristics for the Footer text'))
self.footerFontLabel.setText(translate('OpenLP.ThemeForm', 'Font:'))
self.footerColorLabel.setText(translate('OpenLP.ThemeForm', 'Color:'))
self.footerSizeLabel.setText(translate('OpenLP.ThemeForm', 'Size:'))
self.footerSizeSpinBox.setSuffix(translate('OpenLP.ThemeForm', 'pt'))
self.alignmentPage.setTitle(translate('OpenLP.ThemeForm', 'Text Formatting Details'))
self.alignmentPage.setSubTitle(translate('OpenLP.ThemeForm', 'Allows additional display formatting information to be defined'))
self.horizontalLabel.setText(translate('OpenLP.ThemeForm', 'Horizontal Align:'))
self.horizontalComboBox.setItemText(0, translate('OpenLP.ThemeForm', 'Left'))
self.horizontalComboBox.setItemText(1, translate('OpenLP.ThemeForm', 'Right'))
self.horizontalComboBox.setItemText(2, translate('OpenLP.ThemeForm', 'Center'))
self.verticalLabel.setText(translate('OpenLP.ThemeForm', 'Vertcal Align:'))
self.verticalComboBox.setItemText(0, translate('OpenLP.ThemeForm', 'Top'))
self.verticalComboBox.setItemText(1, translate('OpenLP.ThemeForm', 'Middle'))
self.verticalComboBox.setItemText(2, translate('OpenLP.ThemeForm', 'Bottom'))
self.transitionsCheckBox.setText(translate('OpenLP.ThemeForm', 'Transitions'))
self.areaPositionPage.setTitle(translate('OpenLP.ThemeForm', 'Output Area Locations'))
self.areaPositionPage.setSubTitle(translate('OpenLP.ThemeForm', 'Allows you to change and move the Main and Footer areas.'))
self.mainPositionGroupBox.setTitle(translate('OpenLP.ThemeForm', '&Main Area'))
self.mainDefaultPositionCheckBox.setText(translate('OpenLP.ThemeForm', '&Use default location'))
self.nainXLabel.setText(translate('OpenLP.ThemeForm', 'X position:'))
self.mainXSpinBox.setSuffix(translate('OpenLP.ThemeForm', 'px'))
self.mainYSpinBox.setSuffix(translate('OpenLP.ThemeForm', 'px'))
self.mainYLabel.setText(translate('OpenLP.ThemeForm', 'Y position:'))
self.mainWidthSpinBox.setSuffix(translate('OpenLP.ThemeForm', 'px'))
self.mainWidthLabel.setText(translate('OpenLP.ThemeForm', 'Width:'))
self.mainHeightSpinBox.setSuffix(translate('OpenLP.ThemeForm', 'px'))
self.mainHeightLabel.setText(translate('OpenLP.ThemeForm', 'Height:'))
self.footerPositionGroupBox.setTitle(translate('OpenLP.ThemeForm', 'Footer Area'))
self.footerXLabel.setText(translate('OpenLP.ThemeForm', 'X position:'))
self.footerXSpinBox.setSuffix(translate('OpenLP.ThemeForm', 'px'))
self.footerYLabel.setText(translate('OpenLP.ThemeForm', 'Y position:'))
self.footerYSpinBox.setSuffix(translate('OpenLP.ThemeForm', 'px'))
self.footerWidthLabel.setText(translate('OpenLP.ThemeForm', 'Width:'))
self.footerWidthSpinBox.setSuffix(translate('OpenLP.ThemeForm', 'px'))
self.footerHeightLabel.setText(translate('OpenLP.ThemeForm', 'Height:'))
self.footerHeightSpinBox.setSuffix(translate('OpenLP.ThemeForm', 'px'))
self.footerDefaultPositionCheckBox.setText(translate('OpenLP.ThemeForm', 'Use default location'))
self.previewPage.setTitle(translate('OpenLP.ThemeForm', 'Save and Preview'))
self.previewPage.setSubTitle(translate('OpenLP.ThemeForm', 'View the theme and save it replacing the current one or change the name to create a new theme'))
self.themeNameLabel.setText(translate('OpenLP.ThemeForm', 'Theme name:'))
self.previewLabel.setText(translate('OpenLP.ThemeForm', 'Preview'))

View File

@ -276,6 +276,7 @@ def get_images_filter():
return images_filter return images_filter
from languagemanager import LanguageManager from languagemanager import LanguageManager
from actions import ActionList
__all__ = [u'AppLocation', u'check_latest_version', u'add_actions', __all__ = [u'AppLocation', u'check_latest_version', u'add_actions',
u'get_filesystem_encoding', u'LanguageManager'] u'get_filesystem_encoding', u'LanguageManager', u'ActionList']

View File

@ -0,0 +1,184 @@
# -*- 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 #
###############################################################################
"""
The :mod:`~openlp.core.utils.actions` module provides action list classes used
by the shortcuts system.
"""
class ActionCategory(object):
"""
The :class:`~openlp.core.utils.ActionCategory` class encapsulates a
category for the :class:`~openlp.core.utils.CategoryList` class.
"""
def __init__(self, name, weight=0):
self.name = name
self.weight = weight
self.actions = CategoryActionList()
class CategoryActionList(object):
"""
The :class:`~openlp.core.utils.CategoryActionList` class provides a sorted
list of actions within a category.
"""
def __init__(self):
self.index = 0
self.actions = []
def __getitem__(self, key):
for weight, action in self.actions:
if action.text() == key:
return action
raise KeyError(u'Action "%s" does not exist.' % key)
def __contains__(self, item):
return self.has_key(item)
def __len__(self):
return len(self.actions)
def __iter__(self):
return self
def __next__(self):
"""
Python 3 "next" method.
"""
if self.index >= len(self.actions):
raise StopIteration
else:
self.index += 1
return self.actions[self.index - 1][1]
def next(self):
"""
Python 2 "next" method.
"""
return self.__next__()
def has_key(self, key):
for weight, action in self.actions:
if action.text() == key:
return True
return False
def append(self, name):
weight = 0
if len(self.actions) > 0:
weight = self.actions[-1][0] + 1
self.add(name, weight)
def add(self, action, weight=0):
self.actions.append((weight, action))
self.actions.sort(key=lambda act: act[0])
class CategoryList(object):
"""
The :class:`~openlp.core.utils.CategoryList` class encapsulates a category
list for the :class:`~openlp.core.utils.ActionList` class and provides an
iterator interface for walking through the list of actions in this category.
"""
def __init__(self):
self.index = 0
self.categories = []
def __getitem__(self, key):
for category in self.categories:
if category.name == key:
return category
raise KeyError(u'Category "%s" does not exist.' % key)
def __contains__(self, item):
return self.has_key(item)
def __len__(self):
return len(self.categories)
def __iter__(self):
return self
def __next__(self):
"""
Python 3 "next" method for iterator.
"""
if self.index >= len(self.categories):
raise StopIteration
else:
self.index += 1
return self.categories[self.index - 1]
def next(self):
"""
Python 2 "next" method for iterator.
"""
return self.__next__()
def has_key(self, key):
for category in self.categories:
if category.name == key:
return True
return False
def append(self, name, actions=None):
weight = 0
if len(self.categories) > 0:
weight = self.categories[-1].weight + 1
if actions:
self.add(name, weight, actions)
else:
self.add(name, weight)
def add(self, name, weight=0, actions=None):
category = ActionCategory(name, weight)
if actions:
for action in actions:
if isinstance(action, tuple):
category.actions.add(action[0], action[1])
else:
category.actions.append(action)
self.categories.append(category)
self.categories.sort(key=lambda cat: cat.weight)
class ActionList(object):
"""
The :class:`~openlp.core.utils.ActionList` class contains a list of menu
actions and categories associated with those actions. Each category also
has a weight by which it is sorted when iterating through the list of
actions or categories.
"""
def __init__(self):
self.categories = CategoryList()
def add_action(self, action, category=u'Default', weight=None):
if category not in self.categories:
self.categories.append(category)
if weight is None:
self.categories[category].actions.append(action)
else:
self.categories[category].actions.add(action, weight)

View File

@ -85,7 +85,11 @@ class AlertsPlugin(Plugin):
self.liveController.alertTab = self.alertsTab self.liveController.alertTab = self.alertsTab
def finalise(self): def finalise(self):
"""
Tidy up on exit
"""
log.info(u'Alerts Finalising') log.info(u'Alerts Finalising')
self.manager.finalise()
Plugin.finalise(self) Plugin.finalise(self)
self.toolsAlertItem.setVisible(False) self.toolsAlertItem.setVisible(False)
@ -117,11 +121,3 @@ class AlertsPlugin(Plugin):
self.textStrings[StringContent.VisibleName] = { self.textStrings[StringContent.VisibleName] = {
u'title': translate('AlertsPlugin', 'Alerts') u'title': translate('AlertsPlugin', 'Alerts')
} }
def finalise(self):
"""
Time to tidy up on exit
"""
log.info(u'Alerts Finalising')
self.manager.finalise()
Plugin.finalise(self)

View File

@ -52,7 +52,11 @@ class BiblePlugin(Plugin):
self.exportBibleItem.setVisible(True) self.exportBibleItem.setVisible(True)
def finalise(self): def finalise(self):
"""
Tidy up on exit
"""
log.info(u'Plugin Finalise') log.info(u'Plugin Finalise')
self.manager.finalise()
Plugin.finalise(self) Plugin.finalise(self)
self.importBibleItem.setVisible(False) self.importBibleItem.setVisible(False)
self.exportBibleItem.setVisible(False) self.exportBibleItem.setVisible(False)
@ -172,11 +176,3 @@ class BiblePlugin(Plugin):
u'tooltip': translate('BiblesPlugin', u'tooltip': translate('BiblesPlugin',
'Add the selected Bible to the service') 'Add the selected Bible to the service')
} }
def finalise(self):
"""
Time to tidy up on exit
"""
log.info(u'Bible Finalising')
self.manager.finalise()
Plugin.finalise(self)

View File

@ -133,7 +133,7 @@ class BibleImportForm(QtGui.QWizard, Ui_BibleImportWizard):
self.OSISLocationEdit.setFocus() self.OSISLocationEdit.setFocus()
return False return False
elif self.field(u'source_format').toInt()[0] == BibleFormat.CSV: elif self.field(u'source_format').toInt()[0] == BibleFormat.CSV:
if self.field(u'csv_booksfile').toString() == u'': if not self.field(u'csv_booksfile').toString():
QtGui.QMessageBox.critical(self, QtGui.QMessageBox.critical(self,
translate('BiblesPlugin.ImportWizardForm', translate('BiblesPlugin.ImportWizardForm',
'Invalid Books File'), 'Invalid Books File'),
@ -142,7 +142,7 @@ class BibleImportForm(QtGui.QWizard, Ui_BibleImportWizard):
'the Bible to use in the import.')) 'the Bible to use in the import.'))
self.BooksLocationEdit.setFocus() self.BooksLocationEdit.setFocus()
return False return False
elif self.field(u'csv_versefile').toString() == u'': elif not self.field(u'csv_versefile').toString():
QtGui.QMessageBox.critical(self, QtGui.QMessageBox.critical(self,
translate('BiblesPlugin.ImportWizardForm', translate('BiblesPlugin.ImportWizardForm',
'Invalid Verse File'), 'Invalid Verse File'),
@ -153,7 +153,7 @@ class BibleImportForm(QtGui.QWizard, Ui_BibleImportWizard):
return False return False
elif self.field(u'source_format').toInt()[0] == \ elif self.field(u'source_format').toInt()[0] == \
BibleFormat.OpenSong: BibleFormat.OpenSong:
if self.field(u'opensong_file').toString() == u'': if not self.field(u'opensong_file').toString():
QtGui.QMessageBox.critical(self, QtGui.QMessageBox.critical(self,
translate('BiblesPlugin.ImportWizardForm', translate('BiblesPlugin.ImportWizardForm',
'Invalid OpenSong Bible'), 'Invalid OpenSong Bible'),
@ -168,7 +168,7 @@ class BibleImportForm(QtGui.QWizard, Ui_BibleImportWizard):
license_version = unicode(self.field(u'license_version').toString()) license_version = unicode(self.field(u'license_version').toString())
license_copyright = \ license_copyright = \
unicode(self.field(u'license_copyright').toString()) unicode(self.field(u'license_copyright').toString())
if license_version == u'': if not license_version:
QtGui.QMessageBox.critical(self, QtGui.QMessageBox.critical(self,
translate('BiblesPlugin.ImportWizardForm', translate('BiblesPlugin.ImportWizardForm',
'Empty Version Name'), 'Empty Version Name'),
@ -176,7 +176,7 @@ class BibleImportForm(QtGui.QWizard, Ui_BibleImportWizard):
'You need to specify a version name for your Bible.')) 'You need to specify a version name for your Bible.'))
self.VersionNameEdit.setFocus() self.VersionNameEdit.setFocus()
return False return False
elif license_copyright == u'': elif not license_copyright:
QtGui.QMessageBox.critical(self, QtGui.QMessageBox.critical(self,
translate('BiblesPlugin.ImportWizardForm', translate('BiblesPlugin.ImportWizardForm',
'Empty Copyright'), 'Empty Copyright'),
@ -207,9 +207,11 @@ class BibleImportForm(QtGui.QWizard, Ui_BibleImportWizard):
The index of the combo box. The index of the combo box.
""" """
self.BibleComboBox.clear() self.BibleComboBox.clear()
for bible in self.web_bible_list[index].keys(): bibles = [unicode(translate('BiblesPlugin.ImportWizardForm', bible)) for
self.BibleComboBox.addItem(unicode( bible in self.web_bible_list[index].keys()]
translate('BiblesPlugin.ImportWizardForm', bible))) bibles.sort()
for bible in bibles:
self.BibleComboBox.addItem(bible)
def onOsisFileButtonClicked(self): def onOsisFileButtonClicked(self):
""" """
@ -317,7 +319,7 @@ class BibleImportForm(QtGui.QWizard, Ui_BibleImportWizard):
""" """
Load the list of Crosswalk and BibleGateway bibles. Load the list of Crosswalk and BibleGateway bibles.
""" """
#Load and store Crosswalk Bibles # Load and store Crosswalk Bibles.
filepath = AppLocation.get_directory(AppLocation.PluginsDir) filepath = AppLocation.get_directory(AppLocation.PluginsDir)
filepath = os.path.join(filepath, u'bibles', u'resources') filepath = os.path.join(filepath, u'bibles', u'resources')
books_file = None books_file = None
@ -341,7 +343,7 @@ class BibleImportForm(QtGui.QWizard, Ui_BibleImportWizard):
finally: finally:
if books_file: if books_file:
books_file.close() books_file.close()
#Load and store BibleGateway Bibles # Load and store BibleGateway Bibles.
books_file = None books_file = None
try: try:
self.web_bible_list[WebDownload.BibleGateway] = {} self.web_bible_list[WebDownload.BibleGateway] = {}
@ -379,12 +381,18 @@ class BibleImportForm(QtGui.QWizard, Ui_BibleImportWizard):
Receiver.send_message(u'openlp_process_events') Receiver.send_message(u'openlp_process_events')
def preImport(self): def preImport(self):
bible_type = self.field(u'source_format').toInt()[0]
self.finishButton.setVisible(False) self.finishButton.setVisible(False)
self.ImportProgressBar.setMinimum(0) self.ImportProgressBar.setMinimum(0)
self.ImportProgressBar.setMaximum(1188) self.ImportProgressBar.setMaximum(1188)
self.ImportProgressBar.setValue(0) self.ImportProgressBar.setValue(0)
self.ImportProgressLabel.setText( if bible_type == BibleFormat.WebDownload:
translate('BiblesPlugin.ImportWizardForm', 'Starting import...')) self.ImportProgressLabel.setText(translate(
'BiblesPlugin.ImportWizardForm',
'Starting Registering bible...'))
else:
self.ImportProgressLabel.setText(translate(
'BiblesPlugin.ImportWizardForm', 'Starting import...'))
Receiver.send_message(u'openlp_process_events') Receiver.send_message(u'openlp_process_events')
def performImport(self): def performImport(self):
@ -395,26 +403,26 @@ class BibleImportForm(QtGui.QWizard, Ui_BibleImportWizard):
unicode(self.field(u'license_permissions').toString()) unicode(self.field(u'license_permissions').toString())
importer = None importer = None
if bible_type == BibleFormat.OSIS: if bible_type == BibleFormat.OSIS:
# Import an OSIS bible # Import an OSIS bible.
importer = self.manager.import_bible(BibleFormat.OSIS, importer = self.manager.import_bible(BibleFormat.OSIS,
name=license_version, name=license_version,
filename=unicode(self.field(u'osis_location').toString()) filename=unicode(self.field(u'osis_location').toString())
) )
elif bible_type == BibleFormat.CSV: elif bible_type == BibleFormat.CSV:
# Import a CSV bible # Import a CSV bible.
importer = self.manager.import_bible(BibleFormat.CSV, importer = self.manager.import_bible(BibleFormat.CSV,
name=license_version, name=license_version,
booksfile=unicode(self.field(u'csv_booksfile').toString()), booksfile=unicode(self.field(u'csv_booksfile').toString()),
versefile=unicode(self.field(u'csv_versefile').toString()) versefile=unicode(self.field(u'csv_versefile').toString())
) )
elif bible_type == BibleFormat.OpenSong: elif bible_type == BibleFormat.OpenSong:
# Import an OpenSong bible # Import an OpenSong bible.
importer = self.manager.import_bible(BibleFormat.OpenSong, importer = self.manager.import_bible(BibleFormat.OpenSong,
name=license_version, name=license_version,
filename=unicode(self.field(u'opensong_file').toString()) filename=unicode(self.field(u'opensong_file').toString())
) )
elif bible_type == BibleFormat.WebDownload: elif bible_type == BibleFormat.WebDownload:
# Import a bible from the web # Import a bible from the web.
self.ImportProgressBar.setMaximum(1) self.ImportProgressBar.setMaximum(1)
download_location = self.field(u'web_location').toInt()[0] download_location = self.field(u'web_location').toInt()[0]
bible_version = unicode(self.BibleComboBox.currentText()) bible_version = unicode(self.BibleComboBox.currentText())
@ -438,8 +446,14 @@ class BibleImportForm(QtGui.QWizard, Ui_BibleImportWizard):
self.manager.save_meta_data(license_version, license_version, self.manager.save_meta_data(license_version, license_version,
license_copyright, license_permissions) license_copyright, license_permissions)
self.manager.reload_bibles() self.manager.reload_bibles()
self.ImportProgressLabel.setText( if bible_type == BibleFormat.WebDownload:
translate('BiblesPlugin.ImportWizardForm', 'Finished import.')) self.ImportProgressLabel.setText(
translate('BiblesPlugin.ImportWizardForm', 'Registered '
'bible. Please note, that verses will be downloaded on\n'
'demand and thus an internet connection is required.'))
else:
self.ImportProgressLabel.setText(translate(
'BiblesPlugin.ImportWizardForm', 'Finished import.'))
else: else:
self.ImportProgressLabel.setText( self.ImportProgressLabel.setText(
translate('BiblesPlugin.ImportWizardForm', translate('BiblesPlugin.ImportWizardForm',

View File

@ -110,9 +110,9 @@ class BiblesTab(SettingsTab):
self.BibleThemeComboBox.setObjectName(u'BibleThemeComboBox') self.BibleThemeComboBox.setObjectName(u'BibleThemeComboBox')
self.BibleThemeComboBox.addItem(QtCore.QString()) self.BibleThemeComboBox.addItem(QtCore.QString())
self.BibleThemeLayout.addWidget(self.BibleThemeComboBox) self.BibleThemeLayout.addWidget(self.BibleThemeComboBox)
self.BibleDualCheckBox = QtGui.QCheckBox(self.VerseDisplayGroupBox) self.BibleSecondCheckBox = QtGui.QCheckBox(self.VerseDisplayGroupBox)
self.BibleDualCheckBox.setObjectName(u'BibleDualCheckBox') self.BibleSecondCheckBox.setObjectName(u'BibleSecondCheckBox')
self.VerseDisplayLayout.addWidget(self.BibleDualCheckBox, 3, 0, 1, 1) self.VerseDisplayLayout.addWidget(self.BibleSecondCheckBox, 3, 0, 1, 1)
self.VerseDisplayLayout.addWidget(self.BibleThemeWidget, 4, 0, 1, 1) self.VerseDisplayLayout.addWidget(self.BibleThemeWidget, 4, 0, 1, 1)
self.ChangeNoteLabel = QtGui.QLabel(self.VerseDisplayGroupBox) self.ChangeNoteLabel = QtGui.QLabel(self.VerseDisplayGroupBox)
self.ChangeNoteLabel.setObjectName(u'ChangeNoteLabel') self.ChangeNoteLabel.setObjectName(u'ChangeNoteLabel')
@ -143,8 +143,8 @@ class BiblesTab(SettingsTab):
self.LayoutStyleComboBox, QtCore.SIGNAL(u'activated(int)'), self.LayoutStyleComboBox, QtCore.SIGNAL(u'activated(int)'),
self.onLayoutStyleComboBoxChanged) self.onLayoutStyleComboBoxChanged)
QtCore.QObject.connect( QtCore.QObject.connect(
self.BibleDualCheckBox, QtCore.SIGNAL(u'stateChanged(int)'), self.BibleSecondCheckBox, QtCore.SIGNAL(u'stateChanged(int)'),
self.onBibleDualCheckBox) self.onBibleSecondCheckBox)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'theme_update_list'), self.updateThemeList) QtCore.SIGNAL(u'theme_update_list'), self.updateThemeList)
@ -176,8 +176,8 @@ class BiblesTab(SettingsTab):
translate('BiblesPlugin.BiblesTab', '[ And ]')) translate('BiblesPlugin.BiblesTab', '[ And ]'))
self.ChangeNoteLabel.setText(translate('BiblesPlugin.BiblesTab', self.ChangeNoteLabel.setText(translate('BiblesPlugin.BiblesTab',
'Note:\nChanges do not affect verses already in the service.')) 'Note:\nChanges do not affect verses already in the service.'))
self.BibleDualCheckBox.setText( self.BibleSecondCheckBox.setText(
translate('BiblesPlugin.BiblesTab', 'Display dual Bible verses')) translate('BiblesPlugin.BiblesTab', 'Display second Bible verses'))
def onBibleThemeComboBoxChanged(self): def onBibleThemeComboBoxChanged(self):
self.bible_theme = self.BibleThemeComboBox.currentText() self.bible_theme = self.BibleThemeComboBox.currentText()
@ -190,15 +190,15 @@ class BiblesTab(SettingsTab):
def onNewChaptersCheckBoxChanged(self, check_state): def onNewChaptersCheckBoxChanged(self, check_state):
self.show_new_chapters = False self.show_new_chapters = False
# we have a set value convert to True/False # We have a set value convert to True/False.
if check_state == QtCore.Qt.Checked: if check_state == QtCore.Qt.Checked:
self.show_new_chapters = True self.show_new_chapters = True
def onBibleDualCheckBox(self, check_state): def onBibleSecondCheckBox(self, check_state):
self.dual_bibles = False self.second_bibles = False
# we have a set value convert to True/False # We have a set value convert to True/False.
if check_state == QtCore.Qt.Checked: if check_state == QtCore.Qt.Checked:
self.dual_bibles = True self.second_bibles = True
def load(self): def load(self):
settings = QtCore.QSettings() settings = QtCore.QSettings()
@ -211,12 +211,12 @@ class BiblesTab(SettingsTab):
u'verse layout style', QtCore.QVariant(0)).toInt()[0] u'verse layout style', QtCore.QVariant(0)).toInt()[0]
self.bible_theme = unicode( self.bible_theme = unicode(
settings.value(u'bible theme', QtCore.QVariant(u'')).toString()) settings.value(u'bible theme', QtCore.QVariant(u'')).toString())
self.dual_bibles = settings.value( self.second_bibles = settings.value(
u'dual bibles', QtCore.QVariant(True)).toBool() u'second bibles', QtCore.QVariant(True)).toBool()
self.NewChaptersCheckBox.setChecked(self.show_new_chapters) self.NewChaptersCheckBox.setChecked(self.show_new_chapters)
self.DisplayStyleComboBox.setCurrentIndex(self.display_style) self.DisplayStyleComboBox.setCurrentIndex(self.display_style)
self.LayoutStyleComboBox.setCurrentIndex(self.layout_style) self.LayoutStyleComboBox.setCurrentIndex(self.layout_style)
self.BibleDualCheckBox.setChecked(self.dual_bibles) self.BibleSecondCheckBox.setChecked(self.second_bibles)
settings.endGroup() settings.endGroup()
def save(self): def save(self):
@ -228,13 +228,18 @@ class BiblesTab(SettingsTab):
QtCore.QVariant(self.display_style)) QtCore.QVariant(self.display_style))
settings.setValue(u'verse layout style', settings.setValue(u'verse layout style',
QtCore.QVariant(self.layout_style)) QtCore.QVariant(self.layout_style))
settings.setValue(u'dual bibles', QtCore.QVariant(self.dual_bibles)) settings.setValue(u'second bibles', QtCore.QVariant(self.second_bibles))
settings.setValue(u'bible theme', QtCore.QVariant(self.bible_theme)) settings.setValue(u'bible theme', QtCore.QVariant(self.bible_theme))
settings.endGroup() settings.endGroup()
def updateThemeList(self, theme_list): def updateThemeList(self, theme_list):
""" """
Called from ThemeManager when the Themes have changed Called from ThemeManager when the Themes have changed.
``theme_list``
The list of available themes::
[u'Bible Theme', u'Song Theme']
""" """
self.BibleThemeComboBox.clear() self.BibleThemeComboBox.clear()
self.BibleThemeComboBox.addItem(u'') self.BibleThemeComboBox.addItem(u'')
@ -243,7 +248,7 @@ class BiblesTab(SettingsTab):
index = self.BibleThemeComboBox.findText( index = self.BibleThemeComboBox.findText(
unicode(self.bible_theme), QtCore.Qt.MatchExactly) unicode(self.bible_theme), QtCore.Qt.MatchExactly)
if index == -1: if index == -1:
# Not Found # Not Found.
index = 0 index = 0
self.bible_theme = u'' self.bible_theme = u''
self.BibleThemeComboBox.setCurrentIndex(index) self.BibleThemeComboBox.setCurrentIndex(index)

View File

@ -44,24 +44,28 @@ class BibleMeta(BaseModel):
""" """
pass pass
class Testament(BaseModel): class Testament(BaseModel):
""" """
Bible Testaments Bible Testaments
""" """
pass pass
class Book(BaseModel): class Book(BaseModel):
""" """
Song model Song model
""" """
pass pass
class Verse(BaseModel): class Verse(BaseModel):
""" """
Topic model Topic model
""" """
pass pass
def init_schema(url): def init_schema(url):
""" """
Setup a bible database connection and initialise the database schema. Setup a bible database connection and initialise the database schema.
@ -240,7 +244,7 @@ class BibleDB(QtCore.QObject, Manager):
and the value is the verse text. and the value is the verse text.
""" """
log.debug(u'create_chapter %s,%s', book_id, chapter) log.debug(u'create_chapter %s,%s', book_id, chapter)
# text list has book and chapter as first two elements of the array # Text list has book and chapter as first two elements of the array.
for verse_number, verse_text in textlist.iteritems(): for verse_number, verse_text in textlist.iteritems():
verse = Verse.populate( verse = Verse.populate(
book_id = book_id, book_id = book_id,

View File

@ -213,7 +213,7 @@ class BGExtract(object):
finally: finally:
if not page: if not page:
return None return None
cleaner = [(re.compile('&nbsp;|<br />'), lambda match: '')] cleaner = [(re.compile('&nbsp;|<br />|\'\+\''), lambda match: '')]
soup = None soup = None
try: try:
soup = BeautifulSoup(page, markupMassage=cleaner) soup = BeautifulSoup(page, markupMassage=cleaner)
@ -364,12 +364,11 @@ class HTTPBible(BibleDB):
if self.proxy_server: if self.proxy_server:
self.create_meta(u'proxy server', self.proxy_server) self.create_meta(u'proxy server', self.proxy_server)
if self.proxy_username: if self.proxy_username:
# store the proxy userid # Store the proxy userid.
self.create_meta(u'proxy username', self.proxy_username) self.create_meta(u'proxy username', self.proxy_username)
if self.proxy_password: if self.proxy_password:
# store the proxy password # Store the proxy password.
self.create_meta(u'proxy password', self.proxy_password) self.create_meta(u'proxy password', self.proxy_password)
self.wizard.incrementProgressBar('Registered.')
return True return True
def get_verses(self, reference_list): def get_verses(self, reference_list):
@ -417,7 +416,7 @@ class HTTPBible(BibleDB):
## to request ac and get Acts back. ## to request ac and get Acts back.
bookname = search_results.book bookname = search_results.book
Receiver.send_message(u'openlp_process_events') Receiver.send_message(u'openlp_process_events')
# check to see if book/chapter exists # Check to see if book/chapter exists.
db_book = self.get_book(bookname) db_book = self.get_book(bookname)
self.create_chapter(db_book.id, search_results.chapter, self.create_chapter(db_book.id, search_results.chapter,
search_results.verselist) search_results.verselist)

View File

@ -257,17 +257,34 @@ class BibleManager(object):
'Book Chapter:Verse-Chapter:Verse')) 'Book Chapter:Verse-Chapter:Verse'))
return None return None
def verse_search(self, bible, text): def verse_search(self, bible, second_bible, text):
""" """
Does a verse search for the given bible and text. Does a verse search for the given bible and text.
``bible`` ``bible``
The bible to seach in (unicode). The bible to seach in (unicode).
``second_bible``
The second bible (unicode). We do not search in this bible.
``text`` ``text``
The text to search for (unicode). The text to search for (unicode).
""" """
log.debug(u'BibleManager.verse_search("%s", "%s")', bible, text) log.debug(u'BibleManager.verse_search("%s", "%s")', bible, text)
# Check if the bible or second_bible is a web bible.
webbible = self.db_cache[bible].get_object(BibleMeta,
u'download source')
second_webbible = u''
if second_bible:
second_webbible = self.db_cache[second_bible].get_object(BibleMeta,
u'download source')
if webbible or second_webbible:
QtGui.QMessageBox.information(self.parent.mediaItem,
translate('BiblesPlugin.BibleManager',
'Web Bible cannot be used'),
translate('BiblesPlugin.BibleManager', 'Text Search is not '
'available with Web Bibles.'))
return None
if text: if text:
return self.db_cache[bible].verse_search(text) return self.db_cache[bible].verse_search(text)
else: else:
@ -317,4 +334,3 @@ class BibleManager(object):
""" """
for bible in self.db_cache: for bible in self.db_cache:
self.db_cache[bible].finalise() self.db_cache[bible].finalise()

View File

@ -47,21 +47,22 @@ class BibleListView(BaseListWithDnD):
self.parent().onListViewResize(event.size().width(), self.parent().onListViewResize(event.size().width(),
event.size().width()) event.size().width())
class BibleMediaItem(MediaManagerItem): class BibleMediaItem(MediaManagerItem):
""" """
This is the custom media manager item for Bibles. This is the custom media manager item for Bibles.
""" """
log.info(u'Bible Media Item loaded') log.info(u'Bible Media Item loaded')
def __init__(self, parent, icon, title): def __init__(self, parent, plugin, icon):
self.PluginNameShort = u'Bible' self.PluginNameShort = u'Bible'
self.pluginNameVisible = translate('BiblesPlugin.MediaItem', 'Bible') self.pluginNameVisible = translate('BiblesPlugin.MediaItem', 'Bible')
self.IconPath = u'songs/song' self.IconPath = u'songs/song'
self.ListViewWithDnD_class = BibleListView self.ListViewWithDnD_class = BibleListView
MediaManagerItem.__init__(self, parent, icon, title) MediaManagerItem.__init__(self, parent, plugin, icon)
# place to store the search results for both bibles # Place to store the search results for both bibles.
self.search_results = {} self.search_results = {}
self.dual_search_results = {} self.second_search_results = {}
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'bibles_load_list'), self.reloadBibles) QtCore.SIGNAL(u'bibles_load_list'), self.reloadBibles)
@ -83,7 +84,7 @@ class BibleMediaItem(MediaManagerItem):
self.SearchTabWidget.sizePolicy().hasHeightForWidth()) self.SearchTabWidget.sizePolicy().hasHeightForWidth())
self.SearchTabWidget.setSizePolicy(sizePolicy) self.SearchTabWidget.setSizePolicy(sizePolicy)
self.SearchTabWidget.setObjectName(u'SearchTabWidget') self.SearchTabWidget.setObjectName(u'SearchTabWidget')
# Add the Quick Search tab # Add the Quick Search tab.
self.QuickTab = QtGui.QWidget() self.QuickTab = QtGui.QWidget()
self.QuickTab.setObjectName(u'QuickTab') self.QuickTab.setObjectName(u'QuickTab')
self.QuickLayout = QtGui.QGridLayout(self.QuickTab) self.QuickLayout = QtGui.QGridLayout(self.QuickTab)
@ -144,7 +145,7 @@ class BibleMediaItem(MediaManagerItem):
QuickSpacerItem = QtGui.QSpacerItem(20, 35, QtGui.QSizePolicy.Minimum, QuickSpacerItem = QtGui.QSpacerItem(20, 35, QtGui.QSizePolicy.Minimum,
QtGui.QSizePolicy.Expanding) QtGui.QSizePolicy.Expanding)
self.QuickLayout.addItem(QuickSpacerItem, 6, 2, 1, 1) self.QuickLayout.addItem(QuickSpacerItem, 6, 2, 1, 1)
# Add the Advanced Search tab # Add the Advanced Search tab.
self.AdvancedTab = QtGui.QWidget() self.AdvancedTab = QtGui.QWidget()
self.AdvancedTab.setObjectName(u'AdvancedTab') self.AdvancedTab.setObjectName(u'AdvancedTab')
self.AdvancedLayout = QtGui.QGridLayout(self.AdvancedTab) self.AdvancedLayout = QtGui.QGridLayout(self.AdvancedTab)
@ -226,7 +227,7 @@ class BibleMediaItem(MediaManagerItem):
self.AdvancedLayout.addWidget(self.AdvancedMessage, 8, 0, 1, 3) self.AdvancedLayout.addWidget(self.AdvancedMessage, 8, 0, 1, 3)
self.SearchTabWidget.addTab(self.AdvancedTab, self.SearchTabWidget.addTab(self.AdvancedTab,
translate('BiblesPlugin.MediaItem', 'Advanced')) translate('BiblesPlugin.MediaItem', 'Advanced'))
# Add the search tab widget to the page layout # Add the search tab widget to the page layout.
self.pageLayout.addWidget(self.SearchTabWidget) self.pageLayout.addWidget(self.SearchTabWidget)
# Combo Boxes # Combo Boxes
QtCore.QObject.connect(self.AdvancedVersionComboBox, QtCore.QObject.connect(self.AdvancedVersionComboBox,
@ -239,6 +240,10 @@ class BibleMediaItem(MediaManagerItem):
QtCore.SIGNAL(u'activated(int)'), self.onAdvancedFromVerse) QtCore.SIGNAL(u'activated(int)'), self.onAdvancedFromVerse)
QtCore.QObject.connect(self.AdvancedToChapter, QtCore.QObject.connect(self.AdvancedToChapter,
QtCore.SIGNAL(u'activated(int)'), self.onAdvancedToChapter) QtCore.SIGNAL(u'activated(int)'), self.onAdvancedToChapter)
QtCore.QObject.connect(self.QuickSearchComboBox,
QtCore.SIGNAL(u'activated(int)'), self.updateAutoCompleter)
QtCore.QObject.connect(self.QuickVersionComboBox,
QtCore.SIGNAL(u'activated(int)'), self.updateAutoCompleter)
# Buttons # Buttons
QtCore.QObject.connect(self.AdvancedSearchButton, QtCore.QObject.connect(self.AdvancedSearchButton,
QtCore.SIGNAL(u'pressed()'), self.onAdvancedSearchButton) QtCore.SIGNAL(u'pressed()'), self.onAdvancedSearchButton)
@ -270,7 +275,7 @@ class BibleMediaItem(MediaManagerItem):
def configUpdated(self): def configUpdated(self):
log.debug(u'configUpdated') log.debug(u'configUpdated')
if QtCore.QSettings().value(self.settingsSection + u'/dual bibles', if QtCore.QSettings().value(self.settingsSection + u'/second bibles',
QtCore.QVariant(True)).toBool(): QtCore.QVariant(True)).toBool():
self.AdvancedSecondBibleLabel.setVisible(True) self.AdvancedSecondBibleLabel.setVisible(True)
self.AdvancedSecondBibleComboBox.setVisible(True) self.AdvancedSecondBibleComboBox.setVisible(True)
@ -287,7 +292,7 @@ class BibleMediaItem(MediaManagerItem):
self.QuickVersionLabel.setText( self.QuickVersionLabel.setText(
translate('BiblesPlugin.MediaItem', 'Version:')) translate('BiblesPlugin.MediaItem', 'Version:'))
self.QuickSecondVersionLabel.setText( self.QuickSecondVersionLabel.setText(
translate('BiblesPlugin.MediaItem', 'Dual:')) translate('BiblesPlugin.MediaItem', 'Second:'))
self.QuickSearchLabel.setText( self.QuickSearchLabel.setText(
translate('BiblesPlugin.MediaItem', 'Search type:')) translate('BiblesPlugin.MediaItem', 'Search type:'))
self.QuickSearchLabel.setText( self.QuickSearchLabel.setText(
@ -299,7 +304,7 @@ class BibleMediaItem(MediaManagerItem):
self.AdvancedVersionLabel.setText( self.AdvancedVersionLabel.setText(
translate('BiblesPlugin.MediaItem', 'Version:')) translate('BiblesPlugin.MediaItem', 'Version:'))
self.AdvancedSecondBibleLabel.setText( self.AdvancedSecondBibleLabel.setText(
translate('BiblesPlugin.MediaItem', 'Dual:')) translate('BiblesPlugin.MediaItem', 'Second:'))
self.AdvancedBookLabel.setText( self.AdvancedBookLabel.setText(
translate('BiblesPlugin.MediaItem', 'Book:')) translate('BiblesPlugin.MediaItem', 'Book:'))
self.AdvancedChapterLabel.setText( self.AdvancedChapterLabel.setText(
@ -331,6 +336,7 @@ class BibleMediaItem(MediaManagerItem):
log.debug(u'bible manager initialise') log.debug(u'bible manager initialise')
self.parent.manager.media = self self.parent.manager.media = self
self.loadBibles() self.loadBibles()
self.updateAutoCompleter()
self.configUpdated() self.configUpdated()
log.debug(u'bible manager initialise complete') log.debug(u'bible manager initialise complete')
@ -338,7 +344,7 @@ class BibleMediaItem(MediaManagerItem):
self.QuickMessage.setText(text) self.QuickMessage.setText(text)
self.AdvancedMessage.setText(text) self.AdvancedMessage.setText(text)
Receiver.send_message(u'openlp_process_events') Receiver.send_message(u'openlp_process_events')
# minor delay to get the events processed # Minor delay to get the events processed.
time.sleep(0.1) time.sleep(0.1)
def onListViewResize(self, width, height): def onListViewResize(self, width, height):
@ -358,13 +364,15 @@ class BibleMediaItem(MediaManagerItem):
translate('BiblesPlugin.MediaItem', 'No Book Found'), translate('BiblesPlugin.MediaItem', 'No Book Found'),
translate('BiblesPlugin.MediaItem', translate('BiblesPlugin.MediaItem',
'No matching book could be found in this Bible.')) 'No matching book could be found in this Bible.'))
self.AdvancedSearchButton.setEnabled(True)
def onImportClick(self): def onImportClick(self):
if not hasattr(self, u'import_wizard'): if not hasattr(self, u'import_wizard'):
self.import_wizard = BibleImportForm(self, self.parent.manager, self.import_wizard = BibleImportForm(self, self.parent.manager,
self.parent) self.parent)
self.import_wizard.exec_() # If the import was not canceled then reload.
self.reloadBibles() if self.import_wizard.exec_():
self.reloadBibles()
def loadBibles(self): def loadBibles(self):
log.debug(u'Loading Bibles') log.debug(u'Loading Bibles')
@ -374,8 +382,10 @@ class BibleMediaItem(MediaManagerItem):
self.AdvancedSecondBibleComboBox.clear() self.AdvancedSecondBibleComboBox.clear()
self.QuickSecondBibleComboBox.addItem(u'') self.QuickSecondBibleComboBox.addItem(u'')
self.AdvancedSecondBibleComboBox.addItem(u'') self.AdvancedSecondBibleComboBox.addItem(u'')
# Get all bibles and sort the list.
bibles = self.parent.manager.get_bibles().keys() bibles = self.parent.manager.get_bibles().keys()
# load bibles into the combo boxes bibles.sort()
# Load the bibles into the combo boxes.
first = True first = True
for bible in bibles: for bible in bibles:
if bible: if bible:
@ -393,6 +403,15 @@ class BibleMediaItem(MediaManagerItem):
self.loadBibles() self.loadBibles()
def initialiseBible(self, bible): def initialiseBible(self, bible):
"""
This initialises the given bible, which means that its book names and
their chapter numbers is added to the combo boxes on the
'Advanced Search' Tab. This is not of any importance of the
'Quick Search' Tab.
``bible``
The bible to initialise (unicode).
"""
log.debug(u'initialiseBible %s', bible) log.debug(u'initialiseBible %s', bible)
book_data = self.parent.manager.get_books(bible) book_data = self.parent.manager.get_books(bible)
self.AdvancedBookComboBox.clear() self.AdvancedBookComboBox.clear()
@ -423,6 +442,25 @@ class BibleMediaItem(MediaManagerItem):
self.adjustComboBox(1, verse_count, self.AdvancedFromVerse) self.adjustComboBox(1, verse_count, self.AdvancedFromVerse)
self.adjustComboBox(1, verse_count, self.AdvancedToVerse) self.adjustComboBox(1, verse_count, self.AdvancedToVerse)
def updateAutoCompleter(self):
"""
This updates the bible book completion list for the search field. The
completion depends on the bible. It is only updated when we are doing a
verse search, otherwise the auto completion list is removed.
"""
books = []
# We have to do a 'Verse Search'.
if self.QuickSearchComboBox.currentIndex() == 0:
bibles = self.parent.manager.get_bibles()
bible = unicode(self.QuickVersionComboBox.currentText())
if bible:
book_data = bibles[bible].get_books()
books = [book.name for book in book_data]
books.sort()
completer = QtGui.QCompleter(books)
completer.setCaseSensitivity(QtCore.Qt.CaseInsensitive)
self.QuickSearchEdit.setCompleter(completer)
def onAdvancedVersionComboBox(self): def onAdvancedVersionComboBox(self):
self.initialiseBible( self.initialiseBible(
unicode(self.AdvancedVersionComboBox.currentText())) unicode(self.AdvancedVersionComboBox.currentText()))
@ -482,6 +520,17 @@ class BibleMediaItem(MediaManagerItem):
def adjustComboBox(self, range_from, range_to, combo, restore=False): def adjustComboBox(self, range_from, range_to, combo, restore=False):
""" """
Adjusts the given como box to the given values.
``range_from``
The first number of the range (int).
``range_to``
The last number of the range (int).
``combo``
The combo box itself (QComboBox).
``restore`` ``restore``
If True, then the combo's currentText will be restored after If True, then the combo's currentText will be restored after
adjusting (if possible). adjusting (if possible).
@ -490,16 +539,19 @@ class BibleMediaItem(MediaManagerItem):
if restore: if restore:
old_text = unicode(combo.currentText()) old_text = unicode(combo.currentText())
combo.clear() combo.clear()
for i in range(int(range_from), int(range_to) + 1): for i in range(range_from, range_to + 1):
combo.addItem(unicode(i)) combo.addItem(unicode(i))
if restore and combo.findText(old_text) != -1: if restore and combo.findText(old_text) != -1:
combo.setCurrentIndex(combo.findText(old_text)) combo.setCurrentIndex(combo.findText(old_text))
def onAdvancedSearchButton(self): def onAdvancedSearchButton(self):
"""
Does an advanced search and saves the search results.
"""
log.debug(u'Advanced Search Button pressed') log.debug(u'Advanced Search Button pressed')
self.AdvancedSearchButton.setEnabled(False) self.AdvancedSearchButton.setEnabled(False)
bible = unicode(self.AdvancedVersionComboBox.currentText()) bible = unicode(self.AdvancedVersionComboBox.currentText())
dual_bible = unicode(self.AdvancedSecondBibleComboBox.currentText()) second_bible = unicode(self.AdvancedSecondBibleComboBox.currentText())
book = unicode(self.AdvancedBookComboBox.currentText()) book = unicode(self.AdvancedBookComboBox.currentText())
chapter_from = int(self.AdvancedFromChapter.currentText()) chapter_from = int(self.AdvancedFromChapter.currentText())
chapter_to = int(self.AdvancedToChapter.currentText()) chapter_to = int(self.AdvancedToChapter.currentText())
@ -508,74 +560,81 @@ class BibleMediaItem(MediaManagerItem):
versetext = u'%s %s:%s-%s:%s' % (book, chapter_from, verse_from, versetext = u'%s %s:%s-%s:%s' % (book, chapter_from, verse_from,
chapter_to, verse_to) chapter_to, verse_to)
self.search_results = self.parent.manager.get_verses(bible, versetext) self.search_results = self.parent.manager.get_verses(bible, versetext)
if dual_bible: if second_bible:
self.dual_search_results = self.parent.manager.get_verses( self.second_search_results = self.parent.manager.get_verses(
dual_bible, versetext) second_bible, versetext)
if self.ClearAdvancedSearchComboBox.currentIndex() == 0: if self.ClearAdvancedSearchComboBox.currentIndex() == 0:
self.listView.clear() self.listView.clear()
if self.listView.count() != 0: if self.listView.count() != 0:
# Check if the first item is a second bible item or not.
bitem = self.listView.item(0) bitem = self.listView.item(0)
item_dual_bible = self._decodeQtObject(bitem, 'dual_bible') item_second_bible = self._decodeQtObject(bitem, 'second_bible')
if item_dual_bible and dual_bible or not item_dual_bible and \ if item_second_bible and second_bible or not item_second_bible and \
not dual_bible: not second_bible:
self.displayResults(bible, dual_bible) self.displayResults(bible, second_bible)
elif QtGui.QMessageBox.critical(self, elif QtGui.QMessageBox.critical(self,
translate('BiblePlugin.MediaItem', 'Error'), translate('BiblePlugin.MediaItem', 'Error'),
translate('BiblePlugin.MediaItem', 'You cannot combine single ' translate('BiblePlugin.MediaItem', 'You cannot combine single '
'and dual bible verses. Do you want to delete your search ' 'and second bible verses. Do you want to delete your search '
'results and start a new search?'), 'results and start a new search?'),
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.No | QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.No |
QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.Yes: QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.Yes:
self.listView.clear() self.listView.clear()
self.displayResults(bible, dual_bible) self.displayResults(bible, second_bible)
else: else:
self.displayResults(bible, dual_bible) self.displayResults(bible, second_bible)
self.AdvancedSearchButton.setEnabled(True) self.AdvancedSearchButton.setEnabled(True)
def onQuickSearchButton(self): def onQuickSearchButton(self):
"""
Does a quick search and saves the search results. Quick search can
either be "Verse Search" or "Text Search".
"""
log.debug(u'Quick Search Button pressed') log.debug(u'Quick Search Button pressed')
self.QuickSearchButton.setEnabled(False) self.QuickSearchButton.setEnabled(False)
bible = unicode(self.QuickVersionComboBox.currentText()) bible = unicode(self.QuickVersionComboBox.currentText())
dual_bible = unicode(self.QuickSecondBibleComboBox.currentText()) second_bible = unicode(self.QuickSecondBibleComboBox.currentText())
text = unicode(self.QuickSearchEdit.text()) text = unicode(self.QuickSearchEdit.text())
if self.QuickSearchComboBox.currentIndex() == 0: if self.QuickSearchComboBox.currentIndex() == 0:
# We are doing a 'Verse Search'. # We are doing a 'Verse Search'.
self.search_results = self.parent.manager.get_verses(bible, text) self.search_results = self.parent.manager.get_verses(bible, text)
if dual_bible and self.search_results: if second_bible and self.search_results:
self.dual_search_results = self.parent.manager.get_verses( self.second_search_results = self.parent.manager.get_verses(
dual_bible, text) second_bible, text)
else: else:
# We are doing a ' Text Search'. # We are doing a 'Text Search'.
bibles = self.parent.manager.get_bibles() bibles = self.parent.manager.get_bibles()
self.search_results = self.parent.manager.verse_search(bible, text) self.search_results = self.parent.manager.verse_search(bible,
if dual_bible and self.search_results: second_bible, text)
if second_bible and self.search_results:
text = [] text = []
for verse in self.search_results: for verse in self.search_results:
text.append((verse.book.name, verse.chapter, verse.verse, text.append((verse.book.name, verse.chapter, verse.verse,
verse.verse)) verse.verse))
self.dual_search_results = bibles[dual_bible].get_verses(text) self.second_search_results = \
bibles[second_bible].get_verses(text)
if self.ClearQuickSearchComboBox.currentIndex() == 0: if self.ClearQuickSearchComboBox.currentIndex() == 0:
self.listView.clear() self.listView.clear()
if self.listView.count() != 0 and self.search_results: if self.listView.count() != 0 and self.search_results:
bitem = self.listView.item(0) bitem = self.listView.item(0)
item_dual_bible = self._decodeQtObject(bitem, 'dual_bible') item_second_bible = self._decodeQtObject(bitem, 'second_bible')
if item_dual_bible and dual_bible or not item_dual_bible and \ if item_second_bible and second_bible or not item_second_bible and \
not dual_bible: not second_bible:
self.displayResults(bible, dual_bible) self.displayResults(bible, second_bible)
elif QtGui.QMessageBox.critical(self, elif QtGui.QMessageBox.critical(self,
translate('BiblePlugin.MediaItem', 'Error'), translate('BiblePlugin.MediaItem', 'Error'),
translate('BiblePlugin.MediaItem', 'You cannot combine single ' translate('BiblePlugin.MediaItem', 'You cannot combine single '
'and dual bible verses. Do you want to delete your search ' 'and second bible verses. Do you want to delete your search '
'results and start a new search?'), 'results and start a new search?'),
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.No | QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.No |
QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.Yes: QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.Yes:
self.listView.clear() self.listView.clear()
self.displayResults(bible, dual_bible) self.displayResults(bible, second_bible)
elif self.search_results: elif self.search_results:
self.displayResults(bible, dual_bible) self.displayResults(bible, second_bible)
self.QuickSearchButton.setEnabled(True) self.QuickSearchButton.setEnabled(True)
def displayResults(self, bible, dual_bible=u''): def displayResults(self, bible, second_bible=u''):
""" """
Displays the search results in the media manager. All data needed for Displays the search results in the media manager. All data needed for
further action is saved for/in each row. further action is saved for/in each row.
@ -583,38 +642,41 @@ class BibleMediaItem(MediaManagerItem):
version = self.parent.manager.get_meta_data(bible, u'Version') version = self.parent.manager.get_meta_data(bible, u'Version')
copyright = self.parent.manager.get_meta_data(bible, u'Copyright') copyright = self.parent.manager.get_meta_data(bible, u'Copyright')
permissions = self.parent.manager.get_meta_data(bible, u'Permissions') permissions = self.parent.manager.get_meta_data(bible, u'Permissions')
if dual_bible: if second_bible:
dual_version = self.parent.manager.get_meta_data(dual_bible, second_version = self.parent.manager.get_meta_data(second_bible,
u'Version') u'Version')
dual_copyright = self.parent.manager.get_meta_data(dual_bible, second_copyright = self.parent.manager.get_meta_data(second_bible,
u'Copyright') u'Copyright')
dual_permissions = self.parent.manager.get_meta_data(dual_bible, second_permissions = self.parent.manager.get_meta_data(second_bible,
u'Permissions') u'Permissions')
if not dual_permissions: if not second_permissions:
dual_permissions = u'' second_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): for count, verse in enumerate(self.search_results):
if dual_bible: if second_bible:
vdict = { try:
'book': QtCore.QVariant(verse.book.name), vdict = {
'chapter': QtCore.QVariant(verse.chapter), 'book': QtCore.QVariant(verse.book.name),
'verse': QtCore.QVariant(verse.verse), 'chapter': QtCore.QVariant(verse.chapter),
'bible': QtCore.QVariant(bible), 'verse': QtCore.QVariant(verse.verse),
'version': QtCore.QVariant(version.value), 'bible': QtCore.QVariant(bible),
'copyright': QtCore.QVariant(copyright.value), 'version': QtCore.QVariant(version.value),
'permissions': QtCore.QVariant(permissions.value), 'copyright': QtCore.QVariant(copyright.value),
'text': QtCore.QVariant(verse.text), 'permissions': QtCore.QVariant(permissions.value),
'dual_bible': QtCore.QVariant(dual_bible), 'text': QtCore.QVariant(verse.text),
'dual_version': QtCore.QVariant(dual_version.value), 'second_bible': QtCore.QVariant(second_bible),
'dual_copyright': QtCore.QVariant(dual_copyright.value), 'second_version': QtCore.QVariant(second_version.value),
'dual_permissions': QtCore.QVariant(dual_permissions.value), 'second_copyright': QtCore.QVariant(
'dual_text': QtCore.QVariant( second_copyright.value),
self.dual_search_results[count].text) 'second_permissions': QtCore.QVariant(
} second_permissions.value),
'second_text': QtCore.QVariant(
self.second_search_results[count].text)
}
except IndexError:
break
bible_text = u' %s %d:%d (%s, %s)' % (verse.book.name, bible_text = u' %s %d:%d (%s, %s)' % (verse.book.name,
verse.chapter, verse.verse, version.value, verse.chapter, verse.verse, version.value,
dual_version.value) second_version.value)
else: else:
vdict = { vdict = {
'book': QtCore.QVariant(verse.book.name), 'book': QtCore.QVariant(verse.book.name),
@ -625,22 +687,20 @@ class BibleMediaItem(MediaManagerItem):
'copyright': QtCore.QVariant(copyright.value), 'copyright': QtCore.QVariant(copyright.value),
'permissions': QtCore.QVariant(permissions.value), 'permissions': QtCore.QVariant(permissions.value),
'text': QtCore.QVariant(verse.text), 'text': QtCore.QVariant(verse.text),
'dual_bible': QtCore.QVariant(u''), 'second_bible': QtCore.QVariant(u''),
'dual_version': QtCore.QVariant(u''), 'second_version': QtCore.QVariant(u''),
'dual_copyright': QtCore.QVariant(u''), 'second_copyright': QtCore.QVariant(u''),
'dual_permissions': QtCore.QVariant(u''), 'second_permissions': QtCore.QVariant(u''),
'dual_text': QtCore.QVariant(u'') 'second_text': QtCore.QVariant(u'')
} }
bible_text = u' %s %d:%d (%s)' % (verse.book.name, bible_text = u'%s %d:%d (%s)' % (verse.book.name,
verse.chapter, verse.verse, version.value) verse.chapter, verse.verse, version.value)
bible_verse = QtGui.QListWidgetItem(bible_text) bible_verse = QtGui.QListWidgetItem(bible_text)
bible_verse.setData(QtCore.Qt.UserRole, QtCore.QVariant(vdict)) bible_verse.setData(QtCore.Qt.UserRole, QtCore.QVariant(vdict))
self.listView.addItem(bible_verse) self.listView.addItem(bible_verse)
row = self.listView.setCurrentRow(count + start_count) self.listView.selectAll()
if row:
row.setSelected(True)
self.search_results = {} self.search_results = {}
self.dual_search_results = {} self.second_search_results = {}
def _decodeQtObject(self, bitem, key): def _decodeQtObject(self, bitem, key):
reference = bitem.data(QtCore.Qt.UserRole) reference = bitem.data(QtCore.Qt.UserRole)
@ -651,7 +711,7 @@ class BibleMediaItem(MediaManagerItem):
obj = obj.toPyObject() obj = obj.toPyObject()
return unicode(obj) return unicode(obj)
def generateSlideData(self, service_item, item=None): def generateSlideData(self, service_item, item=None, xmlVersion=False):
""" """
Generates and formats the slides for the service item as well as the Generates and formats the slides for the service item as well as the
service item's title. service item's title.
@ -661,7 +721,7 @@ class BibleMediaItem(MediaManagerItem):
if len(items) == 0: if len(items) == 0:
return False return False
bible_text = u'' bible_text = u''
old_chapter = u'' old_chapter = -1
raw_footer = [] raw_footer = []
raw_slides = [] raw_slides = []
raw_title = [] raw_title = []
@ -676,22 +736,22 @@ class BibleMediaItem(MediaManagerItem):
copyright = self._decodeQtObject(bitem, 'copyright') copyright = self._decodeQtObject(bitem, 'copyright')
permissions = self._decodeQtObject(bitem, 'permissions') permissions = self._decodeQtObject(bitem, 'permissions')
text = self._decodeQtObject(bitem, 'text') text = self._decodeQtObject(bitem, 'text')
dual_bible = self._decodeQtObject(bitem, 'dual_bible') second_bible = self._decodeQtObject(bitem, 'second_bible')
dual_version = self._decodeQtObject(bitem, 'dual_version') second_version = self._decodeQtObject(bitem, 'second_version')
dual_copyright = self._decodeQtObject(bitem, 'dual_copyright') second_copyright = self._decodeQtObject(bitem, 'second_copyright')
dual_permissions = self._decodeQtObject(bitem, 'dual_permissions') second_permissions = self._decodeQtObject(bitem, 'second_permissions')
dual_text = self._decodeQtObject(bitem, 'dual_text') second_text = self._decodeQtObject(bitem, 'second_text')
verse_text = self.formatVerse(old_chapter, chapter, verse) verse_text = self.formatVerse(old_chapter, chapter, verse)
footer = u'%s (%s %s %s)' % (book, version, copyright, permissions) footer = u'%s (%s %s %s)' % (book, version, copyright, permissions)
if footer not in raw_footer: if footer not in raw_footer:
raw_footer.append(footer) raw_footer.append(footer)
if dual_bible: if second_bible:
footer = u'%s (%s %s %s)' % (book, dual_version, dual_copyright, footer = u'%s (%s %s %s)' % (book, second_version,
dual_permissions) second_copyright, second_permissions)
if footer not in raw_footer: if footer not in raw_footer:
raw_footer.append(footer) raw_footer.append(footer)
bible_text = u'%s %s\n\n%s %s' % (verse_text, text, verse_text, bible_text = u'%s %s\n\n%s %s' % (verse_text, text, verse_text,
dual_text) second_text)
raw_slides.append(bible_text) raw_slides.append(bible_text)
bible_text = u'' bible_text = u''
# If we are 'Verse Per Slide' then create a new slide. # If we are 'Verse Per Slide' then create a new slide.
@ -719,7 +779,7 @@ class BibleMediaItem(MediaManagerItem):
raw_slides.append(bible_text) raw_slides.append(bible_text)
bible_text = u'' bible_text = u''
# Service Item: Capabilities # Service Item: Capabilities
if self.parent.settings_tab.layout_style == 2 and not dual_bible: if self.parent.settings_tab.layout_style == 2 and not second_bible:
# Split the line but do not replace line breaks in renderer. # Split the line but do not replace line breaks in renderer.
service_item.add_capability(ItemCapabilities.NoLineBreaks) service_item.add_capability(ItemCapabilities.NoLineBreaks)
service_item.add_capability(ItemCapabilities.AllowsPreview) service_item.add_capability(ItemCapabilities.AllowsPreview)
@ -749,6 +809,12 @@ class BibleMediaItem(MediaManagerItem):
This methode is called, when we have to change the title, because This methode is called, when we have to change the title, because
we are at the end of a verse range. E. g. if we want to add we are at the end of a verse range. E. g. if we want to add
Genesis 1:1-6 as well as Daniel 2:14. Genesis 1:1-6 as well as Daniel 2:14.
``start_item``
The first item of a range.
``old_item``
The last item of a range.
""" """
old_bitem = self.listView.item(old_item.row()) old_bitem = self.listView.item(old_item.row())
old_chapter = int(self._decodeQtObject(old_bitem, 'chapter')) old_chapter = int(self._decodeQtObject(old_bitem, 'chapter'))
@ -758,18 +824,18 @@ class BibleMediaItem(MediaManagerItem):
start_chapter = int(self._decodeQtObject(start_bitem, 'chapter')) start_chapter = int(self._decodeQtObject(start_bitem, 'chapter'))
start_verse = int(self._decodeQtObject(start_bitem, 'verse')) start_verse = int(self._decodeQtObject(start_bitem, 'verse'))
start_bible = self._decodeQtObject(start_bitem, 'bible') start_bible = self._decodeQtObject(start_bitem, 'bible')
start_dual_bible = self._decodeQtObject(start_bitem, 'dual_bible') start_second_bible = self._decodeQtObject(start_bitem, 'second_bible')
if start_dual_bible: if start_second_bible:
if start_verse == old_verse and start_chapter == old_chapter: if start_verse == old_verse and start_chapter == old_chapter:
title = u'%s %s:%s (%s, %s)' % (start_book, start_chapter, title = u'%s %s:%s (%s, %s)' % (start_book, start_chapter,
start_verse, start_bible, start_dual_bible) start_verse, start_bible, start_second_bible)
elif start_chapter == old_chapter: elif start_chapter == old_chapter:
title = u'%s %s:%s-%s (%s, %s)' % (start_book, start_chapter, title = u'%s %s:%s-%s (%s, %s)' % (start_book, start_chapter,
start_verse, old_verse, start_bible, start_dual_bible) start_verse, old_verse, start_bible, start_second_bible)
else: else:
title = u'%s %s:%s-%s:%s (%s, %s)' % (start_book, start_chapter, title = u'%s %s:%s-%s:%s (%s, %s)' % (start_book, start_chapter,
start_verse, old_chapter, old_verse, start_bible, start_verse, old_chapter, old_verse, start_bible,
start_dual_bible) start_second_bible)
else: else:
if start_verse == old_verse and start_chapter == old_chapter: if start_verse == old_verse and start_chapter == old_chapter:
title = u'%s %s:%s (%s)' % (start_book, start_chapter, title = u'%s %s:%s (%s)' % (start_book, start_chapter,
@ -785,34 +851,62 @@ class BibleMediaItem(MediaManagerItem):
def checkTitle(self, item, old_item): def checkTitle(self, item, old_item):
""" """
This methode checks if we are at the end of an verse range. If that is This methode checks if we are at the end of an verse range. If that is
the case, we return True, else False. E. g. if we added Genesis 1:1-6, the case, we return True, otherwise False. E. g. if we added
but the next verse is Daniel 2:14. Genesis 1:1-6, but the next verse is Daniel 2:14, we return True.
``item``
The item we are dealing with at the moment.
``old_item``
The item we were previously dealing with.
""" """
# Get all the necessary meta data.
bitem = self.listView.item(item.row()) bitem = self.listView.item(item.row())
book = self._decodeQtObject(bitem, 'book') book = self._decodeQtObject(bitem, 'book')
chapter = int(self._decodeQtObject(bitem, 'chapter')) chapter = int(self._decodeQtObject(bitem, 'chapter'))
verse = int(self._decodeQtObject(bitem, 'verse')) verse = int(self._decodeQtObject(bitem, 'verse'))
bible = self._decodeQtObject(bitem, 'bible') bible = self._decodeQtObject(bitem, 'bible')
dual_bible = self._decodeQtObject(bitem, 'dual_bible') second_bible = self._decodeQtObject(bitem, 'second_bible')
old_bitem = self.listView.item(old_item.row()) old_bitem = self.listView.item(old_item.row())
old_book = self._decodeQtObject(old_bitem, 'book') old_book = self._decodeQtObject(old_bitem, 'book')
old_chapter = int(self._decodeQtObject(old_bitem, 'chapter')) old_chapter = int(self._decodeQtObject(old_bitem, 'chapter'))
old_verse = int(self._decodeQtObject(old_bitem, 'verse')) old_verse = int(self._decodeQtObject(old_bitem, 'verse'))
old_bible = self._decodeQtObject(old_bitem, 'bible') old_bible = self._decodeQtObject(old_bitem, 'bible')
old_dual_bible = self._decodeQtObject(old_bitem, 'dual_bible') old_second_bible = self._decodeQtObject(old_bitem, 'second_bible')
if old_bible != bible or old_dual_bible != dual_bible or \ if old_bible != bible or old_second_bible != second_bible or \
old_book != book: old_book != book:
# The bible, second bible or book has changed.
return True return True
elif old_verse + 1 != verse and old_chapter == chapter: elif old_verse + 1 != verse and old_chapter == chapter:
# We are still in the same chapter, but a verse has been skipped.
return True return True
elif old_chapter + 1 == chapter and (verse != 1 or elif old_chapter + 1 == chapter and (verse != 1 or
old_verse != self.parent.manager.get_verse_count( old_verse != self.parent.manager.get_verse_count(
old_bible, old_book, old_chapter)): old_bible, old_book, old_chapter)):
# We are in the following chapter, but the last verse was not the
# last verse of the chapter or the current verse is not the
# first one of the chapter.
return True return True
else: else:
return False return False
def formatVerse(self, old_chapter, chapter, verse): def formatVerse(self, old_chapter, chapter, verse):
"""
Formats and returns the text, each verse starts with, for the given
chapter and verse. The text is either surrounded by round, square,
curly brackets or no brackets at all. For example::
u'{su}1:1{/su}'
``old_chapter``
The previous verse's chapter number (int).
``chapter``
The chapter number (int).
``verse``
The verse number (int).
"""
if not self.parent.settings_tab.show_new_chapters or \ if not self.parent.settings_tab.show_new_chapters or \
old_chapter != chapter: old_chapter != chapter:
verse_text = u'%s:%s' % (chapter, verse) verse_text = u'%s:%s' % (chapter, verse)

View File

@ -59,7 +59,7 @@ class CustomPlugin(Plugin):
return CustomTab(self.name, visible_name[u'title']) return CustomTab(self.name, visible_name[u'title'])
def getMediaManagerItem(self): def getMediaManagerItem(self):
# Create the CustomManagerItem object # Create the ManagerItem object
return CustomMediaItem(self, self, self.icon) return CustomMediaItem(self, self, self.icon)
def about(self): def about(self):
@ -76,7 +76,7 @@ class CustomPlugin(Plugin):
Returns True if the theme is being used, otherwise returns False. Returns True if the theme is being used, otherwise returns False.
""" """
if self.custommanager.get_all_objects(CustomSlide, if self.manager.get_all_objects(CustomSlide,
CustomSlide.theme_name == theme): CustomSlide.theme_name == theme):
return True return True
return False return False
@ -92,11 +92,11 @@ class CustomPlugin(Plugin):
``newTheme`` ``newTheme``
The new name the plugin should now use. The new name the plugin should now use.
""" """
customsUsingTheme = self.custommanager.get_all_objects(CustomSlide, customsUsingTheme = self.manager.get_all_objects(CustomSlide,
CustomSlide.theme_name == oldTheme) CustomSlide.theme_name == oldTheme)
for custom in customsUsingTheme: for custom in customsUsingTheme:
custom.theme_name = newTheme custom.theme_name = newTheme
self.custommanager.save_object(custom) self.manager.save_object(custom)
def setPluginTextStrings(self): def setPluginTextStrings(self):
""" """

View File

@ -46,7 +46,6 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
Constructor Constructor
""" """
QtGui.QDialog.__init__(self, parent) QtGui.QDialog.__init__(self, parent)
#self.parent = parent
self.setupUi(self) self.setupUi(self)
# Connecting signals and slots # Connecting signals and slots
self.previewButton = QtGui.QPushButton() self.previewButton = QtGui.QPushButton()
@ -124,8 +123,9 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
self.slideListView.addItem(slide[1]) self.slideListView.addItem(slide[1])
theme = self.customSlide.theme_name theme = self.customSlide.theme_name
id = self.themeComboBox.findText(theme, QtCore.Qt.MatchExactly) id = self.themeComboBox.findText(theme, QtCore.Qt.MatchExactly)
# No theme match
if id == -1: if id == -1:
id = 0 # Not Found id = 0
self.themeComboBox.setCurrentIndex(id) self.themeComboBox.setCurrentIndex(id)
else: else:
self.themeComboBox.setCurrentIndex(0) self.themeComboBox.setCurrentIndex(0)
@ -162,12 +162,10 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
sxml.add_verse_to_lyrics(u'custom', unicode(count), sxml.add_verse_to_lyrics(u'custom', unicode(count),
unicode(self.slideListView.item(i).text())) unicode(self.slideListView.item(i).text()))
count += 1 count += 1
self.customSlide.title = unicode(self.titleEdit.displayText(), u'utf-8') self.customSlide.title = unicode(self.titleEdit.text())
self.customSlide.text = unicode(sxml.extract_xml(), u'utf-8') self.customSlide.text = unicode(sxml.extract_xml(), u'utf-8')
self.customSlide.credits = unicode(self.creditEdit.displayText(), self.customSlide.credits = unicode(self.creditEdit.text())
u'utf-8') self.customSlide.theme_name = unicode(self.themeComboBox.currentText())
self.customSlide.theme_name = unicode(self.themeComboBox.currentText(),
u'utf-8')
return self.manager.save_object(self.customSlide) return self.manager.save_object(self.customSlide)
def onUpButtonPressed(self): def onUpButtonPressed(self):
@ -266,7 +264,7 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
self.titleEdit.setFocus() self.titleEdit.setFocus()
return False, translate('CustomPlugin.EditCustomForm', return False, translate('CustomPlugin.EditCustomForm',
'You need to type in a title.') 'You need to type in a title.')
# We must have one slide. # We must have at least one slide.
if self.slideListView.count() == 0: if self.slideListView.count() == 0:
return False, translate('CustomPlugin.EditCustomForm', return False, translate('CustomPlugin.EditCustomForm',
'You need to add at least one slide') 'You need to add at least one slide')

View File

@ -50,7 +50,7 @@ class EditCustomSlideForm(QtGui.QDialog, Ui_CustomSlideEditDialog):
def setText(self, text): def setText(self, text):
""" """
Set the text for slideTextEdit. Set the text for slideTextEdit.
``text`` ``text``
The text (unicode). The text (unicode).
""" """
@ -67,7 +67,7 @@ class EditCustomSlideForm(QtGui.QDialog, Ui_CustomSlideEditDialog):
def onSplitButtonPressed(self): def onSplitButtonPressed(self):
""" """
Splits a slide in two slides. Adds a slide split at the cursor.
""" """
if self.slideTextEdit.textCursor().columnNumber() != 0: if self.slideTextEdit.textCursor().columnNumber() != 0:
self.slideTextEdit.insertPlainText(u'\n') self.slideTextEdit.insertPlainText(u'\n')

View File

@ -43,6 +43,7 @@ import logging
from xml.dom.minidom import Document from xml.dom.minidom import Document
from xml.etree.ElementTree import ElementTree, XML, dump from xml.etree.ElementTree import ElementTree, XML, dump
from lxml import etree, objectify
from xml.parsers.expat import ExpatError from xml.parsers.expat import ExpatError
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -55,14 +56,14 @@ class CustomXMLBuilder(object):
def __init__(self): def __init__(self):
""" """
Set up the song builder. Set up the custom builder.
""" """
# Create the minidom document # Create the minidom document
self.custom_xml = Document() self.custom_xml = Document()
def new_document(self): def new_document(self):
""" """
Create a new song XML document. Create a new custom XML document.
""" """
# Create the <song> base element # Create the <song> base element
self.song = self.custom_xml.createElement(u'song') self.song = self.custom_xml.createElement(u'song')
@ -72,7 +73,7 @@ class CustomXMLBuilder(object):
def add_lyrics_to_song(self): def add_lyrics_to_song(self):
""" """
Set up and add a ``<lyrics>`` tag which contains the lyrics of the Set up and add a ``<lyrics>`` tag which contains the lyrics of the
song. custom item.
""" """
# Create the main <lyrics> element # Create the main <lyrics> element
self.lyrics = self.custom_xml.createElement(u'lyrics') self.lyrics = self.custom_xml.createElement(u'lyrics')
@ -93,7 +94,6 @@ class CustomXMLBuilder(object):
``content`` ``content``
The actual text of the verse to be stored. The actual text of the verse to be stored.
""" """
#log.debug(u'add_verse_to_lyrics %s, %s\n%s' % (type, number, content))
verse = self.custom_xml.createElement(u'verse') verse = self.custom_xml.createElement(u'verse')
verse.setAttribute(u'type', type) verse.setAttribute(u'type', type)
verse.setAttribute(u'label', number) verse.setAttribute(u'label', number)
@ -102,7 +102,7 @@ class CustomXMLBuilder(object):
cds = self.custom_xml.createCDATASection(content) cds = self.custom_xml.createCDATASection(content)
verse.appendChild(cds) verse.appendChild(cds)
def dump_xml(self): def _dump_xml(self):
""" """
Debugging aid to dump XML so that we can see what we have. Debugging aid to dump XML so that we can see what we have.
""" """
@ -110,29 +110,30 @@ class CustomXMLBuilder(object):
def extract_xml(self): def extract_xml(self):
""" """
Extract our newly created XML song. Extract our newly created XML custom.
""" """
return self.custom_xml.toxml(u'utf-8') return self.custom_xml.toxml(u'utf-8')
class CustomXMLParser(object): class CustomXMLParser(object):
""" """
A class to read in and parse a song's XML. A class to read in and parse a custom's XML.
""" """
log.info(u'CustomXMLParser Loaded') log.info(u'CustomXMLParser Loaded')
def __init__(self, xml): def __init__(self, xml):
""" """
Set up our song XML parser. Set up our custom XML parser.
``xml`` ``xml``
The XML of the song to be parsed. The XML of the custom to be parsed.
""" """
self.custom_xml = None self.custom_xml = None
if xml[:5] == u'<?xml':
xml = xml[38:]
try: try:
self.custom_xml = ElementTree( self.custom_xml = objectify.fromstring(xml)
element=XML(unicode(xml).encode('unicode-escape'))) except etree.XMLSyntaxError:
except ExpatError:
log.exception(u'Invalid xml %s', xml) log.exception(u'Invalid xml %s', xml)
def get_verses(self): def get_verses(self):
@ -146,11 +147,10 @@ class CustomXMLParser(object):
if element.tag == u'verse': if element.tag == u'verse':
if element.text is None: if element.text is None:
element.text = u'' element.text = u''
verse_list.append([element.attrib, verse_list.append([element.attrib, unicode(element.text)])
unicode(element.text).decode('unicode-escape')])
return verse_list return verse_list
def dump_xml(self): def _dump_xml(self):
""" """
Debugging aid to dump XML so that we can see what we have. Debugging aid to dump XML so that we can see what we have.
""" """

View File

@ -74,9 +74,9 @@ class CustomMediaItem(MediaManagerItem):
def initialise(self): def initialise(self):
self.loadCustomListView(self.manager.get_all_objects( self.loadCustomListView(self.manager.get_all_objects(
CustomSlide, order_by_ref=CustomSlide.title)) CustomSlide, order_by_ref=CustomSlide.title))
#Called to redisplay the song list screen edith from a search # Called to redisplay the custom list screen edith from a search
#or from the exit of the Song edit dialog. If remote editing is active # or from the exit of the Custom edit dialog. If remote editing is
#Trigger it and clean up so it will not update again. # active trigger it and clean up so it will not update again.
if self.remoteTriggered == u'L': if self.remoteTriggered == u'L':
self.onAddClick() self.onAddClick()
if self.remoteTriggered == u'P': if self.remoteTriggered == u'P':
@ -140,11 +140,11 @@ class CustomMediaItem(MediaManagerItem):
id_list = [(item.data(QtCore.Qt.UserRole)).toInt()[0] id_list = [(item.data(QtCore.Qt.UserRole)).toInt()[0]
for item in self.listView.selectedIndexes()] for item in self.listView.selectedIndexes()]
for id in id_list: for id in id_list:
self.parent.custommanager.delete_object(CustomSlide, id) self.parent.manager.delete_object(CustomSlide, id)
for row in row_list: for row in row_list:
self.listView.takeItem(row) self.listView.takeItem(row)
def generateSlideData(self, service_item, item=None): def generateSlideData(self, service_item, item=None, xmlVersion=False):
raw_slides = [] raw_slides = []
raw_footer = [] raw_footer = []
slide = None slide = None
@ -162,10 +162,10 @@ class CustomMediaItem(MediaManagerItem):
service_item.add_capability(ItemCapabilities.AllowsEdit) service_item.add_capability(ItemCapabilities.AllowsEdit)
service_item.add_capability(ItemCapabilities.AllowsPreview) service_item.add_capability(ItemCapabilities.AllowsPreview)
service_item.add_capability(ItemCapabilities.AllowsLoop) service_item.add_capability(ItemCapabilities.AllowsLoop)
customSlide = self.parent.custommanager.get_object(CustomSlide, item_id) customSlide = self.parent.manager.get_object(CustomSlide, item_id)
title = customSlide.title title = customSlide.title
credit = customSlide.credits credit = customSlide.credits
service_item.editId = item_id service_item.edit_id = item_id
theme = customSlide.theme_name theme = customSlide.theme_name
if theme: if theme:
service_item.theme = theme service_item.theme = theme

View File

@ -154,7 +154,7 @@ class ImageMediaItem(MediaManagerItem):
item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(file)) item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(file))
self.listView.addItem(item_name) self.listView.addItem(item_name)
def generateSlideData(self, service_item, item=None): def generateSlideData(self, service_item, item=None, xmlVersion=False):
items = self.listView.selectedIndexes() items = self.listView.selectedIndexes()
if items: if items:
service_item.title = unicode( service_item.title = unicode(
@ -163,6 +163,8 @@ class ImageMediaItem(MediaManagerItem):
service_item.add_capability(ItemCapabilities.AllowsPreview) service_item.add_capability(ItemCapabilities.AllowsPreview)
service_item.add_capability(ItemCapabilities.AllowsLoop) service_item.add_capability(ItemCapabilities.AllowsLoop)
service_item.add_capability(ItemCapabilities.AllowsAdditions) service_item.add_capability(ItemCapabilities.AllowsAdditions)
# force a nonexistent theme
service_item.theme = -1
for item in items: for item in items:
bitem = self.listView.item(item.row()) bitem = self.listView.item(item.row())
filename = unicode(bitem.data(QtCore.Qt.UserRole).toString()) filename = unicode(bitem.data(QtCore.Qt.UserRole).toString())

View File

@ -56,7 +56,7 @@ class MediaMediaItem(MediaManagerItem):
u':/media/media_video.png').toImage() u':/media/media_video.png').toImage()
MediaManagerItem.__init__(self, parent, self, icon) MediaManagerItem.__init__(self, parent, self, icon)
self.singleServiceItem = False self.singleServiceItem = False
self.serviceItemIconName = u':/media/media_video.png' self.serviceItemIconName = u':/media/image_clapperboard.png'
def retranslateUi(self): def retranslateUi(self):
self.OnNewPrompt = translate('MediaPlugin.MediaItem', 'Select Media') self.OnNewPrompt = translate('MediaPlugin.MediaItem', 'Select Media')
@ -116,7 +116,7 @@ class MediaMediaItem(MediaManagerItem):
self.parent.liveController.display.video(filename, 0, True) self.parent.liveController.display.video(filename, 0, True)
self.resetButton.setVisible(True) self.resetButton.setVisible(True)
def generateSlideData(self, service_item, item=None): def generateSlideData(self, service_item, item=None, xmlVersion=False):
if item is None: if item is None:
item = self.listView.currentItem() item = self.listView.currentItem()
if item is None: if item is None:
@ -125,6 +125,8 @@ class MediaMediaItem(MediaManagerItem):
service_item.title = unicode( service_item.title = unicode(
translate('MediaPlugin.MediaItem', 'Media')) translate('MediaPlugin.MediaItem', 'Media'))
service_item.add_capability(ItemCapabilities.RequiresMedia) service_item.add_capability(ItemCapabilities.RequiresMedia)
# force a nonexistent theme
service_item.theme = -1
frame = u':/media/image_clapperboard.png' frame = u':/media/image_clapperboard.png'
(path, name) = os.path.split(filename) (path, name) = os.path.split(filename)
service_item.add_from_command(path, name, frame) service_item.add_from_command(path, name, frame)

View File

@ -80,5 +80,3 @@ class MediaTab(SettingsTab):
QtCore.QSettings().setValue(self.settingsSection + u'/use phonon', QtCore.QSettings().setValue(self.settingsSection + u'/use phonon',
QtCore.QVariant(self.usePhonon)) QtCore.QVariant(self.usePhonon))
Receiver.send_message(u'config_screen_changed') Receiver.send_message(u'config_screen_changed')

View File

@ -25,6 +25,7 @@
############################################################################### ###############################################################################
import logging import logging
import mimetypes
from PyQt4.phonon import Phonon from PyQt4.phonon import Phonon
@ -45,6 +46,7 @@ class MediaPlugin(Plugin):
self.dnd_id = u'Media' self.dnd_id = u'Media'
self.audio_list = u'' self.audio_list = u''
self.video_list = u'' self.video_list = u''
mimetypes.init()
for mimetype in Phonon.BackendCapabilities.availableMimeTypes(): for mimetype in Phonon.BackendCapabilities.availableMimeTypes():
mimetype = unicode(mimetype) mimetype = unicode(mimetype)
type = mimetype.split(u'audio/x-') type = mimetype.split(u'audio/x-')
@ -60,13 +62,18 @@ class MediaPlugin(Plugin):
self.video_list, mimetype = self._addToList(self.video_list, self.video_list, mimetype = self._addToList(self.video_list,
type, mimetype) type, mimetype)
def _addToList(self, list, value, type): def _addToList(self, list, value, mimetype):
# Is it a media type
if len(value) == 2: if len(value) == 2:
if list.find(value[1]) == -1: extensions = mimetypes.guess_all_extensions(unicode(mimetype))
list += u'*.%s ' % value[1] # we have an extension
self.serviceManager.supportedSuffixes(value[1]) if extensions:
type = u'' for extension in extensions:
return list, type if list.find(extension) == -1:
list += u'*%s ' % extension
self.serviceManager.supportedSuffixes(extension[1:])
mimetype = u''
return list, mimetype
def getSettingsTab(self): def getSettingsTab(self):
return MediaTab(self.name) return MediaTab(self.name)
@ -97,42 +104,42 @@ class MediaPlugin(Plugin):
## Load Button ## ## Load Button ##
self.textStrings[StringContent.Load] = { self.textStrings[StringContent.Load] = {
u'title': translate('MediaPlugin', 'Load'), u'title': translate('MediaPlugin', 'Load'),
u'tooltip': translate('MediaPlugin', u'tooltip': translate('MediaPlugin',
'Load a new Media') 'Load a new Media')
} }
## New Button ## ## New Button ##
self.textStrings[StringContent.New] = { self.textStrings[StringContent.New] = {
u'title': translate('MediaPlugin', 'Add'), u'title': translate('MediaPlugin', 'Add'),
u'tooltip': translate('MediaPlugin', u'tooltip': translate('MediaPlugin',
'Add a new Media') 'Add a new Media')
} }
## Edit Button ## ## Edit Button ##
self.textStrings[StringContent.Edit] = { self.textStrings[StringContent.Edit] = {
u'title': translate('MediaPlugin', 'Edit'), u'title': translate('MediaPlugin', 'Edit'),
u'tooltip': translate('MediaPlugin', u'tooltip': translate('MediaPlugin',
'Edit the selected Media') 'Edit the selected Media')
} }
## Delete Button ## ## Delete Button ##
self.textStrings[StringContent.Delete] = { self.textStrings[StringContent.Delete] = {
u'title': translate('MediaPlugin', 'Delete'), u'title': translate('MediaPlugin', 'Delete'),
u'tooltip': translate('MediaPlugin', u'tooltip': translate('MediaPlugin',
'Delete the selected Media') 'Delete the selected Media')
} }
## Preview ## ## Preview ##
self.textStrings[StringContent.Preview] = { self.textStrings[StringContent.Preview] = {
u'title': translate('MediaPlugin', 'Preview'), u'title': translate('MediaPlugin', 'Preview'),
u'tooltip': translate('MediaPlugin', u'tooltip': translate('MediaPlugin',
'Preview the selected Media') 'Preview the selected Media')
} }
## Live Button ## ## Live Button ##
self.textStrings[StringContent.Live] = { self.textStrings[StringContent.Live] = {
u'title': translate('MediaPlugin', 'Live'), u'title': translate('MediaPlugin', 'Live'),
u'tooltip': translate('MediaPlugin', u'tooltip': translate('MediaPlugin',
'Send the selected Media live') 'Send the selected Media live')
} }
## Add to service Button ## ## Add to service Button ##
self.textStrings[StringContent.Service] = { self.textStrings[StringContent.Service] = {
u'title': translate('MediaPlugin', 'Service'), u'title': translate('MediaPlugin', 'Service'),
u'tooltip': translate('MediaPlugin', u'tooltip': translate('MediaPlugin',
'Add the selected Media to the service') 'Add the selected Media to the service')
} }

View File

@ -38,7 +38,7 @@ log = logging.getLogger(__name__)
class PresentationListView(BaseListWithDnD): class PresentationListView(BaseListWithDnD):
""" """
Class for the list of Presentations Class for the list of Presentations
We have to explicitly create separate classes for each plugin We have to explicitly create separate classes for each plugin
in order for DnD to the Service manager to work correctly. in order for DnD to the Service manager to work correctly.
""" """
@ -67,7 +67,7 @@ class PresentationMediaItem(MediaManagerItem):
self.message_listener = MessageListener(self) self.message_listener = MessageListener(self)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'mediaitem_presentation_rebuild'), self.rebuild) QtCore.SIGNAL(u'mediaitem_presentation_rebuild'), self.rebuild)
def retranslateUi(self): def retranslateUi(self):
""" """
The name of the plugin media displayed in UI The name of the plugin media displayed in UI
@ -159,7 +159,7 @@ class PresentationMediaItem(MediaManagerItem):
if self.DisplayTypeComboBox.count() > 1: if self.DisplayTypeComboBox.count() > 1:
self.DisplayTypeComboBox.insertItem(0, self.Automatic) self.DisplayTypeComboBox.insertItem(0, self.Automatic)
self.DisplayTypeComboBox.setCurrentIndex(0) self.DisplayTypeComboBox.setCurrentIndex(0)
if QtCore.QSettings().value(self.settingsSection + u'/override app', if QtCore.QSettings().value(self.settingsSection + u'/override app',
QtCore.QVariant(QtCore.Qt.Unchecked)) == QtCore.Qt.Checked: QtCore.QVariant(QtCore.Qt.Unchecked)) == QtCore.Qt.Checked:
self.PresentationWidget.show() self.PresentationWidget.show()
else: else:
@ -238,7 +238,7 @@ class PresentationMediaItem(MediaManagerItem):
SettingsManager.set_list(self.settingsSection, SettingsManager.set_list(self.settingsSection,
self.settingsSection, self.getFileList()) self.settingsSection, self.getFileList())
def generateSlideData(self, service_item, item=None): def generateSlideData(self, service_item, item=None, xmlVersion=False):
""" """
Load the relevant information for displaying the presentation Load the relevant information for displaying the presentation
in the slidecontroller. In the case of powerpoints, an image in the slidecontroller. In the case of powerpoints, an image
@ -277,7 +277,7 @@ class PresentationMediaItem(MediaManagerItem):
def findControllerByType(self, filename): def findControllerByType(self, filename):
""" """
Determine the default application controller to use for the selected Determine the default application controller to use for the selected
file type. This is used if "Automatic" is set as the preferred file type. This is used if "Automatic" is set as the preferred
controller. Find the first (alphabetic) enabled controller which controller. Find the first (alphabetic) enabled controller which
"supports" the extension. If none found, then look for a controller "supports" the extension. If none found, then look for a controller
which "alsosupports" it instead. which "alsosupports" it instead.

View File

@ -61,7 +61,8 @@ class PresentationPlugin(Plugin):
Create the settings Tab Create the settings Tab
""" """
visible_name = self.getString(StringContent.VisibleName) visible_name = self.getString(StringContent.VisibleName)
return PresentationTab(self.name, visible_name[u'title'], self.controllers) return PresentationTab(self.name, visible_name[u'title'],
self.controllers)
def initialise(self): def initialise(self):
""" """
@ -188,4 +189,4 @@ class PresentationPlugin(Plugin):
u'title': translate('PresentationPlugin', 'Service'), u'title': translate('PresentationPlugin', 'Service'),
u'tooltip': translate('PresentationPlugin', u'tooltip': translate('PresentationPlugin',
'Add the selected Presentation to the service') 'Add the selected Presentation to the service')
} }

View File

@ -43,7 +43,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
""" """
log.info(u'%s EditSongForm loaded', __name__) log.info(u'%s EditSongForm loaded', __name__)
def __init__(self, parent, songmanager): def __init__(self, parent, manager):
""" """
Constructor Constructor
""" """
@ -100,7 +100,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
QtCore.QObject.connect(self.ButtonBox, QtCore.QObject.connect(self.ButtonBox,
QtCore.SIGNAL(u'clicked(QAbstractButton*)'), self.onPreview) QtCore.SIGNAL(u'clicked(QAbstractButton*)'), self.onPreview)
# Create other objects and forms # Create other objects and forms
self.songmanager = songmanager self.manager = manager
self.verse_form = EditVerseForm(self) self.verse_form = EditVerseForm(self)
self.initialise() self.initialise()
self.AuthorsListView.setSortingEnabled(False) self.AuthorsListView.setSortingEnabled(False)
@ -116,7 +116,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
self.TopicRemoveButton.setEnabled(False) self.TopicRemoveButton.setEnabled(False)
def loadAuthors(self): def loadAuthors(self):
authors = self.songmanager.get_all_objects(Author, authors = self.manager.get_all_objects(Author,
order_by_ref=Author.display_name) order_by_ref=Author.display_name)
self.AuthorsSelectionComboItem.clear() self.AuthorsSelectionComboItem.clear()
self.AuthorsSelectionComboItem.addItem(u'') self.AuthorsSelectionComboItem.addItem(u'')
@ -127,8 +127,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
row, QtCore.QVariant(author.id)) row, QtCore.QVariant(author.id))
def loadTopics(self): def loadTopics(self):
topics = self.songmanager.get_all_objects(Topic, topics = self.manager.get_all_objects(Topic, order_by_ref=Topic.name)
order_by_ref=Topic.name)
self.SongTopicCombo.clear() self.SongTopicCombo.clear()
self.SongTopicCombo.addItem(u'') self.SongTopicCombo.addItem(u'')
for topic in topics: for topic in topics:
@ -137,7 +136,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
self.SongTopicCombo.setItemData(row, QtCore.QVariant(topic.id)) self.SongTopicCombo.setItemData(row, QtCore.QVariant(topic.id))
def loadBooks(self): def loadBooks(self):
books = self.songmanager.get_all_objects(Book, order_by_ref=Book.name) books = self.manager.get_all_objects(Book, order_by_ref=Book.name)
self.SongbookCombo.clear() self.SongbookCombo.clear()
self.SongbookCombo.addItem(u'') self.SongbookCombo.addItem(u'')
for book in books: for book in books:
@ -153,6 +152,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
def newSong(self): def newSong(self):
log.debug(u'New Song') log.debug(u'New Song')
self.initialise()
self.SongTabWidget.setCurrentIndex(0) self.SongTabWidget.setCurrentIndex(0)
self.TitleEditItem.setText(u'') self.TitleEditItem.setText(u'')
self.AlternativeEdit.setText(u'') self.AlternativeEdit.setText(u'')
@ -171,21 +171,30 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
# it's a new song to preview is not possible # it's a new song to preview is not possible
self.previewButton.setVisible(False) self.previewButton.setVisible(False)
def loadSong(self, id, preview): def loadSong(self, id, preview=False):
"""
Loads a song.
``id``
The song id (int).
``preview``
Should be ``True`` if the song is also previewed (boolean).
"""
log.debug(u'Load Song') log.debug(u'Load Song')
self.initialise()
self.SongTabWidget.setCurrentIndex(0) self.SongTabWidget.setCurrentIndex(0)
self.loadAuthors() self.loadAuthors()
self.loadTopics() self.loadTopics()
self.loadBooks() self.loadBooks()
self.song = self.songmanager.get_object(Song, id) self.song = self.manager.get_object(Song, id)
self.TitleEditItem.setText(self.song.title) self.TitleEditItem.setText(self.song.title)
if self.song.alternate_title: if self.song.alternate_title:
self.AlternativeEdit.setText(self.song.alternate_title) self.AlternativeEdit.setText(self.song.alternate_title)
else: else:
self.AlternativeEdit.setText(u'') self.AlternativeEdit.setText(u'')
if self.song.song_book_id != 0: if self.song.song_book_id != 0:
book_name = self.songmanager.get_object(Book, book_name = self.manager.get_object(Book, self.song.song_book_id)
self.song.song_book_id)
id = self.SongbookCombo.findText( id = self.SongbookCombo.findText(
unicode(book_name.name), QtCore.Qt.MatchExactly) unicode(book_name.name), QtCore.Qt.MatchExactly)
if id == -1: if id == -1:
@ -299,7 +308,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
else: else:
author = Author.populate(first_name=text.rsplit(u' ', 1)[0], author = Author.populate(first_name=text.rsplit(u' ', 1)[0],
last_name=text.rsplit(u' ', 1)[1], display_name=text) last_name=text.rsplit(u' ', 1)[1], display_name=text)
self.songmanager.save_object(author) self.manager.save_object(author)
author_item = QtGui.QListWidgetItem( author_item = QtGui.QListWidgetItem(
unicode(author.display_name)) unicode(author.display_name))
author_item.setData(QtCore.Qt.UserRole, author_item.setData(QtCore.Qt.UserRole,
@ -311,7 +320,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
return return
elif item > 0: elif item > 0:
item_id = (self.AuthorsSelectionComboItem.itemData(item)).toInt()[0] item_id = (self.AuthorsSelectionComboItem.itemData(item)).toInt()[0]
author = self.songmanager.get_object(Author, item_id) author = self.manager.get_object(Author, item_id)
if self.AuthorsListView.findItems(unicode(author.display_name), if self.AuthorsListView.findItems(unicode(author.display_name),
QtCore.Qt.MatchExactly): QtCore.Qt.MatchExactly):
QtGui.QMessageBox.warning(self, QtGui.QMessageBox.warning(self,
@ -354,7 +363,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.Yes | QtGui.QMessageBox.No,
QtGui.QMessageBox.Yes) == QtGui.QMessageBox.Yes: QtGui.QMessageBox.Yes) == QtGui.QMessageBox.Yes:
topic = Topic.populate(name=text) topic = Topic.populate(name=text)
self.songmanager.save_object(topic) self.manager.save_object(topic)
topic_item = QtGui.QListWidgetItem(unicode(topic.name)) topic_item = QtGui.QListWidgetItem(unicode(topic.name))
topic_item.setData(QtCore.Qt.UserRole, topic_item.setData(QtCore.Qt.UserRole,
QtCore.QVariant(topic.id)) QtCore.QVariant(topic.id))
@ -365,7 +374,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
return return
elif item > 0: elif item > 0:
item_id = (self.SongTopicCombo.itemData(item)).toInt()[0] item_id = (self.SongTopicCombo.itemData(item)).toInt()[0]
topic = self.songmanager.get_object(Topic, item_id) topic = self.manager.get_object(Topic, item_id)
if self.TopicsListView.findItems(unicode(topic.name), if self.TopicsListView.findItems(unicode(topic.name),
QtCore.Qt.MatchExactly): QtCore.Qt.MatchExactly):
QtGui.QMessageBox.warning(self, QtGui.QMessageBox.warning(self,
@ -596,9 +605,13 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
""" """
Save and Preview button pressed. Save and Preview button pressed.
The Song is valid so as the plugin to add it to preview to see. The Song is valid so as the plugin to add it to preview to see.
``button``
A button (QPushButton).
""" """
log.debug(u'onPreview') log.debug(u'onPreview')
if unicode(button.objectName()) == u'previewButton' and self.saveSong(): if unicode(button.objectName()) == u'previewButton' and \
self.saveSong(True):
Receiver.send_message(u'songs_preview') Receiver.send_message(u'songs_preview')
def closePressed(self): def closePressed(self):
@ -619,33 +632,44 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.Yes | QtGui.QMessageBox.No,
QtGui.QMessageBox.Yes) == QtGui.QMessageBox.Yes: QtGui.QMessageBox.Yes) == QtGui.QMessageBox.Yes:
book = Book.populate(name=text, publisher=u'') book = Book.populate(name=text, publisher=u'')
self.songmanager.save_object(book) self.manager.save_object(book)
else: else:
return return
if self.saveSong(): if self.saveSong():
Receiver.send_message(u'songs_load_list') Receiver.send_message(u'songs_load_list')
self.close() self.close()
def saveSong(self): def saveSong(self, preview=False):
""" """
Get all the data from the widgets on the form, and then save it to the Get all the data from the widgets on the form, and then save it to the
database. database.
``preview``
Should be ``True`` if the song is also previewed (boolean).
""" """
self.song.title = unicode(self.TitleEditItem.text()) self.song.title = unicode(self.TitleEditItem.text())
self.song.alternate_title = unicode(self.AlternativeEdit.text()) self.song.alternate_title = unicode(self.AlternativeEdit.text())
self.song.copyright = unicode(self.CopyrightEditItem.text()) self.song.copyright = unicode(self.CopyrightEditItem.text())
self.song.search_title = self.song.title + u'@' + \ if self.song.alternate_title:
self.song.alternate_title self.song.search_title = self.song.title + u'@' + \
self.song.alternate_title
else:
self.song.search_title = self.song.title
self.song.comments = unicode(self.CommentsEdit.toPlainText()) self.song.comments = unicode(self.CommentsEdit.toPlainText())
self.song.verse_order = unicode(self.VerseOrderEdit.text()) self.song.verse_order = unicode(self.VerseOrderEdit.text())
self.song.ccli_number = unicode(self.CCLNumberEdit.text()) self.song.ccli_number = unicode(self.CCLNumberEdit.text())
self.song.song_number = unicode(self.songBookNumberEdit.text()) self.song.song_number = unicode(self.songBookNumberEdit.text())
book_name = unicode(self.SongbookCombo.currentText()) book_name = unicode(self.SongbookCombo.currentText())
if book_name: if book_name:
self.song.book = self.songmanager.get_object_filtered(Book, self.song.book = self.manager.get_object_filtered(Book,
Book.name == book_name) Book.name == book_name)
else: else:
self.song.book = None self.song.book = None
theme_name = unicode(self.ThemeSelectionComboItem.currentText())
if theme_name:
self.song.theme_name = theme_name
else:
self.song.theme_name = None
if self._validate_song(): if self._validate_song():
self.processLyrics() self.processLyrics()
self.processTitle() self.processTitle()
@ -653,16 +677,16 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
for row in range(self.AuthorsListView.count()): for row in range(self.AuthorsListView.count()):
item = self.AuthorsListView.item(row) item = self.AuthorsListView.item(row)
authorId = (item.data(QtCore.Qt.UserRole)).toInt()[0] authorId = (item.data(QtCore.Qt.UserRole)).toInt()[0]
self.song.authors.append(self.songmanager.get_object(Author, self.song.authors.append(self.manager.get_object(Author,
authorId)) authorId))
self.song.topics = [] self.song.topics = []
for row in range(self.TopicsListView.count()): for row in range(self.TopicsListView.count()):
item = self.TopicsListView.item(row) item = self.TopicsListView.item(row)
topicId = (item.data(QtCore.Qt.UserRole)).toInt()[0] topicId = (item.data(QtCore.Qt.UserRole)).toInt()[0]
self.song.topics.append(self.songmanager.get_object(Topic, self.song.topics.append(self.manager.get_object(Topic, topicId))
topicId)) self.manager.save_object(self.song)
self.songmanager.save_object(self.song) if not preview:
self.song = None self.song = None
return True return True
return False return False

View File

@ -60,7 +60,6 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog):
def contextMenu(self, point): def contextMenu(self, point):
item = self.serviceManagerList.itemAt(point) item = self.serviceManagerList.itemAt(point)
print item
def insertVerse(self, title, num=1): def insertVerse(self, title, num=1):
if self.verseTextEdit.textCursor().columnNumber() != 0: if self.verseTextEdit.textCursor().columnNumber() != 0:

View File

@ -507,8 +507,7 @@ class SongImportForm(QtGui.QWizard, Ui_SongImportWizard):
filenames=self.getListOfFiles( filenames=self.getListOfFiles(
self.songBeamerFileListWidget) self.songBeamerFileListWidget)
) )
success = importer.do_import() if importer.do_import():
if success:
# reload songs # reload songs
self.importProgressLabel.setText( self.importProgressLabel.setText(
translate('SongsPlugin.SongImportForm', 'Finished import.')) translate('SongsPlugin.SongImportForm', 'Finished import.'))

View File

@ -36,13 +36,13 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
""" """
Class documentation goes here. Class documentation goes here.
""" """
def __init__(self, songmanager, parent=None): def __init__(self, manager, parent=None):
""" """
Constructor Constructor
""" """
QtGui.QDialog.__init__(self, parent) QtGui.QDialog.__init__(self, parent)
self.setupUi(self) self.setupUi(self)
self.songmanager = songmanager self.manager = manager
self.authorform = AuthorsForm(self) self.authorform = AuthorsForm(self)
self.topicform = TopicsForm(self) self.topicform = TopicsForm(self)
self.bookform = SongBookForm(self) self.bookform = SongBookForm(self)
@ -85,12 +85,12 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
del_text, err_text, sel_text): del_text, err_text, sel_text):
item_id = self._getCurrentItemId(list_widget) item_id = self._getCurrentItemId(list_widget)
if item_id != -1: if item_id != -1:
item = self.songmanager.get_object(item_class, item_id) item = self.manager.get_object(item_class, item_id)
if item and len(item.songs) == 0: if item and len(item.songs) == 0:
if QtGui.QMessageBox.warning(self, dlg_title, del_text, if QtGui.QMessageBox.warning(self, dlg_title, del_text,
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.No | QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.No |
QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.Yes: QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.Yes:
self.songmanager.delete_object(item_class, item.id) self.manager.delete_object(item_class, item.id)
reset_func() reset_func()
else: else:
QtGui.QMessageBox.critical(self, dlg_title, err_text) QtGui.QMessageBox.critical(self, dlg_title, err_text)
@ -102,7 +102,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
Reloads the Authors list. Reloads the Authors list.
""" """
self.AuthorsListWidget.clear() self.AuthorsListWidget.clear()
authors = self.songmanager.get_all_objects(Author, authors = self.manager.get_all_objects(Author,
order_by_ref=Author.display_name) order_by_ref=Author.display_name)
for author in authors: for author in authors:
if author.display_name: if author.display_name:
@ -124,8 +124,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
Reloads the Topics list. Reloads the Topics list.
""" """
self.TopicsListWidget.clear() self.TopicsListWidget.clear()
topics = self.songmanager.get_all_objects(Topic, topics = self.manager.get_all_objects(Topic, order_by_ref=Topic.name)
order_by_ref=Topic.name)
for topic in topics: for topic in topics:
topic_name = QtGui.QListWidgetItem(topic.name) topic_name = QtGui.QListWidgetItem(topic.name)
topic_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(topic.id)) topic_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(topic.id))
@ -142,7 +141,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
Reloads the Books list. Reloads the Books list.
""" """
self.BooksListWidget.clear() self.BooksListWidget.clear()
books = self.songmanager.get_all_objects(Book, order_by_ref=Book.name) books = self.manager.get_all_objects(Book, order_by_ref=Book.name)
for book in books: for book in books:
book_name = QtGui.QListWidgetItem(u'%s (%s)' % (book.name, book_name = QtGui.QListWidgetItem(u'%s (%s)' % (book.name,
book.publisher)) book.publisher))
@ -160,7 +159,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
Returns False if the given Author is already in the list otherwise Returns False if the given Author is already in the list otherwise
True. True.
""" """
authors = self.songmanager.get_all_objects(Author, authors = self.manager.get_all_objects(Author,
and_(Author.first_name == new_author.first_name, and_(Author.first_name == new_author.first_name,
Author.last_name == new_author.last_name, Author.last_name == new_author.last_name,
Author.display_name == new_author.display_name)) Author.display_name == new_author.display_name))
@ -182,7 +181,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
""" """
Returns False if the given Topic is already in the list otherwise True. Returns False if the given Topic is already in the list otherwise True.
""" """
topics = self.songmanager.get_all_objects(Topic, topics = self.manager.get_all_objects(Topic,
Topic.name == new_topic.name) Topic.name == new_topic.name)
if len(topics) > 0: if len(topics) > 0:
# If we edit an existing Topic, we need to make sure that we do # If we edit an existing Topic, we need to make sure that we do
@ -202,7 +201,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
""" """
Returns False if the given Book is already in the list otherwise True. Returns False if the given Book is already in the list otherwise True.
""" """
books = self.songmanager.get_all_objects(Book, books = self.manager.get_all_objects(Book,
and_(Book.name == new_book.name, and_(Book.name == new_book.name,
Book.publisher == new_book.publisher)) Book.publisher == new_book.publisher))
if len(books) > 0: if len(books) > 0:
@ -227,7 +226,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
last_name=unicode(self.authorform.LastNameEdit.text()), last_name=unicode(self.authorform.LastNameEdit.text()),
display_name=unicode(self.authorform.DisplayEdit.text())) display_name=unicode(self.authorform.DisplayEdit.text()))
if self.checkAuthor(author): if self.checkAuthor(author):
if self.songmanager.save_object(author): if self.manager.save_object(author):
self.resetAuthors() self.resetAuthors()
else: else:
QtGui.QMessageBox.critical(self, QtGui.QMessageBox.critical(self,
@ -244,7 +243,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
if self.topicform.exec_(): if self.topicform.exec_():
topic = Topic.populate(name=unicode(self.topicform.NameEdit.text())) topic = Topic.populate(name=unicode(self.topicform.NameEdit.text()))
if self.checkTopic(topic): if self.checkTopic(topic):
if self.songmanager.save_object(topic): if self.manager.save_object(topic):
self.resetTopics() self.resetTopics()
else: else:
QtGui.QMessageBox.critical(self, QtGui.QMessageBox.critical(self,
@ -262,7 +261,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
book = Book.populate(name=unicode(self.bookform.NameEdit.text()), book = Book.populate(name=unicode(self.bookform.NameEdit.text()),
publisher=unicode(self.bookform.PublisherEdit.text())) publisher=unicode(self.bookform.PublisherEdit.text()))
if self.checkBook(book): if self.checkBook(book):
if self.songmanager.save_object(book): if self.manager.save_object(book):
self.resetBooks() self.resetBooks()
else: else:
QtGui.QMessageBox.critical(self, QtGui.QMessageBox.critical(self,
@ -278,7 +277,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
def onAuthorEditButtonClick(self): def onAuthorEditButtonClick(self):
author_id = self._getCurrentItemId(self.AuthorsListWidget) author_id = self._getCurrentItemId(self.AuthorsListWidget)
if author_id != -1: if author_id != -1:
author = self.songmanager.get_object(Author, author_id) author = self.manager.get_object(Author, author_id)
self.authorform.setAutoDisplayName(False) self.authorform.setAutoDisplayName(False)
self.authorform.FirstNameEdit.setText(author.first_name) self.authorform.FirstNameEdit.setText(author.first_name)
self.authorform.LastNameEdit.setText(author.last_name) self.authorform.LastNameEdit.setText(author.last_name)
@ -295,7 +294,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
author.display_name = unicode( author.display_name = unicode(
self.authorform.DisplayEdit.text()) self.authorform.DisplayEdit.text())
if self.checkAuthor(author, True): if self.checkAuthor(author, True):
if self.songmanager.save_object(author): if self.manager.save_object(author):
self.resetAuthors() self.resetAuthors()
Receiver.send_message(u'songs_load_list') Receiver.send_message(u'songs_load_list')
else: else:
@ -330,14 +329,14 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
def onTopicEditButtonClick(self): def onTopicEditButtonClick(self):
topic_id = self._getCurrentItemId(self.TopicsListWidget) topic_id = self._getCurrentItemId(self.TopicsListWidget)
if topic_id != -1: if topic_id != -1:
topic = self.songmanager.get_object(Topic, topic_id) topic = self.manager.get_object(Topic, topic_id)
self.topicform.NameEdit.setText(topic.name) self.topicform.NameEdit.setText(topic.name)
# Save the topic's name for the case that he has to be restored. # Save the topic's name for the case that he has to be restored.
temp_name = topic.name temp_name = topic.name
if self.topicform.exec_(False): if self.topicform.exec_(False):
topic.name = unicode(self.topicform.NameEdit.text()) topic.name = unicode(self.topicform.NameEdit.text())
if self.checkTopic(topic, True): if self.checkTopic(topic, True):
if self.songmanager.save_object(topic): if self.manager.save_object(topic):
self.resetTopics() self.resetTopics()
else: else:
QtGui.QMessageBox.critical(self, QtGui.QMessageBox.critical(self,
@ -367,7 +366,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
def onBookEditButtonClick(self): def onBookEditButtonClick(self):
book_id = self._getCurrentItemId(self.BooksListWidget) book_id = self._getCurrentItemId(self.BooksListWidget)
if book_id != -1: if book_id != -1:
book = self.songmanager.get_object(Book, book_id) book = self.manager.get_object(Book, book_id)
if book.publisher is None: if book.publisher is None:
book.publisher = u'' book.publisher = u''
self.bookform.NameEdit.setText(book.name) self.bookform.NameEdit.setText(book.name)
@ -380,7 +379,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
book.name = unicode(self.bookform.NameEdit.text()) book.name = unicode(self.bookform.NameEdit.text())
book.publisher = unicode(self.bookform.PublisherEdit.text()) book.publisher = unicode(self.bookform.PublisherEdit.text())
if self.checkBook(book, True): if self.checkBook(book, True):
if self.songmanager.save_object(book): if self.manager.save_object(book):
self.resetBooks() self.resetBooks()
else: else:
QtGui.QMessageBox.critical(self, QtGui.QMessageBox.critical(self,
@ -406,15 +405,15 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
def mergeAuthors(self, old_author): def mergeAuthors(self, old_author):
""" """
Merges two authors into one author. Merges two authors into one author.
``old_author`` ``old_author``
The author which will be deleted afterwards. The author which will be deleted afterwards.
""" """
existing_author = self.songmanager.get_object_filtered(Author, existing_author = self.manager.get_object_filtered(Author,
and_(Author.first_name == old_author.first_name, and_(Author.first_name == old_author.first_name,
Author.last_name == old_author.last_name, Author.last_name == old_author.last_name,
Author.display_name == old_author.display_name)) Author.display_name == old_author.display_name))
songs = self.songmanager.get_all_objects(Song, songs = self.manager.get_all_objects(Song,
Song.authors.contains(old_author)) Song.authors.contains(old_author))
for song in songs: for song in songs:
# We check if the song has already existing_author as author. If # We check if the song has already existing_author as author. If
@ -422,19 +421,19 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
if existing_author not in song.authors: if existing_author not in song.authors:
song.authors.append(existing_author) song.authors.append(existing_author)
song.authors.remove(old_author) song.authors.remove(old_author)
self.songmanager.save_object(song) self.manager.save_object(song)
self.songmanager.delete_object(Author, old_author.id) self.manager.delete_object(Author, old_author.id)
def mergeTopics(self, old_topic): def mergeTopics(self, old_topic):
""" """
Merges two topics into one topic. Merges two topics into one topic.
``old_topic`` ``old_topic``
The topic which will be deleted afterwards. The topic which will be deleted afterwards.
""" """
existing_topic = self.songmanager.get_object_filtered(Topic, existing_topic = self.manager.get_object_filtered(Topic,
Topic.name == old_topic.name) Topic.name == old_topic.name)
songs = self.songmanager.get_all_objects(Song, songs = self.manager.get_all_objects(Song,
Song.topics.contains(old_topic)) Song.topics.contains(old_topic))
for song in songs: for song in songs:
# We check if the song has already existing_topic as topic. If that # We check if the song has already existing_topic as topic. If that
@ -442,25 +441,25 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
if existing_topic not in song.topics: if existing_topic not in song.topics:
song.topics.append(existing_topic) song.topics.append(existing_topic)
song.topics.remove(old_topic) song.topics.remove(old_topic)
self.songmanager.save_object(song) self.manager.save_object(song)
self.songmanager.delete_object(Topic, old_topic.id) self.manager.delete_object(Topic, old_topic.id)
def mergeBooks(self, old_book): def mergeBooks(self, old_book):
""" """
Merges two books into one book. Merges two books into one book.
``old_book`` ``old_book``
The book which will be deleted afterwards. The book which will be deleted afterwards.
""" """
existing_book = self.songmanager.get_object_filtered(Book, existing_book = self.manager.get_object_filtered(Book,
and_(Book.name == old_book.name, and_(Book.name == old_book.name,
Book.publisher == old_book.publisher)) Book.publisher == old_book.publisher))
songs = self.songmanager.get_all_objects(Song, songs = self.manager.get_all_objects(Song,
Song.song_book_id == old_book.id) Song.song_book_id == old_book.id)
for song in songs: for song in songs:
song.song_book_id = existing_book.id song.song_book_id = existing_book.id
self.songmanager.save_object(song) self.manager.save_object(song)
self.songmanager.delete_object(Book, old_book.id) self.manager.delete_object(Book, old_book.id)
def onAuthorDeleteButtonClick(self): def onAuthorDeleteButtonClick(self):
""" """

View File

@ -62,6 +62,36 @@ class VerseType(object):
elif verse_type == VerseType.Other: elif verse_type == VerseType.Other:
return translate('SongsPlugin.VerseType', 'Other') return translate('SongsPlugin.VerseType', 'Other')
@staticmethod
def expand_string(verse_type):
"""
Return the VerseType for a given string
``verse_type``
The string to return a VerseType for
"""
verse_type = verse_type.lower()
if verse_type == unicode(VerseType.to_string(VerseType.Verse)).lower()[0]:
return translate('SongsPlugin.VerseType', 'Verse')
elif verse_type == \
unicode(VerseType.to_string(VerseType.Chorus)).lower()[0]:
return translate('SongsPlugin.VerseType', 'Chorus')
elif verse_type == \
unicode(VerseType.to_string(VerseType.Bridge)).lower()[0]:
return translate('SongsPlugin.VerseType', 'Bridge')
elif verse_type == \
unicode(VerseType.to_string(VerseType.PreChorus)).lower()[0]:
return translate('SongsPlugin.VerseType', 'PreChorus')
elif verse_type == \
unicode(VerseType.to_string(VerseType.Intro)).lower()[0]:
return translate('SongsPlugin.VerseType', 'Intro')
elif verse_type == \
unicode(VerseType.to_string(VerseType.Ending)).lower()[0]:
return translate('SongsPlugin.VerseType', 'Ending')
elif verse_type == \
unicode(VerseType.to_string(VerseType.Other)).lower()[0]:
return translate('SongsPlugin.VerseType', 'Other')
@staticmethod @staticmethod
def from_string(verse_type): def from_string(verse_type):
""" """
@ -92,7 +122,6 @@ class VerseType(object):
unicode(VerseType.to_string(VerseType.Other)).lower(): unicode(VerseType.to_string(VerseType.Other)).lower():
return VerseType.Other return VerseType.Other
from xml import LyricsXML, SongXMLBuilder, SongXMLParser, OpenLyricsParser
from xml import LyricsXML, SongXMLBuilder, SongXMLParser
from songstab import SongsTab from songstab import SongsTab
from mediaitem import SongMediaItem from mediaitem import SongMediaItem

View File

@ -203,9 +203,9 @@ class CCLIFileImport(SongImport):
SongSelect .txt file format:: SongSelect .txt file format::
Song Title # Contains the song title Song Title # Contains the song title
<Empty line> <Empty line>
Verse type and number # e.g. Verse 1, Chorus 1 Verse type and number # e.g. Verse 1, Chorus 1
Verse lyrics Verse lyrics
<Empty line> <Empty line>
<Empty line> <Empty line>
@ -213,12 +213,16 @@ class CCLIFileImport(SongImport):
Verse lyrics Verse lyrics
<Empty line> <Empty line>
<Empty line> <Empty line>
Song CCLI number # e.g. CCLI Number (e.g.CCLI-Liednummer: 2672885) Song CCLI number
Song copyright # e.g. © 1999 Integrity's Hosanna! Music | LenSongs Publishing # e.g. CCLI Number (e.g.CCLI-Liednummer: 2672885)
Song authors # e.g. Lenny LeBlanc | Paul Baloche Song copyright
Licencing info # e.g. For use solely with the SongSelect Terms of Use. # e.g. © 1999 Integrity's Hosanna! Music | LenSongs Publishing
Song authors # e.g. Lenny LeBlanc | Paul Baloche
Licencing info
# e.g. For use solely with the SongSelect Terms of Use.
All rights Reserved. www.ccli.com All rights Reserved. www.ccli.com
CCLI Licence number of user # e.g. CCL-Liedlizenznummer: 14 / CCLI License No. 14 CCLI Licence number of user
# e.g. CCL-Liedlizenznummer: 14 / CCLI License No. 14
""" """
log.debug(u'TXT file text: %s', textList) log.debug(u'TXT file text: %s', textList)

View File

@ -32,7 +32,7 @@ from openlp.core.lib import MediaManagerItem, BaseListWithDnD, Receiver, \
ItemCapabilities, translate, check_item_selected ItemCapabilities, translate, check_item_selected
from openlp.plugins.songs.forms import EditSongForm, SongMaintenanceForm, \ from openlp.plugins.songs.forms import EditSongForm, SongMaintenanceForm, \
SongImportForm SongImportForm
from openlp.plugins.songs.lib import SongXMLParser from openlp.plugins.songs.lib import SongXMLParser, OpenLyricsParser
from openlp.plugins.songs.lib.db import Author, Song from openlp.plugins.songs.lib.db import Author, Song
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -53,8 +53,8 @@ class SongMediaItem(MediaManagerItem):
self.ListViewWithDnD_class = SongListView self.ListViewWithDnD_class = SongListView
MediaManagerItem.__init__(self, parent, self, icon) MediaManagerItem.__init__(self, parent, self, icon)
self.edit_song_form = EditSongForm(self, self.parent.manager) self.edit_song_form = EditSongForm(self, self.parent.manager)
self.openLyrics = OpenLyricsParser(self.parent.manager)
self.singleServiceItem = False self.singleServiceItem = False
#self.edit_song_form = EditSongForm(self.parent.manager, self)
self.song_maintenance_form = SongMaintenanceForm( self.song_maintenance_form = SongMaintenanceForm(
self.parent.manager, self) self.parent.manager, self)
# Holds information about whether the edit is remotly triggered and # Holds information about whether the edit is remotly triggered and
@ -114,6 +114,8 @@ class SongMediaItem(MediaManagerItem):
self.SearchButtonLayout.addWidget(self.ClearTextButton) self.SearchButtonLayout.addWidget(self.ClearTextButton)
self.pageLayout.addLayout(self.SearchButtonLayout) self.pageLayout.addLayout(self.SearchButtonLayout)
# Signals and slots # Signals and slots
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'plugin_list_refresh'), self.onSearchTextButtonClick)
QtCore.QObject.connect(self.SearchTextEdit, QtCore.QObject.connect(self.SearchTextEdit,
QtCore.SIGNAL(u'returnPressed()'), self.onSearchTextButtonClick) QtCore.SIGNAL(u'returnPressed()'), self.onSearchTextButtonClick)
QtCore.QObject.connect(self.SearchTextButton, QtCore.QObject.connect(self.SearchTextButton,
@ -141,7 +143,7 @@ class SongMediaItem(MediaManagerItem):
self.updateServiceOnEdit = QtCore.QSettings().value( self.updateServiceOnEdit = QtCore.QSettings().value(
self.settingsSection + u'/update service on edit', self.settingsSection + u'/update service on edit',
QtCore.QVariant(u'False')).toBool() QtCore.QVariant(u'False')).toBool()
self.AddSongFromServide = QtCore.QSettings().value( self.addSongFromService = QtCore.QSettings().value(
self.settingsSection + u'/add song from service', self.settingsSection + u'/add song from service',
QtCore.QVariant(u'True')).toBool() QtCore.QVariant(u'True')).toBool()
@ -192,6 +194,7 @@ class SongMediaItem(MediaManagerItem):
Handle the exit from the edit dialog and trigger remote updates Handle the exit from the edit dialog and trigger remote updates
of songs of songs
""" """
log.debug(u'onSongListLoad')
# Called to redisplay the song list screen edit from a search # Called to redisplay the song list screen edit from a search
# or from the exit of the Song edit dialog. If remote editing is active # or from the exit of the Song edit dialog. If remote editing is active
# Trigger it and clean up so it will not update again. # Trigger it and clean up so it will not update again.
@ -259,6 +262,7 @@ class SongMediaItem(MediaManagerItem):
Receiver.send_message(u'songs_load_list') Receiver.send_message(u'songs_load_list')
def onNewClick(self): def onNewClick(self):
log.debug(u'onNewClick')
self.edit_song_form.newSong() self.edit_song_form.newSong()
self.edit_song_form.exec_() self.edit_song_form.exec_()
@ -266,6 +270,7 @@ class SongMediaItem(MediaManagerItem):
self.song_maintenance_form.exec_() self.song_maintenance_form.exec_()
def onRemoteEditClear(self): def onRemoteEditClear(self):
log.debug(u'onRemoteEditClear')
self.remoteTriggered = None self.remoteTriggered = None
self.remoteSong = -1 self.remoteSong = -1
@ -275,6 +280,7 @@ class SongMediaItem(MediaManagerItem):
the Song Id in the payload along with an indicator to say which the Song Id in the payload along with an indicator to say which
type of display is required. type of display is required.
""" """
log.debug(u'onRemoteEdit %s' % songid)
fields = songid.split(u':') fields = songid.split(u':')
valid = self.parent.manager.get_object(Song, fields[1]) valid = self.parent.manager.get_object(Song, fields[1])
if valid: if valid:
@ -287,6 +293,7 @@ class SongMediaItem(MediaManagerItem):
""" """
Edit a song Edit a song
""" """
log.debug(u'onEditClick')
if check_item_selected(self.listView, if check_item_selected(self.listView,
translate('SongsPlugin.MediaItem', translate('SongsPlugin.MediaItem',
'You must select an item to edit.')): 'You must select an item to edit.')):
@ -323,7 +330,8 @@ class SongMediaItem(MediaManagerItem):
self.parent.manager.delete_object(Song, item_id) self.parent.manager.delete_object(Song, item_id)
self.onSearchTextButtonClick() self.onSearchTextButtonClick()
def generateSlideData(self, service_item, item=None): def generateSlideData(self, service_item, item=None, xmlVersion=False):
log.debug(u'generateSlideData (%s:%s)' % (service_item, item))
raw_footer = [] raw_footer = []
author_list = u'' author_list = u''
author_audit = [] author_audit = []
@ -345,11 +353,11 @@ class SongMediaItem(MediaManagerItem):
service_item.add_capability(ItemCapabilities.AddIfNewItem) service_item.add_capability(ItemCapabilities.AddIfNewItem)
song = self.parent.manager.get_object(Song, item_id) song = self.parent.manager.get_object(Song, item_id)
service_item.theme = song.theme_name service_item.theme = song.theme_name
service_item.editId = item_id service_item.edit_id = item_id
if song.lyrics.startswith(u'<?xml version='): if song.lyrics.startswith(u'<?xml version='):
songXML = SongXMLParser(song.lyrics) songXML = SongXMLParser(song.lyrics)
verseList = songXML.get_verses() verseList = songXML.get_verses()
#no verse list or only 1 space (in error) # no verse list or only 1 space (in error)
if not song.verse_order or not song.verse_order.strip(): if not song.verse_order or not song.verse_order.strip():
for verse in verseList: for verse in verseList:
verseTag = u'%s:%s' % ( verseTag = u'%s:%s' % (
@ -357,7 +365,7 @@ class SongMediaItem(MediaManagerItem):
service_item.add_from_text( service_item.add_from_text(
verse[1][:30], unicode(verse[1]), verseTag) verse[1][:30], unicode(verse[1]), verseTag)
else: else:
#Loop through the verse list and expand the song accordingly. # Loop through the verse list and expand the song accordingly.
for order in song.verse_order.upper().split(u' '): for order in song.verse_order.upper().split(u' '):
if len(order) == 0: if len(order) == 0:
break break
@ -389,31 +397,43 @@ class SongMediaItem(MediaManagerItem):
service_item.audit = [ service_item.audit = [
song.title, author_audit, song.copyright, unicode(song.ccli_number) song.title, author_audit, song.copyright, unicode(song.ccli_number)
] ]
service_item.data_string = {u'title':song.search_title, u'authors':author_list} service_item.data_string = {u'title':song.search_title,
u'authors':author_list}
service_item.xml_version = self.openLyrics.song_to_xml(song)
return True return True
def serviceLoad(self, item): def serviceLoad(self, item):
""" """
Triggered by a song being loaded by the service item Triggered by a song being loaded by the service item
""" """
log.debug(u'serviceLoad')
if item.data_string: if item.data_string:
search_results = self.parent.manager.get_all_objects(Song, search_results = self.parent.manager.get_all_objects(Song,
Song.search_title.like(u'%' + Song.search_title ==
item.data_string[u'title'].split(u'@')[0] + u'%'), item.data_string[u'title'].split(u'@')[0].lower() ,
Song.search_title.asc()) Song.search_title.asc())
author_list = item.data_string[u'authors'].split(u',') author_list = item.data_string[u'authors'].split(u', ')
editId = 0 editId = 0
uuid = 0 uuid = item._uuid
if search_results: if search_results:
for song in search_results: for song in search_results:
count = 0 count = 0
for author in song.authors: for author in song.authors:
if author.display_name in author_list: if author.display_name in author_list:
count += 1 count += 1
# All Authors the same
if count == len(author_list): if count == len(author_list):
editId = song.id editId = song.id
uuid = item._uuid else:
# Authors different
if self.addSongFromService:
editId = self.openLyrics. \
xml_to_song(item.xml_version)
else:
# Title does not match
if self.addSongFromService:
editId = self.openLyrics.xml_to_song(item.xml_version)
# Update service with correct song id
if editId != 0: if editId != 0:
Receiver.send_message(u'service_item_update', Receiver.send_message(u'service_item_update',
u'%s:%s' %(editId, uuid)) u'%s:%s' %(editId, uuid))

View File

@ -74,7 +74,8 @@ class OpenLP1SongImport(SongImport):
decoded = unicode(raw, codec) decoded = unicode(raw, codec)
self.last_encoding = codec self.last_encoding = codec
except UnicodeDecodeError: except UnicodeDecodeError:
log.exception(u'Error in detecting openlp.org 1.x database encoding.') log.exception(
u'Error in detecting openlp.org 1.x database encoding.')
try: try:
decoded = unicode(raw, self.last_encoding) decoded = unicode(raw, self.last_encoding)
except UnicodeDecodeError: except UnicodeDecodeError:
@ -152,7 +153,8 @@ class OpenLP1SongImport(SongImport):
break break
for track in tracks: for track in tracks:
if track[0] == track_id[0]: if track[0] == track_id[0]:
self.add_media_file(self.decode_string(track[1], guess)) self.add_media_file(self.decode_string(track[1],
guess))
break break
if self.stop_import_flag: if self.stop_import_flag:
success = False success = False

View File

@ -229,14 +229,16 @@ class OpenSongImport(SongImport):
# drop the square brackets # drop the square brackets
right_bracket = thisline.find(u']') right_bracket = thisline.find(u']')
content = thisline[1:right_bracket].upper() content = thisline[1:right_bracket].upper()
# have we got any digits? If so, versenumber is everything from the digits # have we got any digits?
# If so, versenumber is everything from the digits
# to the end (even if there are some alpha chars on the end) # to the end (even if there are some alpha chars on the end)
match = re.match(u'(.*)(\d+.*)', content) match = re.match(u'(.*)(\d+.*)', content)
if match is not None: if match is not None:
versetype = match.group(1) versetype = match.group(1)
versenum = match.group(2) versenum = match.group(2)
else: else:
# otherwise we assume number 1 and take the whole prefix as versetype # otherwise we assume number 1 and take the whole prefix as
# the versetype
versetype = content versetype = content
versenum = u'1' versenum = u'1'
continue continue
@ -301,6 +303,7 @@ class OpenSongImport(SongImport):
# Assume it's no.1 if there's no digits # Assume it's no.1 if there's no digits
tag = tag + u'1' tag = tag + u'1'
if not versetags.has_key(tag): if not versetags.has_key(tag):
log.info(u'Got order %s but not in versetags, dropping this item from presentation order', tag) log.info(u'Got order %s but not in versetags, dropping this'
u'item from presentation order', tag)
else: else:
self.verse_order_list.append(tag) self.verse_order_list.append(tag)

View File

@ -57,15 +57,17 @@ class SongBeamerTypes(object):
u'Unknown': u'O' u'Unknown': u'O'
} }
class SongBeamerImport(SongImport): class SongBeamerImport(SongImport):
""" """
Import Song Beamer files(s) Import Song Beamer files(s)
Song Beamer file format is text based Song Beamer file format is text based
in the beginning are one or more control tags written in the beginning are one or more control tags written
""" """
def __init__(self, master_manager, **kwargs): def __init__(self, master_manager, **kwargs):
""" """
Initialise the import. Initialise the import.
``master_manager`` ``master_manager``
The song manager for the running OpenLP installation. The song manager for the running OpenLP installation.
""" """
@ -88,6 +90,7 @@ class SongBeamerImport(SongImport):
# TODO: check that it is a valid SongBeamer file # TODO: check that it is a valid SongBeamer file
self.current_verse = u'' self.current_verse = u''
self.current_verse_type = u'V' self.current_verse_type = u'V'
read_verses = False
self.file_name = os.path.split(file)[1] self.file_name = os.path.split(file)[1]
self.import_wizard.incrementProgressBar( self.import_wizard.incrementProgressBar(
"Importing %s" % (self.file_name), 0) "Importing %s" % (self.file_name), 0)
@ -100,134 +103,182 @@ class SongBeamerImport(SongImport):
else: else:
return False return False
for line in self.songData: for line in self.songData:
line = line.strip() # Just make sure that the line is of the type 'Unicode'.
if line.startswith('#'): line = unicode(line).strip()
log.debug(u'find tag: %s' % line) if line.startswith(u'#') and not read_verses:
if not self.parse_tags(line): self.parse_tags(line)
return False elif line.startswith(u'---'):
elif line.startswith('---'): if self.current_verse:
log.debug(u'find ---') self.replace_html_tags()
if len(self.current_verse) > 0: self.add_verse(self.current_verse,
self.add_verse(self.current_verse,
self.current_verse_type) self.current_verse_type)
self.current_verse = u'' self.current_verse = u''
self.current_verse_type = u'V' self.current_verse_type = u'V'
self.read_verse = True read_verses = True
self.verse_start = True verse_start = True
elif self.read_verse: elif read_verses:
if self.verse_start: if verse_start:
self.check_verse_marks(line) verse_start = False
self.verse_start = False if not self.check_verse_marks(line):
self.current_verse = u'%s\n' % line
else: else:
self.current_verse += u'%s\n' % line self.current_verse += u'%s\n' % line
if len(self.current_verse) > 0: if self.current_verse:
self.replace_html_tags()
self.add_verse(self.current_verse, self.current_verse_type) self.add_verse(self.current_verse, self.current_verse_type)
self.finish() self.finish()
self.import_wizard.incrementProgressBar( self.import_wizard.incrementProgressBar(
"Importing %s" % (self.file_name)) "Importing %s" % (self.file_name))
return True return True
def replace_html_tags(self):
"""
This can be called to replace SongBeamer's specific (html) tags with
OpenLP's specific (html) tags.
"""
tag_pairs = [
(u'<b>', u'{st}'),
(u'</b>', u'{/st}'),
(u'<i>', u'{it}'),
(u'</i>', u'{/it}'),
(u'<u>', u'{u}'),
(u'</u>', u'{/u}'),
(u'<br>', u'{st}'),
(u'</br>', u'{st}'),
(u'</ br>', u'{st}'),
(u'<p>', u'{p}'),
(u'</p>', u'{/p}'),
(u'<super>', u'{su}'),
(u'</super>', u'{/su}'),
(u'<sub>', u'{sb}'),
(u'</sub>', u'{/sb}'),
(u'<wordwrap>', u''),
(u'</wordwrap>', u''),
(u'<strike>', u''),
(u'</strike>', u'')
]
for pair in tag_pairs:
self.current_verse = self.current_verse.replace(pair[0], pair[1])
# TODO: check for unsupported tags (see wiki) and remove them as well.
def parse_tags(self, line): def parse_tags(self, line):
tag_val = line.split('=') """
if len(tag_val[0]) == 0 or len(tag_val[1]) == 0: Parses a meta data line.
return True
if tag_val[0] == '#(c)': ``line``
The line in the file. It should consist of a tag and a value
for this tag (unicode)::
u'#Title=Nearer my God to Thee'
"""
tag_val = line.split(u'=', 1)
if len(tag_val) == 1:
return
if not tag_val[0] or not tag_val[1]:
return
if tag_val[0] == u'#(c)':
self.add_copyright(tag_val[1]) self.add_copyright(tag_val[1])
elif tag_val[0] == '#AddCopyrightInfo': elif tag_val[0] == u'#AddCopyrightInfo':
pass pass
elif tag_val[0] == '#Author': elif tag_val[0] == u'#Author':
#TODO split Authors self.parse_author(tag_val[1])
self.add_author(tag_val[1]) elif tag_val[0] == u'#BackgroundImage':
elif tag_val[0] == '#BackgroundImage':
pass pass
elif tag_val[0] == '#Bible': elif tag_val[0] == u'#Bible':
pass pass
elif tag_val[0] == '#Categories': elif tag_val[0] == u'#Categories':
self.topics = line.split(',') self.topics = line.split(',')
elif tag_val[0] == '#CCLI': elif tag_val[0] == u'#CCLI':
self.ccli_number = tag_val[1] self.ccli_number = tag_val[1]
elif tag_val[0] == '#Chords': elif tag_val[0] == u'#Chords':
pass pass
elif tag_val[0] == '#ChurchSongID': elif tag_val[0] == u'#ChurchSongID':
pass pass
elif tag_val[0] == '#ColorChords': elif tag_val[0] == u'#ColorChords':
pass pass
elif tag_val[0] == '#Comments': elif tag_val[0] == u'#Comments':
self.comments = tag_val[1] self.comments = tag_val[1]
elif tag_val[0] == '#Editor': elif tag_val[0] == u'#Editor':
pass pass
elif tag_val[0] == '#Font': elif tag_val[0] == u'#Font':
pass pass
elif tag_val[0] == '#FontLang2': elif tag_val[0] == u'#FontLang2':
pass pass
elif tag_val[0] == '#FontSize': elif tag_val[0] == u'#FontSize':
pass pass
elif tag_val[0] == '#Format': elif tag_val[0] == u'#Format':
pass pass
elif tag_val[0] == '#Format_PreLine': elif tag_val[0] == u'#Format_PreLine':
pass pass
elif tag_val[0] == '#Format_PrePage': elif tag_val[0] == u'#Format_PrePage':
pass pass
elif tag_val[0] == '#ID': elif tag_val[0] == u'#ID':
pass pass
elif tag_val[0] == '#Key': elif tag_val[0] == u'#Key':
pass pass
elif tag_val[0] == '#Keywords': elif tag_val[0] == u'#Keywords':
pass pass
elif tag_val[0] == '#LangCount': elif tag_val[0] == u'#LangCount':
pass pass
elif tag_val[0] == '#Melody': elif tag_val[0] == u'#Melody':
#TODO split Authors self.parse_author(tag_val[1])
self.add_author(tag_val[1]) elif tag_val[0] == u'#NatCopyright':
elif tag_val[0] == '#NatCopyright':
pass pass
elif tag_val[0] == '#OTitle': elif tag_val[0] == u'#OTitle':
pass pass
elif tag_val[0] == '#OutlineColor': elif tag_val[0] == u'#OutlineColor':
pass pass
elif tag_val[0] == '#OutlinedFont': elif tag_val[0] == u'#OutlinedFont':
pass pass
elif tag_val[0] == '#QuickFind': elif tag_val[0] == u'#QuickFind':
pass pass
elif tag_val[0] == '#Rights': elif tag_val[0] == u'#Rights':
song_book_pub = tag_val[1] song_book_pub = tag_val[1]
elif tag_val[0] == '#Songbook': elif tag_val[0] == u'#Songbook':
book_num = tag_val[1].split(' / ') book_num = tag_val[1].split(' / ')
self.song_book_name = book_num[0] self.song_book_name = book_num[0]
if len(book_num) == book_num[1]: if len(book_num) == book_num[1]:
self.song_number = u'' self.song_number = u''
elif tag_val[0] == '#Speed': elif tag_val[0] == u'#Speed':
pass pass
elif tag_val[0] == '#TextAlign': elif tag_val[0] == u'#TextAlign':
pass pass
elif tag_val[0] == '#Title': elif tag_val[0] == u'#Title':
self.title = u'%s' % tag_val[1] self.title = u'%s' % tag_val[1]
elif tag_val[0] == '#TitleAlign': elif tag_val[0] == u'#TitleAlign':
pass pass
elif tag_val[0] == '#TitleFontSize': elif tag_val[0] == u'#TitleFontSize':
pass pass
elif tag_val[0] == '#TitleLang2': elif tag_val[0] == u'#TitleLang2':
pass pass
elif tag_val[0] == '#TitleLang3': elif tag_val[0] == u'#TitleLang3':
pass pass
elif tag_val[0] == '#TitleLang4': elif tag_val[0] == u'#TitleLang4':
pass pass
elif tag_val[0] == '#Translation': elif tag_val[0] == u'#Translation':
pass pass
elif tag_val[0] == '#Transpose': elif tag_val[0] == u'#Transpose':
pass pass
elif tag_val[0] == '#TransposeAccidental': elif tag_val[0] == u'#TransposeAccidental':
pass pass
elif tag_val[0] == '#Version': elif tag_val[0] == u'#Version':
pass pass
else:
pass
return True
def check_verse_marks(self, line): def check_verse_marks(self, line):
marks = line.split(' ') """
Check and add the verse's MarkType. Returns ``True`` if the given line
contains a correct verse mark otherwise ``False``.
``line``
The line to check for marks (unicode).
"""
marks = line.split(u' ')
if len(marks) <= 2 and marks[0] in SongBeamerTypes.MarkTypes: if len(marks) <= 2 and marks[0] in SongBeamerTypes.MarkTypes:
self.current_verse_type = SongBeamerTypes.MarkTypes[marks[0]] self.current_verse_type = SongBeamerTypes.MarkTypes[marks[0]]
if len(marks) == 2: if len(marks) == 2:
#TODO: may check, because of only digits are allowed # If we have a digit, we append it to current_verse_type.
self.current_verse_type += marks[1] if marks[1].isdigit():
self.current_verse_type += marks[1]
return True
else:
return False

View File

@ -47,8 +47,9 @@ class SongImport(QtCore.QObject):
""" """
Initialise and create defaults for properties Initialise and create defaults for properties
song_manager is an instance of a SongManager, through which all ``manager``
database access is performed An instance of a SongManager, through which all database access is
performed.
""" """
self.manager = manager self.manager = manager
self.stop_import_flag = False self.stop_import_flag = False
@ -253,7 +254,8 @@ class SongImport(QtCore.QObject):
All fields have been set to this song. Write it away All fields have been set to this song. Write it away
""" """
if not self.authors: if not self.authors:
self.authors.append(u'Author unknown') self.authors.append(unicode(translate('SongsPlugin.SongImport',
'Author unknown')))
self.commit_song() self.commit_song()
def commit_song(self): def commit_song(self):
@ -296,7 +298,8 @@ class SongImport(QtCore.QObject):
song.lyrics = unicode(sxml.extract_xml(), u'utf-8') song.lyrics = unicode(sxml.extract_xml(), u'utf-8')
for i, current_verse_tag in enumerate(self.verse_order_list): for i, current_verse_tag in enumerate(self.verse_order_list):
if verses_changed_to_other.has_key(current_verse_tag): if verses_changed_to_other.has_key(current_verse_tag):
self.verse_order_list[i] = verses_changed_to_other[current_verse_tag] self.verse_order_list[i] = \
verses_changed_to_other[current_verse_tag]
song.verse_order = u' '.join(self.verse_order_list) song.verse_order = u' '.join(self.verse_order_list)
song.copyright = self.copyright song.copyright = self.copyright
song.comments = self.comments song.comments = self.comments

View File

@ -56,8 +56,10 @@ class SongsTab(SettingsTab):
self.SongUpdateOnEditCheckBox = QtGui.QCheckBox(self.SongsModeGroupBox) self.SongUpdateOnEditCheckBox = QtGui.QCheckBox(self.SongsModeGroupBox)
self.SongUpdateOnEditCheckBox.setObjectName(u'SongUpdateOnEditCheckBox') self.SongUpdateOnEditCheckBox.setObjectName(u'SongUpdateOnEditCheckBox')
self.SongsModeLayout.addWidget(self.SongUpdateOnEditCheckBox) self.SongsModeLayout.addWidget(self.SongUpdateOnEditCheckBox)
self.SongAddFromServiceCheckBox = QtGui.QCheckBox(self.SongsModeGroupBox) self.SongAddFromServiceCheckBox = QtGui.QCheckBox(
self.SongAddFromServiceCheckBox.setObjectName(u'SongAddFromServiceCheckBox') self.SongsModeGroupBox)
self.SongAddFromServiceCheckBox.setObjectName(
u'SongAddFromServiceCheckBox')
self.SongsModeLayout.addWidget(self.SongAddFromServiceCheckBox) self.SongsModeLayout.addWidget(self.SongAddFromServiceCheckBox)
self.SongsLayout.setWidget( self.SongsLayout.setWidget(
0, QtGui.QFormLayout.LabelRole, self.SongsModeGroupBox) 0, QtGui.QFormLayout.LabelRole, self.SongsModeGroupBox)
@ -83,7 +85,8 @@ class SongsTab(SettingsTab):
'Display verses on live tool bar')) 'Display verses on live tool bar'))
self.SongUpdateOnEditCheckBox.setText( self.SongUpdateOnEditCheckBox.setText(
translate('SongsPlugin.SongsTab', 'Update service from song edit')) translate('SongsPlugin.SongsTab', 'Update service from song edit'))
self.SongAddFromServiceCheckBox.setText(translate('SongsPlugin.SongsTab', self.SongAddFromServiceCheckBox.setText(
translate('SongsPlugin.SongsTab',
'Add missing songs when opening service')) 'Add missing songs when opening service'))
def onSearchAsTypeCheckBoxChanged(self, check_state): def onSearchAsTypeCheckBoxChanged(self, check_state):
@ -132,6 +135,8 @@ class SongsTab(SettingsTab):
settings.beginGroup(self.settingsSection) settings.beginGroup(self.settingsSection)
settings.setValue(u'search as type', QtCore.QVariant(self.song_search)) settings.setValue(u'search as type', QtCore.QVariant(self.song_search))
settings.setValue(u'display songbar', QtCore.QVariant(self.song_bar)) settings.setValue(u'display songbar', QtCore.QVariant(self.song_bar))
settings.setValue(u'update service on edit', QtCore.QVariant(self.update_edit)) settings.setValue(u'update service on edit',
settings.setValue(u'add song from service', QtCore.QVariant(self.update_load)) QtCore.QVariant(self.update_edit))
settings.setValue(u'add song from service',
QtCore.QVariant(self.update_load))
settings.endGroup() settings.endGroup()

View File

@ -39,8 +39,11 @@ The basic XML is of the format::
""" """
import logging import logging
import re
from lxml import etree, objectify from lxml import etree, objectify
from openlp.plugins.songs.lib import VerseType
from openlp.plugins.songs.lib.db import Author, Song
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -77,7 +80,6 @@ class SongXMLBuilder(object):
``content`` ``content``
The actual text of the verse to be stored. The actual text of the verse to be stored.
""" """
# log.debug(u'add_verse_to_lyrics %s, %s\n%s' % (type, number, content))
verse = etree.Element(u'verse', type = unicode(type), verse = etree.Element(u'verse', type = unicode(type),
label = unicode(number)) label = unicode(number))
verse.text = etree.CDATA(content) verse.text = etree.CDATA(content)
@ -239,3 +241,153 @@ class LyricsXML(object):
song_output = u'<?xml version="1.0" encoding="UTF-8"?>' + \ song_output = u'<?xml version="1.0" encoding="UTF-8"?>' + \
u'<song version="1.0">%s</song>' % lyrics_output u'<song version="1.0">%s</song>' % lyrics_output
return song_output return song_output
class OpenLyricsParser(object):
"""
This class represents the converter for Song to/from OpenLyrics XML.
"""
def __init__(self, manager):
self.manager = manager
def song_to_xml(self, song):
"""
Convert the song to OpenLyrics Format
"""
song_xml_parser = SongXMLParser(song.lyrics)
verse_list = song_xml_parser.get_verses()
song_xml = objectify.fromstring(
u'<song version="0.7" createdIn="OpenLP 2.0"/>')
properties = etree.SubElement(song_xml, u'properties')
titles = etree.SubElement(properties, u'titles')
self._add_text_to_element(u'title', titles, song.title)
if song.alternate_title:
self._add_text_to_element(u'title', titles, song.alternate_title)
if song.theme_name:
themes = etree.SubElement(properties, u'themes')
self._add_text_to_element(u'theme', themes, song.theme_name)
self._add_text_to_element(u'copyright', properties, song.copyright)
self._add_text_to_element(u'verseOrder', properties, song.verse_order)
if song.ccli_number:
self._add_text_to_element(u'ccliNo', properties, song.ccli_number)
authors = etree.SubElement(properties, u'authors')
for author in song.authors:
self._add_text_to_element(u'author', authors, author.display_name)
lyrics = etree.SubElement(song_xml, u'lyrics')
for verse in verse_list:
verse_tag = u'%s%s' % (
verse[0][u'type'][0].lower(), verse[0][u'label'])
element = \
self._add_text_to_element(u'verse', lyrics, None, verse_tag)
element = self._add_text_to_element(u'lines', element)
for line in unicode(verse[1]).split(u'\n'):
self._add_text_to_element(u'line', element, line)
return self._extract_xml(song_xml)
def xml_to_song(self, xml):
"""
Create a Song from OpenLyrics format xml
"""
# No xml get out of here
if not xml:
return 0
song = Song()
if xml[:5] == u'<?xml':
xml = xml[38:]
song_xml = objectify.fromstring(xml)
properties = song_xml.properties
song.copyright = unicode(properties.copyright.text)
song.verse_order = unicode(properties.verseOrder.text)
if song.verse_order == u'None':
song.verse_order = u''
song.topics = []
song.book = None
theme_name = None
try:
song.ccli_number = unicode(properties.ccliNo.text)
except:
song.ccli_number = u''
try:
theme_name = unicode(properties.themes.theme)
except:
pass
if theme_name:
song.theme_name = theme_name
else:
song.theme_name = u''
# Process Titles
for title in properties.titles.title:
if not song.title:
song.title = unicode(title.text)
song.search_title = unicode(song.title)
song.alternate_title = u''
else:
song.alternate_title = unicode(title.text)
song.search_title += u'@' + song.alternate_title
song.search_title = re.sub(r'[\'"`,;:(){}?]+', u'',
unicode(song.search_title)).lower()
# Process Lyrics
sxml = SongXMLBuilder()
search_text = u''
for lyrics in song_xml.lyrics:
for verse in song_xml.lyrics.verse:
text = u''
for line in verse.lines.line:
line = unicode(line)
if not text:
text = line
else:
text += u'\n' + line
type = VerseType.expand_string(verse.attrib[u'name'][0])
sxml.add_verse_to_lyrics(type, verse.attrib[u'name'][1], text)
search_text = search_text + text
song.search_lyrics = search_text.lower()
song.lyrics = unicode(sxml.extract_xml(), u'utf-8')
song.comments = u''
song.song_number = u''
# Process Authors
for author in properties.authors.author:
self._process_author(author.text, song)
self.manager.save_object(song)
return song.id
def _add_text_to_element(self, tag, parent, text=None, label=None):
if label:
element = etree.Element(tag, name = unicode(label))
else:
element = etree.Element(tag)
if text:
element.text = unicode(text)
parent.append(element)
return element
def _dump_xml(self, xml):
"""
Debugging aid to dump XML so that we can see what we have.
"""
return etree.tostring(xml, encoding=u'UTF-8',
xml_declaration=True, pretty_print=True)
def _extract_xml(self, xml):
"""
Extract our newly created XML song.
"""
return etree.tostring(xml, encoding=u'UTF-8',
xml_declaration=True)
def _process_author(self, name, song):
"""
Find or create an Author from display_name.
"""
name = unicode(name)
author = self.manager.get_object_filtered(Author,
Author.display_name == name)
if author:
# should only be one! so take the first
song.authors.append(author)
else:
# Need a new author
new_author = Author.populate(first_name=name.rsplit(u' ', 1)[0],
last_name=name.rsplit(u' ', 1)[1], display_name=name)
self.manager.save_object(new_author)
song.authors.append(new_author)

View File

@ -25,6 +25,7 @@
############################################################################### ###############################################################################
import logging import logging
import re
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
@ -55,6 +56,7 @@ class SongsPlugin(Plugin):
self.manager = Manager(u'songs', init_schema) self.manager = Manager(u'songs', init_schema)
self.icon_path = u':/plugins/plugin_songs.png' self.icon_path = u':/plugins/plugin_songs.png'
self.icon = build_icon(self.icon_path) self.icon = build_icon(self.icon_path)
self.whitespace = re.compile(r'\W+')
def getSettingsTab(self): def getSettingsTab(self):
visible_name = self.getString(StringContent.VisibleName) visible_name = self.getString(StringContent.VisibleName)
@ -63,6 +65,7 @@ class SongsPlugin(Plugin):
def initialise(self): def initialise(self):
log.info(u'Songs Initialising') log.info(u'Songs Initialising')
Plugin.initialise(self) Plugin.initialise(self)
self.toolsReindexItem.setVisible(True)
self.mediaItem.displayResultsSong( self.mediaItem.displayResultsSong(
self.manager.get_all_objects(Song, order_by_ref=Song.search_title)) self.manager.get_all_objects(Song, order_by_ref=Song.search_title))
@ -106,6 +109,57 @@ class SongsPlugin(Plugin):
# No menu items for now. # No menu items for now.
pass pass
def addToolsMenuItem(self, tools_menu):
"""
Give the alerts plugin the opportunity to add items to the
**Tools** menu.
``tools_menu``
The actual **Tools** menu item, so that your actions can
use it as their parent.
"""
log.info(u'add tools menu')
self.toolsReindexItem = QtGui.QAction(tools_menu)
self.toolsReindexItem.setIcon(build_icon(u':/plugins/plugin_songs.png'))
self.toolsReindexItem.setObjectName(u'toolsReindexItem')
self.toolsReindexItem.setText(
translate('SongsPlugin', '&Re-index Songs'))
self.toolsReindexItem.setStatusTip(
translate('SongsPlugin', 'Re-index the songs database to improve '
'searching and ordering.'))
tools_menu.addAction(self.toolsReindexItem)
QtCore.QObject.connect(self.toolsReindexItem,
QtCore.SIGNAL(u'triggered()'), self.onToolsReindexItemTriggered)
self.toolsReindexItem.setVisible(False)
def onToolsReindexItemTriggered(self):
"""
Rebuild the search title of each song.
"""
maxSongs = self.manager.get_object_count(Song)
progressDialog = QtGui.QProgressDialog(
translate('SongsPlugin', 'Reindexing songs...'),
translate('SongsPlugin', 'Cancel'),
0, maxSongs + 1, self.formparent)
progressDialog.setWindowModality(QtCore.Qt.WindowModal)
songs = self.manager.get_all_objects(Song)
counter = 0
for song in songs:
counter += 1
if song.title is None:
song.title = u''
if song.alternate_title is None:
song.alternate_title = u''
song.search_title = self.whitespace.sub(u' ', \
song.title.lower()) + u' ' + \
self.whitespace.sub(u' ', song.alternate_title.lower())
progressDialog.setValue(counter)
self.manager.save_objects(songs)
counter += 1
progressDialog.setValue(counter)
self.mediaItem.displayResultsSong(
self.manager.get_all_objects(Song, order_by_ref=Song.search_title))
def onSongImportItemClicked(self): def onSongImportItemClicked(self):
if self.mediaItem: if self.mediaItem:
self.mediaItem.onImportClick() self.mediaItem.onImportClick()
@ -206,4 +260,6 @@ class SongsPlugin(Plugin):
""" """
log.info(u'Songs Finalising') log.info(u'Songs Finalising')
self.manager.finalise() self.manager.finalise()
self.toolsReindexItem.setVisible(False)
Plugin.finalise(self) Plugin.finalise(self)

View File

@ -34,11 +34,11 @@ class SongUsageDeleteForm(QtGui.QDialog, Ui_SongUsageDeleteDialog):
""" """
Class documentation goes here. Class documentation goes here.
""" """
def __init__(self, songusagemanager, parent): def __init__(self, manager, parent):
""" """
Constructor Constructor
""" """
self.songusagemanager = songusagemanager self.manager = manager
QtGui.QDialog.__init__(self, parent) QtGui.QDialog.__init__(self, parent)
self.setupUi(self) self.setupUi(self)
@ -53,6 +53,6 @@ class SongUsageDeleteForm(QtGui.QDialog, Ui_SongUsageDeleteDialog):
QtGui.QMessageBox.Cancel) QtGui.QMessageBox.Cancel)
if ret == QtGui.QMessageBox.Ok: if ret == QtGui.QMessageBox.Ok:
deleteDate = self.deleteCalendar.selectedDate().toPyDate() deleteDate = self.deleteCalendar.selectedDate().toPyDate()
self.songusagemanager.delete_all_objects(SongUsageItem, self.manager.delete_all_objects(SongUsageItem,
SongUsageItem.usagedate <= deleteDate) SongUsageItem.usagedate <= deleteDate)
self.close() self.close()

View File

@ -76,7 +76,7 @@ class SongUsageDetailForm(QtGui.QDialog, Ui_SongUsageDetailDialog):
filename = u'usage_detail_%s_%s.txt' % ( filename = u'usage_detail_%s_%s.txt' % (
self.fromDate.selectedDate().toString(u'ddMMyyyy'), self.fromDate.selectedDate().toString(u'ddMMyyyy'),
self.toDate.selectedDate().toString(u'ddMMyyyy')) self.toDate.selectedDate().toString(u'ddMMyyyy'))
usage = self.plugin.songusagemanager.get_all_objects( usage = self.plugin.manager.get_all_objects(
SongUsageItem, and_( SongUsageItem, and_(
SongUsageItem.usagedate >= self.fromDate.selectedDate().toPyDate(), SongUsageItem.usagedate >= self.fromDate.selectedDate().toPyDate(),
SongUsageItem.usagedate < self.toDate.selectedDate().toPyDate()), SongUsageItem.usagedate < self.toDate.selectedDate().toPyDate()),

View File

@ -29,7 +29,8 @@ from datetime import datetime
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import Plugin, StringContent, Receiver, build_icon, translate from openlp.core.lib import Plugin, StringContent, Receiver, build_icon, \
translate
from openlp.core.lib.db import Manager from openlp.core.lib.db import Manager
from openlp.plugins.songusage.forms import SongUsageDetailForm, \ from openlp.plugins.songusage.forms import SongUsageDetailForm, \
SongUsageDeleteForm SongUsageDeleteForm
@ -44,7 +45,7 @@ class SongUsagePlugin(Plugin):
Plugin.__init__(self, u'SongUsage', u'1.9.3', plugin_helpers) Plugin.__init__(self, u'SongUsage', u'1.9.3', plugin_helpers)
self.weight = -4 self.weight = -4
self.icon = build_icon(u':/plugins/plugin_songusage.png') self.icon = build_icon(u':/plugins/plugin_songusage.png')
self.songusagemanager = None self.manager = None
self.songusageActive = False self.songusageActive = False
def addToolsMenuItem(self, tools_menu): def addToolsMenuItem(self, tools_menu):
@ -115,15 +116,20 @@ class SongUsagePlugin(Plugin):
self.settingsSection + u'/active', self.settingsSection + u'/active',
QtCore.QVariant(False)).toBool() QtCore.QVariant(False)).toBool()
self.SongUsageStatus.setChecked(self.SongUsageActive) self.SongUsageStatus.setChecked(self.SongUsageActive)
if self.songusagemanager is None: if self.manager is None:
self.songusagemanager = Manager(u'songusage', init_schema) self.manager = Manager(u'songusage', init_schema)
self.SongUsagedeleteform = SongUsageDeleteForm(self.songusagemanager, self.SongUsagedeleteform = SongUsageDeleteForm(self.manager,
self.formparent) self.formparent)
self.SongUsagedetailform = SongUsageDetailForm(self, self.formparent) self.SongUsagedetailform = SongUsageDetailForm(self, self.formparent)
self.SongUsageMenu.menuAction().setVisible(True) self.SongUsageMenu.menuAction().setVisible(True)
def finalise(self): def finalise(self):
"""
Tidy up on exit
"""
log.info(u'Plugin Finalise') log.info(u'Plugin Finalise')
self.manager.finalise()
Plugin.finalise(self)
self.SongUsageMenu.menuAction().setVisible(False) self.SongUsageMenu.menuAction().setVisible(False)
#stop any events being processed #stop any events being processed
self.SongUsageActive = False self.SongUsageActive = False
@ -148,7 +154,7 @@ class SongUsagePlugin(Plugin):
song_usage_item.authors = u'' song_usage_item.authors = u''
for author in audit[1]: for author in audit[1]:
song_usage_item.authors += author + u' ' song_usage_item.authors += author + u' '
self.songusagemanager.save_object(song_usage_item) self.manager.save_object(song_usage_item)
def onSongUsageDelete(self): def onSongUsageDelete(self):
self.SongUsagedeleteform.exec_() self.SongUsagedeleteform.exec_()
@ -176,11 +182,3 @@ class SongUsagePlugin(Plugin):
self.textStrings[StringContent.VisibleName] = { self.textStrings[StringContent.VisibleName] = {
u'title': translate('SongUsagePlugin', 'SongUsage') u'title': translate('SongUsagePlugin', 'SongUsage')
} }
def finalise(self):
"""
Time to tidy up on exit
"""
log.info(u'SongUsage Finalising')
self.manager.finalise()
Plugin.finalise(self)

View File

@ -1,73 +0,0 @@
[bibles]
display new chapter = False
display brackets = 0
dual bibles = False
db type = sqlite
bible theme =
verse layout style = 1
status = 1
data path = bibles
[media]
status = 1
[alerts]
font color = #ffffff
background color = #660000
font face = Sans Serif
timeout = 5
[remotes]
remote port = 4316
[presentations]
status = 1
impress = 0
data path = presentations
powerpoint = 0
powerpoint viewer = 0
[custom]
status = 1
display footer = True
data path = custom
db type = sqlite
[themes]
global theme =
data path = themes
theme level = 1
[images]
status = 1
data path = images
loop delay = 5
[user interface]
theme manager = True
media manager = True
preview panel = True
service manager = True
[servicemanager]
data path = servicemanager
[general]
monitor = 0
run environment = dev
ccli number =
blank warning = False
show splash = True
last version test = 2010-02-05
songselect username =
save prompt = False
songselect password =
auto open = False
[songs]
status = 1
search as type = False
display songbar = True
data path = songs
db type = sqlite

Binary file not shown.

Before

Width:  |  Height:  |  Size: 343 KiB

View File

@ -1,2 +0,0 @@
<?xml version="1.0" ?>
<theme version="1.0"><name>Bible Readings</name><background mode="opaque" type="image"><filename>open6_2.jpg</filename></background><font type="main"><name>Arial</name><color>#ffffff</color><proportion>40</proportion><proportion>40</proportion><location override="False"/></font><font type="footer"><name>Arial</name><color>#ffffff</color><proportion>12</proportion><proportion>12</proportion><location override="False"/></font><display><shadow color="#000000">False</shadow><outline color="#000000">False</outline><horizontalAlign>2</horizontalAlign><verticalAlign>1</verticalAlign><wrapStyle>0</wrapStyle></display></theme>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

View File

@ -1,64 +0,0 @@
<?xml version="1.0" ?>
<theme version="1.0">
<name>
Blue
</name>
<background mode="opaque" type="solid">
<color>
#0000ff
</color>
</background>
<font type="main">
<name>
DejaVu Sans Mono
</name>
<color>
#ffff00
</color>
<proportion>
45
</proportion>
<weight>
Normal
</weight>
<italics>
False
</italics>
<location override="False"/>
</font>
<font type="footer">
<name>
DejaVu Sans Mono
</name>
<color>
#ffff00
</color>
<proportion>
12
</proportion>
<weight>
Normal
</weight>
<italics>
False
</italics>
<location override="False"/>
</font>
<display>
<shadow color="#000000">
False
</shadow>
<outline color="#000000">
False
</outline>
<horizontalAlign>
0
</horizontalAlign>
<verticalAlign>
1
</verticalAlign>
<wrapStyle>
0
</wrapStyle>
</display>
</theme>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

View File

@ -1,64 +0,0 @@
<?xml version="1.0" ?>
<theme version="1.0">
<name>
theme1
</name>
<background mode="opaque" type="solid">
<color>
#400080
</color>
</background>
<font type="main">
<name>
Tahoma
</name>
<color>
#0080ff
</color>
<proportion>
45
</proportion>
<weight>
Normal
</weight>
<italics>
False
</italics>
<location override="False"/>
</font>
<font type="footer">
<name>
Tahoma
</name>
<color>
#0080ff
</color>
<proportion>
12
</proportion>
<weight>
Normal
</weight>
<italics>
False
</italics>
<location override="False"/>
</font>
<display>
<shadow color="#000000">
False
</shadow>
<outline color="#000000">
False
</outline>
<horizontalAlign>
0
</horizontalAlign>
<verticalAlign>
0
</verticalAlign>
<wrapStyle>
0
</wrapStyle>
</display>
</theme>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

View File

@ -1,70 +0,0 @@
<?xml version="1.0" ?>
<theme version="1.0">
<name>
theme2
</name>
<background mode="opaque" type="gradient">
<startColor>
#ff8000
</startColor>
<endColor>
#0000ff
</endColor>
<direction>
vertical
</direction>
</background>
<font type="main">
<name>
Tahoma
</name>
<color>
#ffffff
</color>
<proportion>
45
</proportion>
<weight>
Normal
</weight>
<italics>
False
</italics>
<location override="False"/>
</font>
<font type="footer">
<name>
Tahoma
</name>
<color>
#ffffff
</color>
<proportion>
12
</proportion>
<weight>
Normal
</weight>
<italics>
False
</italics>
<location override="False"/>
</font>
<display>
<shadow color="#000000">
True
</shadow>
<outline color="#000000">
True
</outline>
<horizontalAlign>
0
</horizontalAlign>
<verticalAlign>
0
</verticalAlign>
<wrapStyle>
0
</wrapStyle>
</display>
</theme>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 462 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

View File

@ -1,2 +0,0 @@
<?xml version="1.0" ?>
<theme version="1.0"><name>theme3</name><background mode="opaque" type="image"><filename>sunset2.jpg</filename></background><font type="main"><name>DejaVu Sans Mono</name><color>#ffff00</color><proportion>32</proportion><weight>Normal</weight><italics>False</italics><location override="False"/></font><font type="footer"><name>DejaVu Sans Mono</name><color>#ffff00</color><proportion>12</proportion><weight>Normal</weight><italics>False</italics><location override="False"/></font><display><shadow color="#000000">False</shadow><outline color="#000000">False</outline><horizontalAlign>1</horizontalAlign><verticalAlign>2</verticalAlign><wrapStyle>0</wrapStyle></display></theme>

View File

@ -1,23 +0,0 @@
[custom]
db type = sqlite
[bibles]
db type = sqlite
[main]
themes path = themes
data path = /home/raoul/.openlp/data
[songs]
db type = sqlite
file name = songs.sqlite
data path = songs
[presentations]
suffix name = ppt,pps,odi
[images]
suffix name = jpg,gif,png,bmp
[videos]
suffix name = avi,mpeg

View File

@ -1,24 +0,0 @@
[custom]
db type = sqlite
[bibles]
db type = sqlite
[main]
themes path = themes
data path = /home/<username>/.openlp/data
[songs]
file name = songs.sqlite
data path = songs
db type = sqlite
[presentations]
suffix name = ppt,pps,odi
[images]
suffix name = jpg,gif,png,bmp
[videos]
suffix name = avi,mpeg

View File

@ -1,23 +0,0 @@
[custom]
db type = sqlite
[bibles]
db type = sqlite
[main]
themes path = themes
data path = c:\\Documents and Settings\\<username>\\Application Data\\.openlp\\data
[songs]
file name = songs.sqlite
data path = songs
db type = sqlite
[presentations]
suffix name = ppt,pps,odi
[images]
suffix name = jpg,gif,png,bmp
[videos]
suffix name = avi,mpeg

File diff suppressed because it is too large Load Diff

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