1
# -*- coding: utf-8 -*-
2
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
4
###############################################################################
5
# OpenLP - Open Source Lyrics Projection #
6
# --------------------------------------------------------------------------- #
7
# Copyright (c) 2008-2012 Raoul Snyman #
8
# Portions copyright (c) 2008-2012 Tim Bentley, Gerald Britton, Jonathan #
9
# Corwin, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, #
10
# Armin Kƶhler, Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias #
11
# PƵldaru, Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
12
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund #
13
# --------------------------------------------------------------------------- #
14
# This program is free software; you can redistribute it and/or modify it #
15
# under the terms of the GNU General Public License as published by the Free #
16
# Software Foundation; version 2 of the License. #
18
# This program is distributed in the hope that it will be useful, but WITHOUT #
19
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
20
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
23
# You should have received a copy of the GNU General Public License along #
24
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
25
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
26
###############################################################################
28
The :mod:`serviceitem` provides the service item functionality including the
29
type and capability of an item.
38
from openlp.core.lib import build_icon, clean_tags, expand_tags, translate
40
log = logging.getLogger(__name__)
42
class ServiceItemType(object):
44
Defines the type of service item
51
class ItemCapabilities(object):
53
Provides an enumeration of a serviceitem's capabilities
64
ProvidesOwnDisplay = 10
65
HasDetailedTitleDisplay = 11
66
HasVariableStartTime = 12
69
HasBackgroundAudio = 15
72
class ServiceItem(object):
74
The service item is a base class for the plugins to use to interact with
75
the service manager, the slide controller, and the projection screen
78
log.info(u'Service Item created')
80
def __init__(self, plugin=None):
82
Set up the service item.
85
The plugin that this service item belongs to.
88
self.renderer = plugin.renderer
89
self.name = plugin.name
94
self.iconic_representation = None
98
self.service_item_type = None
100
self._display_frames = []
103
self.from_plugin = False
104
self.capabilities = []
107
self.themedata = None
110
self.bg_image_bytes = None
111
self.search_string = u''
112
self.data_string = u''
114
self.xml_version = None
117
self.media_length = 0
118
self.from_service = False
119
self.image_border = u'#000000'
120
self.background_audio = []
121
self.theme_overwritten = False
122
self.temporary_edit = False
127
Method to set the internal id of the item. This is used to compare
128
service items to see if they are the same.
130
self._uuid = unicode(uuid.uuid1())
132
def add_capability(self, capability):
134
Add an ItemCapability to a ServiceItem
137
The capability to add
139
self.capabilities.append(capability)
141
def is_capable(self, capability):
143
Tell the caller if a ServiceItem has a capability
146
The capability to test for
148
return capability in self.capabilities
150
def add_icon(self, icon):
152
Add an icon to the service item. This is used when displaying the
153
service item in the service manager.
156
A string to an icon in the resources or on disk.
159
self.iconic_representation = build_icon(icon)
161
def render(self, use_override=False):
163
The render method is what generates the frames for the screen and
164
obtains the display information from the renderer. At this point all
165
slides are built for the given display size.
167
log.debug(u'Render called')
168
self._display_frames = []
169
self.bg_image_bytes = None
170
theme = self.theme if self.theme else None
171
self.main, self.footer = \
172
self.renderer.set_override_theme(theme, use_override)
173
self.themedata = self.renderer.theme_data
174
if self.service_item_type == ServiceItemType.Text:
175
log.debug(u'Formatting slides')
176
for slide in self._raw_frames:
177
pages = self.renderer.format_slide(slide[u'raw_slide'], self)
179
page = page.replace(u'<br>', u'{br}')
180
html = expand_tags(cgi.escape(page.rstrip()))
181
self._display_frames.append({
182
u'title': clean_tags(page),
183
u'text': clean_tags(page.rstrip()),
184
u'html': html.replace(u'&nbsp;', u' '),
185
u'verseTag': slide[u'verseTag']
187
elif self.service_item_type == ServiceItemType.Image or \
188
self.service_item_type == ServiceItemType.Command:
191
log.error(u'Invalid value renderer: %s' % self.service_item_type)
192
self.title = clean_tags(self.title)
193
# The footer should never be None, but to be compatible with a few
194
# nightly builds between 1.9.4 and 1.9.5, we have to correct this to
196
if self.raw_footer is None:
199
u'<br>'.join([footer for footer in self.raw_footer if footer])
201
def add_from_image(self, path, title, background=None):
203
Add an image slide to the service item.
206
The directory in which the image file is located.
209
A title for the slide in the service item.
212
self.image_border = background
213
self.service_item_type = ServiceItemType.Image
214
self._raw_frames.append({u'title': title, u'path': path})
215
self.renderer.imageManager.add_image(title, path, u'image',
219
def add_from_text(self, title, raw_slide, verse_tag=None):
221
Add a text slide to the service item.
224
The title of the slide in the service item.
227
The raw text of the slide.
230
verse_tag = verse_tag.upper()
231
self.service_item_type = ServiceItemType.Text
232
title = title.split(u'\n')[0]
233
self._raw_frames.append(
234
{u'title': title, u'raw_slide': raw_slide, u'verseTag': verse_tag})
237
def add_from_command(self, path, file_name, image):
239
Add a slide from a command.
242
The title of the slide in the service item.
245
The title of the slide in the service item.
248
The command of/for the slide.
250
self.service_item_type = ServiceItemType.Command
251
self._raw_frames.append(
252
{u'title': file_name, u'image': image, u'path': path})
255
def get_service_repr(self):
257
This method returns some text which can be saved into the service
258
file to represent this item.
262
u'plugin': self.name,
263
u'theme': self.theme,
264
u'title': self.title,
266
u'footer': self.raw_footer,
267
u'type': self.service_item_type,
268
u'audit': self.audit,
269
u'notes': self.notes,
270
u'from_plugin': self.from_plugin,
271
u'capabilities': self.capabilities,
272
u'search': self.search_string,
273
u'data': self.data_string,
274
u'xml_version': self.xml_version,
275
u'start_time': self.start_time,
276
u'end_time': self.end_time,
277
u'media_length': self.media_length,
278
u'background_audio': self.background_audio,
279
u'theme_overwritten': self.theme_overwritten
282
if self.service_item_type == ServiceItemType.Text:
283
service_data = [slide for slide in self._raw_frames]
284
elif self.service_item_type == ServiceItemType.Image:
285
service_data = [slide[u'title'] for slide in self._raw_frames]
286
elif self.service_item_type == ServiceItemType.Command:
287
for slide in self._raw_frames:
289
{u'title': slide[u'title'], u'image': slide[u'image']})
290
return {u'header': service_header, u'data': service_data}
292
def set_from_service(self, serviceitem, path=None):
294
This method takes a service item from a saved service file (passed
295
from the ServiceManager) and extracts the data actually required.
298
The item to extract data from.
301
Defaults to *None*. Any path data, usually for images.
303
log.debug(u'set_from_service called with path %s' % path)
304
header = serviceitem[u'serviceitem'][u'header']
305
self.title = header[u'title']
306
self.name = header[u'name']
307
self.service_item_type = header[u'type']
308
self.shortname = header[u'plugin']
309
self.theme = header[u'theme']
310
self.add_icon(header[u'icon'])
311
self.raw_footer = header[u'footer']
312
self.audit = header[u'audit']
313
self.notes = header[u'notes']
314
self.from_plugin = header[u'from_plugin']
315
self.capabilities = header[u'capabilities']
316
# Added later so may not be present in older services.
317
if u'search' in header:
318
self.search_string = header[u'search']
319
self.data_string = header[u'data']
320
if u'xml_version' in header:
321
self.xml_version = header[u'xml_version']
322
if u'start_time' in header:
323
self.start_time = header[u'start_time']
324
if u'end_time' in header:
325
self.end_time = header[u'end_time']
326
if u'media_length' in header:
327
self.media_length = header[u'media_length']
328
if u'background_audio' in header:
329
self.background_audio = []
330
for filename in header[u'background_audio']:
331
# Give them real file paths
332
self.background_audio.append(os.path.join(path, filename))
333
self.theme_overwritten = header.get(u'theme_overwritten', False)
334
if self.service_item_type == ServiceItemType.Text:
335
for slide in serviceitem[u'serviceitem'][u'data']:
336
self._raw_frames.append(slide)
337
elif self.service_item_type == ServiceItemType.Image:
338
for text_image in serviceitem[u'serviceitem'][u'data']:
339
filename = os.path.join(path, text_image)
340
self.add_from_image(filename, text_image)
341
elif self.service_item_type == ServiceItemType.Command:
342
for text_image in serviceitem[u'serviceitem'][u'data']:
343
filename = os.path.join(path, text_image[u'title'])
344
self.add_from_command(
345
path, text_image[u'title'], text_image[u'image'])
348
def get_display_title(self):
350
Returns the title of the service item.
355
if ItemCapabilities.HasDetailedTitleDisplay in self.capabilities:
356
return self._raw_frames[0][u'title']
357
elif len(self._raw_frames) > 1:
360
return self._raw_frames[0][u'title']
362
def merge(self, other):
364
Updates the _uuid with the value from the original one
365
The _uuid is unique for a given service item but this allows one to
366
replace an original version.
369
The service item to be merged with
371
self._uuid = other._uuid
372
self.notes = other.notes
373
self.temporary_edit = other.temporary_edit
374
# Copy theme over if present.
375
if other.theme is not None:
376
self.theme = other.theme
379
if self.is_capable(ItemCapabilities.HasBackgroundAudio):
380
log.debug(self.background_audio)
382
def __eq__(self, other):
384
Confirms the service items are for the same instance
388
return self._uuid == other._uuid
390
def __ne__(self, other):
392
Confirms the service items are not for the same instance
394
return self._uuid != other._uuid
398
Confirms if the ServiceItem is media
400
return ItemCapabilities.RequiresMedia in self.capabilities
402
def is_command(self):
404
Confirms if the ServiceItem is a command
406
return self.service_item_type == ServiceItemType.Command
410
Confirms if the ServiceItem is an image
412
return self.service_item_type == ServiceItemType.Image
416
Confirms if the ServiceItem uses a file
418
return self.service_item_type == ServiceItemType.Image or \
419
self.service_item_type == ServiceItemType.Command
423
Confirms if the ServiceItem is text
425
return self.service_item_type == ServiceItemType.Text
427
def get_frames(self):
429
Returns the frames for the ServiceItem
431
if self.service_item_type == ServiceItemType.Text:
432
return self._display_frames
434
return self._raw_frames
436
def get_rendered_frame(self, row):
438
Returns the correct frame for a given list and
439
renders it if required.
441
if self.service_item_type == ServiceItemType.Text:
442
return self._display_frames[row][u'html'].split(u'\n')[0]
443
elif self.service_item_type == ServiceItemType.Image:
444
return self._raw_frames[row][u'title']
446
return self._raw_frames[row][u'image']
448
def get_frame_title(self, row=0):
450
Returns the title of the raw frame
453
return self._raw_frames[row][u'title']
457
def get_frame_path(self, row=0):
459
Returns the path of the raw frame
462
return self._raw_frames[row][u'path']
466
def get_media_time(self):
468
Returns the start and finish time for a media item
472
if self.start_time != 0:
473
start = unicode(translate('OpenLP.ServiceItem',
474
'<strong>Start</strong>: %s')) % \
475
unicode(datetime.timedelta(seconds=self.start_time))
476
if self.media_length != 0:
477
end = unicode(translate('OpenLP.ServiceItem',
478
'<strong>Length</strong>: %s')) % \
479
unicode(datetime.timedelta(seconds=self.media_length))
480
if not start and not end:
482
elif start and not end:
484
elif not start and end:
487
return u'%s <br>%s' % (start, end)
489
def update_theme(self, theme):
491
updates the theme in the service item
494
The new theme to be replaced in the service item
496
self.theme_overwritten = (theme == None)