r2128 + conflicts

This commit is contained in:
Andreas Preikschat 2012-12-20 13:09:12 +01:00
commit 6ed77d4032
49 changed files with 1811 additions and 73043 deletions

View File

@ -125,7 +125,8 @@ class OpenLP(QtGui.QApplication):
# Correct stylesheet bugs
if os.name == u'nt':
base_color = self.palette().color(QtGui.QPalette.Active, QtGui.QPalette.Base)
application_stylesheet = u'* {alternate-background-color: ' + base_color.name() + ';}\n'
application_stylesheet = \
u'QTableWidget, QListWidget, QTreeWidget {alternate-background-color: ' + base_color.name() + ';}\n'
application_stylesheet += nt_repair_stylesheet
self.setStyleSheet(application_stylesheet)
show_splash = Settings().value(u'general/show splash', True)

View File

@ -37,6 +37,14 @@ from PyQt4 import QtCore, QtGui, Qt
log = logging.getLogger(__name__)
class ServiceItemContext(object):
"""
The context in which a Service Item is being generated
"""
Preview = 0
Live = 1
Service = 2
class ImageSource(object):
"""
@ -457,4 +465,4 @@ from dockwidget import OpenLPDockWidget
from imagemanager import ImageManager
from renderer import Renderer
from mediamanageritem import MediaManagerItem
from openlp.core.utils.actions import ActionList

View File

@ -36,7 +36,8 @@ import re
from PyQt4 import QtCore, QtGui
from openlp.core.lib import SettingsManager, OpenLPToolbar, ServiceItem, \
StringContent, build_icon, translate, Receiver, ListWidgetWithDnD, Settings
StringContent, build_icon, translate, Receiver, ListWidgetWithDnD, \
ServiceItemContext, Settings
from openlp.core.lib.searchedit import SearchEdit
from openlp.core.lib.ui import UiStrings, create_widget_action, \
critical_error_message_box
@ -456,7 +457,7 @@ class MediaManagerItem(QtGui.QWidget):
pass
def generateSlideData(self, serviceItem, item=None, xmlVersion=False,
remote=False):
remote=False, context=ServiceItemContext.Live):
raise NotImplementedError(u'MediaManagerItem.generateSlideData needs '
u'to be defined by the plugin')
@ -518,6 +519,8 @@ class MediaManagerItem(QtGui.QWidget):
if serviceItem:
if not item_id:
serviceItem.from_plugin = True
if remote:
serviceItem.will_auto_start = True
self.plugin.liveController.addServiceItem(serviceItem)
def createItemFromId(self, item_id):
@ -545,7 +548,8 @@ class MediaManagerItem(QtGui.QWidget):
self.addToService(item)
def addToService(self, item=None, replace=None, remote=False):
serviceItem = self.buildServiceItem(item, True, remote=remote)
serviceItem = self.buildServiceItem(item, True, remote=remote,
context=ServiceItemContext.Service)
if serviceItem:
serviceItem.from_plugin = False
self.plugin.serviceManager.addServiceItem(serviceItem,
@ -578,13 +582,15 @@ class MediaManagerItem(QtGui.QWidget):
translate('OpenLP.MediaManagerItem',
'You must select a %s service item.') % self.title)
def buildServiceItem(self, item=None, xmlVersion=False, remote=False):
def buildServiceItem(self, item=None, xmlVersion=False, remote=False,
context=ServiceItemContext.Live):
"""
Common method for generating a service item
"""
serviceItem = ServiceItem(self.plugin)
serviceItem.add_icon(self.plugin.iconPath)
if self.generateSlideData(serviceItem, item, xmlVersion, remote):
if self.generateSlideData(serviceItem, item, xmlVersion, remote,
context):
return serviceItem
else:
return None

View File

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
@ -37,8 +37,7 @@ import logging
import os
import uuid
from openlp.core.lib import build_icon, clean_tags, expand_tags, translate, \
ImageSource
from openlp.core.lib import build_icon, clean_tags, expand_tags, translate, ImageSource
log = logging.getLogger(__name__)
@ -53,7 +52,65 @@ class ServiceItemType(object):
class ItemCapabilities(object):
"""
Provides an enumeration of a serviceitem's capabilities
Provides an enumeration of a service item's capabilities
``CanPreview``
The capability to allow the ServiceManager to add to the preview
tab when making the previous item live.
``CanEdit``
The capability to allow the ServiceManager to allow the item to be
edited
``CanMaintain``
The capability to allow the ServiceManager to allow the item to be
reordered.
``RequiresMedia``
Determines is the serviceItem needs a Media Player
``CanLoop``
The capability to allow the SlideController to allow the loop
processing.
``CanAppend``
The capability to allow the ServiceManager to add leaves to the
item
``NoLineBreaks``
The capability to remove lines breaks in the renderer
``OnLoadUpdate``
The capability to update MediaManager when a service Item is
loaded.
``AddIfNewItem``
Not Used
``ProvidesOwnDisplay``
The capability to tell the SlideController the service Item has a
different display.
``HasDetailedTitleDisplay``
ServiceItem provides a title
``HasVariableStartTime``
The capability to tell the ServiceManager that a change to start
time is possible.
``CanSoftBreak``
The capability to tell the renderer that Soft Break is allowed
``CanWordSplit``
The capability to tell the renderer that it can split words is
allowed
``HasBackgroundAudio``
That a audio file is present with the text.
``CanAutoStartForLive``
The capability to ignore the do not play if display blank flag.
"""
CanPreview = 1
CanEdit = 2
@ -70,6 +127,7 @@ class ItemCapabilities(object):
CanSoftBreak = 13
CanWordSplit = 14
HasBackgroundAudio = 15
CanAutoStartForLive = 16
class ServiceItem(object):
@ -123,6 +181,7 @@ class ServiceItem(object):
self.background_audio = []
self.theme_overwritten = False
self.temporary_edit = False
self.will_auto_start = False
self._new_item()
def _new_item(self):
@ -187,12 +246,10 @@ class ServiceItem(object):
previous_pages = {}
for slide in self._raw_frames:
verse_tag = slide[u'verseTag']
if verse_tag in previous_pages and \
previous_pages[verse_tag][0] == slide[u'raw_slide']:
if verse_tag in previous_pages and previous_pages[verse_tag][0] == slide[u'raw_slide']:
pages = previous_pages[verse_tag][1]
else:
pages = \
self.renderer.format_slide(slide[u'raw_slide'], self)
pages = self.renderer.format_slide(slide[u'raw_slide'], self)
previous_pages[verse_tag] = (slide[u'raw_slide'], pages)
for page in pages:
page = page.replace(u'<br>', u'{br}')
@ -203,8 +260,7 @@ class ServiceItem(object):
u'html': html.replace(u'&amp;nbsp;', u'&nbsp;'),
u'verseTag': verse_tag
})
elif self.service_item_type == ServiceItemType.Image or \
self.service_item_type == ServiceItemType.Command:
elif self.service_item_type == ServiceItemType.Image or self.service_item_type == ServiceItemType.Command:
pass
else:
log.error(u'Invalid value renderer: %s' % self.service_item_type)
@ -230,8 +286,7 @@ class ServiceItem(object):
self.image_border = background
self.service_item_type = ServiceItemType.Image
self._raw_frames.append({u'title': title, u'path': path})
self.renderer.image_manager.addImage(
path, ImageSource.ImagePlugin, self.image_border)
self.renderer.image_manager.addImage(path, ImageSource.ImagePlugin, self.image_border)
self._new_item()
def add_from_text(self, raw_slide, verse_tag=None):
@ -245,8 +300,7 @@ class ServiceItem(object):
verse_tag = verse_tag.upper()
self.service_item_type = ServiceItemType.Text
title = raw_slide[:30].split(u'\n')[0]
self._raw_frames.append(
{u'title': title, u'raw_slide': raw_slide, u'verseTag': verse_tag})
self._raw_frames.append({u'title': title, u'raw_slide': raw_slide, u'verseTag': verse_tag})
self._new_item()
def add_from_command(self, path, file_name, image):
@ -263,11 +317,10 @@ class ServiceItem(object):
The command of/for the slide.
"""
self.service_item_type = ServiceItemType.Command
self._raw_frames.append(
{u'title': file_name, u'image': image, u'path': path})
self._raw_frames.append({u'title': file_name, u'image': image, u'path': path})
self._new_item()
def get_service_repr(self):
def get_service_repr(self, lite_save):
"""
This method returns some text which can be saved into the service
file to represent this item.
@ -291,17 +344,21 @@ class ServiceItem(object):
u'end_time': self.end_time,
u'media_length': self.media_length,
u'background_audio': self.background_audio,
u'theme_overwritten': self.theme_overwritten
u'theme_overwritten': self.theme_overwritten,
u'will_auto_start': self.will_auto_start
}
service_data = []
if self.service_item_type == ServiceItemType.Text:
service_data = [slide for slide in self._raw_frames]
elif self.service_item_type == ServiceItemType.Image:
service_data = [slide[u'title'] for slide in self._raw_frames]
if lite_save:
for slide in self._raw_frames:
service_data.append({u'title': slide[u'title'], u'path': slide[u'path']})
else:
service_data = [slide[u'title'] for slide in self._raw_frames]
elif self.service_item_type == ServiceItemType.Command:
for slide in self._raw_frames:
service_data.append(
{u'title': slide[u'title'], u'image': slide[u'image']})
service_data.append({u'title': slide[u'title'], u'image': slide[u'image'], u'path': slide[u'path']})
return {u'header': service_header, u'data': service_data}
def set_from_service(self, serviceitem, path=None):
@ -313,7 +370,9 @@ class ServiceItem(object):
The item to extract data from.
``path``
Defaults to *None*. Any path data, usually for images.
Defaults to *None*. This is the service manager path for things
which have their files saved with them or None when the saved
service is lite and the original file paths need to be preserved..
"""
log.debug(u'set_from_service called with path %s' % path)
header = serviceitem[u'serviceitem'][u'header']
@ -335,6 +394,7 @@ class ServiceItem(object):
self.start_time = header.get(u'start_time', 0)
self.end_time = header.get(u'end_time', 0)
self.media_length = header.get(u'media_length', 0)
self.will_auto_start = header.get(u'will_auto_start', False)
if u'background_audio' in header:
self.background_audio = []
for filename in header[u'background_audio']:
@ -345,14 +405,20 @@ class ServiceItem(object):
for slide in serviceitem[u'serviceitem'][u'data']:
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)
self.add_from_image(filename, text_image)
if path:
for text_image in serviceitem[u'serviceitem'][u'data']:
filename = os.path.join(path, text_image)
self.add_from_image(filename, text_image)
else:
for text_image in serviceitem[u'serviceitem'][u'data']:
self.add_from_image(text_image[u'path'], text_image[u'title'])
elif self.service_item_type == ServiceItemType.Command:
for text_image in serviceitem[u'serviceitem'][u'data']:
filename = os.path.join(path, text_image[u'title'])
self.add_from_command(
path, text_image[u'title'], text_image[u'image'])
if path:
self.add_from_command(path, text_image[u'title'], text_image[u'image'])
else:
self.add_from_command(text_image[u'path'], text_image[u'title'], text_image[u'image'])
self._new_item()
def get_display_title(self):
@ -425,8 +491,7 @@ class ServiceItem(object):
"""
Confirms if the ServiceItem uses a file
"""
return self.service_item_type == ServiceItemType.Image or \
self.service_item_type == ServiceItemType.Command
return self.service_item_type == ServiceItemType.Image or self.service_item_type == ServiceItemType.Command
def is_text(self):
"""
@ -434,6 +499,17 @@ class ServiceItem(object):
"""
return self.service_item_type == ServiceItemType.Text
def set_media_length(self, length):
"""
Stores the media length of the item
``length``
The length of the media item
"""
self.media_length = length
if length > 0:
self.add_capability(ItemCapabilities.HasVariableStartTime)
def get_frames(self):
"""
Returns the frames for the ServiceItem
@ -446,6 +522,8 @@ class ServiceItem(object):
def get_rendered_frame(self, row):
"""
Returns the correct frame for a given list and renders it if required.
``row``
The service item slide to be returned
"""
if self.service_item_type == ServiceItemType.Text:
return self._display_frames[row][u'html'].split(u'\n')[0]
@ -480,7 +558,7 @@ class ServiceItem(object):
def remove_frame(self, frame):
"""
Remove the soecified frame from the item
Remove the specified frame from the item
"""
if frame in self._raw_frames:
self._raw_frames.remove(frame)

View File

@ -61,6 +61,8 @@ class UiStrings(object):
self.Add = translate('OpenLP.Ui', '&Add')
self.Advanced = translate('OpenLP.Ui', 'Advanced')
self.AllFiles = translate('OpenLP.Ui', 'All Files')
self.Automatic = translate('OpenLP.Ui', 'Automatic')
self.BackgroundColor = translate('OpenLP.Ui', 'Background Color')
self.Bottom = translate('OpenLP.Ui', 'Bottom')
self.Browse = translate('OpenLP.Ui', 'Browse...')
self.Cancel = translate('OpenLP.Ui', 'Cancel')
@ -69,6 +71,7 @@ class UiStrings(object):
self.ConfirmDelete = translate('OpenLP.Ui', 'Confirm Delete')
self.Continuous = translate('OpenLP.Ui', 'Continuous')
self.Default = translate('OpenLP.Ui', 'Default')
self.DefaultColor = translate('OpenLP.Ui', 'Default Color:')
self.Delete = translate('OpenLP.Ui', '&Delete')
self.DisplayStyle = translate('OpenLP.Ui', 'Display style:')
self.Duplicate = translate('OpenLP.Ui', 'Duplicate Error')
@ -106,7 +109,8 @@ class UiStrings(object):
self.NISs = translate('OpenLP.Ui', 'No Item Selected', 'Singular')
self.NISp = translate('OpenLP.Ui', 'No Items Selected', 'Plural')
self.OLPV1 = translate('OpenLP.Ui', 'openlp.org 1.x')
self.OLPV2 = translate('OpenLP.Ui', 'OpenLP 2.0')
self.OLPV2 = translate('OpenLP.Ui', 'OpenLP 2')
self.OLPV2x = translate('OpenLP.Ui', 'OpenLP 2.1')
self.OpenLPStart = translate('OpenLP.Ui', 'OpenLP is already running. '
'Do you wish to continue?')
self.OpenService = translate('OpenLP.Ui', 'Open service.')

File diff suppressed because it is too large Load Diff

View File

@ -72,6 +72,16 @@ class AlertLocation(object):
Middle = 1
Bottom = 2
class DisplayControllerType(object):
"""
This is an enumeration class which says where a display controller
originated from.
"""
Live = 0
Preview = 1
Plugin = 2
from firsttimeform import FirstTimeForm
from firsttimelanguageform import FirstTimeLanguageForm
from themelayoutform import ThemeLayoutForm
@ -82,7 +92,7 @@ from screen import ScreenList
from maindisplay import MainDisplay, Display
from servicenoteform import ServiceNoteForm
from serviceitemeditform import ServiceItemEditForm
from slidecontroller import SlideController, Controller
from slidecontroller import SlideController, DisplayController
from splashscreen import SplashScreen
from generaltab import GeneralTab
from themestab import ThemesTab
@ -98,4 +108,4 @@ from thememanager import ThemeManager
__all__ = ['SplashScreen', 'AboutForm', 'SettingsForm', 'MainDisplay',
'SlideController', 'ServiceManager', 'ThemeManager', 'MediaDockManager',
'ServiceItemEditForm', u'FirstTimeForm']
'ServiceItemEditForm', 'FirstTimeForm']

View File

@ -52,8 +52,8 @@ log = logging.getLogger(__name__)
class Display(QtGui.QGraphicsView):
"""
This is a general display screen class. Here the general display settings
will done. It will be used as specialized classes by Main Display and
Preview display.
will done. It will be used as specialized classes by Main Display and
Preview display.
"""
def __init__(self, parent, live, controller):
if live:
@ -323,7 +323,7 @@ class MainDisplay(Display):
"""
log.debug(u'image to display')
image = self.imageManager.getImageBytes(path, ImageSource.ImagePlugin)
self.controller.mediaController.video_reset(self.controller)
self.controller.mediaController.media_reset(self.controller)
self.displayImage(image)
def displayImage(self, image):

View File

@ -389,7 +389,7 @@ class Ui_MainWindow(object):
"""
Set up the translation system
"""
mainWindow.mainTitle = UiStrings().OLPV2
mainWindow.mainTitle = UiStrings().OLPV2x
mainWindow.setWindowTitle(mainWindow.mainTitle)
self.fileMenu.setTitle(translate('OpenLP.MainWindow', '&File'))
self.fileImportMenu.setTitle(translate('OpenLP.MainWindow', '&Import'))
@ -570,6 +570,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.headerSection = u'SettingsImport'
self.serviceNotSaved = False
self.aboutForm = AboutForm(self)
self.mediaController = MediaController(self)
self.settingsForm = SettingsForm(self, self)
self.formattingTagForm = FormattingTagForm(self)
self.shortcutForm = ShortcutListForm(self)
@ -579,9 +580,10 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.pluginManager = PluginManager(plugin_path)
self.pluginHelpers = {}
self.imageManager = ImageManager()
self.mediaController = MediaController(self)
# Set up the interface
self.setupUi(self)
# Register the active media players and suffixes
self.mediaController.check_available_media_players()
# Load settings after setupUi so default UI sizes are overwritten
self.loadSettings()
# Once settings are loaded update the menu with the recent files.
@ -1155,7 +1157,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
if self.serviceManagerContents.isModified():
ret = self.serviceManagerContents.saveModifiedService()
if ret == QtGui.QMessageBox.Save:
if self.serviceManagerContents.saveFile():
if self.serviceManagerContents.decideSaveMethod():
self.cleanUp()
event.accept()
else:

View File

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
@ -47,7 +47,7 @@ class MediaState(object):
class MediaType(object):
"""
An enumeration of possibible Media Types
An enumeration of possible Media Types
"""
Unused = 0
Audio = 1
@ -59,7 +59,7 @@ class MediaType(object):
class MediaInfo(object):
"""
This class hold the media related infos
This class hold the media related info
"""
file_info = None
volume = 100
@ -72,30 +72,22 @@ class MediaInfo(object):
def get_media_players():
"""
This method extract the configured media players and overridden player from
the settings.
``players_list``
A list with all active media players.
``overridden_player``
Here an special media player is chosen for all media actions.
This method extracts the configured media players and overridden player
from the settings.
"""
log.debug(u'get_media_players')
players = Settings().value(u'media/players', u'')
if not players:
players = u'webkit'
saved_players = Settings().value(u'media/players', u'webkit')
reg_ex = QtCore.QRegExp(".*\[(.*)\].*")
if Settings().value(u'media/override player',
QtCore.Qt.Unchecked) == QtCore.Qt.Checked:
if reg_ex.exactMatch(players):
QtCore.Qt.Unchecked)== QtCore.Qt.Checked:
if reg_ex.exactMatch(saved_players):
overridden_player = u'%s' % reg_ex.cap(1)
else:
overridden_player = u'auto'
else:
overridden_player = u''
players_list = players.replace(u'[', u'').replace(u']', u'').split(u',')
return players_list, overridden_player
saved_players_list = saved_players.replace(u'[', u'').replace(u']',u'').split(u',')
return saved_players_list, overridden_player
def set_media_players(players_list, overridden_player=u'auto'):
@ -111,10 +103,10 @@ def set_media_players(players_list, overridden_player=u'auto'):
"""
log.debug(u'set_media_players')
players = u','.join(players_list)
if Settings().value(u'media/override player',
QtCore.Qt.Unchecked) == QtCore.Qt.Checked and \
if Settings().value(u'media/override player', QtCore.Qt.Unchecked) == QtCore.Qt.Checked and \
overridden_player != u'auto':
players = players.replace(overridden_player, u'[%s]' % overridden_player)
Settings().setValue(u'media/players', players)
from mediacontroller import MediaController
from playertab import PlayerTab

View File

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
@ -33,11 +33,12 @@ import sys
from PyQt4 import QtCore, QtGui
from openlp.core.lib import OpenLPToolbar, Receiver, translate, Settings
from openlp.core.lib.mediaplayer import MediaPlayer
from openlp.core.lib.ui import critical_error_message_box
from openlp.core.lib.ui import UiStrings, critical_error_message_box
from openlp.core.ui.media import MediaState, MediaInfo, MediaType, \
get_media_players, set_media_players
from openlp.core.ui.media.mediaplayer import MediaPlayer
from openlp.core.utils import AppLocation
from openlp.core.ui import DisplayControllerType
log = logging.getLogger(__name__)
@ -45,119 +46,138 @@ class MediaController(object):
"""
The implementation of the Media Controller. The Media Controller adds an own
class for every Player. Currently these are QtWebkit, Phonon and Vlc.
"""
displayControllers are an array of controllers keyed on the
slidecontroller or plugin which built them. ControllerType is the class
containing the key values.
mediaPlayers are an array of media players keyed on player name.
currentMediaPlayer is an array of player instances keyed on ControllerType.
"""
def __init__(self, parent):
self.parent = parent
self.mainWindow = parent
self.mediaPlayers = {}
self.controller = []
self.curDisplayMediaPlayer = {}
self.displayControllers = {}
self.currentMediaPlayer = {}
# Timer for video state
self.timer = QtCore.QTimer()
self.timer.setInterval(200)
self.withLivePreview = False
self.check_available_media_players()
# Signals
QtCore.QObject.connect(self.timer,
QtCore.SIGNAL("timeout()"), self.video_state)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'playbackPlay'), self.video_play)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'playbackPause'), self.video_pause)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'playbackStop'), self.video_stop)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'seekSlider'), self.video_seek)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'volumeSlider'), self.video_volume)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'media_hide'), self.video_hide)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'media_blank'), self.video_blank)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'media_unblank'), self.video_unblank)
QtCore.QObject.connect(self.timer, QtCore.SIGNAL("timeout()"), self.media_state)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'playbackPlay'), self.media_play_msg)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'playbackPause'), self.media_pause_msg)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'playbackStop'), self.media_stop_msg)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'seekSlider'), self.media_seek)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'volumeSlider'), self.media_volume)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'media_hide'), self.media_hide)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'media_blank'), self.media_blank)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'media_unblank'), self.media_unblank)
# Signals for background video
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'songs_hide'), self.video_hide)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'songs_unblank'), self.video_unblank)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'mediaitem_media_rebuild'), self.set_active_players)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'songs_hide'), self.media_hide)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'songs_unblank'), self.media_unblank)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'mediaitem_media_rebuild'),
self._set_active_players)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'mediaitem_suffixes'),
self._generate_extensions_lists)
def set_active_players(self):
def _set_active_players(self):
"""
Set the active players and available media files
"""
savedPlayers = get_media_players()[0]
for player in self.mediaPlayers.keys():
self.mediaPlayers[player].isActive = player in savedPlayers
def register_controllers(self, controller):
def _generate_extensions_lists(self):
"""
Register each media Player controller (Webkit, Phonon, etc) and store
Set the active players and available media files
"""
self.audio_extensions_list = []
for player in self.mediaPlayers.values():
if player.isActive:
for item in player.audio_extensions_list:
if not item in self.audio_extensions_list:
self.audio_extensions_list.append(item)
self.mainWindow.serviceManagerContents.supportedSuffixes(item[2:])
self.video_extensions_list = []
for player in self.mediaPlayers.values():
if player.isActive:
for item in player.video_extensions_list:
if item not in self.video_extensions_list:
self.video_extensions_list.extend(item)
self.mainWindow.serviceManagerContents.supportedSuffixes(item[2:])
def register_players(self, player):
"""
Register each media Player (Webkit, Phonon, etc) and store
for later use
``player``
Individual player class which has been enabled
"""
self.mediaPlayers[controller.name] = controller
self.mediaPlayers[player.name] = player
def check_available_media_players(self):
"""
Check to see if we have any media Player's available. If Not do not
install the plugin.
Check to see if we have any media Player's available.
"""
log.debug(u'check_available_media_players')
log.debug(u'_check_available_media_players')
controller_dir = os.path.join(
AppLocation.get_directory(AppLocation.AppDir),
u'core', u'ui', u'media')
for filename in os.listdir(controller_dir):
if filename.endswith(u'player.py'):
if filename.endswith(u'player.py') and not filename == 'mediaplayer.py':
path = os.path.join(controller_dir, filename)
if os.path.isfile(path):
modulename = u'openlp.core.ui.media.' + \
os.path.splitext(filename)[0]
modulename = u'openlp.core.ui.media.' + os.path.splitext(filename)[0]
log.debug(u'Importing controller %s', modulename)
try:
__import__(modulename, globals(), locals(), [])
# On some platforms importing vlc.py might cause
# also OSError exceptions. (e.g. Mac OS X)
except (ImportError, OSError):
log.warn(u'Failed to import %s on path %s',
modulename, path)
controller_classes = MediaPlayer.__subclasses__()
for controller_class in controller_classes:
controller = controller_class(self)
self.register_controllers(controller)
log.warn(u'Failed to import %s on path %s', modulename, path)
player_classes = MediaPlayer.__subclasses__()
for player_class in player_classes:
player = player_class(self)
self.register_players(player)
if not self.mediaPlayers:
return False
savedPlayers, overriddenPlayer = get_media_players()
invalidMediaPlayers = [mediaPlayer for mediaPlayer in savedPlayers
if not mediaPlayer in self.mediaPlayers or not
self.mediaPlayers[mediaPlayer].check_available()]
if not mediaPlayer in self.mediaPlayers or not self.mediaPlayers[mediaPlayer].check_available()]
if invalidMediaPlayers:
for invalidPlayer in invalidMediaPlayers:
savedPlayers.remove(invalidPlayer)
set_media_players(savedPlayers, overriddenPlayer)
self.set_active_players()
self._set_active_players()
self._generate_extensions_lists()
return True
def video_state(self):
def media_state(self):
"""
Check if there is a running media Player and do updating stuff (e.g.
update the UI)
"""
if not self.curDisplayMediaPlayer.keys():
if not self.currentMediaPlayer.keys():
self.timer.stop()
else:
any_active = False
for display in self.curDisplayMediaPlayer.keys():
self.curDisplayMediaPlayer[display].resize(display)
self.curDisplayMediaPlayer[display].update_ui(display)
if self.curDisplayMediaPlayer[display].state == \
MediaState.Playing:
for source in self.currentMediaPlayer.keys():
display = self._define_display(self.displayControllers[source])
self.currentMediaPlayer[source].resize(display)
self.currentMediaPlayer[source].update_ui(display)
if self.currentMediaPlayer[source].state == MediaState.Playing:
any_active = True
# There are still any active players - no need to stop timer.
# There are still any active players - no need to stop timer.
if any_active:
return
# No players are active anymore.
for display in self.curDisplayMediaPlayer.keys():
if self.curDisplayMediaPlayer[display].state != MediaState.Paused:
# no players are active anymore
for source in self.currentMediaPlayer.keys():
if self.currentMediaPlayer[source].state != MediaState.Paused:
display = self._define_display(self.displayControllers[source])
display.controller.seekSlider.setSliderPosition(0)
self.timer.stop()
@ -191,39 +211,40 @@ class MediaController(object):
html += player.get_media_display_html()
return html
def add_controller_items(self, controller, control_panel):
self.controller.append(controller)
self.setup_generic_controls(controller, control_panel)
self.setup_special_controls(controller, control_panel)
def setup_generic_controls(self, controller, control_panel):
def register_controller(self, controller):
"""
Add generic media control items (valid for all types of medias)
Registers media controls where the players will be placed to run.
``controller``
The controller where a player will be placed
"""
self.displayControllers[controller.controllerType] = controller
self.setup_generic_controls(controller)
def setup_generic_controls(self, controller):
"""
Set up controls on the control_panel for a given controller
``controller``
First element is the controller which should be used
"""
controller.media_info = MediaInfo()
# Build a Media ToolBar
controller.mediabar = OpenLPToolbar(controller)
controller.mediabar.addToolbarAction(u'playbackPlay',
text=u'media_playback_play',
controller.mediabar.addToolbarAction(u'playbackPlay', text=u'media_playback_play',
icon=u':/slides/media_playback_start.png',
tooltip=translate('OpenLP.SlideController', 'Start playing media.'),
triggers=controller.sendToPlugins)
controller.mediabar.addToolbarAction(u'playbackPause',
text=u'media_playback_pause',
tooltip=translate('OpenLP.SlideController', 'Start playing media.'), triggers=controller.sendToPlugins)
controller.mediabar.addToolbarAction(u'playbackPause', text=u'media_playback_pause',
icon=u':/slides/media_playback_pause.png',
tooltip=translate('OpenLP.SlideController', 'Pause playing media.'),
triggers=controller.sendToPlugins)
controller.mediabar.addToolbarAction(u'playbackStop',
text=u'media_playback_stop',
tooltip=translate('OpenLP.SlideController', 'Pause playing media.'), triggers=controller.sendToPlugins)
controller.mediabar.addToolbarAction(u'playbackStop', text=u'media_playback_stop',
icon=u':/slides/media_playback_stop.png',
tooltip=translate('OpenLP.SlideController', 'Stop playing media.'),
triggers=controller.sendToPlugins)
tooltip=translate('OpenLP.SlideController', 'Stop playing media.'), triggers=controller.sendToPlugins)
# Build the seekSlider.
controller.seekSlider = QtGui.QSlider(QtCore.Qt.Horizontal)
controller.seekSlider.setMaximum(1000)
controller.seekSlider.setTracking(False)
controller.seekSlider.setToolTip(translate(
'OpenLP.SlideController', 'Video position.'))
controller.seekSlider.setToolTip(translate('OpenLP.SlideController', 'Video position.'))
controller.seekSlider.setGeometry(QtCore.QRect(90, 260, 221, 24))
controller.seekSlider.setObjectName(u'seekSlider')
controller.mediabar.addToolbarWidget(controller.seekSlider)
@ -234,89 +255,105 @@ class MediaController(object):
controller.volumeSlider.setMinimum(0)
controller.volumeSlider.setMaximum(100)
controller.volumeSlider.setTracking(True)
controller.volumeSlider.setToolTip(translate(
'OpenLP.SlideController', 'Audio Volume.'))
controller.volumeSlider.setToolTip(translate('OpenLP.SlideController', 'Audio Volume.'))
controller.volumeSlider.setValue(controller.media_info.volume)
controller.volumeSlider.setGeometry(QtCore.QRect(90, 160, 221, 24))
controller.volumeSlider.setObjectName(u'volumeSlider')
controller.mediabar.addToolbarWidget(controller.volumeSlider)
control_panel.addWidget(controller.mediabar)
controller.controllerLayout.addWidget(controller.mediabar)
controller.mediabar.setVisible(False)
# Signals
QtCore.QObject.connect(controller.seekSlider,
QtCore.SIGNAL(u'valueChanged(int)'), controller.sendToPlugins)
QtCore.QObject.connect(controller.volumeSlider,
QtCore.SIGNAL(u'valueChanged(int)'), controller.sendToPlugins)
QtCore.QObject.connect(controller.seekSlider, QtCore.SIGNAL(u'valueChanged(int)'), controller.sendToPlugins)
QtCore.QObject.connect(controller.volumeSlider, QtCore.SIGNAL(u'valueChanged(int)'), controller.sendToPlugins)
def setup_special_controls(self, controller, control_panel):
"""
Special media Toolbars will be created here (e.g. for DVD Playback)
"""
controller.media_info = MediaInfo()
# TODO: add Toolbar for DVD, ...
def setup_display(self, display):
def setup_display(self, display, preview):
"""
After a new display is configured, all media related widget will be
created too
``display``
Display on which the output is to be played
``preview``
Whether the display is a main or preview display
"""
# clean up possible running old media files
self.finalise()
# update player status
self.set_active_players()
self._set_active_players()
display.hasAudio = True
if not self.withLivePreview and \
display == self.parent.liveController.previewDisplay:
if display.isLive and preview:
return
if display == self.parent.previewController.previewDisplay or \
display == self.parent.liveController.previewDisplay:
if preview:
display.hasAudio = False
for player in self.mediaPlayers.values():
if player.isActive:
player.setup(display)
def set_controls_visible(self, controller, value):
"""
After a new display is configured, all media related widget will be
created too
``controller``
The controller on which controls act.
``value``
control name to be changed.
"""
# Generic controls
controller.mediabar.setVisible(value)
if controller.isLive and controller.display:
if self.curDisplayMediaPlayer and value:
if self.curDisplayMediaPlayer[controller.display] != \
self.mediaPlayers[u'webkit']:
if self.currentMediaPlayer and value:
if self.currentMediaPlayer[controller.controllerType] != self.mediaPlayers[u'webkit']:
controller.display.setTransparency(False)
# Special controls: Here media type specific Controls will be enabled
# (e.g. for DVD control, ...)
# TODO
def resize(self, controller, display, player):
def resize(self, display, player):
"""
After Mainwindow changes or Splitter moved all related media widgets
have to be resized
``display``
The display on which output is playing.
``player``
The player which is doing the playing.
"""
player.resize(display)
def video(self, controller, file, muted, isBackground, hidden=False,
isInfo=False, controlsVisible=True):
def video(self, source, serviceItem, hidden=False, videoBehindText=False):
"""
Loads and starts a video to run with the option of sound
``source``
Where the call originated form
``serviceItem``
The player which is doing the playing
``hidden``
The player which is doing the playing
``videoBehindText``
Is the video to be played behind text.
"""
log.debug(u'video')
isValid = False
controller = self.displayControllers[source]
# stop running videos
self.video_reset(controller)
self.media_reset(controller)
controller.media_info = MediaInfo()
if muted:
if videoBehindText:
controller.media_info.volume = 0
controller.media_info.is_background = True
else:
controller.media_info.volume = controller.volumeSlider.value()
controller.media_info.file_info = QtCore.QFileInfo(file)
controller.media_info.is_background = isBackground
display = None
controller.media_info.is_background = False
controller.media_info.file_info = QtCore.QFileInfo(serviceItem.get_frame_path())
display = self._define_display(controller)
if controller.isLive:
if self.withLivePreview and controller.previewDisplay:
display = controller.previewDisplay
isValid = self.check_file_type(controller, display)
display = controller.display
isValid = self.check_file_type(controller, display)
isValid = self._check_file_type(controller, display, serviceItem)
display.override[u'theme'] = u''
display.override[u'video'] = True
if controller.media_info.is_background:
@ -324,137 +361,203 @@ class MediaController(object):
controller.media_info.start_time = 0
controller.media_info.end_time = 0
else:
controller.media_info.start_time = \
display.serviceItem.start_time
controller.media_info.end_time = display.serviceItem.end_time
controller.media_info.start_time = display.serviceItem.start_time
controller.media_info.end_time = serviceItem.end_time
elif controller.previewDisplay:
display = controller.previewDisplay
isValid = self.check_file_type(controller, display)
isValid = self._check_file_type(controller, display, serviceItem)
if not isValid:
# Media could not be loaded correctly
critical_error_message_box(
translate('MediaPlugin.MediaItem', 'Unsupported File'),
critical_error_message_box(translate('MediaPlugin.MediaItem', 'Unsupported File'),
translate('MediaPlugin.MediaItem', 'Unsupported File'))
return False
# dont care about actual theme, set a black background
if controller.isLive and not controller.media_info.is_background:
display.frame.evaluateJavaScript(u'show_video( \
"setBackBoard", null, null, null,"visible");')
display.frame.evaluateJavaScript(u'show_video( "setBackBoard", null, null, null,"visible");')
# now start playing - Preview is autoplay!
autoplay = False
# Preview requested
if not controller.isLive:
autoplay = True
# Visible or background requested
elif not hidden or controller.media_info.is_background:
# Visible or background requested or Service Item wants to autostart
elif not hidden or controller.media_info.is_background or serviceItem.will_auto_start:
autoplay = True
# Unblank on load set
elif Settings().value(u'general/auto unblank', False):
autoplay = True
# Start playback only for visible widgets. If we need just load a video
# and get video information, do not start playback.
if autoplay and not isInfo:
if not self.video_play([controller]):
critical_error_message_box(
translate('MediaPlugin.MediaItem', 'Unsupported File'),
if autoplay:
if not self.media_play(controller):
critical_error_message_box(translate('MediaPlugin.MediaItem', 'Unsupported File'),
translate('MediaPlugin.MediaItem', 'Unsupported File'))
return False
self.set_controls_visible(controller, controlsVisible)
log.debug(u'use %s controller' % self.curDisplayMediaPlayer[display])
self.set_controls_visible(controller, True)
log.debug(u'use %s controller' % self.currentMediaPlayer[controller.controllerType])
return True
def check_file_type(self, controller, display):
def media_length(self, serviceItem):
"""
Loads and starts a media item to obtain the media length
``serviceItem``
The ServiceItem containing the details to be played.
"""
controller = self.displayControllers[DisplayControllerType.Plugin]
log.debug(u'media_length')
# stop running videos
self.media_reset(controller)
controller.media_info = MediaInfo()
controller.media_info.volume = 0
controller.media_info.file_info = QtCore.QFileInfo(serviceItem.get_frame_path())
display = controller.previewDisplay
if not self._check_file_type(controller, display, serviceItem):
# Media could not be loaded correctly
critical_error_message_box(translate('MediaPlugin.MediaItem', 'Unsupported File'),
translate('MediaPlugin.MediaItem', 'Unsupported File'))
return False
if not self.media_play(controller):
critical_error_message_box(translate('MediaPlugin.MediaItem', 'Unsupported File'),
translate('MediaPlugin.MediaItem', 'Unsupported File'))
return False
serviceItem.set_media_length(controller.media_info.length)
self.media_stop(controller)
log.debug(u'use %s controller' % self.currentMediaPlayer[controller.controllerType])
return True
def _check_file_type(self, controller, display, serviceItem):
"""
Select the correct media Player type from the prioritized Player list
``controller``
First element is the controller which should be used
``serviceItem``
The ServiceItem containing the details to be played.
"""
usedPlayers, overriddenPlayer = get_media_players()
if overriddenPlayer and overriddenPlayer != u'auto':
usedPlayers = [overriddenPlayer]
usedPlayers = get_media_players()[0]
if serviceItem.title != UiStrings().Automatic:
usedPlayers = [serviceItem.title.lower()]
if controller.media_info.file_info.isFile():
suffix = u'*.%s' % controller.media_info.file_info.suffix().lower()
for title in usedPlayers:
player = self.mediaPlayers[title]
if suffix in player.video_extensions_list:
if not controller.media_info.is_background or \
controller.media_info.is_background and \
player.canBackground:
self.resize(controller, display, player)
if not controller.media_info.is_background or controller.media_info.is_background and \
player.canBackground:
self.resize(display, player)
if player.load(display):
self.curDisplayMediaPlayer[display] = player
self.currentMediaPlayer[controller.controllerType] = player
controller.media_info.media_type = MediaType.Video
return True
if suffix in player.audio_extensions_list:
if player.load(display):
self.curDisplayMediaPlayer[display] = player
self.currentMediaPlayer[controller.controllerType] = player
controller.media_info.media_type = MediaType.Audio
return True
else:
for title in usedPlayers:
player = self.mediaPlayers[title]
if player.canFolder:
self.resize(controller, display, player)
self.resize(display, player)
if player.load(display):
self.curDisplayMediaPlayer[display] = player
self.currentMediaPlayer[controller.controllerType] = player
controller.media_info.media_type = MediaType.Video
return True
# no valid player found
return False
def video_play(self, msg, status=True):
def media_play_msg(self, msg, status=True):
"""
Responds to the request to play a loaded video
``msg``
First element is the controller which should be used
"""
log.debug(u'video_play')
controller = msg[0]
for display in self.curDisplayMediaPlayer.keys():
if display.controller == controller:
if not self.curDisplayMediaPlayer[display].play(display):
return False
if status:
display.frame.evaluateJavaScript(u'show_blank("desktop");')
self.curDisplayMediaPlayer[display].set_visible(display,
True)
if controller.isLive:
if controller.hideMenu.defaultAction().isChecked():
controller.hideMenu.defaultAction().trigger()
log.debug(u'media_play_msg')
self.media_play(msg[0],status)
def media_play(self, controller, status=True):
"""
Responds to the request to play a loaded video
``controller``
The controller to be played
"""
log.debug(u'media_play')
display = self._define_display(controller)
if not self.currentMediaPlayer[controller.controllerType].play(display):
return False
if status:
display.frame.evaluateJavaScript(u'show_blank("desktop");')
self.currentMediaPlayer[controller.controllerType].set_visible(display, True)
# Flash needs to be played and will not AutoPlay
if controller.media_info.is_flash:
controller.mediabar.actions[u'playbackPlay'].setVisible(True)
controller.mediabar.actions[u'playbackPause'].setVisible(False)
else:
controller.mediabar.actions[u'playbackPlay'].setVisible(False)
controller.mediabar.actions[u'playbackPause'].setVisible(True)
controller.mediabar.actions[u'playbackStop'].setVisible(True)
if controller.isLive:
if controller.hideMenu.defaultAction().isChecked():
controller.hideMenu.defaultAction().trigger()
# Start Timer for ui updates
if not self.timer.isActive():
self.timer.start()
return True
def video_pause(self, msg):
def media_pause_msg(self, msg):
"""
Responds to the request to pause a loaded video
``msg``
First element is the controller which should be used
"""
log.debug(u'video_pause')
controller = msg[0]
for display in self.curDisplayMediaPlayer.keys():
if display.controller == controller:
self.curDisplayMediaPlayer[display].pause(display)
log.debug(u'media_pause_msg')
self.media_pause( msg[0])
def video_stop(self, msg):
def media_pause(self, controller):
"""
Responds to the request to pause a loaded video
``controller``
The Controller to be paused
"""
log.debug(u'media_pause')
display = self._define_display(controller)
self.currentMediaPlayer[controller.controllerType].pause(display)
controller.mediabar.actions[u'playbackPlay'].setVisible(True)
controller.mediabar.actions[u'playbackStop'].setVisible(True)
controller.mediabar.actions[u'playbackPause'].setVisible(False)
def media_stop_msg(self, msg):
"""
Responds to the request to stop a loaded video
``msg``
First element is the controller which should be used
"""
log.debug(u'video_stop')
controller = msg[0]
for display in self.curDisplayMediaPlayer.keys():
if display.controller == controller:
display.frame.evaluateJavaScript(u'show_blank("black");')
self.curDisplayMediaPlayer[display].stop(display)
self.curDisplayMediaPlayer[display].set_visible(display, False)
controller.seekSlider.setSliderPosition(0)
log.debug(u'media_stop_msg')
self.media_stop(msg[0])
def video_volume(self, msg):
def media_stop(self, controller):
"""
Responds to the request to stop a loaded video
``controller``
The controller that needs to be stopped
"""
log.debug(u'media_stop')
display = self._define_display(controller)
if controller.controllerType in self.currentMediaPlayer:
display.frame.evaluateJavaScript(u'show_blank("black");')
self.currentMediaPlayer[controller.controllerType].stop(display)
self.currentMediaPlayer[controller.controllerType].set_visible(display, False)
controller.seekSlider.setSliderPosition(0)
controller.mediabar.actions[u'playbackPlay'].setVisible(True)
controller.mediabar.actions[u'playbackStop'].setVisible(False)
controller.mediabar.actions[u'playbackPause'].setVisible(False)
def media_volume(self, msg):
"""
Changes the volume of a running video
@ -463,12 +566,11 @@ class MediaController(object):
"""
controller = msg[0]
vol = msg[1][0]
log.debug(u'video_volume %d' % vol)
for display in self.curDisplayMediaPlayer.keys():
if display.controller == controller:
self.curDisplayMediaPlayer[display].volume(display, vol)
log.debug(u'media_volume %d' % vol)
display = self._define_display(controller)
self.currentMediaPlayer[controller.controllerType].volume(display, vol)
def video_seek(self, msg):
def media_seek(self, msg):
"""
Responds to the request to change the seek Slider of a loaded video
@ -476,29 +578,27 @@ class MediaController(object):
First element is the controller which should be used
Second element is a list with the seek Value as first element
"""
log.debug(u'video_seek')
log.debug(u'media_seek')
controller = msg[0]
seekVal = msg[1][0]
for display in self.curDisplayMediaPlayer.keys():
if display.controller == controller:
self.curDisplayMediaPlayer[display].seek(display, seekVal)
display = self._define_display(controller)
self.currentMediaPlayer[controller.controllerType].seek(display, seekVal)
def video_reset(self, controller):
def media_reset(self, controller):
"""
Responds to the request to reset a loaded video
"""
log.debug(u'video_reset')
log.debug(u'media_reset')
self.set_controls_visible(controller, False)
for display in self.curDisplayMediaPlayer.keys():
if display.controller == controller:
display.override = {}
self.curDisplayMediaPlayer[display].reset(display)
self.curDisplayMediaPlayer[display].set_visible(display, False)
display.frame.evaluateJavaScript(u'show_video( \
"setBackBoard", null, null, null,"hidden");')
del self.curDisplayMediaPlayer[display]
display = self._define_display(controller)
if controller.controllerType in self.currentMediaPlayer:
display.override = {}
self.currentMediaPlayer[controller.controllerType].reset(display)
self.currentMediaPlayer[controller.controllerType].set_visible(display, False)
display.frame.evaluateJavaScript(u'show_video( "setBackBoard", null, null, null,"hidden");')
del self.currentMediaPlayer[controller.controllerType]
def video_hide(self, msg):
def media_hide(self, msg):
"""
Hide the related video Widget
@ -508,15 +608,13 @@ class MediaController(object):
isLive = msg[1]
if not isLive:
return
controller = self.parent.liveController
for display in self.curDisplayMediaPlayer.keys():
if display.controller != controller or \
self.curDisplayMediaPlayer[display].state != MediaState.Playing:
continue
self.curDisplayMediaPlayer[display].pause(display)
self.curDisplayMediaPlayer[display].set_visible(display, False)
controller = self.mainWindow.liveController
display = self._define_display(controller)
if self.currentMediaPlayer[controller.controllerType].state == MediaState.Playing:
self.currentMediaPlayer[controller.controllerType].pause(display)
self.currentMediaPlayer[controller.controllerType].set_visible(display, False)
def video_blank(self, msg):
def media_blank(self, msg):
"""
Blank the related video Widget
@ -529,15 +627,13 @@ class MediaController(object):
if not isLive:
return
Receiver.send_message(u'live_display_hide', hide_mode)
controller = self.parent.liveController
for display in self.curDisplayMediaPlayer.keys():
if display.controller != controller or \
self.curDisplayMediaPlayer[display].state != MediaState.Playing:
continue
self.curDisplayMediaPlayer[display].pause(display)
self.curDisplayMediaPlayer[display].set_visible(display, False)
controller = self.mainWindow.liveController
display = self._define_display(controller)
if self.currentMediaPlayer[controller.controllerType].state == MediaState.Playing:
self.currentMediaPlayer[controller.controllerType].pause(display)
self.currentMediaPlayer[controller.controllerType].set_visible(display, False)
def video_unblank(self, msg):
def media_unblank(self, msg):
"""
Unblank the related video Widget
@ -549,35 +645,28 @@ class MediaController(object):
isLive = msg[1]
if not isLive:
return
controller = self.parent.liveController
for display in self.curDisplayMediaPlayer.keys():
if display.controller != controller or \
self.curDisplayMediaPlayer[display].state != MediaState.Paused:
continue
if self.curDisplayMediaPlayer[display].play(display):
self.curDisplayMediaPlayer[display].set_visible(display, True)
controller = self.mainWindow.liveController
display = self._define_display(controller)
if controller.controllerType in self.currentMediaPlayer and \
self.currentMediaPlayer[controller.controllerType].state != MediaState.Playing:
if self.currentMediaPlayer[controller.controllerType].play(display):
self.currentMediaPlayer[controller.controllerType].set_visible(display, True)
# Start Timer for ui updates
if not self.timer.isActive():
self.timer.start()
def get_audio_extensions_list(self):
audio_list = []
for player in self.mediaPlayers.values():
if player.isActive:
for item in player.audio_extensions_list:
if not item in audio_list:
audio_list.append(item)
return audio_list
def get_video_extensions_list(self):
video_list = []
for player in self.mediaPlayers.values():
if player.isActive:
video_list.extend([item for item in player.video_extensions_list
if item not in video_list])
return video_list
def finalise(self):
self.timer.stop()
for controller in self.controller:
self.video_reset(controller)
for controller in self.displayControllers:
self.media_reset(self.displayControllers[controller])
def _define_display(self, controller):
"""
Extract the correct display for a given controller
``controller``
Controller to be used
"""
if controller.isLive:
return controller.display
return controller.previewDisplay

View File

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
@ -31,8 +31,8 @@ from openlp.core.ui.media import MediaState
class MediaPlayer(object):
"""
This is the base class media Player class to provide OpenLP with a pluggable media display
framework.
This is the base class media Player class to provide OpenLP with a
pluggable media display framework.
"""
def __init__(self, parent, name=u'media_player'):
@ -137,3 +137,9 @@ class MediaPlayer(object):
Add html code to htmlbuilder
"""
return u''
def get_info(self):
"""
Returns Information about the player
"""
return u''

View File

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
@ -31,11 +31,14 @@ import logging
import mimetypes
from datetime import datetime
from PyQt4 import QtCore, QtGui
from PyQt4.phonon import Phonon
from openlp.core.lib import Receiver
from openlp.core.lib.mediaplayer import MediaPlayer
from openlp.core.lib import Receiver, translate, Settings
from openlp.core.ui.media import MediaState
from openlp.core.ui.media.mediaplayer import MediaPlayer
log = logging.getLogger(__name__)
@ -56,6 +59,20 @@ ADDITIONAL_EXT = {
u'video/mpeg' : [u'.mp4', u'.mts', u'.mov'],
u'video/x-ms-wmv': [u'.wmv']}
VIDEO_CSS = u"""
#videobackboard {
z-index:3;
background-color: %s;
}
#video1 {
background-color: %s;
z-index:4;
}
#video2 {
background-color: %s;
z-index:4;
}
"""
class PhononPlayer(MediaPlayer):
"""
@ -84,8 +101,7 @@ class PhononPlayer(MediaPlayer):
ext = u'*%s' % extension
if ext not in list:
list.append(ext)
log.info(u'MediaPlugin: %s extensions: %s' % (mimetype,
u' '.join(extensions)))
log.info(u'MediaPlugin: %s extensions: %s' % (mimetype, u' '.join(extensions)))
# Add extensions for this mimetype from self.additional_extensions.
# This hack clears mimetypes' and operating system's shortcomings
# by providing possibly missing extensions.
@ -94,8 +110,8 @@ class PhononPlayer(MediaPlayer):
ext = u'*%s' % extension
if ext not in list:
list.append(ext)
log.info(u'MediaPlugin: %s additional extensions: %s' % (mimetype,
u' '.join(self.additional_extensions[mimetype])))
log.info(u'MediaPlugin: %s additional extensions: %s' %
(mimetype, u' '.join(self.additional_extensions[mimetype])))
def setup(self, display):
display.phononWidget = Phonon.VideoWidget(display)
@ -103,8 +119,7 @@ class PhononPlayer(MediaPlayer):
display.mediaObject = Phonon.MediaObject(display)
Phonon.createPath(display.mediaObject, display.phononWidget)
if display.hasAudio:
display.audio = Phonon.AudioOutput(
Phonon.VideoCategory, display.mediaObject)
display.audio = Phonon.AudioOutput(Phonon.VideoCategory, display.mediaObject)
Phonon.createPath(display.mediaObject, display.audio)
display.phononWidget.raise_()
display.phononWidget.hide()
@ -155,8 +170,7 @@ class PhononPlayer(MediaPlayer):
if start_time > 0:
self.seek(display, controller.media_info.start_time * 1000)
self.volume(display, controller.media_info.volume)
controller.media_info.length = \
int(display.mediaObject.totalTime() / 1000)
controller.media_info.length = int(display.mediaObject.totalTime() / 1000)
controller.seekSlider.setMaximum(controller.media_info.length * 1000)
self.state = MediaState.Playing
display.phononWidget.raise_()
@ -193,15 +207,28 @@ class PhononPlayer(MediaPlayer):
display.phononWidget.setVisible(status)
def update_ui(self, display):
if display.mediaObject.state() == Phonon.PausedState and \
self.state != MediaState.Paused:
if display.mediaObject.state() == Phonon.PausedState and self.state != MediaState.Paused:
self.stop(display)
controller = display.controller
if controller.media_info.end_time > 0:
if display.mediaObject.currentTime() > \
controller.media_info.end_time * 1000:
if display.mediaObject.currentTime() > controller.media_info.end_time * 1000:
self.stop(display)
self.set_visible(display, False)
if not controller.seekSlider.isSliderDown():
controller.seekSlider.setSliderPosition(
display.mediaObject.currentTime())
def get_media_display_css(self):
"""
Add css style sheets to htmlbuilder
"""
background = QtGui.QColor(Settings().value(u'players/background color', u'#000000')).name()
return VIDEO_CSS % (background,background,background)
def get_info(self):
return(translate('Media.player', 'Phonon is a media player which '
'interacts with the operating system to provide media capabilities.') +
u'<br/> <strong>' + translate('Media.player', 'Audio') +
u'</strong><br/>' + unicode(self.audio_extensions_list) +
u'<br/><strong>' + translate('Media.player', 'Video') +
u'</strong><br/>' + unicode(self.video_extensions_list) + u'<br/>')

View File

@ -0,0 +1,235 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2012 Raoul Snyman #
# Portions copyright (c) 2008-2012 Tim Bentley, Gerald Britton, Jonathan #
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
# Meinert Jordan, Armin Köhler, Eric Ludin, Edwin Lunando, Brian T. Meyer, #
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
# Erode Woldsund, Martin Zibricky #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
from PyQt4 import QtCore, QtGui
from openlp.core.lib import SettingsTab, translate, Receiver, Settings
from openlp.core.lib.ui import UiStrings, create_button
from openlp.core.ui.media import get_media_players, set_media_players
class MediaQCheckBox(QtGui.QCheckBox):
"""
MediaQCheckBox adds an extra property, playerName to the QCheckBox class.
"""
def setPlayerName(self, name):
self.playerName = name
class PlayerTab(SettingsTab):
"""
MediaTab is the Media settings tab in the settings dialog.
"""
def __init__(self, parent, mainWindow):
self.parent = parent
self.mainWindow = mainWindow
self.mediaPlayers = mainWindow.mediaController.mediaPlayers
self.savedUsedPlayers = None
self.iconPath = u':/media/multimedia-player.png'
player_translated = translate('OpenLP.PlayerTab', 'Players')
SettingsTab.__init__(self, parent, u'Players', player_translated)
def setupUi(self):
self.setObjectName(u'MediaTab')
SettingsTab.setupUi(self)
self.bgColorGroupBox = QtGui.QGroupBox(self.leftColumn)
self.bgColorGroupBox.setObjectName(u'FontGroupBox')
self.formLayout = QtGui.QFormLayout(self.bgColorGroupBox)
self.formLayout.setObjectName(u'FormLayout')
self.colorLayout = QtGui.QHBoxLayout()
self.backgroundColorLabel = QtGui.QLabel(self.bgColorGroupBox)
self.backgroundColorLabel.setObjectName(u'BackgroundColorLabel')
self.colorLayout.addWidget(self.backgroundColorLabel)
self.backgroundColorButton = QtGui.QPushButton(self.bgColorGroupBox)
self.backgroundColorButton.setObjectName(u'BackgroundColorButton')
self.colorLayout.addWidget(self.backgroundColorButton)
self.formLayout.addRow(self.colorLayout)
self.informationLabel = QtGui.QLabel(self.bgColorGroupBox)
self.informationLabel.setObjectName(u'InformationLabel')
self.informationLabel.setWordWrap(True)
self.formLayout.addRow(self.informationLabel)
self.leftLayout.addWidget(self.bgColorGroupBox)
self.leftLayout.addStretch()
self.rightColumn.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Preferred)
self.rightLayout.addStretch()
self.mediaPlayerGroupBox = QtGui.QGroupBox(self.leftColumn)
self.mediaPlayerGroupBox.setObjectName(u'mediaPlayerGroupBox')
self.mediaPlayerLayout = QtGui.QVBoxLayout(self.mediaPlayerGroupBox)
self.mediaPlayerLayout.setObjectName(u'mediaPlayerLayout')
self.playerCheckBoxes = {}
self.leftLayout.addWidget(self.mediaPlayerGroupBox)
self.playerOrderGroupBox = QtGui.QGroupBox(self.leftColumn)
self.playerOrderGroupBox.setObjectName(u'playerOrderGroupBox')
self.playerOrderLayout = QtGui.QHBoxLayout(self.playerOrderGroupBox)
self.playerOrderLayout.setObjectName(u'playerOrderLayout')
self.playerOrderlistWidget = QtGui.QListWidget(
self.playerOrderGroupBox)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.playerOrderlistWidget.sizePolicy().hasHeightForWidth())
self.playerOrderlistWidget.setSizePolicy(sizePolicy)
self.playerOrderlistWidget.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
self.playerOrderlistWidget.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.playerOrderlistWidget.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
self.playerOrderlistWidget.setObjectName(u'playerOrderlistWidget')
self.playerOrderLayout.addWidget(self.playerOrderlistWidget)
self.orderingButtonLayout = QtGui.QVBoxLayout()
self.orderingButtonLayout.setObjectName(u'orderingButtonLayout')
self.orderingButtonLayout.addStretch(1)
self.orderingUpButton = create_button(self, u'orderingUpButton', role=u'up', click=self.onUpButtonClicked)
self.orderingDownButton = create_button(self, u'orderingDownButton', role=u'down',
click=self.onDownButtonClicked)
self.orderingButtonLayout.addWidget(self.orderingUpButton)
self.orderingButtonLayout.addWidget(self.orderingDownButton)
self.orderingButtonLayout.addStretch(1)
self.playerOrderLayout.addLayout(self.orderingButtonLayout)
self.leftLayout.addWidget(self.playerOrderGroupBox)
self.leftLayout.addStretch()
self.rightLayout.addStretch()
# Signals and slots
QtCore.QObject.connect(self.backgroundColorButton, QtCore.SIGNAL(u'clicked()'),
self.onbackgroundColorButtonClicked)
def retranslateUi(self):
self.mediaPlayerGroupBox.setTitle(translate('OpenLP.PlayerTab', 'Available Media Players'))
self.playerOrderGroupBox.setTitle(translate('OpenLP.PlayerTab', 'Player Search Order'))
self.bgColorGroupBox.setTitle(UiStrings().BackgroundColor)
self.backgroundColorLabel.setText(UiStrings().DefaultColor)
self.informationLabel.setText(translate('OpenLP.PlayerTab',
'Visible background for videos with aspect ratio different to screen.'))
self.retranslatePlayers()
def onbackgroundColorButtonClicked(self):
new_color = QtGui.QColorDialog.getColor(QtGui.QColor(self.bg_color), self)
if new_color.isValid():
self.bg_color = new_color.name()
self.backgroundColorButton.setStyleSheet(u'background-color: %s' % self.bg_color)
def onPlayerCheckBoxChanged(self, check_state):
player = self.sender().playerName
if check_state == QtCore.Qt.Checked:
if player not in self.usedPlayers:
self.usedPlayers.append(player)
else:
if player in self.usedPlayers:
self.usedPlayers.remove(player)
self.updatePlayerList()
def updatePlayerList(self):
self.playerOrderlistWidget.clear()
for player in self.usedPlayers:
if player in self.playerCheckBoxes.keys():
if len(self.usedPlayers) == 1:
# At least one media player has to stay active
self.playerCheckBoxes[u'%s' % player].setEnabled(False)
else:
self.playerCheckBoxes[u'%s' % player].setEnabled(True)
self.playerOrderlistWidget.addItem(self.mediaPlayers[unicode(player)].original_name)
def onUpButtonClicked(self):
row = self.playerOrderlistWidget.currentRow()
if row <= 0:
return
item = self.playerOrderlistWidget.takeItem(row)
self.playerOrderlistWidget.insertItem(row - 1, item)
self.playerOrderlistWidget.setCurrentRow(row - 1)
self.usedPlayers.insert(row - 1, self.usedPlayers.pop(row))
def onDownButtonClicked(self):
row = self.playerOrderlistWidget.currentRow()
if row == -1 or row > self.playerOrderlistWidget.count() - 1:
return
item = self.playerOrderlistWidget.takeItem(row)
self.playerOrderlistWidget.insertItem(row + 1, item)
self.playerOrderlistWidget.setCurrentRow(row + 1)
self.usedPlayers.insert(row + 1, self.usedPlayers.pop(row))
def load(self):
if self.savedUsedPlayers:
self.usedPlayers = self.savedUsedPlayers
self.usedPlayers = get_media_players()[0]
self.savedUsedPlayers = self.usedPlayers
settings = Settings()
settings.beginGroup(self.settingsSection)
self.updatePlayerList()
self.bg_color = settings.value(u'background color', u'#000000')
self.initial_color = self.bg_color
settings.endGroup()
self.backgroundColorButton.setStyleSheet(u'background-color: %s' % self.bg_color)
def save(self):
player_string_changed = False
settings = Settings()
settings.beginGroup(self.settingsSection)
settings.setValue(u'background color', self.bg_color)
settings.endGroup()
old_players, override_player = get_media_players()
if self.usedPlayers != old_players:
# clean old Media stuff
set_media_players(self.usedPlayers, override_player)
player_string_changed = True
if player_string_changed:
self.parent.resetSupportedSuffixes()
Receiver.send_message(u'mediaitem_media_rebuild')
Receiver.send_message(u'config_screen_changed')
def postSetUp(self, postUpdate=False):
"""
Late setup for players as the MediaController has to be initialised
first.
"""
for key, player in self.mediaPlayers.iteritems():
player = self.mediaPlayers[key]
checkbox = MediaQCheckBox(self.mediaPlayerGroupBox)
checkbox.setEnabled(player.available)
checkbox.setObjectName(player.name + u'CheckBox')
checkbox.setToolTip(player.get_info())
checkbox.setPlayerName(player.name)
self.playerCheckBoxes[player.name] = checkbox
QtCore.QObject.connect(checkbox,QtCore.SIGNAL(u'stateChanged(int)'), self.onPlayerCheckBoxChanged)
self.mediaPlayerLayout.addWidget(checkbox)
if player.available and player.name in self.usedPlayers:
checkbox.setChecked(True)
else:
checkbox.setChecked(False)
self.updatePlayerList()
self.retranslatePlayers()
def retranslatePlayers(self):
"""
Translations for players is dependent on their setup as well
"""
for key in self.mediaPlayers:
player = self.mediaPlayers[key]
checkbox = self.playerCheckBoxes[player.name]
checkbox.setPlayerName(player.name)
if player.available:
checkbox.setText(player.display_name)
else:
checkbox.setText(translate('OpenLP.PlayerTab', '%s (unavailable)') % player.display_name)

28
openlp/core/ui/media/vendor/__init__.py vendored Normal file
View File

@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2012 Raoul Snyman #
# Portions copyright (c) 2008-2012 Tim Bentley, Gerald Britton, Jonathan #
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
# Meinert Jordan, Armin Köhler, Eric Ludin, Edwin Lunando, Brian T. Meyer, #
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
# Erode Woldsund, Martin Zibricky #
# --------------------------------------------------------------------------- #
# 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 #
###############################################################################

View File

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
@ -35,15 +35,15 @@ import sys
from PyQt4 import QtCore, QtGui
from openlp.core.lib import Receiver, Settings
from openlp.core.lib.mediaplayer import MediaPlayer
from openlp.core.lib import Receiver, translate, Settings
from openlp.core.ui.media import MediaState
from openlp.core.ui.media.mediaplayer import MediaPlayer
log = logging.getLogger(__name__)
VLC_AVAILABLE = False
try:
import vlc
from openlp.core.ui.media.vendor import vlc
VLC_AVAILABLE = bool(vlc.get_default_instance())
except (ImportError, NameError, NotImplementedError):
pass
@ -113,8 +113,7 @@ class VlcPlayer(MediaPlayer):
command_line_options = u'--no-video-title-show'
if not display.hasAudio:
command_line_options += u' --no-audio --no-video-title-show'
if Settings().value(u'advanced/hide mouse', True) and \
display.controller.isLive:
if Settings().value(u'advanced/hide mouse', True) and display.controller.isLive:
command_line_options += u' --mouse-hide-timeout=0'
display.vlcInstance = vlc.Instance(command_line_options)
display.vlcInstance.set_log_verbosity(2)
@ -161,8 +160,7 @@ class VlcPlayer(MediaPlayer):
# and once to just get media length.
#
# Media plugin depends on knowing media length before playback.
controller.media_info.length = \
int(display.vlcMediaPlayer.get_media().get_duration() / 1000)
controller.media_info.length = int(display.vlcMediaPlayer.get_media().get_duration() / 1000)
return True
def media_state_wait(self, display, mediaState):
@ -185,15 +183,14 @@ class VlcPlayer(MediaPlayer):
def play(self, display):
controller = display.controller
start_time = 0
if controller.media_info.start_time > 0:
if self.state != MediaState.Paused and controller.media_info.start_time > 0:
start_time = controller.media_info.start_time
display.vlcMediaPlayer.play()
if not self.media_state_wait(display, vlc.State.Playing):
return False
if start_time > 0:
self.seek(display, controller.media_info.start_time * 1000)
controller.media_info.length = \
int(display.vlcMediaPlayer.get_media().get_duration() / 1000)
controller.media_info.length = int(display.vlcMediaPlayer.get_media().get_duration() / 1000)
controller.seekSlider.setMaximum(controller.media_info.length * 1000)
self.state = MediaState.Playing
display.vlcWidget.raise_()
@ -233,11 +230,16 @@ class VlcPlayer(MediaPlayer):
self.stop(display)
controller = display.controller
if controller.media_info.end_time > 0:
if display.vlcMediaPlayer.get_time() > \
controller.media_info.end_time * 1000:
if display.vlcMediaPlayer.get_time() > controller.media_info.end_time * 1000:
self.stop(display)
self.set_visible(display, False)
if not controller.seekSlider.isSliderDown():
controller.seekSlider.setSliderPosition( \
display.vlcMediaPlayer.get_time())
controller.seekSlider.setSliderPosition(display.vlcMediaPlayer.get_time())
def get_info(self):
return(translate('Media.player', 'VLC is an external player which '
'supports a number of different formats.') +
u'<br/> <strong>' + translate('Media.player', 'Audio') +
u'</strong><br/>' + unicode(AUDIO_EXT) + u'<br/><strong>' +
translate('Media.player', 'Video') + u'</strong><br/>' +
unicode(VIDEO_EXT) + u'<br/>')

View File

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
@ -27,22 +27,27 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
from PyQt4 import QtCore, QtGui
import logging
from openlp.core.lib.mediaplayer import MediaPlayer
from openlp.core.lib import translate, Settings
from openlp.core.ui.media import MediaState
from openlp.core.ui.media.mediaplayer import MediaPlayer
log = logging.getLogger(__name__)
VIDEO_CSS = u"""
#videobackboard {
z-index:3;
background-color: black;
background-color: %s;
}
#video1 {
background-color: %s;
z-index:4;
}
#video2 {
background-color: %s;
z-index:4;
}
"""
@ -277,7 +282,9 @@ class WebkitPlayer(MediaPlayer):
"""
Add css style sheets to htmlbuilder
"""
return VIDEO_CSS + FLASH_CSS
background = QtGui.QColor(Settings().value(u'players/background color', u'#000000')).name()
css = VIDEO_CSS % (background,background,background)
return css + FLASH_CSS
def get_media_display_javascript(self):
"""
@ -315,16 +322,13 @@ class WebkitPlayer(MediaPlayer):
display.webView.setVisible(True)
if controller.media_info.file_info.suffix() == u'swf':
controller.media_info.is_flash = True
js = u'show_flash("load","%s");' % \
(path.replace(u'\\', u'\\\\'))
js = u'show_flash("load","%s");' % (path.replace(u'\\', u'\\\\'))
else:
js = u'show_video("init", "%s", %s, %s);' % \
(path.replace(u'\\', u'\\\\'), str(vol), loop)
js = u'show_video("init", "%s", %s, %s);' % (path.replace(u'\\', u'\\\\'), str(vol), loop)
display.frame.evaluateJavaScript(js)
return True
def resize(self, display):
controller = display.controller
display.webView.resize(display.size())
def play(self, display):
@ -332,8 +336,7 @@ class WebkitPlayer(MediaPlayer):
display.webLoaded = True
length = 0
start_time = 0
if self.state != MediaState.Paused and \
controller.media_info.start_time > 0:
if self.state != MediaState.Paused and controller.media_info.start_time > 0:
start_time = controller.media_info.start_time
self.set_visible(display, True)
if controller.media_info.is_flash:
@ -399,18 +402,15 @@ class WebkitPlayer(MediaPlayer):
else:
is_visible = "hidden"
if controller.media_info.is_flash:
display.frame.evaluateJavaScript(u'show_flash( \
"setVisible", null, null, "%s");' % (is_visible))
display.frame.evaluateJavaScript(u'show_flash("setVisible", null, null, "%s");' % (is_visible))
else:
display.frame.evaluateJavaScript(u'show_video( \
"setVisible", null, null, null, "%s");' % (is_visible))
display.frame.evaluateJavaScript(u'show_video("setVisible", null, null, null, "%s");' % (is_visible))
def update_ui(self, display):
controller = display.controller
if controller.media_info.is_flash:
currentTime = display.frame.evaluateJavaScript(
u'show_flash("currentTime");')
length = display.frame.evaluateJavaScript( u'show_flash("length");')
currentTime = display.frame.evaluateJavaScript(u'show_flash("currentTime");')
length = display.frame.evaluateJavaScript(u'show_flash("length");')
else:
if display.frame.evaluateJavaScript(
u'show_video("isEnded");') == 'true':
@ -420,8 +420,7 @@ class WebkitPlayer(MediaPlayer):
# check if conversion was ok and value is not 'NaN'
if ok and currentTime != float('inf'):
currentTime = int(currentTime * 1000)
(length, ok) = display.frame.evaluateJavaScript(
u'show_video("length");')
(length, ok) = display.frame.evaluateJavaScript(u'show_video("length");')
# check if conversion was ok and value is not 'NaN'
if ok and length != float('inf'):
length = int(length * 1000)
@ -430,3 +429,12 @@ class WebkitPlayer(MediaPlayer):
controller.seekSlider.setMaximum(length)
if not controller.seekSlider.isSliderDown():
controller.seekSlider.setSliderPosition(currentTime)
def get_info(self):
return(translate('Media.player', 'Webkit is a media player which runs '
'inside a web browser. This player allows text over video to be '
'rendered.') +
u'<br/> <strong>' + translate('Media.player', 'Audio') +
u'</strong><br/>' + unicode(AUDIO_EXT) + u'<br/><strong>' +
translate('Media.player', 'Video') + u'</strong><br/>' +
unicode(VIDEO_EXT) + u'<br/>')

View File

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
@ -39,16 +39,13 @@ log = logging.getLogger(__name__)
from PyQt4 import QtCore, QtGui
from openlp.core.lib import OpenLPToolbar, ServiceItem, Receiver, build_icon, \
ItemCapabilities, SettingsManager, translate, str_to_bool, \
check_directory_exists, Settings
from openlp.core.lib import OpenLPToolbar, ServiceItem, Receiver, build_icon, ItemCapabilities, SettingsManager, \
translate, str_to_bool, check_directory_exists, Settings
from openlp.core.lib.theme import ThemeLevel
from openlp.core.lib.ui import UiStrings, critical_error_message_box, \
create_widget_action, find_and_set_in_combo_box
from openlp.core.lib.ui import UiStrings, critical_error_message_box, create_widget_action, find_and_set_in_combo_box
from openlp.core.ui import ServiceNoteForm, ServiceItemEditForm, StartTimeForm
from openlp.core.ui.printserviceform import PrintServiceForm
from openlp.core.utils import AppLocation, delete_file, split_filename, \
format_time
from openlp.core.utils import AppLocation, delete_file, split_filename, format_time
from openlp.core.utils.actions import ActionList, CategoryOrder
class ServiceManagerList(QtGui.QTreeWidget):
@ -98,14 +95,16 @@ class ServiceManager(QtGui.QWidget):
"""
Manages the services. This involves taking text strings from plugins and
adding them to the service. This service can then be zipped up with all
the resources used into one OSZ file for use on any OpenLP v2 installation.
Also handles the UI tasks of moving things up and down etc.
the resources used into one OSZ or oszl file for use on any OpenLP v2
installation. Also handles the UI tasks of moving things up and down etc.
"""
def __init__(self, mainwindow, parent=None):
"""
Sets up the service manager, toolbars, list view, et al.
"""
QtGui.QWidget.__init__(self, parent)
self.active = build_icon(QtGui.QImage(u':/media/auto-start_active.png'))
self.inactive = build_icon(QtGui.QImage(u':/media/auto-start_inactive.png'))
self.mainwindow = mainwindow
self.serviceItems = []
self.suffixes = []
@ -124,30 +123,21 @@ class ServiceManager(QtGui.QWidget):
self.layout.setMargin(0)
# Create the top toolbar
self.toolbar = OpenLPToolbar(self)
self.toolbar.addToolbarAction(u'newService',
text=UiStrings().NewService, icon=u':/general/general_new.png',
tooltip=UiStrings().CreateService,
triggers=self.onNewServiceClicked)
self.toolbar.addToolbarAction(u'openService',
text=UiStrings().OpenService, icon=u':/general/general_open.png',
tooltip=translate('OpenLP.ServiceManager',
'Load an existing service.'), triggers=self.onLoadServiceClicked)
self.toolbar.addToolbarAction(u'saveService',
text=UiStrings().SaveService, icon=u':/general/general_save.png',
tooltip=translate('OpenLP.ServiceManager', 'Save this service.'),
triggers=self.saveFile)
self.toolbar.addToolbarAction(u'newService', text=UiStrings().NewService, icon=u':/general/general_new.png',
tooltip=UiStrings().CreateService, triggers=self.onNewServiceClicked)
self.toolbar.addToolbarAction(u'openService', text=UiStrings().OpenService, icon=u':/general/general_open.png',
tooltip=translate('OpenLP.ServiceManager', 'Load an existing service.'), triggers=self.onLoadServiceClicked)
self.toolbar.addToolbarAction(u'saveService', text=UiStrings().SaveService, icon=u':/general/general_save.png',
tooltip=translate('OpenLP.ServiceManager', 'Save this service.'), triggers=self.decideSaveMethod)
self.toolbar.addSeparator()
self.themeLabel = QtGui.QLabel(u'%s:' % UiStrings().Theme, self)
self.themeLabel.setMargin(3)
self.themeLabel.setObjectName(u'themeLabel')
self.toolbar.addToolbarWidget(self.themeLabel)
self.themeComboBox = QtGui.QComboBox(self.toolbar)
self.themeComboBox.setToolTip(translate('OpenLP.ServiceManager',
'Select a theme for the service.'))
self.themeComboBox.setSizeAdjustPolicy(
QtGui.QComboBox.AdjustToMinimumContentsLength)
self.themeComboBox.setSizePolicy(
QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Fixed)
self.themeComboBox.setToolTip(translate('OpenLP.ServiceManager', 'Select a theme for the service.'))
self.themeComboBox.setSizeAdjustPolicy(QtGui.QComboBox.AdjustToMinimumContentsLength)
self.themeComboBox.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Fixed)
self.themeComboBox.setObjectName(u'themeComboBox')
self.toolbar.addToolbarWidget(self.themeComboBox)
self.toolbar.setObjectName(u'toolbar')
@ -158,15 +148,12 @@ class ServiceManager(QtGui.QWidget):
QtGui.QAbstractItemView.CurrentChanged |
QtGui.QAbstractItemView.DoubleClicked |
QtGui.QAbstractItemView.EditKeyPressed)
self.serviceManagerList.setDragDropMode(
QtGui.QAbstractItemView.DragDrop)
self.serviceManagerList.setDragDropMode(QtGui.QAbstractItemView.DragDrop)
self.serviceManagerList.setAlternatingRowColors(True)
self.serviceManagerList.setHeaderHidden(True)
self.serviceManagerList.setExpandsOnDoubleClick(False)
self.serviceManagerList.setContextMenuPolicy(
QtCore.Qt.CustomContextMenu)
QtCore.QObject.connect(self.serviceManagerList,
QtCore.SIGNAL('customContextMenuRequested(QPoint)'),
self.serviceManagerList.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
QtCore.QObject.connect(self.serviceManagerList, QtCore.SIGNAL('customContextMenuRequested(QPoint)'),
self.contextMenu)
self.serviceManagerList.setObjectName(u'serviceManagerList')
# enable drop
@ -179,108 +166,71 @@ class ServiceManager(QtGui.QWidget):
action_list = ActionList.get_instance()
action_list.add_category(
UiStrings().Service, CategoryOrder.standardToolbar)
self.serviceManagerList.moveTop = self.orderToolbar.addToolbarAction(
u'moveTop', text=translate('OpenLP.ServiceManager', 'Move to &top'),
icon=u':/services/service_top.png', tooltip=translate(
'OpenLP.ServiceManager', 'Move item to the top of the service.'),
shortcuts=[QtCore.Qt.Key_Home], category=UiStrings().Service,
triggers=self.onServiceTop)
self.serviceManagerList.moveUp = self.orderToolbar.addToolbarAction(
u'moveUp', text=translate('OpenLP.ServiceManager', 'Move &up'),
icon=u':/services/service_up.png',
tooltip=translate('OpenLP.ServiceManager',
'Move item up one position in the service.'),
shortcuts=[QtCore.Qt.Key_PageUp], category=UiStrings().Service,
triggers=self.onServiceUp)
self.serviceManagerList.moveDown = self.orderToolbar.addToolbarAction(
u'moveDown', text=translate('OpenLP.ServiceManager', 'Move &down'),
icon=u':/services/service_down.png',
tooltip=translate('OpenLP.ServiceManager',
'Move item down one position in the service.'),
shortcuts=[QtCore.Qt.Key_PageDown], category=UiStrings().Service,
triggers=self.onServiceDown)
self.serviceManagerList.moveBottom = self.orderToolbar.addToolbarAction(
u'moveBottom',
text=translate('OpenLP.ServiceManager', 'Move to &bottom'),
icon=u':/services/service_bottom.png', tooltip=translate(
'OpenLP.ServiceManager', 'Move item to the end of the service.'),
shortcuts=[QtCore.Qt.Key_End], category=UiStrings().Service,
triggers=self.onServiceEnd)
self.serviceManagerList.down = self.orderToolbar.addToolbarAction(
u'down', text=translate('OpenLP.ServiceManager', 'Move &down'),
tooltip=translate('OpenLP.ServiceManager',
'Moves the selection down the window.'), visible=False,
self.serviceManagerList.moveTop = self.orderToolbar.addToolbarAction(u'moveTop',
text=translate('OpenLP.ServiceManager', 'Move to &top'), icon=u':/services/service_top.png',
tooltip=translate('OpenLP.ServiceManager', 'Move item to the top of the service.'),
shortcuts=[QtCore.Qt.Key_Home], category=UiStrings().Service, triggers=self.onServiceTop)
self.serviceManagerList.moveUp = self.orderToolbar.addToolbarAction(u'moveUp',
text=translate('OpenLP.ServiceManager', 'Move &up'), icon=u':/services/service_up.png',
tooltip=translate('OpenLP.ServiceManager', 'Move item up one position in the service.'),
shortcuts=[QtCore.Qt.Key_PageUp], category=UiStrings().Service, triggers=self.onServiceUp)
self.serviceManagerList.moveDown = self.orderToolbar.addToolbarAction(u'moveDown',
text=translate('OpenLP.ServiceManager', 'Move &down'), icon=u':/services/service_down.png',
tooltip=translate('OpenLP.ServiceManager', 'Move item down one position in the service.'),
shortcuts=[QtCore.Qt.Key_PageDown], category=UiStrings().Service, triggers=self.onServiceDown)
self.serviceManagerList.moveBottom = self.orderToolbar.addToolbarAction(u'moveBottom',
text=translate('OpenLP.ServiceManager', 'Move to &bottom'), icon=u':/services/service_bottom.png',
tooltip=translate('OpenLP.ServiceManager', 'Move item to the end of the service.'),
shortcuts=[QtCore.Qt.Key_End], category=UiStrings().Service, triggers=self.onServiceEnd)
self.serviceManagerList.down = self.orderToolbar.addToolbarAction(u'down',
text=translate('OpenLP.ServiceManager', 'Move &down'),
tooltip=translate('OpenLP.ServiceManager', 'Moves the selection down the window.'), visible=False,
shortcuts=[QtCore.Qt.Key_Down], triggers=self.onMoveSelectionDown)
action_list.add_action(self.serviceManagerList.down)
self.serviceManagerList.up = self.orderToolbar.addToolbarAction(
u'up', text=translate('OpenLP.ServiceManager', 'Move up'),
tooltip=translate('OpenLP.ServiceManager',
'Moves the selection up the window.'), visible=False,
shortcuts=[QtCore.Qt.Key_Up], triggers=self.onMoveSelectionUp)
self.serviceManagerList.up = self.orderToolbar.addToolbarAction(u'up',
text=translate('OpenLP.ServiceManager', 'Move up'), tooltip=translate('OpenLP.ServiceManager',
'Moves the selection up the window.'), visible=False, shortcuts=[QtCore.Qt.Key_Up],
triggers=self.onMoveSelectionUp)
action_list.add_action(self.serviceManagerList.up)
self.orderToolbar.addSeparator()
self.serviceManagerList.delete = self.orderToolbar.addToolbarAction(
u'delete',
text=translate('OpenLP.ServiceManager', '&Delete From Service'),
icon=u':/general/general_delete.png',
tooltip=translate('OpenLP.ServiceManager',
'Delete the selected item from the service.'),
shortcuts=[QtCore.Qt.Key_Delete],
triggers=self.onDeleteFromService)
self.serviceManagerList.delete = self.orderToolbar.addToolbarAction(u'delete',
text=translate('OpenLP.ServiceManager', '&Delete From Service'), icon=u':/general/general_delete.png',
tooltip=translate('OpenLP.ServiceManager', 'Delete the selected item from the service.'),
shortcuts=[QtCore.Qt.Key_Delete], triggers=self.onDeleteFromService)
self.orderToolbar.addSeparator()
self.serviceManagerList.expand = self.orderToolbar.addToolbarAction(
u'expand', text=translate('OpenLP.ServiceManager', '&Expand all'),
icon=u':/services/service_expand_all.png', tooltip=translate(
'OpenLP.ServiceManager', 'Expand all the service items.'),
shortcuts=[QtCore.Qt.Key_Plus], category=UiStrings().Service,
triggers=self.onExpandAll)
self.serviceManagerList.collapse = self.orderToolbar.addToolbarAction(
u'collapse',
text=translate('OpenLP.ServiceManager', '&Collapse all'),
icon=u':/services/service_collapse_all.png', tooltip=translate(
'OpenLP.ServiceManager', 'Collapse all the service items.'),
shortcuts=[QtCore.Qt.Key_Minus], category=UiStrings().Service,
triggers=self.onCollapseAll)
self.serviceManagerList.expand = self.orderToolbar.addToolbarAction(u'expand',
text=translate('OpenLP.ServiceManager', '&Expand all'), icon=u':/services/service_expand_all.png',
tooltip=translate('OpenLP.ServiceManager', 'Expand all the service items.'),
shortcuts=[QtCore.Qt.Key_Plus], category=UiStrings().Service, triggers=self.onExpandAll)
self.serviceManagerList.collapse = self.orderToolbar.addToolbarAction(u'collapse',
text=translate('OpenLP.ServiceManager', '&Collapse all'), icon=u':/services/service_collapse_all.png',
tooltip=translate('OpenLP.ServiceManager', 'Collapse all the service items.'),
shortcuts=[QtCore.Qt.Key_Minus], category=UiStrings().Service, triggers=self.onCollapseAll)
self.orderToolbar.addSeparator()
self.serviceManagerList.makeLive = self.orderToolbar.addToolbarAction(
u'makeLive', text=translate('OpenLP.ServiceManager', 'Go Live'),
icon=u':/general/general_live.png', tooltip=translate(
'OpenLP.ServiceManager', 'Send the selected item to Live.'),
shortcuts=[QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return],
category=UiStrings().Service, triggers=self.makeLive)
self.serviceManagerList.makeLive = self.orderToolbar.addToolbarAction(u'makeLive',
text=translate('OpenLP.ServiceManager', 'Go Live'), icon=u':/general/general_live.png',
tooltip=translate('OpenLP.ServiceManager', 'Send the selected item to Live.'),
shortcuts=[QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return], category=UiStrings().Service, triggers=self.makeLive)
self.layout.addWidget(self.orderToolbar)
# Connect up our signals and slots
QtCore.QObject.connect(self.themeComboBox,
QtCore.SIGNAL(u'activated(int)'), self.onThemeComboBoxSelected)
QtCore.QObject.connect(self.serviceManagerList,
QtCore.SIGNAL(u'doubleClicked(QModelIndex)'), self.onMakeLive)
QtCore.QObject.connect(self.serviceManagerList,
QtCore.SIGNAL(u'itemCollapsed(QTreeWidgetItem*)'), self.collapsed)
QtCore.QObject.connect(self.serviceManagerList,
QtCore.SIGNAL(u'itemExpanded(QTreeWidgetItem*)'), self.expanded)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'theme_update_list'), self.updateThemeList)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'servicemanager_preview_live'), self.previewLive)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'servicemanager_next_item'), self.nextItem)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'servicemanager_previous_item'), self.previousItem)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'servicemanager_set_item'), self.onSetItem)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'config_updated'), self.configUpdated)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'config_screen_changed'),
QtCore.QObject.connect(self.themeComboBox, QtCore.SIGNAL(u'activated(int)'), self.onThemeComboBoxSelected)
QtCore.QObject.connect(self.serviceManagerList, QtCore.SIGNAL(u'doubleClicked(QModelIndex)'), self.onMakeLive)
QtCore.QObject.connect(self.serviceManagerList, QtCore.SIGNAL(u'itemCollapsed(QTreeWidgetItem*)'),
self.collapsed)
QtCore.QObject.connect(self.serviceManagerList, QtCore.SIGNAL(u'itemExpanded(QTreeWidgetItem*)'), self.expanded)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'theme_update_list'), self.updateThemeList)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'servicemanager_preview_live'), self.previewLive)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'servicemanager_next_item'), self.nextItem)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'servicemanager_previous_item'),
self.previousItem)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'servicemanager_set_item'), self.onSetItem)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'config_updated'), self.configUpdated)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'config_screen_changed'),
self.regenerateServiceItems)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'theme_update_global'), self.themeChange)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'service_item_update'), self.serviceItemUpdate)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'theme_update_global'), self.themeChange)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'service_item_update'), self.serviceItemUpdate)
# Last little bits of setting up
self.service_theme = Settings().value(
self.mainwindow.serviceManagerSettingsSection + u'/service theme',
u'')
self.service_theme = Settings().value(self.mainwindow.serviceManagerSettingsSection + u'/service theme', u'')
self.servicePath = AppLocation.get_section_data_path(u'servicemanager')
# build the drag and drop context menu
self.dndMenu = QtGui.QMenu()
@ -292,31 +242,25 @@ class ServiceManager(QtGui.QWidget):
self.addToAction.setIcon(build_icon(u':/general/general_edit.png'))
# build the context menu
self.menu = QtGui.QMenu()
self.editAction = create_widget_action(self.menu,
text=translate('OpenLP.ServiceManager', '&Edit Item'),
self.editAction = create_widget_action(self.menu, text=translate('OpenLP.ServiceManager', '&Edit Item'),
icon=u':/general/general_edit.png', triggers=self.remoteEdit)
self.maintainAction = create_widget_action(self.menu,
text=translate('OpenLP.ServiceManager', '&Reorder Item'),
icon=u':/general/general_edit.png',
triggers=self.onServiceItemEditForm)
self.notesAction = create_widget_action(self.menu,
text=translate('OpenLP.ServiceManager', '&Notes'),
icon=u':/services/service_notes.png',
triggers=self.onServiceItemNoteForm)
self.timeAction = create_widget_action(self.menu,
text=translate('OpenLP.ServiceManager', '&Start Time'),
self.maintainAction = create_widget_action(self.menu, text=translate('OpenLP.ServiceManager', '&Reorder Item'),
icon=u':/general/general_edit.png', triggers=self.onServiceItemEditForm)
self.notesAction = create_widget_action(self.menu, text=translate('OpenLP.ServiceManager', '&Notes'),
icon=u':/services/service_notes.png', triggers=self.onServiceItemNoteForm)
self.timeAction = create_widget_action(self.menu, text=translate('OpenLP.ServiceManager', '&Start Time'),
icon=u':/media/media_time.png', triggers=self.onStartTimeForm)
self.autoStartAction = create_widget_action(self.menu, text=u'',
icon=u':/media/auto-start_active.png', triggers=self.onAutoStart)
# Add already existing delete action to the menu.
self.menu.addAction(self.serviceManagerList.delete)
self.menu.addSeparator()
self.previewAction = create_widget_action(self.menu,
text=translate('OpenLP.ServiceManager', 'Show &Preview'),
self.previewAction = create_widget_action(self.menu, text=translate('OpenLP.ServiceManager', 'Show &Preview'),
icon=u':/general/general_preview.png', triggers=self.makePreview)
# Add already existing make live action to the menu.
self.menu.addAction(self.serviceManagerList.makeLive)
self.menu.addSeparator()
self.themeMenu = QtGui.QMenu(
translate('OpenLP.ServiceManager', '&Change Item Theme'))
self.themeMenu = QtGui.QMenu(translate('OpenLP.ServiceManager', '&Change Item Theme'))
self.menu.addMenu(self.themeMenu)
self.serviceManagerList.addActions(
[self.serviceManagerList.moveDown,
@ -339,8 +283,7 @@ class ServiceManager(QtGui.QWidget):
if modified:
self.serviceId += 1
self._modified = modified
serviceFile = self.shortFileName() or translate(
'OpenLP.ServiceManager', 'Untitled Service')
serviceFile = self.shortFileName() or translate('OpenLP.ServiceManager', 'Untitled Service')
self.mainwindow.setServiceModified(modified, serviceFile)
def isModified(self):
@ -357,6 +300,7 @@ class ServiceManager(QtGui.QWidget):
self.mainwindow.setServiceModified(self.isModified(),
self.shortFileName())
Settings().setValue(u'servicemanager/last file', fileName)
self._saveLite = self._fileName.endswith(u'.oszl')
def fileName(self):
"""
@ -374,8 +318,14 @@ class ServiceManager(QtGui.QWidget):
"""
Triggered when Config dialog is updated.
"""
self.expandTabs = Settings().value(
u'advanced/expand service item', False)
self.expandTabs = Settings().value(u'advanced/expand service item', False)
def resetSupportedSuffixes(self):
"""
Resets the Suffixes list.
"""
self.suffixes = []
def supportedSuffixes(self, suffix):
"""
@ -384,7 +334,8 @@ class ServiceManager(QtGui.QWidget):
``suffix``
New Suffix to be supported
"""
self.suffixes.append(suffix)
if not suffix in self.suffixes:
self.suffixes.append(suffix)
def onNewServiceClicked(self):
"""
@ -395,7 +346,7 @@ class ServiceManager(QtGui.QWidget):
if result == QtGui.QMessageBox.Cancel:
return False
elif result == QtGui.QMessageBox.Save:
if not self.saveFile():
if not self.decideSaveMethod():
return False
self.newFile()
@ -413,31 +364,25 @@ class ServiceManager(QtGui.QWidget):
if result == QtGui.QMessageBox.Cancel:
return False
elif result == QtGui.QMessageBox.Save:
self.saveFile()
self.decideSaveMethod()
if not loadFile:
fileName = QtGui.QFileDialog.getOpenFileName(
self.mainwindow,
fileName = QtGui.QFileDialog.getOpenFileName(self.mainwindow,
translate('OpenLP.ServiceManager', 'Open File'),
SettingsManager.get_last_dir(
self.mainwindow.serviceManagerSettingsSection),
translate('OpenLP.ServiceManager',
'OpenLP Service Files (*.osz)'))
SettingsManager.get_last_dir(self.mainwindow.serviceManagerSettingsSection),
translate('OpenLP.ServiceManager', 'OpenLP Service Files (*.osz *.oszl)'))
if not fileName:
return False
else:
fileName = loadFile
SettingsManager.set_last_dir(
self.mainwindow.serviceManagerSettingsSection,
split_filename(fileName)[0])
SettingsManager.set_last_dir(self.mainwindow.serviceManagerSettingsSection, split_filename(fileName)[0])
self.loadFile(fileName)
def saveModifiedService(self):
return QtGui.QMessageBox.question(self.mainwindow,
translate('OpenLP.ServiceManager', 'Modified Service'),
translate('OpenLP.ServiceManager', 'The current service has '
'been modified. Would you like to save this service?'),
QtGui.QMessageBox.Save | QtGui.QMessageBox.Discard |
QtGui.QMessageBox.Cancel, QtGui.QMessageBox.Save)
translate('OpenLP.ServiceManager',
'The current service has been modified. Would you like to save this service?'),
QtGui.QMessageBox.Save | QtGui.QMessageBox.Discard | QtGui.QMessageBox.Cancel, QtGui.QMessageBox.Save)
def onRecentServiceClicked(self):
sender = self.sender()
@ -500,16 +445,12 @@ class ServiceManager(QtGui.QWidget):
write_list.append(path_from)
if missing_list:
Receiver.send_message(u'cursor_normal')
title = translate('OpenLP.ServiceManager',
'Service File(s) Missing')
title = translate('OpenLP.ServiceManager', 'Service File(s) Missing')
message = translate('OpenLP.ServiceManager',
'The following file(s) in the service are missing:\n\t%s\n\n'
'These files will be removed if you continue to save.') % \
"\n\t".join(missing_list)
answer = QtGui.QMessageBox.critical(self, title,
message,
QtGui.QMessageBox.StandardButtons(
QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel))
'These files will be removed if you continue to save.') % "\n\t".join(missing_list)
answer = QtGui.QMessageBox.critical(self, title, message,
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel))
if answer == QtGui.QMessageBox.Cancel:
self.mainwindow.finishedProgressBar()
return False
@ -521,23 +462,21 @@ class ServiceManager(QtGui.QWidget):
if not item[u'service_item'].validate():
self.serviceItems.remove(item)
else:
service_item = item[u'service_item'].get_service_repr()
service_item = item[u'service_item'].get_service_repr(self._saveLite)
if service_item[u'header'][u'background_audio']:
for i, filename in enumerate(
service_item[u'header'][u'background_audio']):
new_file = os.path.join(u'audio',
item[u'service_item']._uuid, filename)
audio_files.append((filename, new_file))
service_item[u'header'][u'background_audio'][i] = \
new_file
service_item[u'header'][u'background_audio'][i] = new_file
# Add the service item to the service.
service.append({u'serviceitem': service_item})
self.repaintServiceList(-1, -1)
for file in write_list:
file_size = os.path.getsize(file)
total_size += file_size
log.debug(u'ServiceManager.saveFile - ZIP contents size is %i bytes' %
total_size)
log.debug(u'ServiceManager.saveFile - ZIP contents size is %i bytes' % total_size)
service_content = cPickle.dumps(service)
# Usual Zip file cannot exceed 2GiB, file with Zip64 cannot be
# extracted using unzip in UNIX.
@ -547,8 +486,7 @@ class ServiceManager(QtGui.QWidget):
success = True
self.mainwindow.incrementProgressBar()
try:
zip = zipfile.ZipFile(temp_file_name, 'w', zipfile.ZIP_STORED,
allow_zip_64)
zip = zipfile.ZipFile(temp_file_name, 'w', zipfile.ZIP_STORED, allow_zip_64)
# First we add service contents.
# We save ALL filenames into ZIP using UTF-8.
zip.writestr(service_file_name.encode(u'utf-8'), service_content)
@ -571,10 +509,70 @@ class ServiceManager(QtGui.QWidget):
except IOError:
log.exception(u'Failed to save service to disk: %s', temp_file_name)
Receiver.send_message(u'openlp_error_message', {
u'title': translate(u'OpenLP.ServiceManager',
u'Error Saving File'),
u'message': translate(u'OpenLP.ServiceManager',
u'There was an error saving your file.')
u'title': translate(u'OpenLP.ServiceManager', u'Error Saving File'),
u'message': translate(u'OpenLP.ServiceManager', u'There was an error saving your file.')
})
success = False
finally:
if zip:
zip.close()
self.mainwindow.finishedProgressBar()
Receiver.send_message(u'cursor_normal')
if success:
try:
shutil.copy(temp_file_name, path_file_name)
except:
return self.saveFileAs()
self.mainwindow.addRecentFile(path_file_name)
self.setModified(False)
delete_file(temp_file_name)
return success
def saveLocalFile(self):
"""
Save the current service file.
A temporary file is created so that we don't overwrite the existing one
and leave a mangled service file should there be an error when saving.
No files are added to this version of the service as it is deisgned
to only work on the machine it was save on if there are files.
"""
if not self.fileName():
return self.saveFileAs()
temp_file, temp_file_name = mkstemp(u'.oszl', u'openlp_')
# We don't need the file handle.
os.close(temp_file)
log.debug(temp_file_name)
path_file_name = unicode(self.fileName())
path, file_name = os.path.split(path_file_name)
basename = os.path.splitext(file_name)[0]
service_file_name = '%s.osd' % basename
log.debug(u'ServiceManager.saveFile - %s', path_file_name)
SettingsManager.set_last_dir(self.mainwindow.serviceManagerSettingsSection, path)
service = []
Receiver.send_message(u'cursor_busy')
# Number of items + 1 to zip it
self.mainwindow.displayProgressBar(len(self.serviceItems) + 1)
for item in self.serviceItems:
self.mainwindow.incrementProgressBar()
service_item = item[u'service_item'].get_service_repr(self._saveLite)
#@todo check for file item on save.
service.append({u'serviceitem': service_item})
self.mainwindow.incrementProgressBar()
service_content = cPickle.dumps(service)
zip = None
success = True
self.mainwindow.incrementProgressBar()
try:
zip = zipfile.ZipFile(temp_file_name, 'w', zipfile.ZIP_STORED,
True)
# First we add service contents.
zip.writestr(service_file_name.encode(u'utf-8'), service_content)
except IOError:
log.exception(u'Failed to save service to disk: %s', temp_file_name)
Receiver.send_message(u'openlp_error_message', {
u'title': translate(u'OpenLP.ServiceManager', u'Error Saving File'),
u'message': translate(u'OpenLP.ServiceManager', u'There was an error saving your file.')
})
success = False
finally:
@ -597,39 +595,39 @@ class ServiceManager(QtGui.QWidget):
Get a file name and then call :func:`ServiceManager.saveFile` to
save the file.
"""
default_service_enabled = Settings().value(
u'advanced/default service enabled', True)
default_service_enabled = Settings().value(u'advanced/default service enabled', True)
if default_service_enabled:
service_day = Settings().value(u'advanced/default service day', 7)
if service_day == 7:
local_time = datetime.now()
else:
service_hour = Settings().value(
u'advanced/default service hour', 11)
service_minute = Settings().value(
u'advanced/default service minute', 0)
service_hour = Settings().value(u'advanced/default service hour', 11)
service_minute = Settings().value(u'advanced/default service minute', 0)
now = datetime.now()
day_delta = service_day - now.weekday()
if day_delta < 0:
day_delta += 7
time = now + timedelta(days=day_delta)
local_time = time.replace(hour=service_hour, minute=service_minute)
default_pattern = Settings().value(
u'advanced/default service name',
default_pattern = Settings().value(u'advanced/default service name',
translate('OpenLP.AdvancedTab', 'Service %Y-%m-%d %H-%M',
'This may not contain any of the following characters: '
'/\\?*|<>\[\]":+\nSee http://docs.python.org/library/'
'datetime.html#strftime-strptime-behavior for more '
'information.'))
'datetime.html#strftime-strptime-behavior for more information.'))
default_filename = format_time(default_pattern, local_time)
else:
default_filename = u''
directory = SettingsManager.get_last_dir(
self.mainwindow.serviceManagerSettingsSection)
directory = SettingsManager.get_last_dir(self.mainwindow.serviceManagerSettingsSection)
path = os.path.join(directory, default_filename)
fileName = QtGui.QFileDialog.getSaveFileName(self.mainwindow,
UiStrings().SaveService, path,
translate('OpenLP.ServiceManager', 'OpenLP Service Files (*.osz)'))
# SaveAs from osz to oszl is not valid as the files will be deleted
# on exit which is not sensible or usable in the long term.
if self._fileName.endswith(u'oszl') or not self._fileName:
fileName = QtGui.QFileDialog.getSaveFileName(self.mainwindow, UiStrings().SaveService, path,
translate('OpenLP.ServiceManager',
'OpenLP Service Files (*.osz);; OpenLP Service Files - lite (*.oszl)'))
else:
fileName = QtGui.QFileDialog.getSaveFileName(self.mainwindow, UiStrings().SaveService, path,
translate('OpenLP.ServiceManager', 'OpenLP Service Files (*.osz);;'))
if not fileName:
return False
if os.path.splitext(fileName)[1] == u'':
@ -638,9 +636,23 @@ class ServiceManager(QtGui.QWidget):
ext = os.path.splitext(fileName)[1]
fileName.replace(ext, u'.osz')
self.setFileName(fileName)
return self.saveFile()
self.decideSaveMethod()
def decideSaveMethod(self):
"""
Determine which type of save method to use.
"""
if not self.fileName():
return self.saveFileAs()
if self._saveLite:
return self.saveLocalFile()
else:
return self.saveFile()
def loadFile(self, fileName):
"""
Load an existing service file
"""
if not fileName:
return False
fileName = unicode(fileName)
@ -654,12 +666,9 @@ class ServiceManager(QtGui.QWidget):
try:
ucsfile = zipinfo.filename.decode(u'utf-8')
except UnicodeDecodeError:
log.exception(u'Filename "%s" is not valid UTF-8' %
zipinfo.filename.decode(u'utf-8', u'replace'))
critical_error_message_box(
message=translate('OpenLP.ServiceManager',
'File is not a valid service.\n'
'The content encoding is not UTF-8.'))
log.exception(u'Filename "%s" is not valid UTF-8' % zipinfo.filename.decode(u'utf-8', u'replace'))
critical_error_message_box(message=translate('OpenLP.ServiceManager',
'File is not a valid service.\n The content encoding is not UTF-8.'))
continue
osfile = ucsfile.replace(u'/', os.path.sep)
if not osfile.startswith(u'audio'):
@ -675,52 +684,47 @@ class ServiceManager(QtGui.QWidget):
items = cPickle.load(fileTo)
fileTo.close()
self.newFile()
self.setFileName(fileName)
self.mainwindow.displayProgressBar(len(items))
for item in items:
self.mainwindow.incrementProgressBar()
serviceItem = ServiceItem()
serviceItem.renderer = self.mainwindow.renderer
serviceItem.set_from_service(item, self.servicePath)
if self._saveLite:
serviceItem.set_from_service(item)
else:
serviceItem.set_from_service(item, self.servicePath)
self.validateItem(serviceItem)
self.load_item_uuid = 0
if serviceItem.is_capable(ItemCapabilities.OnLoadUpdate):
Receiver.send_message(u'%s_service_load' %
serviceItem.name.lower(), serviceItem)
Receiver.send_message(u'%s_service_load' % serviceItem.name.lower(), serviceItem)
# if the item has been processed
if serviceItem._uuid == self.load_item_uuid:
serviceItem.edit_id = int(self.load_item_edit_id)
serviceItem.temporary_edit = self.load_item_temporary
self.addServiceItem(serviceItem, repaint=False)
delete_file(p_file)
self.setFileName(fileName)
self.mainwindow.addRecentFile(fileName)
self.setModified(False)
Settings().setValue(
'servicemanager/last file', fileName)
Settings().setValue('servicemanager/last file', fileName)
else:
critical_error_message_box(
message=translate('OpenLP.ServiceManager',
'File is not a valid service.'))
critical_error_message_box(message=translate('OpenLP.ServiceManager', 'File is not a valid service.'))
log.exception(u'File contains no service data')
except (IOError, NameError, zipfile.BadZipfile):
log.exception(u'Problem loading service file %s' % fileName)
critical_error_message_box(
message=translate('OpenLP.ServiceManager',
critical_error_message_box(message=translate('OpenLP.ServiceManager',
'File could not be opened because it is corrupt.'))
except zipfile.BadZipfile:
if os.path.getsize(fileName) == 0:
log.exception(u'Service file is zero sized: %s' % fileName)
QtGui.QMessageBox.information(self,
translate('OpenLP.ServiceManager', 'Empty File'),
translate('OpenLP.ServiceManager', 'This service file '
'does not contain any data.'))
QtGui.QMessageBox.information(self, translate('OpenLP.ServiceManager', 'Empty File'),
translate('OpenLP.ServiceManager', 'This service file does not contain any data.'))
else:
log.exception(u'Service file is cannot be extracted as zip: '
u'%s' % fileName)
QtGui.QMessageBox.information(self,
translate('OpenLP.ServiceManager', 'Corrupt File'),
translate('OpenLP.ServiceManager', 'This file is either '
'corrupt or it is not an OpenLP 2.0 service file.'))
QtGui.QMessageBox.information(self, translate('OpenLP.ServiceManager', 'Corrupt File'),
translate('OpenLP.ServiceManager',
'This file is either corrupt or it is not an OpenLP 2 service file.'))
return
finally:
if fileTo:
@ -737,9 +741,9 @@ class ServiceManager(QtGui.QWidget):
service was last closed. Can be blank if there was no service
present.
"""
file_name = Settings().value(u'servicemanager/last file', u'')
if file_name:
self.loadFile(file_name)
fileName = Settings().value(u'servicemanager/last file', u'')
if fileName:
self.loadFile(fileName)
def contextMenu(self, point):
item = self.serviceManagerList.itemAt(point)
@ -754,27 +758,31 @@ class ServiceManager(QtGui.QWidget):
self.maintainAction.setVisible(False)
self.notesAction.setVisible(False)
self.timeAction.setVisible(False)
if serviceItem[u'service_item'].is_capable(ItemCapabilities.CanEdit)\
and serviceItem[u'service_item'].edit_id:
self.autoStartAction.setVisible(False)
if serviceItem[u'service_item'].is_capable(ItemCapabilities.CanEdit) and serviceItem[u'service_item'].edit_id:
self.editAction.setVisible(True)
if serviceItem[u'service_item'].is_capable(
ItemCapabilities.CanMaintain):
if serviceItem[u'service_item'].is_capable(ItemCapabilities.CanMaintain):
self.maintainAction.setVisible(True)
self.notesAction.setVisible(item.parent() is None)
if serviceItem[u'service_item'].is_capable(
ItemCapabilities.HasVariableStartTime):
if item.parent() is None:
self.notesAction.setVisible(True)
if serviceItem[u'service_item'].is_capable(ItemCapabilities.HasVariableStartTime):
self.timeAction.setVisible(True)
if serviceItem[u'service_item'].is_capable(ItemCapabilities.CanAutoStartForLive):
self.autoStartAction.setVisible(True)
self.autoStartAction.setIcon(self.inactive)
self.autoStartAction.setText(translate('OpenLP.ServiceManager','&Auto Start - inactive'))
if serviceItem[u'service_item'].will_auto_start:
self.autoStartAction.setText(translate('OpenLP.ServiceManager', '&Auto Start - active'))
self.autoStartAction.setIcon(self.active)
self.themeMenu.menuAction().setVisible(False)
# Set up the theme menu.
if serviceItem[u'service_item'].is_text() and \
self.mainwindow.renderer.theme_level == ThemeLevel.Song:
if serviceItem[u'service_item'].is_text() and self.mainwindow.renderer.theme_level == ThemeLevel.Song:
self.themeMenu.menuAction().setVisible(True)
# The service item does not have a theme, check the "Default".
if serviceItem[u'service_item'].theme is None:
themeAction = self.themeMenu.defaultAction()
else:
themeAction = self.themeMenu.findChild(
QtGui.QAction, serviceItem[u'service_item'].theme)
themeAction = self.themeMenu.findChild(QtGui.QAction, serviceItem[u'service_item'].theme)
if themeAction is not None:
themeAction.setChecked(True)
self.menu.exec_(self.serviceManagerList.mapToGlobal(point))
@ -784,8 +792,7 @@ class ServiceManager(QtGui.QWidget):
self.serviceNoteForm.textEdit.setPlainText(
self.serviceItems[item][u'service_item'].notes)
if self.serviceNoteForm.exec_():
self.serviceItems[item][u'service_item'].notes = \
self.serviceNoteForm.textEdit.toPlainText()
self.serviceItems[item][u'service_item'].notes = self.serviceNoteForm.textEdit.toPlainText()
self.repaintServiceList(item, -1)
self.setModified()
@ -798,6 +805,14 @@ class ServiceManager(QtGui.QWidget):
if self.startTimeForm.exec_():
self.repaintServiceList(item, -1)
def onAutoStart(self):
"""
Toggles to Auto Start Setting.
"""
item = self.findServiceItem()[0]
self.serviceItems[item][u'service_item'].will_auto_start = \
not self.serviceItems[item][u'service_item'].will_auto_start
def onServiceItemEditForm(self):
"""
Opens a dialog to edit the service item and update the service
@ -1023,22 +1038,18 @@ class ServiceManager(QtGui.QWidget):
if serviceitem.is_valid:
if serviceitem.notes:
icon = QtGui.QImage(serviceitem.icon)
icon = icon.scaled(80, 80, QtCore.Qt.KeepAspectRatio,
QtCore.Qt.SmoothTransformation)
icon = icon.scaled(80, 80, QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation)
overlay = QtGui.QImage(':/services/service_item_notes.png')
overlay = overlay.scaled(80, 80, QtCore.Qt.KeepAspectRatio,
QtCore.Qt.SmoothTransformation)
overlay = overlay.scaled(80, 80, QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation)
painter = QtGui.QPainter(icon)
painter.drawImage(0, 0, overlay)
painter.end()
treewidgetitem.setIcon(0, build_icon(icon))
elif serviceitem.temporary_edit:
icon = QtGui.QImage(serviceitem.icon)
icon = icon.scaled(80, 80, QtCore.Qt.KeepAspectRatio,
QtCore.Qt.SmoothTransformation)
icon = icon.scaled(80, 80, QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation)
overlay = QtGui.QImage(':/general/general_export.png')
overlay = overlay.scaled(40, 40, QtCore.Qt.KeepAspectRatio,
QtCore.Qt.SmoothTransformation)
overlay = overlay.scaled(40, 40, QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation)
painter = QtGui.QPainter(icon)
painter.drawImage(40, 0, overlay)
painter.end()
@ -1046,25 +1057,20 @@ class ServiceManager(QtGui.QWidget):
else:
treewidgetitem.setIcon(0, serviceitem.iconic_representation)
else:
treewidgetitem.setIcon(0,
build_icon(u':/general/general_delete.png'))
treewidgetitem.setIcon(0, build_icon(u':/general/general_delete.png'))
treewidgetitem.setText(0, serviceitem.get_display_title())
tips = []
if serviceitem.temporary_edit:
tips.append(u'<strong>%s:</strong> <em>%s</em>' %
(translate('OpenLP.ServiceManager', 'Edit'),
(translate('OpenLP.ServiceManager',
'Service copy only'))))
(translate('OpenLP.ServiceManager', 'Service copy only'))))
if serviceitem.theme and serviceitem.theme != -1:
tips.append(u'<strong>%s:</strong> <em>%s</em>' %
(translate('OpenLP.ServiceManager', 'Slide theme'),
serviceitem.theme))
(translate('OpenLP.ServiceManager', 'Slide theme'), serviceitem.theme))
if serviceitem.notes:
tips.append(u'<strong>%s: </strong> %s' %
(translate('OpenLP.ServiceManager', 'Notes'),
cgi.escape(unicode(serviceitem.notes))))
if item[u'service_item'] \
.is_capable(ItemCapabilities.HasVariableStartTime):
(translate('OpenLP.ServiceManager', 'Notes'), cgi.escape(serviceitem.notes)))
if item[u'service_item'].is_capable(ItemCapabilities.HasVariableStartTime):
tips.append(item[u'service_item'].get_media_time())
treewidgetitem.setToolTip(0, u'<br>'.join(tips))
treewidgetitem.setData(0, QtCore.Qt.UserRole, item[u'order'])
@ -1087,10 +1093,12 @@ class ServiceManager(QtGui.QWidget):
Validates the service item and if the suffix matches an accepted
one it allows the item to be displayed.
"""
#@todo check file items exist
if serviceItem.is_command():
type = serviceItem._raw_frames[0][u'title'].split(u'.')[-1]
if type.lower() not in self.suffixes:
serviceItem.is_valid = False
#@todo check file items exist
def cleanUp(self):
"""
@ -1110,9 +1118,7 @@ class ServiceManager(QtGui.QWidget):
log.debug(u'onThemeComboBoxSelected')
self.service_theme = self.themeComboBox.currentText()
self.mainwindow.renderer.set_service_theme(self.service_theme)
Settings().setValue(
self.mainwindow.serviceManagerSettingsSection +
u'/service theme', self.service_theme)
Settings().setValue(self.mainwindow.serviceManagerSettingsSection + u'/service theme', self.service_theme)
self.regenerateServiceItems(True)
def themeChange(self):
@ -1137,8 +1143,7 @@ class ServiceManager(QtGui.QWidget):
if self.serviceItems:
for item in self.serviceItems:
item[u'selected'] = False
serviceIterator = QtGui.QTreeWidgetItemIterator(
self.serviceManagerList)
serviceIterator = QtGui.QTreeWidgetItemIterator(self.serviceManagerList)
selectedItem = None
while serviceIterator.value():
if serviceIterator.value().isSelected():
@ -1155,9 +1160,8 @@ class ServiceManager(QtGui.QWidget):
self.serviceItems = []
self.isNew = True
for item in tempServiceItems:
self.addServiceItem(
item[u'service_item'], False, expand=item[u'expanded'],
repaint=False, selected=item[u'selected'])
self.addServiceItem(item[u'service_item'], False, expand=item[u'expanded'], repaint=False,
selected=item[u'selected'])
# Set to False as items may have changed rendering
# does not impact the saved song so True may also be valid
if changed:
@ -1181,18 +1185,15 @@ class ServiceManager(QtGui.QWidget):
if found.
"""
for itemcount, item in enumerate(self.serviceItems):
if item[u'service_item'].edit_id == newItem.edit_id and \
item[u'service_item'].name == newItem.name:
if item[u'service_item'].edit_id == newItem.edit_id and item[u'service_item'].name == newItem.name:
newItem.render()
newItem.merge(item[u'service_item'])
item[u'service_item'] = newItem
self.repaintServiceList(itemcount + 1, 0)
self.mainwindow.liveController.replaceServiceManagerItem(
newItem)
self.mainwindow.liveController.replaceServiceManagerItem(newItem)
self.setModified()
def addServiceItem(self, item, rebuild=False, expand=None, replace=False,
repaint=True, selected=False):
def addServiceItem(self, item, rebuild=False, expand=None, replace=False, repaint=True, selected=False):
"""
Add a Service item to the list
@ -1248,10 +1249,9 @@ class ServiceManager(QtGui.QWidget):
self.mainwindow.previewController.addServiceManagerItem(
self.serviceItems[item][u'service_item'], child)
else:
critical_error_message_box(
translate('OpenLP.ServiceManager', 'Missing Display Handler'),
translate('OpenLP.ServiceManager', 'Your item cannot be '
'displayed as there is no handler to display it'))
critical_error_message_box(translate('OpenLP.ServiceManager', 'Missing Display Handler'),
translate('OpenLP.ServiceManager',
'Your item cannot be displayed as there is no handler to display it'))
Receiver.send_message(u'cursor_normal')
def getServiceItem(self):
@ -1294,17 +1294,13 @@ class ServiceManager(QtGui.QWidget):
False):
item += 1
if self.serviceItems and item < len(self.serviceItems) and \
self.serviceItems[item][u'service_item'].is_capable(
ItemCapabilities.CanPreview):
self.mainwindow.previewController.addServiceManagerItem(
self.serviceItems[item][u'service_item'], 0)
self.serviceItems[item][u'service_item'].is_capable(ItemCapabilities.CanPreview):
self.mainwindow.previewController.addServiceManagerItem(self.serviceItems[item][u'service_item'], 0)
self.mainwindow.liveController.previewListWidget.setFocus()
else:
critical_error_message_box(
translate('OpenLP.ServiceManager', 'Missing Display Handler'),
translate('OpenLP.ServiceManager', 'Your item cannot be '
'displayed as the plugin required to display it is missing '
'or inactive'))
critical_error_message_box(translate('OpenLP.ServiceManager', 'Missing Display Handler'),
translate('OpenLP.ServiceManager',
'Your item cannot be displayed as the plugin required to display it is missing or inactive'))
Receiver.send_message(u'cursor_normal')
def remoteEdit(self):
@ -1312,10 +1308,8 @@ class ServiceManager(QtGui.QWidget):
Posts a remote edit message to a plugin to allow item to be edited.
"""
item = self.findServiceItem()[0]
if self.serviceItems[item][u'service_item']\
.is_capable(ItemCapabilities.CanEdit):
Receiver.send_message(u'%s_edit' %
self.serviceItems[item][u'service_item'].name.lower(),
if self.serviceItems[item][u'service_item'].is_capable(ItemCapabilities.CanEdit):
Receiver.send_message(u'%s_edit' % self.serviceItems[item][u'service_item'].name.lower(),
u'L:%s' % self.serviceItems[item][u'service_item'].edit_id)
def findServiceItem(self):
@ -1369,6 +1363,9 @@ class ServiceManager(QtGui.QWidget):
filename = url.toLocalFile()
if filename.endswith(u'.osz'):
self.onLoadServiceClicked(filename)
elif filename.endswith(u'.oszl'):
# todo correct
self.onLoadServiceClicked(filename)
elif link.hasText():
plugin = link.text()
item = self.serviceManagerList.itemAt(event.pos())
@ -1397,8 +1394,7 @@ class ServiceManager(QtGui.QWidget):
pos = self._getParentItemData(item) - 1
serviceItem = self.serviceItems[pos]
if (plugin == serviceItem[u'service_item'].name and
serviceItem[u'service_item'].is_capable(
ItemCapabilities.CanAppend)):
serviceItem[u'service_item'].is_capable(ItemCapabilities.CanAppend)):
action = self.dndMenu.exec_(QtGui.QCursor.pos())
# New action required
if action == self.newAction:
@ -1427,16 +1423,15 @@ class ServiceManager(QtGui.QWidget):
themeGroup.setObjectName(u'themeGroup')
# Create a "Default" theme, which allows the user to reset the item's
# theme to the service theme or global theme.
defaultTheme = create_widget_action(self.themeMenu,
text=UiStrings().Default, checked=False,
defaultTheme = create_widget_action(self.themeMenu, text=UiStrings().Default, checked=False,
triggers=self.onThemeChangeAction)
self.themeMenu.setDefaultAction(defaultTheme)
themeGroup.addAction(defaultTheme)
self.themeMenu.addSeparator()
for theme in theme_list:
self.themeComboBox.addItem(theme)
themeGroup.addAction(create_widget_action(self.themeMenu, theme,
text=theme, checked=False, triggers=self.onThemeChangeAction))
themeGroup.addAction(create_widget_action(self.themeMenu, theme, text=theme, checked=False,
triggers=self.onThemeChangeAction))
find_and_set_in_combo_box(self.themeComboBox, self.service_theme)
self.mainwindow.renderer.set_service_theme(self.service_theme)
self.regenerateServiceItems()

View File

@ -35,6 +35,7 @@ from PyQt4 import QtCore, QtGui
from openlp.core.lib import Receiver, build_icon, PluginStatus
from openlp.core.ui import AdvancedTab, GeneralTab, ThemesTab
from openlp.core.ui.media import PlayerTab
from settingsdialog import Ui_SettingsDialog
log = logging.getLogger(__name__)
@ -47,6 +48,7 @@ class SettingsForm(QtGui.QDialog, Ui_SettingsDialog):
"""
Initialise the settings form
"""
self.mainWindow = mainWindow
QtGui.QDialog.__init__(self, parent)
self.setupUi(self)
# General tab
@ -55,6 +57,8 @@ class SettingsForm(QtGui.QDialog, Ui_SettingsDialog):
self.themesTab = ThemesTab(self, mainWindow)
# Advanced tab
self.advancedTab = AdvancedTab(self)
# Advanced tab
self.playerTab = PlayerTab(self, mainWindow)
def exec_(self):
# load all the settings
@ -65,7 +69,8 @@ class SettingsForm(QtGui.QDialog, Ui_SettingsDialog):
self.insertTab(self.generalTab, 0, PluginStatus.Active)
self.insertTab(self.themesTab, 1, PluginStatus.Active)
self.insertTab(self.advancedTab, 2, PluginStatus.Active)
count = 3
self.insertTab(self.playerTab, 3, PluginStatus.Active)
count = 4
for plugin in self.plugins:
if plugin.settingsTab:
self.insertTab(plugin.settingsTab, count, plugin.status)
@ -94,6 +99,7 @@ class SettingsForm(QtGui.QDialog, Ui_SettingsDialog):
"""
Process the form saving the settings
"""
self.resetSuffixes = True
for tabIndex in range(self.stackedLayout.count()):
self.stackedLayout.widget(tabIndex).save()
# Must go after all settings are save
@ -115,6 +121,7 @@ class SettingsForm(QtGui.QDialog, Ui_SettingsDialog):
self.generalTab.postSetUp()
self.themesTab.postSetUp()
self.advancedTab.postSetUp()
self.playerTab.postSetUp()
for plugin in self.plugins:
if plugin.settingsTab:
plugin.settingsTab.postSetUp()
@ -125,3 +132,13 @@ class SettingsForm(QtGui.QDialog, Ui_SettingsDialog):
"""
self.stackedLayout.setCurrentIndex(tabIndex)
self.stackedLayout.currentWidget().tabVisible()
def resetSupportedSuffixes(self):
"""
Control the resetting of the serviceManager suffix list as can be
called by a number of settings tab and only needs to be called once
per save.
"""
if self.resetSuffixes:
self.mainWindow.serviceManagerContents.resetSupportedSuffixes()
self.resetSuffixes = False

View File

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
@ -39,14 +39,17 @@ from openlp.core.lib import OpenLPToolbar, Receiver, ItemCapabilities, \
ImageSource, SlideLimits, ServiceItemAction, Settings
from openlp.core.ui import HideMode, MainDisplay, Display, ScreenList
from openlp.core.lib.ui import UiStrings, create_action
from openlp.core.lib import SlideLimits, ServiceItemAction
from openlp.core.ui import HideMode, MainDisplay, Display, ScreenList, \
DisplayControllerType
from openlp.core.utils.actions import ActionList, CategoryOrder
log = logging.getLogger(__name__)
class Controller(QtGui.QWidget):
class DisplayController(QtGui.QWidget):
"""
Controller is a general controller widget.
Controller is a general display controller widget.
"""
def __init__(self, parent, isLive=False):
"""
@ -55,6 +58,7 @@ class Controller(QtGui.QWidget):
QtGui.QWidget.__init__(self, parent)
self.isLive = isLive
self.display = None
self.controllerType = DisplayControllerType.Plugin
def sendToPlugins(self, *args):
"""
@ -62,13 +66,12 @@ class Controller(QtGui.QWidget):
created from within other plugins
This function is needed to catch the current controller
"""
sender = self.sender().objectName() if self.sender().objectName() \
else self.sender().text()
sender = self.sender().objectName() if self.sender().objectName() else self.sender().text()
controller = self
Receiver.send_message('%s' % sender, [controller, args])
class SlideController(Controller):
class SlideController(DisplayController):
"""
SlideController is the slide controller widget. This widget is what the
user uses to control the displaying of verses/slides/etc on the screen.
@ -77,11 +80,10 @@ class SlideController(Controller):
"""
Set up the Slide Controller.
"""
Controller.__init__(self, parent, isLive)
DisplayController.__init__(self, parent, isLive)
self.screens = ScreenList()
try:
self.ratio = float(self.screens.current[u'size'].width()) / \
float(self.screens.current[u'size'].height())
self.ratio = float(self.screens.current[u'size'].width()) / float(self.screens.current[u'size'].height())
except ZeroDivisionError:
self.ratio = 1
self.imageManager = self.parent().imageManager
@ -117,8 +119,7 @@ class SlideController(Controller):
self.keypress_queue = deque()
self.keypress_loop = False
self.category = UiStrings().LiveToolbar
ActionList.get_instance().add_category(
unicode(self.category), CategoryOrder.standardToolbar)
ActionList.get_instance().add_category(unicode(self.category), CategoryOrder.standardToolbar)
else:
self.typeLabel.setText(UiStrings().Preview)
self.split = 0
@ -134,9 +135,7 @@ class SlideController(Controller):
# Actual controller section
self.controller = QtGui.QWidget(self.splitter)
self.controller.setGeometry(QtCore.QRect(0, 0, 100, 536))
self.controller.setSizePolicy(
QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred,
QtGui.QSizePolicy.Maximum))
self.controller.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Maximum))
self.controllerLayout = QtGui.QVBoxLayout(self.controller)
self.controllerLayout.setSpacing(0)
self.controllerLayout.setMargin(0)
@ -147,67 +146,53 @@ class SlideController(Controller):
self.previewListWidget.setColumnWidth(0, self.controller.width())
self.previewListWidget.isLive = self.isLive
self.previewListWidget.setObjectName(u'previewListWidget')
self.previewListWidget.setSelectionBehavior(
QtGui.QAbstractItemView.SelectRows)
self.previewListWidget.setSelectionMode(
QtGui.QAbstractItemView.SingleSelection)
self.previewListWidget.setEditTriggers(
QtGui.QAbstractItemView.NoEditTriggers)
self.previewListWidget.setHorizontalScrollBarPolicy(
QtCore.Qt.ScrollBarAlwaysOff)
self.previewListWidget.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
self.previewListWidget.setSelectionMode(QtGui.QAbstractItemView.SingleSelection)
self.previewListWidget.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
self.previewListWidget.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.previewListWidget.setAlternatingRowColors(True)
self.controllerLayout.addWidget(self.previewListWidget)
# Build the full toolbar
self.toolbar = OpenLPToolbar(self)
sizeToolbarPolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed,
QtGui.QSizePolicy.Fixed)
sizeToolbarPolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
sizeToolbarPolicy.setHorizontalStretch(0)
sizeToolbarPolicy.setVerticalStretch(0)
sizeToolbarPolicy.setHeightForWidth(
self.toolbar.sizePolicy().hasHeightForWidth())
sizeToolbarPolicy.setHeightForWidth(self.toolbar.sizePolicy().hasHeightForWidth())
self.toolbar.setSizePolicy(sizeToolbarPolicy)
self.previousItem = create_action(self,
u'previousItem_' + self.typePrefix,
text=translate('OpenLP.SlideController', 'Previous Slide'),
icon=u':/slides/slide_previous.png',
self.previousItem = create_action(self, u'previousItem_' + self.typePrefix,
text=translate('OpenLP.SlideController', 'Previous Slide'), icon=u':/slides/slide_previous.png',
tooltip=translate('OpenLP.SlideController', 'Move to previous.'),
shortcuts=[QtCore.Qt.Key_Up, QtCore.Qt.Key_PageUp],
context=QtCore.Qt.WidgetWithChildrenShortcut,
shortcuts=[QtCore.Qt.Key_Up, QtCore.Qt.Key_PageUp], context=QtCore.Qt.WidgetWithChildrenShortcut,
category=self.category, triggers=self.onSlideSelectedPrevious)
self.toolbar.addAction(self.previousItem)
self.nextItem = create_action(self, u'nextItem_' + self.typePrefix,
text=translate('OpenLP.SlideController', 'Next Slide'),
icon=u':/slides/slide_next.png',
text=translate('OpenLP.SlideController', 'Next Slide'), icon=u':/slides/slide_next.png',
tooltip=translate('OpenLP.SlideController', 'Move to next.'),
shortcuts=[QtCore.Qt.Key_Down, QtCore.Qt.Key_PageDown],
context=QtCore.Qt.WidgetWithChildrenShortcut,
shortcuts=[QtCore.Qt.Key_Down, QtCore.Qt.Key_PageDown], context=QtCore.Qt.WidgetWithChildrenShortcut,
category=self.category, triggers=self.onSlideSelectedNextAction)
self.toolbar.addAction(self.nextItem)
self.toolbar.addSeparator()
self.controllerType = DisplayControllerType.Preview
if self.isLive:
self.controllerType = DisplayControllerType.Live
# Hide Menu
self.hideMenu = QtGui.QToolButton(self.toolbar)
self.hideMenu.setObjectName(u'hideMenu')
self.hideMenu.setText(translate('OpenLP.SlideController', 'Hide'))
self.hideMenu.setPopupMode(QtGui.QToolButton.MenuButtonPopup)
self.hideMenu.setMenu(QtGui.QMenu(
translate('OpenLP.SlideController', 'Hide'), self.toolbar))
self.hideMenu.setMenu(QtGui.QMenu(translate('OpenLP.SlideController', 'Hide'), self.toolbar))
self.toolbar.addToolbarWidget(self.hideMenu)
self.blankScreen = create_action(self, u'blankScreen',
text=translate('OpenLP.SlideController', 'Blank Screen'),
icon=u':/slides/slide_blank.png', checked=False,
shortcuts=[QtCore.Qt.Key_Period],
category=self.category, triggers=self.onBlankDisplay)
text=translate('OpenLP.SlideController', 'Blank Screen'), icon=u':/slides/slide_blank.png',
checked=False, shortcuts=[QtCore.Qt.Key_Period], category=self.category, triggers=self.onBlankDisplay)
self.themeScreen = create_action(self, u'themeScreen',
text=translate('OpenLP.SlideController', 'Blank to Theme'),
icon=u':/slides/slide_theme.png', checked=False,
shortcuts=[QtGui.QKeySequence(u'T')],
category=self.category, triggers=self.onThemeDisplay)
text=translate('OpenLP.SlideController', 'Blank to Theme'), icon=u':/slides/slide_theme.png',
checked=False, shortcuts=[QtGui.QKeySequence(u'T')], category=self.category,
triggers=self.onThemeDisplay)
self.desktopScreen = create_action(self, u'desktopScreen',
text=translate('OpenLP.SlideController', 'Show Desktop'),
icon=u':/slides/slide_desktop.png', checked=False,
shortcuts=[QtGui.QKeySequence(u'D')],
category=self.category, triggers=self.onHideDisplay)
text=translate('OpenLP.SlideController', 'Show Desktop'), icon=u':/slides/slide_desktop.png',
checked=False, shortcuts=[QtGui.QKeySequence(u'D')], category=self.category,
triggers=self.onHideDisplay)
self.hideMenu.setDefaultAction(self.blankScreen)
self.hideMenu.menu().addAction(self.blankScreen)
self.hideMenu.menu().addAction(self.themeScreen)
@ -216,23 +201,17 @@ class SlideController(Controller):
# Play Slides Menu
self.playSlidesMenu = QtGui.QToolButton(self.toolbar)
self.playSlidesMenu.setObjectName(u'playSlidesMenu')
self.playSlidesMenu.setText(translate('OpenLP.SlideController',
'Play Slides'))
self.playSlidesMenu.setText(translate('OpenLP.SlideController', 'Play Slides'))
self.playSlidesMenu.setPopupMode(QtGui.QToolButton.MenuButtonPopup)
self.playSlidesMenu.setMenu(QtGui.QMenu(
translate('OpenLP.SlideController', 'Play Slides'),
self.toolbar))
self.playSlidesMenu.setMenu(QtGui.QMenu(translate('OpenLP.SlideController', 'Play Slides'), self.toolbar))
self.toolbar.addToolbarWidget(self.playSlidesMenu)
self.playSlidesLoop = create_action(self, u'playSlidesLoop',
text=UiStrings().PlaySlidesInLoop,
self.playSlidesLoop = create_action(self, u'playSlidesLoop', text=UiStrings().PlaySlidesInLoop,
icon=u':/media/media_time.png', checked=False, shortcuts=[],
category=self.category, triggers=self.onPlaySlidesLoop)
self.playSlidesOnce = create_action(self, u'playSlidesOnce',
text=UiStrings().PlaySlidesToEnd,
self.playSlidesOnce = create_action(self, u'playSlidesOnce', text=UiStrings().PlaySlidesToEnd,
icon=u':/media/media_time.png', checked=False, shortcuts=[],
category=self.category, triggers=self.onPlaySlidesOnce)
if Settings().value(self.parent().generalSettingsSection +
u'/enable slide loop', True):
if Settings().value(self.parent().generalSettingsSection + u'/enable slide loop', True):
self.playSlidesMenu.setDefaultAction(self.playSlidesLoop)
else:
self.playSlidesMenu.setDefaultAction(self.playSlidesOnce)
@ -243,61 +222,46 @@ class SlideController(Controller):
self.delaySpinBox.setObjectName(u'delaySpinBox')
self.delaySpinBox.setRange(1, 180)
self.delaySpinBox.setSuffix(UiStrings().Seconds)
self.delaySpinBox.setToolTip(translate('OpenLP.SlideController',
'Delay between slides in seconds.'))
self.delaySpinBox.setToolTip(translate('OpenLP.SlideController', 'Delay between slides in seconds.'))
self.toolbar.addToolbarWidget(self.delaySpinBox)
else:
self.toolbar.addToolbarAction(u'goLive',
icon=u':/general/general_live.png',
tooltip=translate('OpenLP.SlideController', 'Move to live.'),
triggers=self.onGoLive)
self.toolbar.addToolbarAction(u'addToService',
icon=u':/general/general_add.png',
tooltip=translate('OpenLP.SlideController', 'Add to Service.'),
triggers=self.onPreviewAddToService)
self.toolbar.addToolbarAction(u'goLive', icon=u':/general/general_live.png',
tooltip=translate('OpenLP.SlideController', 'Move to live.'), triggers=self.onGoLive)
self.toolbar.addToolbarAction(u'addToService', icon=u':/general/general_add.png',
tooltip=translate('OpenLP.SlideController', 'Add to Service.'), triggers=self.onPreviewAddToService)
self.toolbar.addSeparator()
self.toolbar.addToolbarAction(u'editSong',
icon=u':/general/general_edit.png',
tooltip=translate('OpenLP.SlideController',
'Edit and reload song preview.'), triggers=self.onEditSong)
self.toolbar.addToolbarAction(u'editSong', icon=u':/general/general_edit.png',
tooltip=translate('OpenLP.SlideController', 'Edit and reload song preview.'), triggers=self.onEditSong)
self.controllerLayout.addWidget(self.toolbar)
# Build the Media Toolbar
self.mediaController.add_controller_items(self, self.controllerLayout)
self.mediaController.register_controller(self)
if self.isLive:
# Build the Song Toolbar
self.songMenu = QtGui.QToolButton(self.toolbar)
self.songMenu.setObjectName(u'songMenu')
self.songMenu.setText(translate('OpenLP.SlideController', 'Go To'))
self.songMenu.setPopupMode(QtGui.QToolButton.InstantPopup)
self.songMenu.setMenu(QtGui.QMenu(
translate('OpenLP.SlideController', 'Go To'), self.toolbar))
self.songMenu.setMenu(QtGui.QMenu(translate('OpenLP.SlideController', 'Go To'), self.toolbar))
self.toolbar.addToolbarWidget(self.songMenu)
# Stuff for items with background audio.
self.audioPauseItem = self.toolbar.addToolbarAction(
u'audioPauseItem', icon=u':/slides/media_playback_pause.png',
text=translate('OpenLP.SlideController', 'Pause Audio'),
self.audioPauseItem = self.toolbar.addToolbarAction(u'audioPauseItem',
icon=u':/slides/media_playback_pause.png', text=translate('OpenLP.SlideController', 'Pause Audio'),
tooltip=translate('OpenLP.SlideController', 'Pause audio.'),
checked=False, visible=False, category=self.category,
context=QtCore.Qt.WindowShortcut,
checked=False, visible=False, category=self.category, context=QtCore.Qt.WindowShortcut,
shortcuts=[], triggers=self.onAudioPauseClicked)
self.audioMenu = QtGui.QMenu(
translate('OpenLP.SlideController', 'Background Audio'), self.toolbar)
self.audioMenu = QtGui.QMenu(translate('OpenLP.SlideController', 'Background Audio'), self.toolbar)
self.audioPauseItem.setMenu(self.audioMenu)
self.audioPauseItem.setParent(self.toolbar)
self.toolbar.widgetForAction(self.audioPauseItem).setPopupMode(
QtGui.QToolButton.MenuButtonPopup)
self.nextTrackItem = create_action(self, u'nextTrackItem',
text=UiStrings().NextTrack,
icon=u':/slides/media_playback_next.png', tooltip=translate(
'OpenLP.SlideController', 'Go to next audio track.'),
category=self.category,
shortcuts=[], triggers=self.onNextTrackClicked)
self.nextTrackItem = create_action(self, u'nextTrackItem', text=UiStrings().NextTrack,
icon=u':/slides/media_playback_next.png',
tooltip=translate('OpenLP.SlideController', 'Go to next audio track.'),
category=self.category, shortcuts=[], triggers=self.onNextTrackClicked)
self.audioMenu.addAction(self.nextTrackItem)
self.trackMenu = self.audioMenu.addMenu(
translate('OpenLP.SlideController', 'Tracks'))
self.trackMenu = self.audioMenu.addMenu(translate('OpenLP.SlideController', 'Tracks'))
self.audioTimeLabel = QtGui.QLabel(u' 00:00 ', self.toolbar)
self.audioTimeLabel.setAlignment(
QtCore.Qt.AlignCenter|QtCore.Qt.AlignHCenter)
self.audioTimeLabel.setAlignment(QtCore.Qt.AlignCenter|QtCore.Qt.AlignHCenter)
self.audioTimeLabel.setStyleSheet(
u'background-color: palette(background); '
u'border-top-color: palette(shadow); '
@ -314,8 +278,7 @@ class SlideController(Controller):
self.previewFrame = QtGui.QFrame(self.splitter)
self.previewFrame.setGeometry(QtCore.QRect(0, 0, 300, 300 * self.ratio))
self.previewFrame.setMinimumHeight(100)
self.previewFrame.setSizePolicy(QtGui.QSizePolicy(
QtGui.QSizePolicy.Ignored, QtGui.QSizePolicy.Ignored,
self.previewFrame.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.Ignored, QtGui.QSizePolicy.Ignored,
QtGui.QSizePolicy.Label))
self.previewFrame.setFrameShape(QtGui.QFrame.StyledPanel)
self.previewFrame.setFrameShadow(QtGui.QFrame.Sunken)
@ -335,8 +298,7 @@ class SlideController(Controller):
self.previewDisplay.hide()
# Actual preview screen
self.slidePreview = QtGui.QLabel(self)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed,
QtGui.QSizePolicy.Fixed)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(
@ -380,20 +342,16 @@ class SlideController(Controller):
self.shortcutTimer, QtCore.SIGNAL(u'timeout()'),
self._slideShortcutActivated)
# Signals
QtCore.QObject.connect(self.previewListWidget,
QtCore.SIGNAL(u'clicked(QModelIndex)'), self.onSlideSelected)
QtCore.QObject.connect(self.previewListWidget, QtCore.SIGNAL(u'clicked(QModelIndex)'), self.onSlideSelected)
if self.isLive:
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'slidecontroller_live_spin_delay'),
self.receiveSpinDelay)
QtCore.SIGNAL(u'slidecontroller_live_spin_delay'), self.receiveSpinDelay)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'slidecontroller_toggle_display'),
self.toggleDisplay)
QtCore.SIGNAL(u'slidecontroller_toggle_display'), self.toggleDisplay)
self.toolbar.setWidgetVisible(self.loopList, False)
else:
QtCore.QObject.connect(self.previewListWidget,
QtCore.SIGNAL(u'doubleClicked(QModelIndex)'),
self.onGoLiveClick)
QtCore.SIGNAL(u'doubleClicked(QModelIndex)'), self.onGoLiveClick)
self.toolbar.setWidgetVisible([u'editSong'], False)
if self.isLive:
self.setLiveHotkeys(self)
@ -402,29 +360,21 @@ class SlideController(Controller):
self.previewListWidget.addActions(
[self.nextItem, self.previousItem])
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'slidecontroller_%s_stop_loop' % self.typePrefix),
self.onStopLoop)
QtCore.SIGNAL(u'slidecontroller_%s_stop_loop' % self.typePrefix), self.onStopLoop)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'slidecontroller_%s_next' % self.typePrefix),
self.onSlideSelectedNext)
QtCore.SIGNAL(u'slidecontroller_%s_next' % self.typePrefix), self.onSlideSelectedNext)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'slidecontroller_%s_previous' % self.typePrefix),
self.onSlideSelectedPrevious)
QtCore.SIGNAL(u'slidecontroller_%s_previous' % self.typePrefix), self.onSlideSelectedPrevious)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'slidecontroller_%s_change' % self.typePrefix),
self.onSlideChange)
QtCore.SIGNAL(u'slidecontroller_%s_change' % self.typePrefix), self.onSlideChange)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'slidecontroller_%s_set' % self.typePrefix),
self.onSlideSelectedIndex)
QtCore.SIGNAL(u'slidecontroller_%s_set' % self.typePrefix), self.onSlideSelectedIndex)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'slidecontroller_%s_blank' % self.typePrefix),
self.onSlideBlank)
QtCore.SIGNAL(u'slidecontroller_%s_blank' % self.typePrefix), self.onSlideBlank)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'slidecontroller_%s_unblank' % self.typePrefix),
self.onSlideUnblank)
QtCore.SIGNAL(u'slidecontroller_%s_unblank' % self.typePrefix), self.onSlideUnblank)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'slidecontroller_update_slide_limits'),
self.updateSlideLimits)
QtCore.SIGNAL(u'slidecontroller_update_slide_limits'), self.updateSlideLimits)
def _slideShortcutActivated(self):
"""
@ -443,30 +393,22 @@ class SlideController(Controller):
except ImportError:
SONGS_PLUGIN_AVAILABLE = False
sender_name = self.sender().objectName()
verse_type = sender_name[15:] \
if sender_name[:15] == u'shortcutAction_' else u''
verse_type = sender_name[15:] if sender_name[:15] == u'shortcutAction_' else u''
if SONGS_PLUGIN_AVAILABLE:
if verse_type == u'V':
self.current_shortcut = \
VerseType.TranslatedTags[VerseType.Verse]
self.current_shortcut = VerseType.TranslatedTags[VerseType.Verse]
elif verse_type == u'C':
self.current_shortcut = \
VerseType.TranslatedTags[VerseType.Chorus]
self.current_shortcut = VerseType.TranslatedTags[VerseType.Chorus]
elif verse_type == u'B':
self.current_shortcut = \
VerseType.TranslatedTags[VerseType.Bridge]
self.current_shortcut = VerseType.TranslatedTags[VerseType.Bridge]
elif verse_type == u'P':
self.current_shortcut = \
VerseType.TranslatedTags[VerseType.PreChorus]
self.current_shortcut = VerseType.TranslatedTags[VerseType.PreChorus]
elif verse_type == u'I':
self.current_shortcut = \
VerseType.TranslatedTags[VerseType.Intro]
self.current_shortcut = VerseType.TranslatedTags[VerseType.Intro]
elif verse_type == u'E':
self.current_shortcut = \
VerseType.TranslatedTags[VerseType.Ending]
self.current_shortcut = VerseType.TranslatedTags[VerseType.Ending]
elif verse_type == u'O':
self.current_shortcut = \
VerseType.TranslatedTags[VerseType.Other]
self.current_shortcut = VerseType.TranslatedTags[VerseType.Other]
elif verse_type.isnumeric():
self.current_shortcut += verse_type
self.current_shortcut = self.current_shortcut.upper()
@ -490,8 +432,7 @@ class SlideController(Controller):
if self.current_shortcut in keys:
# We had more than one match for example "V1" and "V10", but
# "V1" was the slide we wanted to go.
self.__checkUpdateSelectedSlide(
self.slideList[self.current_shortcut])
self.__checkUpdateSelectedSlide(self.slideList[self.current_shortcut])
self.slideSelected()
# Reset the shortcut.
self.current_shortcut = u''
@ -499,23 +440,20 @@ class SlideController(Controller):
def setLiveHotkeys(self, parent=None):
self.previousService = create_action(parent, u'previousService',
text=translate('OpenLP.SlideController', 'Previous Service'),
shortcuts=[QtCore.Qt.Key_Left],
context=QtCore.Qt.WidgetWithChildrenShortcut,
category=self.category, triggers=self.servicePrevious)
shortcuts=[QtCore.Qt.Key_Left], context=QtCore.Qt.WidgetWithChildrenShortcut, category=self.category,
triggers=self.servicePrevious)
self.nextService = create_action(parent, 'nextService',
text=translate('OpenLP.SlideController', 'Next Service'),
shortcuts=[QtCore.Qt.Key_Right],
context=QtCore.Qt.WidgetWithChildrenShortcut,
category=self.category, triggers=self.serviceNext)
shortcuts=[QtCore.Qt.Key_Right], context=QtCore.Qt.WidgetWithChildrenShortcut, category=self.category,
triggers=self.serviceNext)
self.escapeItem = create_action(parent, 'escapeItem',
text=translate('OpenLP.SlideController', 'Escape Item'),
shortcuts=[QtCore.Qt.Key_Escape],
context=QtCore.Qt.WidgetWithChildrenShortcut,
category=self.category, triggers=self.liveEscape)
shortcuts=[QtCore.Qt.Key_Escape],context=QtCore.Qt.WidgetWithChildrenShortcut, category=self.category,
triggers=self.liveEscape)
def liveEscape(self):
self.display.setVisible(False)
self.mediaController.video_stop([self])
self.mediaController.media_stop(self)
def toggleDisplay(self, action):
"""
@ -559,8 +497,7 @@ class SlideController(Controller):
Receiver.send_message('servicemanager_previous_item')
elif keypressCommand == ServiceItemAction.PreviousLastSlide:
# Go to the last slide of the previous item
Receiver.send_message('servicemanager_previous_item',
u'last slide')
Receiver.send_message('servicemanager_previous_item', u'last slide')
else:
Receiver.send_message('servicemanager_next_item')
self.keypress_loop = False
@ -577,22 +514,19 @@ class SlideController(Controller):
self.display.setup()
if self.isLive:
self.__addActionsToWidget(self.display)
self.display.audioPlayer.connectSlot(
QtCore.SIGNAL(u'tick(qint64)'), self.onAudioTimeRemaining)
self.display.audioPlayer.connectSlot(QtCore.SIGNAL(u'tick(qint64)'), self.onAudioTimeRemaining)
# The SlidePreview's ratio.
try:
self.ratio = float(self.screens.current[u'size'].width()) / \
float(self.screens.current[u'size'].height())
self.ratio = float(self.screens.current[u'size'].width()) / float(self.screens.current[u'size'].height())
except ZeroDivisionError:
self.ratio = 1
self.mediaController.setup_display(self.display)
self.mediaController.setup_display(self.display, False)
self.previewSizeChanged()
self.previewDisplay.setup()
serviceItem = ServiceItem()
self.previewDisplay.webView.setHtml(build_html(serviceItem,
self.previewDisplay.screen, None, self.isLive,
self.previewDisplay.webView.setHtml(build_html(serviceItem, self.previewDisplay.screen, None, self.isLive,
plugins=PluginManager.get_instance().plugins))
self.mediaController.setup_display(self.previewDisplay)
self.mediaController.setup_display(self.previewDisplay,True)
if self.serviceItem:
self.refreshServiceItem()
@ -608,23 +542,18 @@ class SlideController(Controller):
splitters is moved or when the screen size is changed. Note, that this
method is (also) called frequently from the mainwindow *paintEvent*.
"""
if self.ratio < float(self.previewFrame.width()) / float(
self.previewFrame.height()):
if self.ratio < float(self.previewFrame.width()) / float(self.previewFrame.height()):
# We have to take the height as limit.
max_height = self.previewFrame.height() - self.grid.margin() * 2
self.slidePreview.setFixedSize(QtCore.QSize(
max_height * self.ratio, max_height))
self.previewDisplay.setFixedSize(QtCore.QSize(
max_height * self.ratio, max_height))
self.slidePreview.setFixedSize(QtCore.QSize(max_height * self.ratio, max_height))
self.previewDisplay.setFixedSize(QtCore.QSize(max_height * self.ratio, max_height))
self.previewDisplay.screen = {
u'size': self.previewDisplay.geometry()}
else:
# We have to take the width as limit.
max_width = self.previewFrame.width() - self.grid.margin() * 2
self.slidePreview.setFixedSize(QtCore.QSize(max_width,
max_width / self.ratio))
self.previewDisplay.setFixedSize(QtCore.QSize(max_width,
max_width / self.ratio))
self.slidePreview.setFixedSize(QtCore.QSize(max_width, max_width / self.ratio))
self.previewDisplay.setFixedSize(QtCore.QSize(max_width, max_width / self.ratio))
self.previewDisplay.screen = {
u'size': self.previewDisplay.geometry()}
# Make sure that the frames have the correct size.
@ -638,8 +567,7 @@ class SlideController(Controller):
# Sort out image heights.
width = self.parent().controlSplitter.sizes()[self.split]
for framenumber in range(len(self.serviceItem.get_frames())):
self.previewListWidget.setRowHeight(
framenumber, width / self.ratio)
self.previewListWidget.setRowHeight(framenumber, width / self.ratio)
def onSongBarHandler(self):
request = self.sender().text()
@ -657,9 +585,7 @@ class SlideController(Controller):
"""
Updates the Slide Limits variable from the settings.
"""
self.slide_limits = Settings().value(
self.parent().advancedSettingsSection + u'/slide limits',
SlideLimits.End)
self.slide_limits = Settings().value(self.parent().advancedSettingsSection + u'/slide limits', SlideLimits.End)
def enableToolBar(self, item):
"""
@ -687,12 +613,9 @@ class SlideController(Controller):
self.playSlidesLoop.setChecked(False)
self.playSlidesLoop.setIcon(build_icon(u':/media/media_time.png'))
if item.is_text():
if Settings().value(
self.parent().songsSettingsSection + u'/display songbar',
True) and self.slideList:
if Settings().value(self.parent().songsSettingsSection + u'/display songbar', True) and self.slideList:
self.songMenu.show()
if item.is_capable(ItemCapabilities.CanLoop) and \
len(item.get_frames()) > 1:
if item.is_capable(ItemCapabilities.CanLoop) and len(item.get_frames()) > 1:
self.toolbar.setWidgetVisible(self.loopList)
if item.is_media():
self.mediabar.show()
@ -780,8 +703,7 @@ class SlideController(Controller):
old_item = self.serviceItem
# take a copy not a link to the servicemanager copy.
self.serviceItem = copy.copy(serviceItem)
if old_item and self.isLive and old_item.is_capable(
ItemCapabilities.ProvidesOwnDisplay):
if old_item and self.isLive and old_item.is_capable(ItemCapabilities.ProvidesOwnDisplay):
self._resetBlank()
Receiver.send_message(u'%s_start' % serviceItem.name.lower(),
[serviceItem, self.isLive, self.hideMode(), slideno])
@ -798,23 +720,15 @@ class SlideController(Controller):
# If the current item has background audio
if self.serviceItem.is_capable(ItemCapabilities.HasBackgroundAudio):
log.debug(u'Starting to play...')
self.display.audioPlayer.addToPlaylist(
self.serviceItem.background_audio)
self.display.audioPlayer.addToPlaylist(self.serviceItem.background_audio)
self.trackMenu.clear()
for counter in range(len(self.serviceItem.background_audio)):
action = self.trackMenu.addAction(os.path.basename(
self.serviceItem.background_audio[counter]))
action = self.trackMenu.addAction(os.path.basename(self.serviceItem.background_audio[counter]))
action.setData(counter)
QtCore.QObject.connect(action,
QtCore.SIGNAL(u'triggered(bool)'),
self.onTrackTriggered)
QtCore.QObject.connect(action, QtCore.SIGNAL(u'triggered(bool)'), self.onTrackTriggered)
self.display.audioPlayer.repeat = Settings().value(
self.parent().generalSettingsSection + \
u'/audio repeat list',False)
if Settings().value(
self.parent().generalSettingsSection + \
u'/audio start paused',
True):
self.parent().generalSettingsSection + u'/audio repeat list', False)
if Settings().value(self.parent().generalSettingsSection + u'/audio start paused', True):
self.audioPauseItem.setChecked(True)
self.display.audioPlayer.pause()
else:
@ -823,8 +737,7 @@ class SlideController(Controller):
row = 0
text = []
for framenumber, frame in enumerate(self.serviceItem.get_frames()):
self.previewListWidget.setRowCount(
self.previewListWidget.rowCount() + 1)
self.previewListWidget.setRowCount(self.previewListWidget.rowCount() + 1)
item = QtGui.QTableWidgetItem()
slideHeight = 0
if self.serviceItem.is_text():
@ -847,8 +760,7 @@ class SlideController(Controller):
label = QtGui.QLabel()
label.setMargin(4)
if serviceItem.is_media():
label.setAlignment(QtCore.Qt.AlignHCenter |
QtCore.Qt.AlignVCenter)
label.setAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter)
else:
label.setScaledContents(True)
if self.serviceItem.is_command():
@ -856,11 +768,9 @@ class SlideController(Controller):
else:
# If current slide set background to image
if framenumber == slideno:
self.serviceItem.bg_image_bytes = \
self.imageManager.getImageBytes(frame[u'path'],
self.serviceItem.bg_image_bytes = self.imageManager.getImageBytes(frame[u'path'],
ImageSource.ImagePlugin)
image = self.imageManager.getImage(frame[u'path'],
ImageSource.ImagePlugin)
image = self.imageManager.getImage(frame[u'path'], ImageSource.ImagePlugin)
label.setPixmap(QtGui.QPixmap.fromImage(image))
self.previewListWidget.setCellWidget(framenumber, 0, label)
slideHeight = width * (1 / self.ratio)
@ -892,12 +802,10 @@ class SlideController(Controller):
# However opening a new item of the same type will automatically
# close the previous, so make sure we don't close the new one.
if old_item.is_command() and not serviceItem.is_command():
Receiver.send_message(u'%s_stop' %
old_item.name.lower(), [old_item, self.isLive])
Receiver.send_message(u'%s_stop' % old_item.name.lower(), [old_item, self.isLive])
if old_item.is_media() and not serviceItem.is_media():
self.onMediaClose()
Receiver.send_message(u'slidecontroller_%s_started' % self.typePrefix,
[serviceItem])
Receiver.send_message(u'slidecontroller_%s_started' % self.typePrefix, [serviceItem])
def __updatePreviewSelection(self, slideno):
"""
@ -918,8 +826,7 @@ class SlideController(Controller):
if not self.serviceItem:
return
if self.serviceItem.is_command():
Receiver.send_message(u'%s_slide' % self.serviceItem.name.lower(),
[self.serviceItem, self.isLive, index])
Receiver.send_message(u'%s_slide' % self.serviceItem.name.lower(), [self.serviceItem, self.isLive, index])
self.updatePreview()
else:
self.__checkUpdateSelectedSlide(index)
@ -930,10 +837,9 @@ class SlideController(Controller):
Allow the main display to blank the main display at startup time
"""
log.debug(u'mainDisplaySetBackground live = %s' % self.isLive)
display_type = Settings().value(
self.parent().generalSettingsSection + u'/screen blank', u'')
if self.screens.which_screen(self.window()) != \
self.screens.which_screen(self.display):
display_type = Settings().value(self.parent().generalSettingsSection + u'/screen blank',
u'')
if self.screens.which_screen(self.window()) != self.screens.which_screen(self.display):
# Order done to handle initial conversion
if display_type == u'themed':
self.onThemeDisplay(True)
@ -970,12 +876,9 @@ class SlideController(Controller):
self.themeScreen.setChecked(False)
self.desktopScreen.setChecked(False)
if checked:
Settings().setValue(
self.parent().generalSettingsSection + u'/screen blank',
u'blanked')
Settings().setValue(self.parent().generalSettingsSection + u'/screen blank', u'blanked')
else:
Settings().remove(
self.parent().generalSettingsSection + u'/screen blank')
Settings().remove(self.parent().generalSettingsSection + u'/screen blank')
self.blankPlugin()
self.updatePreview()
@ -991,12 +894,9 @@ class SlideController(Controller):
self.themeScreen.setChecked(checked)
self.desktopScreen.setChecked(False)
if checked:
Settings().setValue(
self.parent().generalSettingsSection + u'/screen blank',
u'themed')
Settings().setValue(self.parent().generalSettingsSection + u'/screen blank', u'themed')
else:
Settings().remove(
self.parent().generalSettingsSection + u'/screen blank')
Settings().remove(self.parent().generalSettingsSection + u'/screen blank')
self.blankPlugin()
self.updatePreview()
@ -1012,12 +912,9 @@ class SlideController(Controller):
self.themeScreen.setChecked(False)
self.desktopScreen.setChecked(checked)
if checked:
Settings().setValue(
self.parent().generalSettingsSection + u'/screen blank',
u'hidden')
Settings().setValue(self.parent().generalSettingsSection + u'/screen blank', u'hidden')
else:
Settings().remove(
self.parent().generalSettingsSection + u'/screen blank')
Settings().remove(self.parent().generalSettingsSection + u'/screen blank')
self.hidePlugin(checked)
self.updatePreview()
@ -1031,14 +928,12 @@ class SlideController(Controller):
if hide_mode:
if not self.serviceItem.is_command():
Receiver.send_message(u'live_display_hide', hide_mode)
Receiver.send_message(u'%s_blank'
% self.serviceItem.name.lower(),
Receiver.send_message(u'%s_blank' % self.serviceItem.name.lower(),
[self.serviceItem, self.isLive, hide_mode])
else:
if not self.serviceItem.is_command():
Receiver.send_message(u'live_display_show')
Receiver.send_message(u'%s_unblank'
% self.serviceItem.name.lower(),
Receiver.send_message(u'%s_unblank' % self.serviceItem.name.lower(),
[self.serviceItem, self.isLive])
else:
if hide_mode:
@ -1054,14 +949,12 @@ class SlideController(Controller):
if self.serviceItem is not None:
if hide:
Receiver.send_message(u'live_display_hide', HideMode.Screen)
Receiver.send_message(u'%s_hide'
% self.serviceItem.name.lower(),
Receiver.send_message(u'%s_hide' % self.serviceItem.name.lower(),
[self.serviceItem, self.isLive])
else:
if not self.serviceItem.is_command():
Receiver.send_message(u'live_display_show')
Receiver.send_message(u'%s_unblank'
% self.serviceItem.name.lower(),
Receiver.send_message(u'%s_unblank' % self.serviceItem.name.lower(),
[self.serviceItem, self.isLive])
else:
if hide:
@ -1085,8 +978,7 @@ class SlideController(Controller):
if -1 < row < self.previewListWidget.rowCount():
if self.serviceItem.is_command():
if self.isLive and not start:
Receiver.send_message(
u'%s_slide' % self.serviceItem.name.lower(),
Receiver.send_message(u'%s_slide' % self.serviceItem.name.lower(),
[self.serviceItem, self.isLive, row])
else:
to_display = self.serviceItem.get_rendered_frame(row)
@ -1102,8 +994,7 @@ class SlideController(Controller):
self.updatePreview()
self.selectedRow = row
self.__checkUpdateSelectedSlide(row)
Receiver.send_message(u'slidecontroller_%s_changed' % self.typePrefix,
row)
Receiver.send_message(u'slidecontroller_%s_changed' % self.typePrefix, row)
def onSlideChange(self, row):
"""
@ -1111,8 +1002,7 @@ class SlideController(Controller):
"""
self.__checkUpdateSelectedSlide(row)
self.updatePreview()
Receiver.send_message(u'slidecontroller_%s_changed' % self.typePrefix,
row)
Receiver.send_message(u'slidecontroller_%s_changed' % self.typePrefix, row)
def updatePreview(self):
"""
@ -1121,7 +1011,7 @@ class SlideController(Controller):
"""
log.debug(u'updatePreview %s ' % self.screens.current[u'primary'])
if not self.screens.current[u'primary'] and self.serviceItem and \
self.serviceItem.is_capable(ItemCapabilities.ProvidesOwnDisplay):
self.serviceItem.is_capable(ItemCapabilities.ProvidesOwnDisplay):
# Grab now, but try again in a couple of seconds if slide change
# is slow
QtCore.QTimer.singleShot(0.5, self.grabMainDisplay)
@ -1135,8 +1025,7 @@ class SlideController(Controller):
"""
winid = QtGui.QApplication.desktop().winId()
rect = self.screens.current[u'size']
winimg = QtGui.QPixmap.grabWindow(winid, rect.x(),
rect.y(), rect.width(), rect.height())
winimg = QtGui.QPixmap.grabWindow(winid, rect.x(), rect.y(), rect.width(), rect.height())
self.slidePreview.setPixmap(winimg)
def onSlideSelectedNextAction(self, checked):
@ -1152,8 +1041,7 @@ class SlideController(Controller):
"""
if not self.serviceItem:
return
Receiver.send_message(u'%s_next' % self.serviceItem.name.lower(),
[self.serviceItem, self.isLive])
Receiver.send_message(u'%s_next' % self.serviceItem.name.lower(), [self.serviceItem, self.isLive])
if self.serviceItem.is_command() and self.isLive:
self.updatePreview()
else:
@ -1180,8 +1068,7 @@ class SlideController(Controller):
"""
if not self.serviceItem:
return
Receiver.send_message(u'%s_previous' % self.serviceItem.name.lower(),
[self.serviceItem, self.isLive])
Receiver.send_message(u'%s_previous' % self.serviceItem.name.lower(), [self.serviceItem, self.isLive])
if self.serviceItem.is_command() and self.isLive:
self.updatePreview()
else:
@ -1190,8 +1077,7 @@ class SlideController(Controller):
if self.slide_limits == SlideLimits.Wrap:
row = self.previewListWidget.rowCount() - 1
elif self.isLive and self.slide_limits == SlideLimits.Next:
self.keypress_queue.append(
ServiceItemAction.PreviousLastSlide)
self.keypress_queue.append(ServiceItemAction.PreviousLastSlide)
self._process_queue()
return
else:
@ -1201,8 +1087,7 @@ class SlideController(Controller):
def __checkUpdateSelectedSlide(self, row):
if row + 1 < self.previewListWidget.rowCount():
self.previewListWidget.scrollToItem(
self.previewListWidget.item(row + 1, 0))
self.previewListWidget.scrollToItem(self.previewListWidget.item(row + 1, 0))
self.previewListWidget.selectRow(row)
def onToggleLoop(self):
@ -1219,8 +1104,7 @@ class SlideController(Controller):
Start the timer loop running and store the timer id
"""
if self.previewListWidget.rowCount() > 1:
self.timer_id = self.startTimer(
int(self.delaySpinBox.value()) * 1000)
self.timer_id = self.startTimer(int(self.delaySpinBox.value()) * 1000)
def onStopLoop(self):
"""
@ -1295,16 +1179,14 @@ class SlideController(Controller):
From the preview display requires the service Item to be editied
"""
self.songEdit = True
Receiver.send_message(u'%s_edit' % self.serviceItem.name.lower(),
u'P:%s' % self.serviceItem.edit_id)
Receiver.send_message(u'%s_edit' % self.serviceItem.name.lower(), u'P:%s' % self.serviceItem.edit_id)
def onPreviewAddToService(self):
"""
From the preview display request the Item to be added to service
"""
if self.serviceItem:
self.parent().serviceManagerContents.addServiceItem(
self.serviceItem)
self.parent().serviceManagerContents.addServiceItem(self.serviceItem)
def onGoLiveClick(self):
"""
@ -1314,9 +1196,7 @@ class SlideController(Controller):
# Live and Preview have issues if we have video or presentations
# playing in both at the same time.
if self.serviceItem.is_command():
Receiver.send_message(u'%s_stop' %
self.serviceItem.name.lower(),
[self.serviceItem, self.isLive])
Receiver.send_message(u'%s_stop' % self.serviceItem.name.lower(), [self.serviceItem, self.isLive])
if self.serviceItem.is_media():
self.onMediaClose()
self.onGoLive()
@ -1328,20 +1208,17 @@ class SlideController(Controller):
row = self.previewListWidget.currentRow()
if -1 < row < self.previewListWidget.rowCount():
if self.serviceItem.from_service:
Receiver.send_message('servicemanager_preview_live',
u'%s:%s' % (self.serviceItem._uuid, row))
Receiver.send_message('servicemanager_preview_live', u'%s:%s' % (self.serviceItem._uuid, row))
else:
self.parent().liveController.addServiceManagerItem(
self.serviceItem, row)
self.parent().liveController.addServiceManagerItem(self.serviceItem, row)
def onMediaStart(self, item):
"""
Respond to the arrival of a media service item
"""
log.debug(u'SlideController onMediaStart')
file = item.get_frame_path()
self.mediaController.video(self, file, False, False, self.hideMode())
if not self.isLive or self.mediaController.withLivePreview:
self.mediaController.video(self.controllerType, item, self.hideMode())
if not self.isLive:
self.previewDisplay.show()
self.slidePreview.hide()
@ -1350,7 +1227,7 @@ class SlideController(Controller):
Respond to a request to close the Video
"""
log.debug(u'SlideController onMediaClose')
self.mediaController.video_reset(self)
self.mediaController.media_reset(self)
self.previewDisplay.hide()
self.slidePreview.show()

View File

@ -133,8 +133,7 @@ class AppLocation(object):
"""
# Check if we have a different data location.
if Settings().contains(u'advanced/data path'):
path = unicode(Settings().value(
u'advanced/data path').toString())
path = Settings().value(u'advanced/data path')
else:
path = AppLocation.get_directory(AppLocation.DataDir)
check_directory_exists(path)

View File

@ -122,7 +122,7 @@ class AlertsTab(SettingsTab):
translate('AlertsPlugin.AlertsTab', 'Alert timeout:'))
self.timeoutSpinBox.setSuffix(UiStrings().Seconds)
self.previewGroupBox.setTitle(UiStrings().Preview)
self.fontPreview.setText(UiStrings().OLPV2)
self.fontPreview.setText(UiStrings().OLPV2x)
def onBackgroundColorButtonClicked(self):
new_color = QtGui.QColorDialog.getColor(

View File

@ -32,7 +32,7 @@ import logging
from PyQt4 import QtCore, QtGui
from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, \
translate, create_separated_list, Settings
translate, create_separated_list, ServiceItemContext, Settings
from openlp.core.lib.searchedit import SearchEdit
from openlp.core.lib.ui import UiStrings, set_case_insensitive_completer, \
create_horizontal_adjusting_combo_box, critical_error_message_box, \
@ -884,7 +884,7 @@ class BibleMediaItem(MediaManagerItem):
return items
def generateSlideData(self, service_item, item=None, xmlVersion=False,
remote=False):
remote=False, context=ServiceItemContext.Service):
"""
Generates and formats the slides for the service item as well as the
service item's title.

View File

@ -33,7 +33,7 @@ from PyQt4 import QtCore, QtGui
from sqlalchemy.sql import or_, func
from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, \
check_item_selected, translate, Settings
check_item_selected, translate, ServiceItemContext, Settings
from openlp.core.lib.ui import UiStrings
from openlp.plugins.custom.forms import EditCustomForm
from openlp.plugins.custom.lib import CustomXMLParser
@ -192,7 +192,7 @@ class CustomMediaItem(MediaManagerItem):
self.searchTextEdit.setFocus()
def generateSlideData(self, service_item, item=None, xmlVersion=False,
remote=False):
remote=False, context=ServiceItemContext.Service):
item_id = self._getIdOfItemToGenerate(item, self.remoteCustom)
service_item.add_capability(ItemCapabilities.CanEdit)
service_item.add_capability(ItemCapabilities.CanPreview)

View File

@ -29,7 +29,8 @@
from PyQt4 import QtCore, QtGui
from openlp.core.lib import Receiver, Settings, SettingsTab, translate
from openlp.core.lib import SettingsTab, translate, Receiver, Settings
from openlp.core.lib.ui import UiStrings
class ImageTab(SettingsTab):
"""
@ -67,10 +68,8 @@ class ImageTab(SettingsTab):
QtCore.SIGNAL(u'clicked()'), self.onbackgroundColorButtonClicked)
def retranslateUi(self):
self.bgColorGroupBox.setTitle(
translate('ImagesPlugin.ImageTab', 'Background Color'))
self.backgroundColorLabel.setText(
translate('ImagesPlugin.ImageTab', 'Default Color:'))
self.bgColorGroupBox.setTitle(UiStrings().BackgroundColor)
self.backgroundColorLabel.setText(UiStrings().DefaultColor)
self.informationLabel.setText(
translate('ImagesPlugin.ImageTab', 'Visible background for images '
'with aspect ratio different to screen.'))

View File

@ -34,7 +34,7 @@ from PyQt4 import QtCore, QtGui
from openlp.core.lib import MediaManagerItem, build_icon, ItemCapabilities, \
SettingsManager, translate, check_item_selected, check_directory_exists, \
Receiver, create_thumb, validate_thumb, Settings
Receiver, create_thumb, validate_thumb, ServiceItemContext, Settings
from openlp.core.lib.ui import UiStrings, critical_error_message_box
from openlp.core.utils import AppLocation, delete_file, locale_compare, \
get_images_filter
@ -151,7 +151,7 @@ class ImageMediaItem(MediaManagerItem):
Receiver.send_message(u'cursor_normal')
def generateSlideData(self, service_item, item=None, xmlVersion=False,
remote=False):
remote=False, context=ServiceItemContext.Service):
background = QtGui.QColor(Settings().value(self.settingsSection
+ u'/background color', u'#000000'))
if item:

View File

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
@ -32,22 +32,20 @@ import os
from PyQt4 import QtCore, QtGui
from openlp.core.lib import MediaManagerItem, build_icon, ItemCapabilities, \
SettingsManager, translate, check_item_selected, Receiver, MediaType, \
ServiceItem, build_html
from openlp.core.lib.ui import UiStrings, critical_error_message_box, \
create_horizontal_adjusting_combo_box
from openlp.core.ui import Controller, Display
from openlp.core.lib import MediaManagerItem, build_icon, ItemCapabilities, SettingsManager, translate, \
check_item_selected, Receiver, MediaType, ServiceItem, build_html, ServiceItemContext, Settings
from openlp.core.lib.ui import UiStrings, critical_error_message_box, create_horizontal_adjusting_combo_box
from openlp.core.ui import DisplayController, Display, DisplayControllerType
from openlp.core.ui.media import get_media_players, set_media_players
from openlp.core.utils import locale_compare
log = logging.getLogger(__name__)
CLAPPERBOARD = u':/media/slidecontroller_multimedia.png'
VIDEO = QtGui.QImage(u':/media/media_video.png')
AUDIO = QtGui.QImage(u':/media/media_audio.png')
DVD_ICON = QtGui.QImage(u':/media/media_video.png')
ERROR = QtGui.QImage(u':/general/general_delete.png')
VIDEO = build_icon(QtGui.QImage(u':/media/media_video.png'))
AUDIO = build_icon(QtGui.QImage(u':/media/media_audio.png'))
DVDICON = build_icon(QtGui.QImage(u':/media/media_video.png'))
ERROR = build_icon(QtGui.QImage(u':/general/general_delete.png'))
class MediaMediaItem(MediaManagerItem):
"""
@ -58,57 +56,37 @@ class MediaMediaItem(MediaManagerItem):
def __init__(self, parent, plugin, icon):
self.iconPath = u'images/image'
self.background = False
self.previewFunction = CLAPPERBOARD
self.automatic = u''
MediaManagerItem.__init__(self, parent, plugin, icon)
self.singleServiceItem = False
self.hasSearch = True
self.mediaObject = None
self.mediaController = Controller(parent)
self.mediaController.controllerLayout = QtGui.QVBoxLayout()
self.plugin.mediaController.add_controller_items(self.mediaController, \
self.mediaController.controllerLayout)
self.plugin.mediaController.set_controls_visible(self.mediaController, \
False)
self.mediaController.previewDisplay = Display(self.mediaController, \
False, self.mediaController)
self.mediaController.previewDisplay.setGeometry(
QtCore.QRect(0, 0, 300, 300))
self.mediaController.previewDisplay.screen = \
{u'size':self.mediaController.previewDisplay.geometry()}
self.mediaController.previewDisplay.setup()
serviceItem = ServiceItem()
self.mediaController.previewDisplay.webView.setHtml(build_html( \
serviceItem, self.mediaController.previewDisplay.screen, None, \
False, None))
self.mediaController.previewDisplay.setup()
self.plugin.mediaController.setup_display( \
self.mediaController.previewDisplay)
self.mediaController.previewDisplay.hide()
self.displayController = DisplayController(parent)
self.displayController.controllerLayout = QtGui.QVBoxLayout()
self.plugin.mediaController.register_controller(self.displayController)
self.plugin.mediaController.set_controls_visible(self.displayController, False)
self.displayController.previewDisplay = Display(self.displayController, False, self.displayController)
self.displayController.previewDisplay.hide()
self.displayController.previewDisplay.setGeometry(QtCore.QRect(0, 0, 300, 300))
self.displayController.previewDisplay.screen = {u'size':self.displayController.previewDisplay.geometry()}
self.displayController.previewDisplay.setup()
self.plugin.mediaController.setup_display(self.displayController.previewDisplay, False)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'video_background_replaced'),
self.videobackgroundReplaced)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'mediaitem_media_rebuild'), self.rebuild)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'config_screen_changed'), self.displaySetup)
QtCore.SIGNAL(u'video_background_replaced'), self.videobackgroundReplaced)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'mediaitem_media_rebuild'), self.rebuild_players)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'config_screen_changed'), self.displaySetup)
# Allow DnD from the desktop
self.listView.activateDnD()
def retranslateUi(self):
self.onNewPrompt = translate('MediaPlugin.MediaItem', 'Select Media')
self.onNewFileMasks = translate('MediaPlugin.MediaItem',
'Videos (%s);;Audio (%s);;%s (*)') % (
u' '.join(self.plugin.video_extensions_list),
u' '.join(self.plugin.audio_extensions_list), UiStrings().AllFiles)
self.replaceAction.setText(UiStrings().ReplaceBG)
self.replaceAction.setToolTip(UiStrings().ReplaceLiveBG)
self.resetAction.setText(UiStrings().ResetBG)
self.resetAction.setToolTip(UiStrings().ResetLiveBG)
self.automatic = translate('MediaPlugin.MediaItem', 'Automatic')
self.displayTypeLabel.setText(
translate('MediaPlugin.MediaItem', 'Use Player:'))
self.automatic = UiStrings().Automatic
self.displayTypeLabel.setText(translate('MediaPlugin.MediaItem', 'Use Player:'))
self.rebuild_players()
def requiredIcons(self):
MediaManagerItem.requiredIcons(self)
@ -122,11 +100,10 @@ class MediaMediaItem(MediaManagerItem):
def addEndHeaderBar(self):
# Replace backgrounds do not work at present so remove functionality.
self.replaceAction = self.toolbar.addToolbarAction(u'replaceAction',
icon=u':/slides/slide_blank.png', triggers=self.onReplaceClick)
self.resetAction = self.toolbar.addToolbarAction(u'resetAction',
icon=u':/system/system_close.png', visible=False,
triggers=self.onResetClick)
self.replaceAction = self.toolbar.addToolbarAction(u'replaceAction', icon=u':/slides/slide_blank.png',
triggers=self.onReplaceClick)
self.resetAction = self.toolbar.addToolbarAction(u'resetAction', icon=u':/system/system_close.png',
visible=False, triggers=self.onResetClick)
self.mediaWidget = QtGui.QWidget(self)
self.mediaWidget.setObjectName(u'mediaWidget')
self.displayLayout = QtGui.QFormLayout(self.mediaWidget)
@ -134,15 +111,12 @@ class MediaMediaItem(MediaManagerItem):
self.displayLayout.setObjectName(u'displayLayout')
self.displayTypeLabel = QtGui.QLabel(self.mediaWidget)
self.displayTypeLabel.setObjectName(u'displayTypeLabel')
self.displayTypeComboBox = create_horizontal_adjusting_combo_box(
self.mediaWidget, u'displayTypeComboBox')
self.displayTypeComboBox = create_horizontal_adjusting_combo_box(self.mediaWidget, u'displayTypeComboBox')
self.displayTypeLabel.setBuddy(self.displayTypeComboBox)
self.displayLayout.addRow(self.displayTypeLabel,
self.displayTypeComboBox)
self.displayLayout.addRow(self.displayTypeLabel, self.displayTypeComboBox)
# Add the Media widget to the page layout
self.pageLayout.addWidget(self.mediaWidget)
QtCore.QObject.connect(self.displayTypeComboBox,
QtCore.SIGNAL(u'currentIndexChanged (int)'),
QtCore.QObject.connect(self.displayTypeComboBox, QtCore.SIGNAL(u'currentIndexChanged (int)'),
self.overridePlayerChanged)
def overridePlayerChanged(self, index):
@ -156,7 +130,7 @@ class MediaMediaItem(MediaManagerItem):
"""
Called to reset the Live background with the media selected,
"""
self.plugin.liveController.mediaController.video_reset( \
self.plugin.liveController.mediaController.media_reset(
self.plugin.liveController)
self.resetAction.setVisible(False)
@ -176,21 +150,24 @@ class MediaMediaItem(MediaManagerItem):
item = self.listView.currentItem()
filename = item.data(QtCore.Qt.UserRole)
if os.path.exists(filename):
if self.plugin.liveController.mediaController.video( \
self.plugin.liveController, filename, True, True):
service_item = ServiceItem()
service_item.title = u'webkit'
service_item.shortname = service_item.title
(path, name) = os.path.split(filename)
service_item.add_from_command(path, name,CLAPPERBOARD)
if self.plugin.liveController.mediaController.video(DisplayControllerType.Live, service_item,
videoBehindText=True):
self.resetAction.setVisible(True)
else:
critical_error_message_box(UiStrings().LiveBGError,
translate('MediaPlugin.MediaItem',
'There was no display item to amend.'))
translate('MediaPlugin.MediaItem', 'There was no display item to amend.'))
else:
critical_error_message_box(UiStrings().LiveBGError,
translate('MediaPlugin.MediaItem',
'There was a problem replacing your background, '
'the media file "%s" no longer exists.') % filename)
'There was a problem replacing your background, the media file "%s" no longer exists.') % filename)
def generateSlideData(self, service_item, item=None, xmlVersion=False,
remote=False):
remote=False, context=ServiceItemContext.Live):
if item is None:
item = self.listView.currentItem()
if item is None:
@ -201,37 +178,24 @@ class MediaMediaItem(MediaManagerItem):
# File is no longer present
critical_error_message_box(
translate('MediaPlugin.MediaItem', 'Missing Media File'),
translate('MediaPlugin.MediaItem',
'The file %s no longer exists.') % filename)
translate('MediaPlugin.MediaItem', 'The file %s no longer exists.') % filename)
return False
self.mediaLength = 0
# Get media information and its length.
#
# This code (mediaController.video()) starts playback but we
# need only media information not video to start. Otherwise
# video is played twice. Find another way to get media info
# without loading and starting video playback.
#
# TODO Test getting media length with other media backends
# Phonon/Webkit.
if self.plugin.mediaController.video(self.mediaController,
filename, muted=False, isBackground=False, isInfo=True,
controlsVisible=False):
self.mediaLength = self.mediaController.media_info.length
service_item.media_length = self.mediaLength
if self.mediaLength > 0:
service_item.add_capability(
ItemCapabilities.HasVariableStartTime)
else:
return False
service_item.media_length = self.mediaLength
service_item.title = unicode(self.plugin.nameStrings[u'singular'])
service_item.add_capability(ItemCapabilities.RequiresMedia)
# force a non-existent theme
service_item.theme = -1
frame = CLAPPERBOARD
service_item.title = self.displayTypeComboBox.currentText()
service_item.shortname = service_item.title
(path, name) = os.path.split(filename)
service_item.add_from_command(path, name, frame)
service_item.add_from_command(path, name, CLAPPERBOARD)
# Only get start and end times if going to a service
if context == ServiceItemContext.Service:
# Start media and obtain the length
if not self.plugin.mediaController.media_length(service_item):
return False
service_item.add_capability(ItemCapabilities.CanAutoStartForLive)
service_item.add_capability(ItemCapabilities.RequiresMedia)
service_item.add_capability(ItemCapabilities.HasDetailedTitleDisplay)
if Settings().value(self.settingsSection + u'/media auto start', QtCore.Qt.Unchecked) == QtCore.Qt.Checked:
service_item.will_auto_start = True
# force a non-existent theme
service_item.theme = -1
return True
def initialise(self):
@ -240,27 +204,25 @@ class MediaMediaItem(MediaManagerItem):
self.loadList(SettingsManager.load_list(self.settingsSection, u'media'))
self.populateDisplayTypes()
def rebuild(self):
def rebuild_players(self):
"""
Rebuild the tab in the media manager when changes are made in
the settings
"""
self.populateDisplayTypes()
self.onNewFileMasks = translate('MediaPlugin.MediaItem',
'Videos (%s);;Audio (%s);;%s (*)') % (
u' '.join(self.plugin.video_extensions_list),
u' '.join(self.plugin.audio_extensions_list), UiStrings().AllFiles)
self.onNewFileMasks = translate('MediaPlugin.MediaItem', 'Videos (%s);;Audio (%s);;%s (*)') % (
u' '.join(self.plugin.mediaController.video_extensions_list),
u' '.join(self.plugin.mediaController.audio_extensions_list), UiStrings().AllFiles)
def displaySetup(self):
self.plugin.mediaController.setup_display( \
self.mediaController.previewDisplay)
self.plugin.mediaController.setup_display(self.displayController.previewDisplay, False)
def populateDisplayTypes(self):
"""
Load the combobox with the enabled media players,
allowing user to select a specific player if settings allow
"""
# block signals to avoid unnecessary overridePlayerChanged Signales
# block signals to avoid unnecessary overridePlayerChanged Signals
# while combo box creation
self.displayTypeComboBox.blockSignals(True)
self.displayTypeComboBox.clear()
@ -286,7 +248,7 @@ class MediaMediaItem(MediaManagerItem):
Remove a media item from the list.
"""
if check_item_selected(self.listView, translate('MediaPlugin.MediaItem',
'You must select a media file to delete.')):
'You must select a media file to delete.')):
row_list = [item.row() for item in self.listView.selectedIndexes()]
row_list.sort(reverse=True)
for row in row_list:
@ -297,38 +259,38 @@ class MediaMediaItem(MediaManagerItem):
def loadList(self, media):
# Sort the media by its filename considering language specific
# characters.
media.sort(cmp=locale_compare,
key=lambda filename: os.path.split(unicode(filename))[1])
media.sort(cmp=locale_compare, key=lambda filename: os.path.split(unicode(filename))[1])
for track in media:
track_info = QtCore.QFileInfo(track)
if not os.path.exists(track):
filename = os.path.split(unicode(track))[1]
item_name = QtGui.QListWidgetItem(filename)
item_name.setIcon(build_icon(ERROR))
item_name.setIcon(ERROR)
item_name.setData(QtCore.Qt.UserRole, track)
elif track_info.isFile():
filename = os.path.split(unicode(track))[1]
item_name = QtGui.QListWidgetItem(filename)
item_name.setIcon(build_icon(VIDEO))
if u'*.%s' % (filename.split(u'.')[-1].lower()) in self.plugin.mediaController.audio_extensions_list:
item_name.setIcon(AUDIO)
else:
item_name.setIcon(VIDEO)
item_name.setData(QtCore.Qt.UserRole, track)
else:
filename = os.path.split(unicode(track))[1]
item_name = QtGui.QListWidgetItem(filename)
#TODO: add the appropriate Icon
#item_name.setIcon(build_icon(DVD_ICON))
item_name.setIcon(build_icon(DVDICON))
item_name.setData(QtCore.Qt.UserRole, track)
item_name.setToolTip(track)
self.listView.addItem(item_name)
def getList(self, type=MediaType.Audio):
media = SettingsManager.load_list(self.settingsSection, u'media')
media.sort(cmp=locale_compare,
key=lambda filename: os.path.split(unicode(filename))[1])
media.sort(cmp=locale_compare, key=lambda filename: os.path.split(unicode(filename))[1])
ext = []
if type == MediaType.Audio:
ext = self.plugin.audio_extensions_list
ext = self.plugin.mediaController.audio_extensions_list
else:
ext = self.plugin.video_extensions_list
ext = self.plugin.mediaController.video_extensions_list
ext = map(lambda x: x[1:], ext)
media = filter(lambda x: os.path.splitext(x)[1] in ext, media)
return media

View File

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
@ -32,6 +32,7 @@ from PyQt4 import QtCore, QtGui
from openlp.core.lib import Receiver, Settings, SettingsTab, translate
from openlp.core.lib.ui import UiStrings, create_button
from openlp.core.ui.media import get_media_players, set_media_players
class MediaQCheckBox(QtGui.QCheckBox):
"""
MediaQCheckBox adds an extra property, playerName to the QCheckBox class.
@ -44,59 +45,13 @@ class MediaTab(SettingsTab):
"""
MediaTab is the Media settings tab in the settings dialog.
"""
def __init__(self, parent, title, visible_title, media_players, icon_path):
self.mediaPlayers = media_players
self.savedUsedPlayers = None
def __init__(self, parent, title, visible_title, icon_path):
self.parent = parent
SettingsTab.__init__(self, parent, title, visible_title, icon_path)
def setupUi(self):
self.setObjectName(u'MediaTab')
SettingsTab.setupUi(self)
self.mediaPlayerGroupBox = QtGui.QGroupBox(self.leftColumn)
self.mediaPlayerGroupBox.setObjectName(u'mediaPlayerGroupBox')
self.mediaPlayerLayout = QtGui.QVBoxLayout(self.mediaPlayerGroupBox)
self.mediaPlayerLayout.setObjectName(u'mediaPlayerLayout')
self.playerCheckBoxes = {}
for key, player in self.mediaPlayers.iteritems():
player = self.mediaPlayers[key]
checkbox = MediaQCheckBox(self.mediaPlayerGroupBox)
checkbox.setEnabled(player.available)
checkbox.setObjectName(player.name + u'CheckBox')
self.playerCheckBoxes[player.name] = checkbox
self.mediaPlayerLayout.addWidget(checkbox)
self.leftLayout.addWidget(self.mediaPlayerGroupBox)
self.playerOrderGroupBox = QtGui.QGroupBox(self.leftColumn)
self.playerOrderGroupBox.setObjectName(u'playerOrderGroupBox')
self.playerOrderLayout = QtGui.QHBoxLayout(self.playerOrderGroupBox)
self.playerOrderLayout.setObjectName(u'playerOrderLayout')
self.playerOrderlistWidget = QtGui.QListWidget(self.playerOrderGroupBox)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum,
QtGui.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.playerOrderlistWidget. \
sizePolicy().hasHeightForWidth())
self.playerOrderlistWidget.setSizePolicy(sizePolicy)
self.playerOrderlistWidget.setVerticalScrollBarPolicy(
QtCore.Qt.ScrollBarAsNeeded)
self.playerOrderlistWidget.setHorizontalScrollBarPolicy(
QtCore.Qt.ScrollBarAlwaysOff)
self.playerOrderlistWidget.setEditTriggers(
QtGui.QAbstractItemView.NoEditTriggers)
self.playerOrderlistWidget.setObjectName(u'playerOrderlistWidget')
self.playerOrderLayout.addWidget(self.playerOrderlistWidget)
self.orderingButtonLayout = QtGui.QVBoxLayout()
self.orderingButtonLayout.setObjectName(u'orderingButtonLayout')
self.orderingButtonLayout.addStretch(1)
self.orderingUpButton = create_button(self, u'orderingUpButton',
role=u'up', click=self.onUpButtonClicked)
self.orderingDownButton = create_button(self, u'orderingDownButton',
role=u'down', click=self.onDownButtonClicked)
self.orderingButtonLayout.addWidget(self.orderingUpButton)
self.orderingButtonLayout.addWidget(self.orderingDownButton)
self.orderingButtonLayout.addStretch(1)
self.playerOrderLayout.addLayout(self.orderingButtonLayout)
self.leftLayout.addWidget(self.playerOrderGroupBox)
self.advancedGroupBox = QtGui.QGroupBox(self.leftColumn)
self.advancedGroupBox.setObjectName(u'advancedGroupBox')
self.advancedLayout = QtGui.QVBoxLayout(self.advancedGroupBox)
@ -104,107 +59,34 @@ class MediaTab(SettingsTab):
self.overridePlayerCheckBox = QtGui.QCheckBox(self.advancedGroupBox)
self.overridePlayerCheckBox.setObjectName(u'overridePlayerCheckBox')
self.advancedLayout.addWidget(self.overridePlayerCheckBox)
self.autoStartCheckBox = QtGui.QCheckBox(self.advancedGroupBox)
self.autoStartCheckBox.setObjectName(u'autoStartCheckBox')
self.advancedLayout.addWidget(self.autoStartCheckBox)
self.leftLayout.addWidget(self.advancedGroupBox)
self.leftLayout.addStretch()
self.rightLayout.addStretch()
for key in self.mediaPlayers:
player = self.mediaPlayers[key]
checkbox = self.playerCheckBoxes[player.name]
QtCore.QObject.connect(checkbox,
QtCore.SIGNAL(u'stateChanged(int)'),
self.onPlayerCheckBoxChanged)
def retranslateUi(self):
self.mediaPlayerGroupBox.setTitle(
translate('MediaPlugin.MediaTab', 'Available Media Players'))
for key in self.mediaPlayers:
player = self.mediaPlayers[key]
checkbox = self.playerCheckBoxes[player.name]
checkbox.setPlayerName(player.name)
if player.available:
checkbox.setText(player.display_name)
else:
checkbox.setText(translate('MediaPlugin.MediaTab',
'%s (unavailable)') % player.display_name)
self.playerOrderGroupBox.setTitle(
translate('MediaPlugin.MediaTab', 'Player Order'))
self.advancedGroupBox.setTitle(UiStrings().Advanced)
self.overridePlayerCheckBox.setText(
translate('MediaPlugin.MediaTab',
'Allow media player to be overridden'))
def onPlayerCheckBoxChanged(self, check_state):
player = self.sender().playerName
if check_state == QtCore.Qt.Checked:
if player not in self.usedPlayers:
self.usedPlayers.append(player)
else:
if player in self.usedPlayers:
self.usedPlayers.remove(player)
self.updatePlayerList()
def updatePlayerList(self):
self.playerOrderlistWidget.clear()
for player in self.usedPlayers:
if player in self.playerCheckBoxes.keys():
if len(self.usedPlayers) == 1:
# At least one media player has to stay active
self.playerCheckBoxes[u'%s' % player].setEnabled(False)
else:
self.playerCheckBoxes[u'%s' % player].setEnabled(True)
self.playerOrderlistWidget.addItem(
self.mediaPlayers[unicode(player)].original_name)
def onUpButtonClicked(self):
row = self.playerOrderlistWidget.currentRow()
if row <= 0:
return
item = self.playerOrderlistWidget.takeItem(row)
self.playerOrderlistWidget.insertItem(row - 1, item)
self.playerOrderlistWidget.setCurrentRow(row - 1)
self.usedPlayers.insert(row - 1, self.usedPlayers.pop(row))
def onDownButtonClicked(self):
row = self.playerOrderlistWidget.currentRow()
if row == -1 or row > self.playerOrderlistWidget.count() - 1:
return
item = self.playerOrderlistWidget.takeItem(row)
self.playerOrderlistWidget.insertItem(row + 1, item)
self.playerOrderlistWidget.setCurrentRow(row + 1)
self.usedPlayers.insert(row + 1, self.usedPlayers.pop(row))
self.overridePlayerCheckBox.setText(translate('MediaPlugin.MediaTab', 'Allow media player to be overridden'))
self.autoStartCheckBox.setText(translate('MediaPlugin.MediaTab', 'Start Live items automatically'))
def load(self):
if self.savedUsedPlayers:
self.usedPlayers = self.savedUsedPlayers
self.usedPlayers = get_media_players()[0]
self.savedUsedPlayers = self.usedPlayers
for key in self.mediaPlayers:
player = self.mediaPlayers[key]
checkbox = self.playerCheckBoxes[player.name]
if player.available and player.name in self.usedPlayers:
checkbox.setChecked(True)
else:
checkbox.setChecked(False)
self.updatePlayerList()
self.overridePlayerCheckBox.setChecked(Settings().value(
self.settingsSection + u'/override player', QtCore.Qt.Unchecked))
self.overridePlayerCheckBox.setChecked(Settings().value(self.settingsSection + u'/override player',
QtCore.Qt.Unchecked))
self.autoStartCheckBox.setChecked(Settings().value(self.settingsSection + u'/media auto start',
QtCore.Qt.Unchecked))
def save(self):
override_changed = False
player_string_changed = False
old_players, override_player = get_media_players()
if self.usedPlayers != old_players:
# clean old Media stuff
set_media_players(self.usedPlayers, override_player)
player_string_changed = True
override_changed = True
setting_key = self.settingsSection + u'/override player'
if Settings().value(setting_key, QtCore.Qt.Unchecked) != \
self.overridePlayerCheckBox.checkState():
Settings().setValue(setting_key,
self.overridePlayerCheckBox.checkState())
if Settings().value(setting_key, QtCore.Qt.Unchecked) != self.overridePlayerCheckBox.checkState():
Settings().setValue(setting_key, self.overridePlayerCheckBox.checkState())
override_changed = True
if player_string_changed or override_changed:
if override_changed:
Receiver.send_message(u'mediaitem_media_rebuild')
Receiver.send_message(u'config_screen_changed')
setting_key = self.settingsSection + u'/media auto start'
if Settings().value(setting_key, QtCore.Qt.Unchecked) != self.autoStartCheckBox.checkState():
Settings().setValue(setting_key, self.autoStartCheckBox.checkState())
if override_changed:
self.parent.resetSupportedSuffixes()
Receiver.send_message(u'mediaitem_media_rebuild')
Receiver.send_message(u'mediaitem_suffixes')

View File

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
@ -41,29 +41,19 @@ class MediaPlugin(Plugin):
log.info(u'%s MediaPlugin loaded', __name__)
def __init__(self, plugin_helpers):
Plugin.__init__(self, u'media', plugin_helpers,
MediaMediaItem)
Plugin.__init__(self, u'media', plugin_helpers, MediaMediaItem)
self.weight = -6
self.iconPath = u':/plugins/plugin_media.png'
self.icon = build_icon(self.iconPath)
# passed with drag and drop messages
self.dnd_id = u'Media'
self.audio_extensions_list = \
self.mediaController.get_audio_extensions_list()
for ext in self.audio_extensions_list:
self.serviceManager.supportedSuffixes(ext[2:])
self.video_extensions_list = \
self.mediaController.get_video_extensions_list()
for ext in self.video_extensions_list:
self.serviceManager.supportedSuffixes(ext[2:])
def createSettingsTab(self, parent):
"""
Create the settings Tab
"""
visible_name = self.getString(StringContent.VisibleName)
self.settingsTab = MediaTab(parent, self.name, visible_name[u'title'],
self.mediaController.mediaPlayers, self.iconPath)
self.settingsTab = MediaTab(parent, self.name, visible_name[u'title'], self.iconPath)
def about(self):
about_text = translate('MediaPlugin', '<strong>Media Plugin</strong>'
@ -92,8 +82,7 @@ class MediaPlugin(Plugin):
u'delete': translate('MediaPlugin', 'Delete the selected media.'),
u'preview': translate('MediaPlugin', 'Preview the selected media.'),
u'live': translate('MediaPlugin', 'Send the selected media live.'),
u'service': translate('MediaPlugin',
'Add the selected media to the service.')
u'service': translate('MediaPlugin', 'Add the selected media to the service.')
}
self.setPluginUiTextStrings(tooltips)
@ -139,8 +128,7 @@ class MediaPlugin(Plugin):
log.debug(u'Converting old setting to new setting')
new_players = []
if players:
new_players = [player for player in players \
if player != u'phonon']
new_players = [player for player in players if player != u'phonon']
new_players.insert(0, u'phonon')
self.mediaController.mediaPlayers[u'phonon'].isActive = True
settings.setValue(u'players', u','.join(new_players))

View File

@ -34,7 +34,7 @@ from PyQt4 import QtCore, QtGui
from openlp.core.lib import MediaManagerItem, build_icon, SettingsManager, \
translate, check_item_selected, Receiver, ItemCapabilities, create_thumb, \
validate_thumb, Settings
validate_thumb, ServiceItemContext, Settings
from openlp.core.lib.ui import UiStrings, critical_error_message_box, \
create_horizontal_adjusting_combo_box
from openlp.core.utils import locale_compare
@ -63,7 +63,10 @@ class PresentationMediaItem(MediaManagerItem):
self.hasSearch = True
self.singleServiceItem = False
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'mediaitem_presentation_rebuild'), self.rebuild)
QtCore.SIGNAL(u'mediaitem_presentation_rebuild'),
self.populateDisplayTypes)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'mediaitem_suffixes'), self.buildFileMaskString)
# Allow DnD from the desktop
self.listView.activateDnD()
@ -132,14 +135,6 @@ class PresentationMediaItem(MediaManagerItem):
self.loadList(files, True)
self.populateDisplayTypes()
def rebuild(self):
"""
Rebuild the tab in the media manager when changes are made in
the settings
"""
self.populateDisplayTypes()
self.buildFileMaskString()
def populateDisplayTypes(self):
"""
Load the combobox with the enabled presentation controllers,
@ -258,7 +253,7 @@ class PresentationMediaItem(MediaManagerItem):
u'presentations', self.getFileList())
def generateSlideData(self, service_item, item=None, xmlVersion=False,
remote=False):
remote=False, context=ServiceItemContext.Service):
"""
Load the relevant information for displaying the presentation
in the slidecontroller. In the case of powerpoints, an image

View File

@ -40,6 +40,7 @@ class PresentationTab(SettingsTab):
"""
Constructor
"""
self.parent = parent
self.controllers = controllers
SettingsTab.__init__(self, parent, title, visible_title, icon_path)
self.activated = False
@ -139,7 +140,9 @@ class PresentationTab(SettingsTab):
self.OverrideAppCheckBox.checkState())
changed = True
if changed:
self.parent.resetSupportedSuffixes()
Receiver.send_message(u'mediaitem_presentation_rebuild')
Receiver.send_message(u'mediaitem_suffixes')
def tabVisible(self):
"""

View File

@ -182,8 +182,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
for plugin in self.parent().pluginManager.plugins:
if plugin.name == u'media' and plugin.status == PluginStatus.Active:
self.audioAddFromMediaButton.setVisible(True)
self.mediaForm.populateFiles(
plugin.mediaItem.getList(MediaType.Audio))
self.mediaForm.populateFiles(plugin.mediaItem.getList(MediaType.Audio))
break
def newSong(self):

View File

@ -37,7 +37,7 @@ from sqlalchemy.sql import or_
from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, \
translate, check_item_selected, PluginStatus, create_separated_list, \
check_directory_exists, Settings
check_directory_exists, ServiceItemContext, Settings
from openlp.core.lib.ui import UiStrings, create_widget_action
from openlp.core.utils import AppLocation, locale_direct_compare
from openlp.plugins.songs.forms import EditSongForm, SongMaintenanceForm, \
@ -482,7 +482,7 @@ class SongMediaItem(MediaManagerItem):
self.onSongListLoad()
def generateSlideData(self, service_item, item=None, xmlVersion=False,
remote=False):
remote=False, context=ServiceItemContext.Service):
log.debug(u'generateSlideData: %s, %s, %s' %
(service_item, item, self.remoteSong))
item_id = self._getIdOfItemToGenerate(item, self.remoteSong)

View File

@ -89,10 +89,10 @@ class ZionWorxImport(SongImport):
try:
records = list(songs_reader)
except csv.Error, e:
self.logError(unicode(translate('SongsPlugin.ZionWorxImport',
'Error reading CSV file.')),
unicode(translate('SongsPlugin.ZionWorxImport',
'Line %d: %s')) % (songs_reader.line_num, e))
self.logError(translate('SongsPlugin.ZionWorxImport',
'Error reading CSV file.'),
translate('SongsPlugin.ZionWorxImport',
'Line %d: %s') % (songs_reader.line_num, e))
return
num_records = len(records)
log.info(u'%s records found in CSV file' % num_records)
@ -109,15 +109,15 @@ class ZionWorxImport(SongImport):
self.addCopyright(self._decode(record[u'Copyright']))
lyrics = self._decode(record[u'Lyrics'])
except UnicodeDecodeError, e:
self.logError(unicode(translate(
'SongsPlugin.ZionWorxImport', 'Record %d' % index)),
unicode(translate('SongsPlugin.ZionWorxImport',
'Decoding error: %s')) % e)
self.logError(translate(
'SongsPlugin.ZionWorxImport', 'Record %d' % index),
translate('SongsPlugin.ZionWorxImport',
'Decoding error: %s') % e)
continue
except TypeError, e:
self.logError(unicode(translate(
self.logError(translate(
'SongsPlugin.ZionWorxImport', 'File not valid ZionWorx '
'CSV format.')), u'TypeError: %s' % e)
'CSV format.'), u'TypeError: %s' % e)
return
verse = u''
for line in lyrics.splitlines():
@ -130,8 +130,7 @@ class ZionWorxImport(SongImport):
self.addVerse(verse)
title = self.title
if not self.finish():
self.logError(unicode(translate(
'SongsPlugin.ZionWorxImport', 'Record %d')) % index
self.logError(translate('SongsPlugin.ZionWorxImport', 'Record %d') % index
+ (u': "' + title + u'"' if title else u''))
def _decode(self, str):

Binary file not shown.

After

Width:  |  Height:  |  Size: 815 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 767 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 597 B

View File

@ -133,6 +133,9 @@
<file>media_audio.png</file>
<file>media_video.png</file>
<file>slidecontroller_multimedia.png</file>
<file>auto-start_active.png</file>
<file>auto-start_inactive.png</file>
<file>multimedia-player.png</file>
</qresource>
<qresource prefix="messagebox">
<file>messagebox_critical.png</file>

View File

@ -17,6 +17,11 @@ Notes:
<sub-class-of type="application/zip"/>
<comment>OpenLP Service File</comment>
<glob pattern="*.osz"/>
</mime-type>
<mime-type type="application/x-openlp-service">
<sub-class-of type="application/zip"/>
<comment>OpenLP Service File</comment>
<glob pattern="*.oszl"/>
</mime-type>
<mime-type type="application/x-openlp-theme">
<sub-class-of type="application/zip"/>

34
tests/README.txt Normal file
View File

@ -0,0 +1,34 @@
Tests for OpenLP
================
This directory contains unit tests for OpenLP. The ``functional`` directory contains functional unit tests.
Prerequisites
-------------
In order to run the unit tests, you will need the following Python packages/libraries installed:
- Mock
- Nose
On Ubuntu you can simple install the python-mock and python-nose packages. Most other distributions will also have these
packages. On Windows and Mac OS X you will need to use ``pip`` or ``easy_install`` to install these packages.
Running the Tests
-----------------
To run the tests, navigate to the root directory of the OpenLP project, and then run the following command::
nosetests -v tests
Or, to run only the functional tests, run the following command::
nosetests -v tests/functional
Or, to run only a particular test suite within a file, run the following command::
nosetests -v tests/functional/test_applocation.py
Finally, to only run a particular test, run the following command::
nosetests -v tests/functional/test_applocation.py:TestAppLocation.get_frozen_path_test

View File

@ -0,0 +1,158 @@
"""
Package to test the openlp.core.lib package.
"""
from unittest import TestCase
from mock import MagicMock, patch
from openlp.core.lib import str_to_bool, translate, check_directory_exists
class TestLib(TestCase):
def str_to_bool_with_bool_test(self):
"""
Test the str_to_bool function with boolean input
"""
#GIVEN: A boolean value set to true
true_boolean = True
# WHEN: We "convert" it to a bool
true_result = str_to_bool(true_boolean)
# THEN: We should get back a True bool
assert isinstance(true_result, bool), u'The result should be a boolean'
assert true_result is True, u'The result should be True'
#GIVEN: A boolean value set to false
false_boolean = False
# WHEN: We "convert" it to a bool
false_result = str_to_bool(false_boolean)
# THEN: We should get back a True bool
assert isinstance(false_result, bool), u'The result should be a boolean'
assert false_result is False, u'The result should be True'
def str_to_bool_with_invalid_test(self):
"""
Test the str_to_bool function with a set of invalid inputs
"""
# GIVEN: An integer value
int_string = 1
# WHEN: we convert it to a bool
int_result = str_to_bool(int_string)
# THEN: we should get back a false
assert int_result is False, u'The result should be False'
# GIVEN: An string value with completely invalid input
invalid_string = u'my feet are wet'
# WHEN: we convert it to a bool
str_result = str_to_bool(invalid_string)
# THEN: we should get back a false
assert str_result is False, u'The result should be False'
def str_to_bool_with_false_values_test(self):
"""
Test the str_to_bool function with a set of false inputs
"""
# GIVEN: A string set to "false"
false_string = u'false'
# WHEN: we convert it to a bool
false_result = str_to_bool(false_string)
# THEN: we should get back a false
assert false_result is False, u'The result should be False'
# GIVEN: An string set to "NO"
no_string = u'NO'
# WHEN: we convert it to a bool
str_result = str_to_bool(no_string)
# THEN: we should get back a false
assert str_result is False, u'The result should be False'
def str_to_bool_with_true_values_test(self):
"""
Test the str_to_bool function with a set of true inputs
"""
# GIVEN: A string set to "True"
true_string = u'True'
# WHEN: we convert it to a bool
true_result = str_to_bool(true_string)
# THEN: we should get back a true
assert true_result is True, u'The result should be True'
# GIVEN: An string set to "yes"
yes_string = u'yes'
# WHEN: we convert it to a bool
str_result = str_to_bool(yes_string)
# THEN: we should get back a true
assert str_result is True, u'The result should be True'
def translate_test(self):
"""
Test the translate() function
"""
# GIVEN: A string to translate and a mocked Qt translate function
context = u'OpenLP.Tests'
text = u'Untranslated string'
comment = u'A comment'
encoding = 1
n = 1
mocked_translate = MagicMock(return_value=u'Translated string')
# WHEN: we call the translate function
result = translate(context, text, comment, encoding, n, mocked_translate)
# THEN: the translated string should be returned, and the mocked function should have been called
mocked_translate.assert_called_with(context, text, comment, encoding, n)
assert result == u'Translated string', u'The translated string should have been returned'
def check_directory_exists_test(self):
"""
Test the check_directory_exists() function
"""
with patch(u'openlp.core.lib.os.path.exists') as mocked_exists, \
patch(u'openlp.core.lib.os.makedirs') as mocked_makedirs:
# GIVEN: A directory to check and a mocked out os.makedirs and os.path.exists
directory_to_check = u'existing/directory'
# WHEN: os.path.exists returns True and we check to see if the directory exists
mocked_exists.return_value = True
check_directory_exists(directory_to_check)
# THEN: Only os.path.exists should have been called
mocked_exists.assert_called_with(directory_to_check)
assert not mocked_makedirs.called, u'os.makedirs should not have been called'
# WHEN: os.path.exists returns False and we check the directory exists
mocked_exists.return_value = False
check_directory_exists(directory_to_check)
# THEN: Both the mocked functions should have been called
mocked_exists.assert_called_with(directory_to_check)
mocked_makedirs.assert_called_with(directory_to_check)
# WHEN: os.path.exists raises an IOError
mocked_exists.side_effect = IOError()
check_directory_exists(directory_to_check)
# THEN: We shouldn't get an exception though the mocked exists has been called
mocked_exists.assert_called_with(directory_to_check)
# WHEN: Some other exception is raised
mocked_exists.side_effect = ValueError()
# THEN: check_directory_exists raises an exception
mocked_exists.assert_called_with(directory_to_check)
self.assertRaises(ValueError, check_directory_exists, directory_to_check)

View File

@ -0,0 +1 @@
__author__ = 'raoul'

View File

@ -0,0 +1,98 @@
"""
Functional tests to test the AppLocation class and related methods.
"""
from unittest import TestCase
from mock import patch
from openlp.core.utils import AppLocation
class TestAppLocation(TestCase):
"""
A test suite to test out various methods around the AppLocation class.
"""
def get_data_path_test(self):
"""
Test the AppLocation.get_data_path() method
"""
with patch(u'openlp.core.utils.Settings') as mocked_class, \
patch(u'openlp.core.utils.AppLocation.get_directory') as mocked_get_directory, \
patch(u'openlp.core.utils.check_directory_exists') as mocked_check_directory_exists, \
patch(u'openlp.core.utils.os') as mocked_os:
# GIVEN: A mocked out Settings class and a mocked out AppLocation.get_directory()
mocked_settings = mocked_class.return_value
mocked_settings.contains.return_value = False
mocked_get_directory.return_value = u'test/dir'
mocked_check_directory_exists.return_value = True
mocked_os.path.normpath.return_value = u'test/dir'
# WHEN: we call AppLocation.get_data_path()
data_path = AppLocation.get_data_path()
# THEN: check that all the correct methods were called, and the result is correct
mocked_settings.contains.assert_called_with(u'advanced/data path')
mocked_get_directory.assert_called_with(AppLocation.DataDir)
mocked_check_directory_exists.assert_called_with(u'test/dir')
assert data_path == u'test/dir', u'Result should be "test/dir"'
def get_data_path_with_custom_location_test(self):
"""
Test the AppLocation.get_data_path() method when a custom location is set in the settings
"""
with patch(u'openlp.core.utils.Settings') as mocked_class,\
patch(u'openlp.core.utils.os') as mocked_os:
# GIVEN: A mocked out Settings class which returns a custom data location
mocked_settings = mocked_class.return_value
mocked_settings.contains.return_value = True
mocked_settings.value.return_value.toString.return_value = u'custom/dir'
mocked_os.path.normpath.return_value = u'custom/dir'
# WHEN: we call AppLocation.get_data_path()
data_path = AppLocation.get_data_path()
# THEN: the mocked Settings methods were called and the value returned was our set up value
mocked_settings.contains.assert_called_with(u'advanced/data path')
mocked_settings.value.assert_called_with(u'advanced/data path')
mocked_settings.value.return_value.toString.assert_called_with()
assert data_path == u'custom/dir', u'Result should be "custom/dir"'
def get_section_data_path_test(self):
"""
Test the AppLocation.get_section_data_path() method
"""
with patch(u'openlp.core.utils.AppLocation.get_data_path') as mocked_get_data_path, \
patch(u'openlp.core.utils.check_directory_exists') as mocked_check_directory_exists:
# GIVEN: A mocked out AppLocation.get_data_path()
mocked_get_data_path.return_value = u'test/dir'
mocked_check_directory_exists.return_value = True
# WHEN: we call AppLocation.get_data_path()
data_path = AppLocation.get_section_data_path(u'section')
# THEN: check that all the correct methods were called, and the result is correct
mocked_check_directory_exists.assert_called_with(u'test/dir/section')
assert data_path == u'test/dir/section', u'Result should be "test/dir/section"'
def get_directory_for_app_dir_test(self):
"""
Test the AppLocation.get_directory() method for AppLocation.AppDir
"""
with patch(u'openlp.core.utils._get_frozen_path') as mocked_get_frozen_path:
mocked_get_frozen_path.return_value = u'app/dir'
# WHEN: We call AppLocation.get_directory
directory = AppLocation.get_directory(AppLocation.AppDir)
# THEN:
assert directory == u'app/dir', u'Directory should be "app/dir"'
def get_directory_for_plugins_dir_test(self):
"""
Test the AppLocation.get_directory() method for AppLocation.PluginsDir
"""
with patch(u'openlp.core.utils._get_frozen_path') as mocked_get_frozen_path, \
patch(u'openlp.core.utils.os.path.abspath') as mocked_abspath, \
patch(u'openlp.core.utils.os.path.split') as mocked_split, \
patch(u'openlp.core.utils.sys') as mocked_sys:
mocked_abspath.return_value = u'plugins/dir'
mocked_split.return_value = [u'openlp']
mocked_get_frozen_path.return_value = u'plugins/dir'
mocked_sys.frozen = 1
mocked_sys.argv = ['openlp']
# WHEN: We call AppLocation.get_directory
directory = AppLocation.get_directory(AppLocation.PluginsDir)
# THEN:
assert directory == u'plugins/dir', u'Directory should be "plugins/dir"'

View File

@ -0,0 +1,58 @@
"""
Functional tests to test the AppLocation class and related methods.
"""
from unittest import TestCase
from mock import patch
from openlp.core.utils import get_filesystem_encoding, _get_frozen_path
class TestUtils(TestCase):
"""
A test suite to test out various methods around the AppLocation class.
"""
def get_filesystem_encoding_test(self):
"""
Test the get_filesystem_encoding() function
"""
with patch(u'openlp.core.utils.sys.getfilesystemencoding') as mocked_getfilesystemencoding, \
patch(u'openlp.core.utils.sys.getdefaultencoding') as mocked_getdefaultencoding:
# GIVEN: sys.getfilesystemencoding returns "cp1252"
mocked_getfilesystemencoding.return_value = u'cp1252'
# WHEN: get_filesystem_encoding() is called
result = get_filesystem_encoding()
# THEN: getdefaultencoding should have been called
mocked_getfilesystemencoding.assert_called_with()
assert not mocked_getdefaultencoding.called
assert result == u'cp1252', u'The result should be "cp1252"'
# GIVEN: sys.getfilesystemencoding returns None and sys.getdefaultencoding returns "utf-8"
mocked_getfilesystemencoding.return_value = None
mocked_getdefaultencoding.return_value = u'utf-8'
# WHEN: get_filesystem_encoding() is called
result = get_filesystem_encoding()
# THEN: getdefaultencoding should have been called
mocked_getfilesystemencoding.assert_called_with()
mocked_getdefaultencoding.assert_called_with()
assert result == u'utf-8', u'The result should be "utf-8"'
def get_frozen_path_test(self):
"""
Test the _get_frozen_path() function
"""
with patch(u'openlp.core.utils.sys') as mocked_sys:
# GIVEN: The sys module "without" a "frozen" attribute
mocked_sys.frozen = None
# WHEN: We call _get_frozen_path() with two parameters
# THEN: The non-frozen parameter is returned
assert _get_frozen_path(u'frozen', u'not frozen') == u'not frozen', u'Should return "not frozen"'
# GIVEN: The sys module *with* a "frozen" attribute
mocked_sys.frozen = 1
# WHEN: We call _get_frozen_path() with two parameters
# THEN: The frozen parameter is returned
assert _get_frozen_path(u'frozen', u'not frozen') == u'frozen', u'Should return "frozen"'