openlp/openlp/core/lib/serviceitem.py

448 lines
15 KiB
Python
Raw Normal View History

# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
2010-12-26 11:04:47 +00:00
# Copyright (c) 2008-2011 Raoul Snyman #
# Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael #
# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, 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 #
###############################################################################
2010-06-10 21:30:50 +00:00
"""
The :mod:`serviceitem` provides the service item functionality including the
type and capability of an item.
"""
2011-02-13 10:37:27 +00:00
import datetime
2009-05-02 11:16:08 +00:00
import logging
import os
2009-11-04 17:48:46 +00:00
import uuid
2009-07-10 13:16:15 +00:00
2010-11-03 17:40:45 +00:00
from openlp.core.lib import build_icon, clean_tags, expand_tags
2011-02-13 10:37:27 +00:00
from openlp.core.lib.ui import UiStrings
2009-07-10 13:16:15 +00:00
2010-02-27 15:31:23 +00:00
log = logging.getLogger(__name__)
class ServiceItemType(object):
2009-09-29 04:58:26 +00:00
"""
Defines the type of service item
"""
Text = 1
Image = 2
Command = 3
2010-04-03 07:10:31 +00:00
class ItemCapabilities(object):
2010-06-10 21:30:50 +00:00
"""
Provides an enumeration of a serviceitem's capabilities
"""
2010-05-24 22:37:20 +00:00
AllowsPreview = 1
AllowsEdit = 2
AllowsMaintain = 3
RequiresMedia = 4
AllowsLoop = 5
AllowsAdditions = 6
2010-08-03 19:23:05 +00:00
NoLineBreaks = 7
2010-09-30 05:12:06 +00:00
OnLoadUpdate = 8
AddIfNewItem = 9
ProvidesOwnDisplay = 10
2011-01-29 07:53:21 +00:00
AllowsDetailedTitleDisplay = 11
AllowsVarableStartTime = 12
2010-04-03 07:10:31 +00:00
2011-01-12 19:31:46 +00:00
2009-07-10 13:16:15 +00:00
class ServiceItem(object):
"""
The service item is a base class for the plugins to use to interact with
the service manager, the slide controller, and the projection screen
compositor.
"""
2009-05-02 11:16:08 +00:00
log.info(u'Service Item created')
2009-11-14 08:40:14 +00:00
def __init__(self, plugin=None):
"""
2009-07-10 13:16:15 +00:00
Set up the service item.
2009-11-14 08:40:14 +00:00
``plugin``
2009-07-10 13:16:15 +00:00
The plugin that this service item belongs to.
"""
2009-11-14 08:40:14 +00:00
if plugin:
2010-07-02 18:21:45 +00:00
self.render_manager = plugin.renderManager
2009-11-14 08:40:14 +00:00
self.name = plugin.name
self.title = u''
2010-06-12 20:22:58 +00:00
self.shortname = u''
self.audit = u''
2009-05-02 11:16:08 +00:00
self.items = []
self.iconic_representation = None
self.raw_footer = None
2010-07-19 18:03:00 +00:00
self.foot_text = None
2009-05-02 11:16:08 +00:00
self.theme = None
self.service_item_type = None
2009-11-14 09:06:25 +00:00
self._raw_frames = []
self._display_frames = []
2010-08-02 19:08:55 +00:00
self._uuid = 0
2010-03-02 19:44:55 +00:00
self.notes = u''
2010-03-28 15:56:49 +00:00
self.from_plugin = False
2010-04-03 07:10:31 +00:00
self.capabilities = []
2010-05-07 18:29:17 +00:00
self.is_valid = True
2010-06-12 20:22:58 +00:00
self.icon = None
2010-07-17 08:59:15 +00:00
self.themedata = None
2010-07-25 08:58:08 +00:00
self.main = None
self.footer = None
2010-09-16 21:19:51 +00:00
self.bg_image_bytes = None
2010-09-30 17:07:27 +00:00
self.search_string = u''
self.data_string = u''
self.edit_id = None
self.xml_version = None
2011-02-13 13:11:15 +00:00
self.start_time = 0
2011-02-14 17:54:09 +00:00
self.media_length = 0
self._new_item()
2010-04-02 19:02:38 +00:00
2010-08-02 19:08:55 +00:00
def _new_item(self):
2010-08-21 08:24:14 +00:00
"""
Method to set the internal id of the item
This is used to compare service items to see if they are
the same
"""
2010-08-02 19:23:39 +00:00
self._uuid = unicode(uuid.uuid1())
2010-08-02 19:08:55 +00:00
2010-04-03 07:10:31 +00:00
def add_capability(self, capability):
2010-06-10 21:30:50 +00:00
"""
Add an ItemCapability to a ServiceItem
``capability``
The capability to add
"""
2010-04-03 07:10:31 +00:00
self.capabilities.append(capability)
2010-04-02 19:02:38 +00:00
2010-04-03 07:10:31 +00:00
def is_capable(self, capability):
2010-06-10 21:30:50 +00:00
"""
Tell the caller if a ServiceItem has a capability
``capability``
The capability to test for
"""
2010-04-03 07:10:31 +00:00
return capability in self.capabilities
2009-05-02 11:16:08 +00:00
2010-06-12 20:22:58 +00:00
def add_icon(self, icon):
2009-07-10 13:16:15 +00:00
"""
Add an icon to the service item. This is used when displaying the
service item in the service manager.
``icon``
2010-07-10 01:21:03 +00:00
A string to an icon in the resources or on disk.
2009-07-10 13:16:15 +00:00
"""
2009-06-08 19:06:42 +00:00
self.icon = icon
self.iconic_representation = build_icon(icon)
2010-08-07 08:50:58 +00:00
def render(self, useOverride=False):
"""
2010-07-14 17:36:48 +00:00
The render method is what generates the frames for the screen and
obtains the display information from the renderemanager.
At this point all the slides are build for the given
display size.
"""
2009-05-02 11:16:08 +00:00
log.debug(u'Render called')
2009-11-14 09:06:25 +00:00
self._display_frames = []
2010-09-16 21:19:51 +00:00
self.bg_image_bytes = None
2010-08-03 19:23:05 +00:00
line_break = True
if self.is_capable(ItemCapabilities.NoLineBreaks):
line_break = False
2011-03-02 18:20:47 +00:00
theme = self.theme if self.theme else None
self.main, self.footer = \
self.render_manager.set_override_theme(theme, useOverride)
self.themedata = self.render_manager.renderer._theme
if self.service_item_type == ServiceItemType.Text:
2009-09-13 07:39:48 +00:00
log.debug(u'Formatting slides')
2009-11-14 09:06:25 +00:00
for slide in self._raw_frames:
formatted = self.render_manager \
2010-08-03 19:23:05 +00:00
.format_slide(slide[u'raw_slide'], line_break)
for page in formatted:
2010-07-19 18:03:00 +00:00
self._display_frames.append(
2010-08-21 19:17:56 +00:00
{u'title': clean_tags(page),
u'text': clean_tags(page.rstrip()),
u'html': expand_tags(page.rstrip()),
2010-05-26 16:01:45 +00:00
u'verseTag': slide[u'verseTag'] })
2010-10-23 17:37:10 +00:00
elif self.service_item_type == ServiceItemType.Image or \
self.service_item_type == ServiceItemType.Command:
pass
else:
log.error(u'Invalid value renderer :%s' % self.service_item_type)
2010-08-24 17:12:47 +00:00
self.title = clean_tags(self.title)
2010-07-19 18:03:00 +00:00
self.foot_text = None
if self.raw_footer:
2011-03-02 18:20:47 +00:00
self.foot_text = u'<br>'.join(self.raw_footer)
2010-10-23 17:37:10 +00:00
def add_from_image(self, path, title):
2009-07-10 13:16:15 +00:00
"""
Add an image slide to the service item.
``path``
The directory in which the image file is located.
2009-11-14 08:40:14 +00:00
``title``
2009-07-10 13:16:15 +00:00
A title for the slide in the service item.
"""
self.service_item_type = ServiceItemType.Image
2011-03-02 18:20:47 +00:00
self._raw_frames.append({u'title': title, u'path': path})
self.render_manager.image_manager.add_image(title, path)
2010-08-02 19:08:55 +00:00
self._new_item()
2010-06-12 20:22:58 +00:00
def add_from_text(self, title, raw_slide, verse_tag=None):
2009-07-10 13:16:15 +00:00
"""
Add a text slide to the service item.
``frame_title``
The title of the slide in the service item.
``raw_slide``
The raw text of the slide.
"""
self.service_item_type = ServiceItemType.Text
2009-11-14 08:40:14 +00:00
title = title.split(u'\n')[0]
2009-11-14 09:06:25 +00:00
self._raw_frames.append(
2010-11-04 16:26:30 +00:00
{u'title': title, u'raw_slide': raw_slide, u'verseTag': verse_tag})
2010-08-02 19:08:55 +00:00
self._new_item()
2009-11-14 08:40:14 +00:00
def add_from_command(self, path, file_name, image):
2009-07-10 13:16:15 +00:00
"""
Add a slide from a command.
2009-11-14 08:40:14 +00:00
``path``
2009-07-10 13:16:15 +00:00
The title of the slide in the service item.
2009-11-14 08:40:14 +00:00
``file_name``
2009-07-10 13:16:15 +00:00
The title of the slide in the service item.
``image``
2009-07-10 13:16:15 +00:00
The command of/for the slide.
"""
self.service_item_type = ServiceItemType.Command
2009-11-14 09:06:25 +00:00
self._raw_frames.append(
2010-11-04 16:26:30 +00:00
{u'title': file_name, u'image': image, u'path': path})
2010-08-02 19:08:55 +00:00
self._new_item()
2009-05-02 11:16:08 +00:00
2009-09-19 21:45:50 +00:00
def get_service_repr(self):
"""
2009-09-19 21:45:50 +00:00
This method returns some text which can be saved into the service
2009-07-10 13:16:15 +00:00
file to represent this item.
"""
2009-09-19 21:45:50 +00:00
service_header = {
u'name': self.name,
2009-11-14 08:40:14 +00:00
u'plugin': self.name,
2010-11-04 16:26:30 +00:00
u'theme': self.theme,
u'title': self.title,
u'icon': self.icon,
u'footer': self.raw_footer,
u'type': self.service_item_type,
u'audit': self.audit,
u'notes': self.notes,
u'from_plugin': self.from_plugin,
u'capabilities': self.capabilities,
u'search': self.search_string,
u'data': self.data_string,
u'xml_version': self.xml_version,
2011-02-14 17:54:09 +00:00
u'start_time': self.start_time,
u'media_length': self.media_length
2009-07-10 13:16:15 +00:00
}
2009-09-19 21:45:50 +00:00
service_data = []
if self.service_item_type == ServiceItemType.Text:
2009-11-14 09:06:25 +00:00
for slide in self._raw_frames:
2009-09-19 21:45:50 +00:00
service_data.append(slide)
elif self.service_item_type == ServiceItemType.Image:
2009-11-14 09:06:25 +00:00
for slide in self._raw_frames:
2009-09-19 21:45:50 +00:00
service_data.append(slide[u'title'])
elif self.service_item_type == ServiceItemType.Command:
2009-11-14 09:06:25 +00:00
for slide in self._raw_frames:
2010-05-26 16:01:45 +00:00
service_data.append(
2010-11-04 16:26:30 +00:00
{u'title': slide[u'title'], u'image': slide[u'image']})
2009-09-19 21:45:50 +00:00
return {u'header': service_header, u'data': service_data}
2009-09-19 21:45:50 +00:00
def set_from_service(self, serviceitem, path=None):
"""
2009-07-10 13:16:15 +00:00
This method takes a service item from a saved service file (passed
from the ServiceManager) and extracts the data actually required.
``serviceitem``
The item to extract data from.
``path``
Defaults to *None*. Any path data, usually for images.
"""
header = serviceitem[u'serviceitem'][u'header']
self.title = header[u'title']
2009-09-05 13:30:09 +00:00
self.name = header[u'name']
self.service_item_type = header[u'type']
self.shortname = header[u'plugin']
self.theme = header[u'theme']
2010-06-12 20:22:58 +00:00
self.add_icon(header[u'icon'])
self.raw_footer = header[u'footer']
self.audit = header[u'audit']
2010-03-02 19:44:55 +00:00
self.notes = header[u'notes']
2010-03-28 15:56:49 +00:00
self.from_plugin = header[u'from_plugin']
2010-04-03 07:10:31 +00:00
self.capabilities = header[u'capabilities']
2010-09-30 17:07:27 +00:00
# Added later so may not be present in older services.
if u'search' in header:
self.search_string = header[u'search']
self.data_string = header[u'data']
if u'xml_version' in header:
self.xml_version = header[u'xml_version']
if u'start_time' in header:
self.start_time = header[u'start_time']
2011-02-14 17:54:09 +00:00
if u'media_length' in header:
self.media_length = header[u'media_length']
if self.service_item_type == ServiceItemType.Text:
for slide in serviceitem[u'serviceitem'][u'data']:
2009-11-14 09:06:25 +00:00
self._raw_frames.append(slide)
elif self.service_item_type == ServiceItemType.Image:
for text_image in serviceitem[u'serviceitem'][u'data']:
filename = os.path.join(path, text_image)
2010-10-23 17:37:10 +00:00
self.add_from_image(filename, text_image)
elif self.service_item_type == ServiceItemType.Command:
2009-08-31 18:27:36 +00:00
for text_image in serviceitem[u'serviceitem'][u'data']:
filename = os.path.join(path, text_image[u'title'])
2010-05-26 16:01:45 +00:00
self.add_from_command(
2011-02-16 03:28:06 +00:00
path, text_image[u'title'], text_image[u'image'])
self._new_item()
2009-11-05 17:03:37 +00:00
2011-01-29 07:53:21 +00:00
def get_display_title(self):
2011-01-28 19:46:55 +00:00
"""
Returns the title of the service item.
"""
if self.is_text():
return self.title
else:
2011-01-29 07:53:21 +00:00
if ItemCapabilities.AllowsDetailedTitleDisplay in self.capabilities:
return self._raw_frames[0][u'title']
elif len(self._raw_frames) > 1:
2011-01-28 19:46:55 +00:00
return self.title
else:
return self._raw_frames[0][u'title']
2009-11-05 17:03:37 +00:00
def merge(self, other):
"""
2009-11-14 09:06:25 +00:00
Updates the _uuid with the value from the original one
2010-06-25 00:25:21 +00:00
The _uuid is unique for a given service item but this allows one to
2009-11-05 17:03:37 +00:00
replace an original version.
"""
2009-11-14 09:06:25 +00:00
self._uuid = other._uuid
2009-11-05 17:03:37 +00:00
def __eq__(self, other):
"""
Confirms the service items are for the same instance
"""
if not other:
return False
2009-11-14 09:06:25 +00:00
return self._uuid == other._uuid
2009-11-05 17:03:37 +00:00
def __ne__(self, other):
"""
Confirms the service items are not for the same instance
"""
2009-11-14 09:06:25 +00:00
return self._uuid != other._uuid
2009-11-05 17:03:37 +00:00
def is_media(self):
2010-06-10 21:30:50 +00:00
"""
Confirms if the ServiceItem is media
"""
2010-04-03 07:10:31 +00:00
return ItemCapabilities.RequiresMedia in self.capabilities
2009-11-11 19:10:38 +00:00
def is_command(self):
2010-06-10 21:30:50 +00:00
"""
Confirms if the ServiceItem is a command
"""
return self.service_item_type == ServiceItemType.Command
2009-11-11 19:10:38 +00:00
def is_image(self):
2010-06-10 21:30:50 +00:00
"""
Confirms if the ServiceItem is an image
"""
return self.service_item_type == ServiceItemType.Image
def uses_file(self):
2010-06-10 21:30:50 +00:00
"""
Confirms if the ServiceItem uses a file
"""
return self.service_item_type == ServiceItemType.Image or \
self.service_item_type == ServiceItemType.Command
def is_text(self):
2010-06-10 21:30:50 +00:00
"""
Confirms if the ServiceItem is text
"""
return self.service_item_type == ServiceItemType.Text
2009-11-14 08:40:14 +00:00
def get_frames(self):
2010-06-10 21:30:50 +00:00
"""
Returns the frames for the ServiceItem
"""
2009-11-14 09:02:30 +00:00
if self.service_item_type == ServiceItemType.Text:
2009-11-14 09:06:25 +00:00
return self._display_frames
2009-11-14 09:02:30 +00:00
else:
2009-11-14 09:06:25 +00:00
return self._raw_frames
2009-11-14 09:02:30 +00:00
def get_rendered_frame(self, row):
2009-11-14 09:06:25 +00:00
"""
Returns the correct frame for a given list and
renders it if required.
"""
2009-11-14 09:02:30 +00:00
if self.service_item_type == ServiceItemType.Text:
2010-10-23 17:37:10 +00:00
return self._display_frames[row][u'html'].split(u'\n')[0]
2010-10-24 06:26:07 +00:00
elif self.service_item_type == ServiceItemType.Image:
2010-10-23 17:37:10 +00:00
return self._raw_frames[row][u'title']
2010-10-24 06:26:07 +00:00
else:
return self._raw_frames[row][u'image']
def get_frame_title(self, row=0):
"""
Returns the title of the raw frame
"""
try:
return self._raw_frames[row][u'title']
2011-01-22 12:48:16 +00:00
except IndexError:
return u''
2010-03-30 19:01:23 +00:00
def get_frame_path(self, row=0):
"""
2010-10-15 08:35:00 +00:00
Returns the path of the raw frame
2010-03-30 19:01:23 +00:00
"""
try:
return self._raw_frames[row][u'path']
2011-01-22 12:48:16 +00:00
except IndexError:
return u''
2011-02-13 10:37:27 +00:00
def get_media_time(self):
"""
Returns the start and finish time for a media item
"""
start = None
end = None
2011-02-13 13:11:15 +00:00
if self.start_time != 0:
start = UiStrings.StartTimeCode % \
unicode(datetime.timedelta(seconds=self.start_time))
2011-02-14 17:54:09 +00:00
if self.media_length != 0:
end = UiStrings.LengthTime % \
2011-02-14 18:32:46 +00:00
unicode(datetime.timedelta(seconds=self.media_length))
2011-02-13 10:37:27 +00:00
if not start and not end:
return None
elif start and not end:
return start
elif not start and end:
return end
else:
return u'%s : %s' % (start, end)