openlp-core team mailing list archive
-
openlp-core team
-
Mailing list archive
-
Message #12929
[Merge] lp:~crichter/openlp/media_rewrite into lp:openlp
rimach has proposed merging lp:~crichter/openlp/media_rewrite into lp:openlp.
Requested reviews:
Raoul Snyman (raoul-snyman)
Andreas Preikschat (googol)
Tim Bentley (trb143)
Jonathan Corwin (j-corwin)
Related bugs:
Bug #813995 in OpenLP: "opengl rendering"
https://bugs.launchpad.net/openlp/+bug/813995
For more details, see:
https://code.launchpad.net/~crichter/openlp/media_rewrite/+merge/84155
Rewrite of the multimedia stuff.
- add separated multimedia code in own subdirectory in openlp/ui
--
https://code.launchpad.net/~crichter/openlp/media_rewrite/+merge/84155
Your team OpenLP Core is subscribed to branch lp:openlp.
=== modified file 'openlp/core/lib/htmlbuilder.py'
--- openlp/core/lib/htmlbuilder.py 2011-11-24 21:25:38 +0000
+++ openlp/core/lib/htmlbuilder.py 2011-12-01 18:30:31 +0000
@@ -53,8 +53,8 @@
position: absolute;
left: 0px;
top: 0px;
- width: %spx;
- height: %spx;
+ width: 100%%;
+ height: 100%%;
}
#black {
z-index: 8;
@@ -67,12 +67,6 @@
#image {
z-index: 2;
}
-#video1 {
- z-index: 3;
-}
-#video2 {
- z-index: 3;
-}
%s
#footer {
position: absolute;
@@ -90,90 +84,9 @@
</style>
<script>
var timer = null;
- var video_timer = null;
- var current_video = '1';
var transition = %s;
-
- function show_video(state, path, volume, loop){
- // Note, the preferred method for looping would be to use the
- // video tag loop attribute.
- // But QtWebKit doesn't support this. Neither does it support the
- // onended event, hence the setInterval()
- // In addition, setting the currentTime attribute to zero to restart
- // the video raises an INDEX_SIZE_ERROR: DOM Exception 1
- // To complicate it further, sometimes vid.currentTime stops
- // slightly short of vid.duration and vid.ended is intermittent!
- //
- // Note, currently the background may go black between loops. Not
- // desirable. Need to investigate using two <video>'s, and hiding/
- // preloading one, and toggle between the two when looping.
-
- if(current_video=='1'){
- var vid = document.getElementById('video1');
- var vid2 = document.getElementById('video2');
- } else {
- var vid = document.getElementById('video2');
- var vid2 = document.getElementById('video1');
- }
- if(volume != null){
- vid.volume = volume;
- vid2.volume = volume;
- }
- switch(state){
- case 'init':
- vid.src = 'file:///' + path;
- vid2.src = 'file:///' + path;
- if(loop == null) loop = false;
- vid.looping = loop;
- vid2.looping = loop;
- vid.load();
- break;
- case 'load':
- vid2.style.visibility = 'hidden';
- vid2.load();
- break;
- case 'play':
- vid.play();
- vid.style.visibility = 'visible';
- if(vid.looping){
- video_timer = setInterval(
- function() {
- show_video('poll');
- }, 200);
- }
- break;
- case 'pause':
- if(video_timer!=null){
- clearInterval(video_timer);
- video_timer = null;
- }
- vid.pause();
- break;
- case 'stop':
- show_video('pause');
- vid.style.visibility = 'hidden';
- break;
- case 'poll':
- if(vid.ended||vid.currentTime+0.2>vid.duration)
- show_video('swap');
- break;
- case 'swap':
- show_video('pause');
- if(current_video=='1')
- current_video = '2';
- else
- current_video = '1';
- show_video('play');
- show_video('load');
- break;
- case 'close':
- show_video('stop');
- vid.src = '';
- vid2.src = '';
- break;
- }
- }
%s
+
function show_image(src){
var img = document.getElementById('image');
img.src = src;
@@ -186,18 +99,14 @@
function show_blank(state){
var black = 'none';
var lyrics = '';
- var pause = false;
switch(state){
case 'theme':
lyrics = 'hidden';
- pause = true;
break;
case 'black':
black = 'block';
- pause = true;
break;
case 'desktop':
- pause = true;
break;
}
document.getElementById('black').style.display = black;
@@ -210,13 +119,6 @@
if(shadow!=null)
shadow.style.visibility = lyrics;
document.getElementById('footer').style.visibility = lyrics;
- var vid = document.getElementById('video');
- if(vid.src != ''){
- if(pause)
- vid.pause();
- else
- vid.play();
- }
}
function show_footer(footertext){
@@ -277,10 +179,6 @@
<body>
<img id="bgimage" class="size" %s />
<img id="image" class="size" %s />
-<video id="video1" class="size" style="visibility:hidden" autobuffer preload>
-</video>
-<video id="video2" class="size" style="visibility:hidden" autobuffer preload>
-</video>
%s
%s
<div id="footer" class="footer"></div>
@@ -336,7 +234,6 @@
js_additions += plugin.getDisplayJavaScript()
html_additions += plugin.getDisplayHtml()
html = HTMLSRC % (build_background_css(item, width, height),
- width, height,
css_additions,
build_footer_css(item, height),
build_lyrics_css(item, webkitvers),
@@ -609,4 +506,3 @@
item.footer.width(), theme.font_footer_name,
theme.font_footer_size, theme.font_footer_color)
return lyrics_html
-
=== added file 'openlp/core/lib/mediaplayer.py'
--- openlp/core/lib/mediaplayer.py 1970-01-01 00:00:00 +0000
+++ openlp/core/lib/mediaplayer.py 2011-12-01 18:30:31 +0000
@@ -0,0 +1,137 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2011 Raoul Snyman #
+# Portions copyright (c) 2008-2011 Tim Bentley, Gerald Britton, Jonathan #
+# Corwin, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, #
+# Armin Köhler, Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias #
+# Põldaru, Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
+# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it #
+# under the terms of the GNU General Public License as published by the Free #
+# Software Foundation; version 2 of the License. #
+# #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
+# more details. #
+# #
+# You should have received a copy of the GNU General Public License along #
+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
+###############################################################################
+
+from 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.
+ """
+
+ def __init__(self, parent, name=u'media_player'):
+ self.parent = parent
+ self.name = name
+ self.available = self.check_available()
+ self.isActive = False
+ self.canBackground = False
+ self.canFolder = False
+ self.state = MediaState.Off
+ self.hasOwnWidget = False
+ self.audio_extensions_list = []
+ self.video_extensions_list = []
+
+ def check_available(self):
+ """
+ Player is available on this machine
+ """
+ return False
+
+ def setup(self, display):
+ """
+ Create the related widgets for the current display
+ """
+ pass
+
+ def load(self, display):
+ """
+ Load a new media file and check if it is valid
+ """
+ return True
+
+ def resize(self, display):
+ """
+ If the main display size or position is changed, the media widgets
+ should also resized
+ """
+ pass
+
+ def play(self, display):
+ """
+ Starts playing of current Media File
+ """
+ pass
+
+ def pause(self, display):
+ """
+ Pause of current Media File
+ """
+ pass
+
+ def stop(self, display):
+ """
+ Stop playing of current Media File
+ """
+ pass
+
+ def volume(self, display, vol):
+ """
+ Change volume of current Media File
+ """
+ pass
+
+ def seek(self, display, seekVal):
+ """
+ Change playing position of current Media File
+ """
+ pass
+
+ def reset(self, display):
+ """
+ Remove the current loaded video
+ """
+ pass
+
+ def set_visible(self, display, status):
+ """
+ Show/Hide the media widgets
+ """
+ pass
+
+ def update_ui(self, display):
+ """
+ Do some ui related stuff (e.g. update the seek slider)
+ """
+ pass
+
+ def get_media_display_css(self):
+ """
+ Add css style sheets to htmlbuilder
+ """
+ return u''
+
+ def get_media_display_javascript(self):
+ """
+ Add javascript functions to htmlbuilder
+ """
+ return u''
+
+ def get_media_display_html(self):
+ """
+ Add html code to htmlbuilder
+ """
+ return u''
=== modified file 'openlp/core/lib/plugin.py'
--- openlp/core/lib/plugin.py 2011-10-17 18:01:07 +0000
+++ openlp/core/lib/plugin.py 2011-12-01 18:30:31 +0000
@@ -168,6 +168,7 @@
self.mediadock = plugin_helpers[u'toolbox']
self.pluginManager = plugin_helpers[u'pluginmanager']
self.formparent = plugin_helpers[u'formparent']
+ self.mediaController = plugin_helpers[u'mediacontroller']
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'%s_add_service_item' % self.name),
self.processAddServiceEvent)
@@ -395,4 +396,3 @@
Add html code to htmlbuilder.
"""
return u''
-
=== modified file 'openlp/core/lib/renderer.py'
--- openlp/core/lib/renderer.py 2011-11-02 20:09:06 +0000
+++ openlp/core/lib/renderer.py 2011-12-01 18:30:31 +0000
@@ -76,7 +76,7 @@
self.theme_data = None
self.bg_frame = None
self.force_page = False
- self.display = MainDisplay(None, self.imageManager, False)
+ self.display = MainDisplay(None, self.imageManager, False, self)
self.display.setup()
def update_display(self):
@@ -87,7 +87,7 @@
self._calculate_default()
if self.display:
self.display.close()
- self.display = MainDisplay(None, self.imageManager, False)
+ self.display = MainDisplay(None, self.imageManager, False, self)
self.display.setup()
self.bg_frame = None
self.theme_data = None
=== modified file 'openlp/core/ui/__init__.py'
--- openlp/core/ui/__init__.py 2011-10-29 19:13:11 +0000
+++ openlp/core/ui/__init__.py 2011-12-01 18:30:31 +0000
@@ -77,10 +77,10 @@
from filerenameform import FileRenameForm
from starttimeform import StartTimeForm
from screen import ScreenList
-from maindisplay import MainDisplay
+from maindisplay import MainDisplay, Display
from servicenoteform import ServiceNoteForm
from serviceitemeditform import ServiceItemEditForm
-from slidecontroller import SlideController
+from slidecontroller import SlideController, Controller
from splashscreen import SplashScreen
from generaltab import GeneralTab
from themestab import ThemesTab
=== modified file 'openlp/core/ui/maindisplay.py'
--- openlp/core/ui/maindisplay.py 2011-11-01 06:09:21 +0000
+++ openlp/core/ui/maindisplay.py 2011-12-01 18:30:31 +0000
@@ -31,7 +31,7 @@
import logging
import os
-from PyQt4 import QtCore, QtGui, QtWebKit
+from PyQt4 import QtCore, QtGui, QtWebKit, QtOpenGL
from PyQt4.phonon import Phonon
from openlp.core.lib import Receiver, build_html, ServiceItem, image_to_byte, \
@@ -44,11 +44,13 @@
#http://www.steveheffernan.com/html5-video-player/demo-video-player.html
#http://html5demos.com/two-videos
-class MainDisplay(QtGui.QGraphicsView):
- """
- This is the display screen.
- """
- def __init__(self, parent, imageManager, live):
+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.
+ """
+ def __init__(self, parent, live, controller):
if live:
QtGui.QGraphicsView.__init__(self)
# Overwrite the parent() method.
@@ -56,12 +58,60 @@
else:
QtGui.QGraphicsView.__init__(self, parent)
self.isLive = live
+ self.controller = controller
+ self.screen = {}
+ self.plugins = PluginManager.get_instance().plugins
+ self.setViewport(QtOpenGL.QGLWidget())
+
+ def setup(self):
+ """
+ Set up and build the screen base
+ """
+ log.debug(u'Start Display base setup (live = %s)' % self.isLive)
+ self.setGeometry(self.screen[u'size'])
+ log.debug(u'Setup webView')
+ self.webView = QtWebKit.QWebView(self)
+ self.webView.setGeometry(0, 0,
+ self.screen[u'size'].width(), self.screen[u'size'].height())
+ self.webView.settings().setAttribute(
+ QtWebKit.QWebSettings.PluginsEnabled, True)
+ self.page = self.webView.page()
+ self.frame = self.page.mainFrame()
+ if self.isLive and log.getEffectiveLevel() == logging.DEBUG:
+ self.webView.settings().setAttribute(
+ QtWebKit.QWebSettings.DeveloperExtrasEnabled, True)
+ QtCore.QObject.connect(self.webView,
+ QtCore.SIGNAL(u'loadFinished(bool)'), self.isWebLoaded)
+ self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
+ self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
+ self.frame.setScrollBarPolicy(QtCore.Qt.Vertical,
+ QtCore.Qt.ScrollBarAlwaysOff)
+ self.frame.setScrollBarPolicy(QtCore.Qt.Horizontal,
+ QtCore.Qt.ScrollBarAlwaysOff)
+
+ def resizeEvent(self, ev):
+ self.webView.setGeometry(0, 0,
+ self.width(), self.height())
+
+ def isWebLoaded(self):
+ """
+ Called by webView event to show display is fully loaded
+ """
+ log.debug(u'Webloaded')
+ self.webLoaded = True
+
+
+class MainDisplay(Display):
+ """
+ This is the display screen as a specialized class from the Display class
+ """
+ def __init__(self, parent, imageManager, live, controller):
+ Display.__init__(self, parent, live, controller)
self.imageManager = imageManager
self.screens = ScreenList.get_instance()
self.plugins = PluginManager.get_instance().plugins
self.rebuildCSS = False
self.hideMode = None
- self.videoHide = False
self.override = {}
self.retranslateUi()
self.mediaObject = None
@@ -81,9 +131,6 @@
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'live_display_show'), self.showDisplay)
QtCore.QObject.connect(Receiver.get_receiver(),
- QtCore.SIGNAL(u'openlp_phonon_creation'),
- self.createMediaObject)
- QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'update_display_css'), self.cssChanged)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'config_updated'), self.configChanged)
@@ -115,36 +162,9 @@
Set up and build the output screen
"""
log.debug(u'Start MainDisplay setup (live = %s)' % self.isLive)
- self.usePhonon = QtCore.QSettings().value(
- u'media/use phonon', QtCore.QVariant(True)).toBool()
- self.phononActive = False
self.screen = self.screens.current
self.setVisible(False)
- self.setGeometry(self.screen[u'size'])
- self.videoWidget = Phonon.VideoWidget(self)
- self.videoWidget.setVisible(False)
- self.videoWidget.setGeometry(QtCore.QRect(0, 0,
- self.screen[u'size'].width(), self.screen[u'size'].height()))
- if self.isLive:
- if not self.firstTime:
- self.createMediaObject()
- log.debug(u'Setup webView')
- self.webView = QtWebKit.QWebView(self)
- self.webView.setGeometry(0, 0,
- self.screen[u'size'].width(), self.screen[u'size'].height())
- self.page = self.webView.page()
- self.frame = self.page.mainFrame()
- if self.isLive and log.getEffectiveLevel() == logging.DEBUG:
- self.webView.settings().setAttribute(
- QtWebKit.QWebSettings.DeveloperExtrasEnabled, True)
- QtCore.QObject.connect(self.webView,
- QtCore.SIGNAL(u'loadFinished(bool)'), self.isWebLoaded)
- self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
- self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
- self.frame.setScrollBarPolicy(QtCore.Qt.Vertical,
- QtCore.Qt.ScrollBarAlwaysOff)
- self.frame.setScrollBarPolicy(QtCore.Qt.Horizontal,
- QtCore.Qt.ScrollBarAlwaysOff)
+ Display.setup(self)
if self.isLive:
# Build the initial frame.
image_file = QtCore.QSettings().value(u'advanced/default image',
@@ -180,24 +200,6 @@
self.primary = True
log.debug(u'Finished MainDisplay setup')
- def createMediaObject(self):
- self.firstTime = False
- log.debug(u'Creating Phonon objects - Start for %s', self.isLive)
- self.mediaObject = Phonon.MediaObject(self)
- self.audio = Phonon.AudioOutput(Phonon.VideoCategory, self.mediaObject)
- Phonon.createPath(self.mediaObject, self.videoWidget)
- Phonon.createPath(self.mediaObject, self.audio)
- QtCore.QObject.connect(self.mediaObject,
- QtCore.SIGNAL(u'stateChanged(Phonon::State, Phonon::State)'),
- self.videoState)
- QtCore.QObject.connect(self.mediaObject,
- QtCore.SIGNAL(u'finished()'),
- self.videoFinished)
- QtCore.QObject.connect(self.mediaObject,
- QtCore.SIGNAL(u'tick(qint64)'),
- self.videoTick)
- log.debug(u'Creating Phonon objects - Finished for %s', self.isLive)
-
def text(self, slide):
"""
Add the slide text from slideController
@@ -221,8 +223,8 @@
The text to be displayed.
"""
log.debug(u'alert to display')
- if self.height() != self.screen[u'size'].height() or not \
- self.isVisible() or self.videoWidget.isVisible():
+ if self.height() != self.screen[u'size'].height() or \
+ not self.isVisible():
shrink = True
js = u'show_alert("%s", "%s")' % (
text.replace(u'\\', u'\\\\').replace(u'\"', u'\\\"'),
@@ -233,22 +235,18 @@
text.replace(u'\\', u'\\\\').replace(u'\"', u'\\\"'))
height = self.frame.evaluateJavaScript(js)
if shrink:
- if self.phononActive:
- shrinkItem = self.webView
- else:
- shrinkItem = self
if text:
alert_height = int(height.toString())
- shrinkItem.resize(self.width(), alert_height)
- shrinkItem.setVisible(True)
+ self.resize(self.width(), alert_height)
+ self.setVisible(True)
if location == AlertLocation.Middle:
- shrinkItem.move(self.screen[u'size'].left(),
+ self.move(self.screen[u'size'].left(),
(self.screen[u'size'].height() - alert_height) / 2)
elif location == AlertLocation.Bottom:
- shrinkItem.move(self.screen[u'size'].left(),
+ self.move(self.screen[u'size'].left(),
self.screen[u'size'].height() - alert_height)
else:
- shrinkItem.setVisible(False)
+ self.setVisible(False)
self.setGeometry(self.screen[u'size'])
def directImage(self, name, path, background):
@@ -276,7 +274,7 @@
"""
log.debug(u'image to display')
image = self.imageManager.get_image_bytes(name)
- self.resetVideo()
+ self.controller.mediaController.video_reset(self.controller)
self.displayImage(image)
def displayImage(self, image):
@@ -303,135 +301,6 @@
# clear the cache
self.override = {}
- def resetVideo(self):
- """
- Used after Video plugin has changed the background
- """
- log.debug(u'resetVideo')
- if self.phononActive:
- self.mediaObject.stop()
- self.mediaObject.clearQueue()
- self.webView.setVisible(True)
- self.videoWidget.setVisible(False)
- self.phononActive = False
- else:
- self.frame.evaluateJavaScript(u'show_video("close");')
- self.override = {}
-
- def videoPlay(self):
- """
- Responds to the request to play a loaded video
- """
- log.debug(u'videoPlay')
- if self.phononActive:
- self.mediaObject.play()
- else:
- self.frame.evaluateJavaScript(u'show_video("play");')
- # show screen
- if self.isLive:
- self.setVisible(True)
-
- def videoPause(self):
- """
- Responds to the request to pause a loaded video
- """
- log.debug(u'videoPause')
- if self.phononActive:
- self.mediaObject.pause()
- else:
- self.frame.evaluateJavaScript(u'show_video("pause");')
-
- def videoStop(self):
- """
- Responds to the request to stop a loaded video
- """
- log.debug(u'videoStop')
- if self.phononActive:
- self.mediaObject.stop()
- else:
- self.frame.evaluateJavaScript(u'show_video("stop");')
-
- def videoVolume(self, volume):
- """
- Changes the volume of a running video
- """
- log.debug(u'videoVolume %d' % volume)
- vol = float(volume) / float(10)
- if self.phononActive:
- self.audio.setVolume(vol)
- else:
- self.frame.evaluateJavaScript(u'show_video(null, null, %s);' %
- str(vol))
-
- def video(self, videoPath, volume, isBackground=False):
- """
- Loads and starts a video to run with the option of sound
- """
- # We request a background video but have no service Item
- if isBackground and not hasattr(self, u'serviceItem'):
- return False
- if not self.mediaObject:
- self.createMediaObject()
- log.debug(u'video')
- self.webLoaded = True
- self.setGeometry(self.screen[u'size'])
- # We are running a background theme
- self.override[u'theme'] = u''
- self.override[u'video'] = True
- vol = float(volume) / float(10)
- if isBackground or not self.usePhonon:
- js = u'show_video("init", "%s", %s, true); show_video("play");' % \
- (videoPath.replace(u'\\', u'\\\\'), str(vol))
- self.frame.evaluateJavaScript(js)
- else:
- self.phononActive = True
- self.mediaObject.stop()
- self.mediaObject.clearQueue()
- self.mediaObject.setCurrentSource(Phonon.MediaSource(videoPath))
- # Need the timer to trigger set the trigger to 200ms
- # Value taken from web documentation.
- if self.serviceItem.end_time != 0:
- self.mediaObject.setTickInterval(200)
- self.mediaObject.play()
- self.webView.setVisible(False)
- self.videoWidget.setVisible(True)
- self.audio.setVolume(vol)
- return True
-
- def videoState(self, newState, oldState):
- """
- Start the video at a predetermined point.
- """
- if newState == Phonon.PlayingState \
- and oldState != Phonon.PausedState \
- and self.serviceItem.start_time > 0:
- # set start time in milliseconds
- self.mediaObject.seek(self.serviceItem.start_time * 1000)
-
- def videoFinished(self):
- """
- Blank the Video when it has finished so the final frame is not left
- hanging
- """
- self.videoStop()
- self.hideDisplay(HideMode.Blank)
- self.phononActive = False
- self.videoHide = True
-
- def videoTick(self, tick):
- """
- Triggered on video tick every 200 milli seconds
- """
- if tick > self.serviceItem.end_time * 1000:
- self.videoFinished()
-
- def isWebLoaded(self):
- """
- Called by webView event to show display is fully loaded
- """
- log.debug(u'Webloaded')
- self.webLoaded = True
-
def preview(self):
"""
Generates a preview of the image displayed.
@@ -511,16 +380,12 @@
if serviceItem.foot_text:
self.footer(serviceItem.foot_text)
# if was hidden keep it hidden
- if self.hideMode and self.isLive:
+ if self.hideMode and self.isLive and not serviceItem.is_media():
if QtCore.QSettings().value(u'general/auto unblank',
QtCore.QVariant(False)).toBool():
Receiver.send_message(u'slidecontroller_live_unblank')
else:
self.hideDisplay(self.hideMode)
- # display hidden for video end we have a new item so must be shown
- if self.videoHide and self.isLive:
- self.videoHide = False
- self.showDisplay()
self.__hideMouse()
def footer(self, text):
@@ -538,8 +403,6 @@
Store the images so they can be replaced when required
"""
log.debug(u'hideDisplay mode = %d', mode)
- if self.phononActive:
- self.videoPause()
if mode == HideMode.Screen:
self.frame.evaluateJavaScript(u'show_blank("desktop");')
self.setVisible(False)
@@ -550,7 +413,6 @@
if mode != HideMode.Screen:
if self.isHidden():
self.setVisible(True)
- if self.phononActive:
self.webView.setVisible(True)
self.hideMode = mode
@@ -564,9 +426,6 @@
self.frame.evaluateJavaScript('show_blank("show");')
if self.isHidden():
self.setVisible(True)
- if self.phononActive:
- self.webView.setVisible(False)
- self.videoPlay()
self.hideMode = None
# Trigger actions when display is active again
if self.isLive:
=== modified file 'openlp/core/ui/mainwindow.py'
--- openlp/core/ui/mainwindow.py 2011-10-22 11:09:01 +0000
+++ openlp/core/ui/mainwindow.py 2011-12-01 18:30:31 +0000
@@ -42,6 +42,7 @@
from openlp.core.ui import AboutForm, SettingsForm, ServiceManager, \
ThemeManager, SlideController, PluginForm, MediaDockManager, \
ShortcutListForm, FormattingTagForm
+from openlp.core.ui.media import MediaController
from openlp.core.utils import AppLocation, add_actions, LanguageManager, \
get_application_version, delete_file
from openlp.core.utils.actions import ActionList, CategoryOrder
@@ -557,6 +558,7 @@
self.pluginManager = PluginManager(pluginpath)
self.pluginHelpers = {}
self.imageManager = ImageManager()
+ self.mediaController = MediaController(self)
# Set up the interface
self.setupUi(self)
# Load settings after setupUi so default UI sizes are overwritten
@@ -644,6 +646,7 @@
self.pluginHelpers[u'toolbox'] = self.mediaDockManager
self.pluginHelpers[u'pluginmanager'] = self.pluginManager
self.pluginHelpers[u'formparent'] = self
+ self.pluginHelpers[u'mediacontroller'] = self.mediaController
self.pluginManager.find_plugins(pluginpath, self.pluginHelpers)
# hook methods have to happen after find_plugins. Find plugins needs
# the controllers hence the hooks have moved from setupUI() to here
=== added directory 'openlp/core/ui/media'
=== added file 'openlp/core/ui/media/__init__.py'
--- openlp/core/ui/media/__init__.py 1970-01-01 00:00:00 +0000
+++ openlp/core/ui/media/__init__.py 2011-12-01 18:30:31 +0000
@@ -0,0 +1,65 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2011 Raoul Snyman #
+# Portions copyright (c) 2008-2011 Tim Bentley, Gerald Britton, Jonathan #
+# Corwin, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, #
+# Armin Köhler, Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias #
+# Põldaru, Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
+# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it #
+# under the terms of the GNU General Public License as published by the Free #
+# Software Foundation; version 2 of the License. #
+# #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
+# more details. #
+# #
+# You should have received a copy of the GNU General Public License along #
+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
+###############################################################################
+
+class MediaState(object):
+ """
+ An enumeration for possible States of the Media Player (copied partially
+ from Phonon::State)
+ """
+ Loading = 0
+ Stopped = 1
+ Playing = 2
+ Paused = 4
+ Off = 6
+
+
+class MediaType(object):
+ """
+ An enumeration of possibible Media Types
+ """
+ Unused = 0
+ Audio = 1
+ Video = 2
+ CD = 3
+ DVD = 4
+ Folder = 5
+
+
+class MediaInfo(object):
+ """
+ This class hold the media related infos
+ """
+ file_info = None
+ volume = 100
+ is_flash = False
+ is_background = False
+ length = 0
+ start_time = 0
+ end_time = 0
+ media_type = MediaType()
+
+from mediacontroller import MediaController
=== added file 'openlp/core/ui/media/mediacontroller.py'
--- openlp/core/ui/media/mediacontroller.py 1970-01-01 00:00:00 +0000
+++ openlp/core/ui/media/mediacontroller.py 2011-12-01 18:30:31 +0000
@@ -0,0 +1,576 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2011 Raoul Snyman #
+# Portions copyright (c) 2008-2011 Tim Bentley, Gerald Britton, Jonathan #
+# Corwin, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, #
+# Armin Köhler, Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias #
+# Põldaru, Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
+# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it #
+# under the terms of the GNU General Public License as published by the Free #
+# Software Foundation; version 2 of the License. #
+# #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
+# more details. #
+# #
+# You should have received a copy of the GNU General Public License along #
+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
+###############################################################################
+
+import logging
+
+import sys, os,time
+from PyQt4 import QtCore, QtGui, QtWebKit
+
+from openlp.core.lib import OpenLPToolbar, Receiver, translate
+from openlp.core.lib.mediaplayer import MediaPlayer
+from openlp.core.lib.ui import UiStrings, critical_error_message_box
+from openlp.core.ui.media import MediaState, MediaInfo, MediaType
+from openlp.core.utils import AppLocation
+
+log = logging.getLogger(__name__)
+
+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 planed Vlc.
+ """
+
+ def __init__(self, parent):
+ self.parent = parent
+ self.mediaPlayers = {}
+ self.controller = []
+ self.overridenPlayer = ''
+ self.curDisplayMediaPlayer = {}
+ # 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'media_playback_play'), self.video_play)
+ QtCore.QObject.connect(Receiver.get_receiver(),
+ QtCore.SIGNAL(u'media_playback_pause'), self.video_pause)
+ QtCore.QObject.connect(Receiver.get_receiver(),
+ QtCore.SIGNAL(u'media_playback_stop'), self.video_stop)
+ QtCore.QObject.connect(Receiver.get_receiver(),
+ QtCore.SIGNAL(u'seek_slider'), self.video_seek)
+ QtCore.QObject.connect(Receiver.get_receiver(),
+ QtCore.SIGNAL(u'volume_slider'), 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(Receiver.get_receiver(),
+ QtCore.SIGNAL(u'media_override_player'), self.override_player)
+ # 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)
+
+ def set_active_players(self):
+ playerSettings = str(QtCore.QSettings().value(u'media/players',
+ QtCore.QVariant(u'webkit')).toString())
+ if len(playerSettings) == 0:
+ playerSettings = u'webkit'
+ savedPlayers = playerSettings.split(u',')
+ for player in self.mediaPlayers.keys():
+ if player in savedPlayers:
+ self.mediaPlayers[player].isActive = True
+ else:
+ self.mediaPlayers[player].isActive = False
+
+ def register_controllers(self, controller):
+ """
+ Register each media Player controller (Webkit, Phonon, etc) and store
+ for later use
+ """
+ if controller.check_available():
+ self.mediaPlayers[controller.name] = controller
+
+ def check_available_media_players(self):
+ """
+ Check to see if we have any media Player's available. If Not do not
+ install the plugin.
+ """
+ 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') and \
+ not filename == 'media_player.py':
+ path = os.path.join(controller_dir, filename)
+ if os.path.isfile(path):
+ modulename = u'openlp.core.ui.media.' + \
+ os.path.splitext(filename)[0]
+ log.debug(u'Importing controller %s', modulename)
+ try:
+ __import__(modulename, globals(), locals(), [])
+ except ImportError:
+ 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)
+ if self.mediaPlayers:
+ playerSettings = str(QtCore.QSettings().value(u'media/players',
+ QtCore.QVariant(u'webkit')).toString())
+ savedPlayers = playerSettings.split(u',')
+ invalidMediaPlayers = [mediaPlayer for mediaPlayer in savedPlayers \
+ if not mediaPlayer in self.mediaPlayers]
+ if len(invalidMediaPlayers)>0:
+ [savedPlayers.remove(invalidPlayer) for invalidPlayer in invalidMediaPlayers]
+ newPlayerSetting = u','.join(savedPlayers)
+ QtCore.QSettings().setValue(u'media/players',
+ QtCore.QVariant(newPlayerSetting))
+ self.set_active_players()
+ return True
+ else:
+ return False
+
+ def video_state(self):
+ """
+ Check if there is a running media Player and do updating stuff (e.g.
+ update the UI)
+ """
+ if len(self.curDisplayMediaPlayer.keys()) == 0:
+ self.timer.stop()
+ else:
+ for display in self.curDisplayMediaPlayer.keys():
+ self.curDisplayMediaPlayer[display].resize(display)
+ self.curDisplayMediaPlayer[display].update_ui(display)
+ if self.curDisplayMediaPlayer[display] \
+ .state == MediaState.Playing:
+ return
+ self.timer.stop()
+
+ def get_media_display_css(self):
+ """
+ Add css style sheets to htmlbuilder
+ """
+ css = u''
+ for player in self.mediaPlayers.values():
+ if player.isActive:
+ css += player.get_media_display_css()
+ return css
+
+ def get_media_display_javascript(self):
+ """
+ Add javascript functions to htmlbuilder
+ """
+ js = u''
+ for player in self.mediaPlayers.values():
+ if player.isActive:
+ js += player.get_media_display_javascript()
+ return js
+
+ def get_media_display_html(self):
+ """
+ Add html code to htmlbuilder
+ """
+ html = u''
+ for player in self.mediaPlayers.values():
+ if player.isActive:
+ 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):
+ """
+ Add generic media control items (valid for all types of medias)
+ """
+ controller.media_info = MediaInfo()
+ # Build a Media ToolBar
+ controller.mediabar = OpenLPToolbar(controller)
+ controller.mediabar.addToolbarButton(
+ u'media_playback_play', u':/slides/media_playback_start.png',
+ translate('OpenLP.SlideController', 'Start playing media'),
+ controller.sendToPlugins)
+ controller.mediabar.addToolbarButton(
+ u'media_playback_pause', u':/slides/media_playback_pause.png',
+ translate('OpenLP.SlideController', 'Pause playing media'),
+ controller.sendToPlugins)
+ controller.mediabar.addToolbarButton(
+ u'media_playback_stop', u':/slides/media_playback_stop.png',
+ translate('OpenLP.SlideController', 'Stop playing media'),
+ controller.sendToPlugins)
+ # Build the seekSlider.
+ controller.seekSlider = QtGui.QSlider(QtCore.Qt.Horizontal)
+ controller.seekSlider.setMaximum(1000)
+ controller.seekSlider.setToolTip(translate(
+ 'OpenLP.SlideController', 'Video position.'))
+ controller.seekSlider.setGeometry(QtCore.QRect(90, 260, 221, 24))
+ controller.seekSlider.setObjectName(u'seek_slider')
+ controller.mediabar.addToolbarWidget(u'Seek Slider',
+ controller.seekSlider)
+ # Build the volumeSlider.
+ controller.volumeSlider = QtGui.QSlider(QtCore.Qt.Horizontal)
+ controller.volumeSlider.setTickInterval(10)
+ controller.volumeSlider.setTickPosition(QtGui.QSlider.TicksAbove)
+ controller.volumeSlider.setMinimum(0)
+ controller.volumeSlider.setMaximum(100)
+ 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'volume_slider')
+ controller.mediabar.addToolbarWidget(u'Audio Volume',
+ controller.volumeSlider)
+ control_panel.addWidget(controller.mediabar)
+ controller.mediabar.setVisible(False)
+ # Signals
+ QtCore.QObject.connect(controller.seekSlider,
+ QtCore.SIGNAL(u'sliderMoved(int)'), controller.sendToPlugins)
+ QtCore.QObject.connect(controller.volumeSlider,
+ QtCore.SIGNAL(u'sliderMoved(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):
+ """
+ After a new display is configured, all media related widget will be
+ created too
+ """
+ # clean up possible running old media files
+ self.finalise()
+ # update player status
+ self.set_active_players()
+ display.hasAudio = True
+ if not self.withLivePreview and \
+ display == self.parent.liveController.previewDisplay:
+ return
+ if display == self.parent.previewController.previewDisplay or \
+ display == self.parent.liveController.previewDisplay:
+ display.hasAudio = False
+ for player in self.mediaPlayers.values():
+ if player.isActive:
+ player.setup(display)
+
+ def set_controls_visible(self, controller, value):
+ # Generic controls
+ controller.mediabar.setVisible(value)
+ # Special controls: Here media type specific Controls will be enabled
+ # (e.g. for DVD control, ...)
+ # TODO
+
+ def resize(self, controller, display, player):
+ """
+ After Mainwindow changes or Splitter moved all related media widgets
+ have to be resized
+ """
+ player.resize(display)
+
+ def video(self, controller, file, muted, isBackground):
+ """
+ Loads and starts a video to run with the option of sound
+ """
+ log.debug(u'video')
+ isValid = False
+ # stop running videos
+ self.video_reset(controller)
+ controller.media_info = MediaInfo()
+ if muted:
+ controller.media_info.volume = 0
+ else:
+ controller.media_info.volume = controller.volumeSlider.value()
+ controller.media_info.file_info = QtCore.QFileInfo(file)
+ controller.media_info.is_background = isBackground
+ display = None
+ 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)
+ display.override[u'theme'] = u''
+ display.override[u'video'] = True
+ controller.media_info.start_time = display.serviceItem.start_time
+ controller.media_info.end_time = display.serviceItem.end_time
+ elif controller.previewDisplay:
+ display = controller.previewDisplay
+ isValid = self.check_file_type(controller, display)
+ if not isValid:
+ # Media could not be loaded correctly
+ critical_error_message_box(
+ translate('MediaPlugin.MediaItem', 'Unsupported File'),
+ unicode(translate('MediaPlugin.MediaItem',
+ 'Unsupported File')))
+ return False
+ # dont care about actual theme, set a black background
+ if controller.isLive and ( \
+ controller.media_info.is_background == False):
+ display.frame.evaluateJavaScript(u'show_video( \
+ "setBackBoard", null, null, null,"visible");')
+ # now start playing
+ if controller.isLive and \
+ (QtCore.QSettings().value(u'general/auto unblank',
+ QtCore.QVariant(False)).toBool() or \
+ controller.media_info.is_background == True) or \
+ controller.isLive == False:
+ if not self.video_play([controller]):
+ critical_error_message_box(
+ translate('MediaPlugin.MediaItem', 'Unsupported File'),
+ unicode(translate('MediaPlugin.MediaItem',
+ 'Unsupported File')))
+ return False
+ self.set_controls_visible(controller, True)
+ log.debug(u'use %s controller' % self.curDisplayMediaPlayer[display])
+ return True
+
+ def check_file_type(self, controller, display):
+ """
+ Used to choose the right media Player type from the prioritized Player list
+ """
+ playerSettings = str(QtCore.QSettings().value(u'media/players',
+ QtCore.QVariant(u'webkit')).toString())
+ usedPlayers = playerSettings.split(u',')
+ if QtCore.QSettings().value(u'media/override player',
+ QtCore.QVariant(QtCore.Qt.Unchecked)) == QtCore.Qt.Checked:
+ if self.overridenPlayer != '':
+ usedPlayers = [self.overridenPlayer]
+ if controller.media_info.file_info.isFile():
+ suffix = u'*.%s' % controller.media_info.file_info.suffix().toLower()
+ 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 player.load(display):
+ self.curDisplayMediaPlayer[display] = 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
+ 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)
+ if player.load(display):
+ self.curDisplayMediaPlayer[display] = player
+ controller.media_info.media_type = MediaType.Video
+ return True
+ # no valid player found
+ return False
+
+ def video_play(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()
+ # Start Timer for ui updates
+ if not self.timer.isActive():
+ self.timer.start()
+ return True
+
+ def video_pause(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)
+
+ def video_stop(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)
+
+ def video_volume(self, msg):
+ """
+ Changes the volume of a running video
+
+ ``msg``
+ First element is the controller which should be used
+ """
+ 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)
+
+ def video_seek(self, msg):
+ """
+ Responds to the request to change the seek Slider of a loaded video
+
+ ``msg``
+ 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')
+ controller = msg[0]
+ seekVal = msg[1][0]
+ for display in self.curDisplayMediaPlayer.keys():
+ if display.controller == controller:
+ self.curDisplayMediaPlayer[display].seek(display, seekVal)
+
+ def video_reset(self, controller):
+ """
+ Responds to the request to reset a loaded video
+ """
+ log.debug(u'video_reset')
+ 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]
+ self.set_controls_visible(controller, False)
+
+ def video_hide(self, msg):
+ """
+ Hide the related video Widget
+
+ ``msg``
+ First element is the boolean for Live indication
+ """
+ isLive = msg[1]
+ if isLive:
+ controller = self.parent.liveController
+ for display in self.curDisplayMediaPlayer.keys():
+ if display.controller == controller:
+ if self.curDisplayMediaPlayer[display] \
+ .state == MediaState.Playing:
+ self.curDisplayMediaPlayer[display].pause(display)
+ self.curDisplayMediaPlayer[display] \
+ .set_visible(display, False)
+
+ def video_blank(self, msg):
+ """
+ Blank the related video Widget
+
+ ``msg``
+ First element is the boolean for Live indication
+ Second element is the hide mode
+ """
+ isLive = msg[1]
+ hide_mode = msg[2]
+ if isLive:
+ Receiver.send_message(u'live_display_hide', hide_mode)
+ controller = self.parent.liveController
+ for display in self.curDisplayMediaPlayer.keys():
+ if display.controller == controller:
+ if self.curDisplayMediaPlayer[display] \
+ .state == MediaState.Playing:
+ self.curDisplayMediaPlayer[display].pause(display)
+ self.curDisplayMediaPlayer[display] \
+ .set_visible(display, False)
+
+ def video_unblank(self, msg):
+ """
+ Unblank the related video Widget
+
+ ``msg``
+ First element is not relevant in this context
+ Second element is the boolean for Live indication
+ """
+ Receiver.send_message(u'live_display_show')
+ isLive = msg[1]
+ if isLive:
+ controller = self.parent.liveController
+ for display in self.curDisplayMediaPlayer.keys():
+ if display.controller == controller:
+ if self.curDisplayMediaPlayer[display] \
+ .state == MediaState.Paused:
+ if self.curDisplayMediaPlayer[display].play(display):
+ self.curDisplayMediaPlayer[display] \
+ .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:
+ for item in player.video_extensions_list:
+ if not item in video_list:
+ video_list.append(item)
+ return video_list
+
+ def override_player(self, override_player):
+ playerSettings = str(QtCore.QSettings().value(u'media/players',
+ QtCore.QVariant(u'webkit')).toString())
+ usedPlayers = playerSettings.split(u',')
+ if override_player in usedPlayers:
+ self.overridenPlayer = override_player
+ else:
+ self.overridenPlayer = ''
+
+ def finalise(self):
+ self.timer.stop()
+ for controller in self.controller:
+ self.video_reset(controller)
=== added file 'openlp/core/ui/media/phononplayer.py'
--- openlp/core/ui/media/phononplayer.py 1970-01-01 00:00:00 +0000
+++ openlp/core/ui/media/phononplayer.py 2011-12-01 18:30:31 +0000
@@ -0,0 +1,201 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2011 Raoul Snyman #
+# Portions copyright (c) 2008-2011 Tim Bentley, Gerald Britton, Jonathan #
+# Corwin, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, #
+# Armin Köhler, Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias #
+# Põldaru, Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
+# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it #
+# under the terms of the GNU General Public License as published by the Free #
+# Software Foundation; version 2 of the License. #
+# #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
+# more details. #
+# #
+# You should have received a copy of the GNU General Public License along #
+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
+###############################################################################
+
+import logging
+import 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.ui.media import MediaState
+
+log = logging.getLogger(__name__)
+
+ADDITIONAL_EXT = {
+ u'audio/ac3': [u'.ac3'],
+ u'audio/flac': [u'.flac'],
+ u'audio/x-m4a': [u'.m4a'],
+ u'audio/midi': [u'.mid', u'.midi'],
+ u'audio/x-mp3': [u'.mp3'],
+ u'audio/mpeg': [u'.mp3', u'.mp2', u'.mpga', u'.mpega', u'.m4a'],
+ u'audio/qcelp': [u'.qcp'],
+ u'audio/x-wma': [u'.wma'],
+ u'audio/x-ms-wma': [u'.wma'],
+ u'video/x-flv': [u'.flv'],
+ u'video/x-matroska': [u'.mpv', u'.mkv'],
+ u'video/x-wmv': [u'.wmv'],
+ u'video/x-mpg': [u'.mpg'],
+ u'video/x-ms-wmv': [u'.wmv']}
+
+
+class PhononPlayer(MediaPlayer):
+ """
+ A specialised version of the MediaPlayer class, which provides a Phonon
+ display.
+ """
+
+ def __init__(self, parent):
+ MediaPlayer.__init__(self, parent, u'phonon')
+ self.parent = parent
+ self.additional_extensions = ADDITIONAL_EXT
+ mimetypes.init()
+ for mimetype in Phonon.BackendCapabilities.availableMimeTypes():
+ mimetype = unicode(mimetype)
+ if mimetype.startswith(u'audio/'):
+ self._addToList(self.audio_extensions_list, mimetype)
+ elif mimetype.startswith(u'video/'):
+ self._addToList(self.video_extensions_list, mimetype)
+
+ def _addToList(self, list, mimetype):
+ # Add all extensions which mimetypes provides us for supported types.
+ extensions = mimetypes.guess_all_extensions(unicode(mimetype))
+ for extension in extensions:
+ ext = u'*%s' % extension
+ if ext not in list:
+ list.append(ext)
+ 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.
+ if mimetype in self.additional_extensions.keys():
+ for extension in self.additional_extensions[mimetype]:
+ 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])))
+
+ def setup(self, display):
+ display.phononWidget = Phonon.VideoWidget(display)
+ display.phononWidget.resize(display.size())
+ display.mediaObject = Phonon.MediaObject(display)
+ Phonon.createPath(display.mediaObject, display.phononWidget)
+ if display.hasAudio:
+ display.audio = Phonon.AudioOutput( \
+ Phonon.VideoCategory, display.mediaObject)
+ Phonon.createPath(display.mediaObject, display.audio)
+ display.phononWidget.raise_()
+ display.phononWidget.hide()
+ self.hasOwnWidget = True
+
+ def check_available(self):
+ return True
+
+ def load(self, display):
+ log.debug(u'load vid in Phonon Controller')
+ controller = display.controller
+ volume = controller.media_info.volume
+ path = controller.media_info.file_info.absoluteFilePath()
+ display.mediaObject.setCurrentSource(Phonon.MediaSource(path))
+ if not self.media_state_wait(display, Phonon.StoppedState):
+ return False
+ self.volume(display, volume)
+ return True
+
+ def media_state_wait(self, display, mediaState):
+ """
+ Wait for the video to change its state
+ Wait no longer than 5 seconds.
+ """
+ start = datetime.now()
+ current_state = display.mediaObject.state()
+ while current_state != mediaState:
+ current_state = display.mediaObject.state()
+ if current_state == Phonon.ErrorState:
+ return False
+ Receiver.send_message(u'openlp_process_events')
+ if (datetime.now() - start).seconds > 5:
+ return False
+ return True
+
+ def resize(self, display):
+ display.phononWidget.resize(display.size())
+
+ def play(self, display):
+ controller = display.controller
+ start_time = 0
+ if display.mediaObject.state() != Phonon.PausedState and \
+ controller.media_info.start_time > 0:
+ start_time = controller.media_info.start_time
+ display.mediaObject.play()
+ if self.media_state_wait(display, Phonon.PlayingState):
+ 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.seekSlider.setMaximum(controller.media_info.length*1000)
+ self.state = MediaState.Playing
+ display.phononWidget.raise_()
+ return True
+ else:
+ return False
+
+ def pause(self, display):
+ display.mediaObject.pause()
+ if self.media_state_wait(display, Phonon.PausedState):
+ self.state = MediaState.Paused
+
+ def stop(self, display):
+ display.mediaObject.stop()
+ self.set_visible(display, False)
+ self.state = MediaState.Stopped
+
+ def volume(self, display, vol):
+ # 1.0 is the highest value
+ if display.hasAudio:
+ vol = float(vol) / float(100)
+ display.audio.setVolume(vol)
+
+ def seek(self, display, seekVal):
+ display.mediaObject.seek(seekVal)
+
+ def reset(self, display):
+ display.mediaObject.stop()
+ display.mediaObject.clearQueue()
+ self.set_visible(display, False)
+ display.phononWidget.setVisible(False)
+ self.state = MediaState.Off
+
+ def set_visible(self, display, status):
+ if self.hasOwnWidget:
+ display.phononWidget.setVisible(status)
+
+ def update_ui(self, display):
+ controller = display.controller
+ if controller.media_info.end_time > 0:
+ 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())
=== added file 'openlp/core/ui/media/webkitplayer.py'
--- openlp/core/ui/media/webkitplayer.py 1970-01-01 00:00:00 +0000
+++ openlp/core/ui/media/webkitplayer.py 2011-12-01 18:30:31 +0000
@@ -0,0 +1,426 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2011 Raoul Snyman #
+# Portions copyright (c) 2008-2011 Tim Bentley, Gerald Britton, Jonathan #
+# Corwin, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, #
+# Armin Köhler, Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias #
+# Põldaru, Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
+# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it #
+# under the terms of the GNU General Public License as published by the Free #
+# Software Foundation; version 2 of the License. #
+# #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
+# more details. #
+# #
+# You should have received a copy of the GNU General Public License along #
+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
+###############################################################################
+
+import logging
+
+from PyQt4 import QtCore, QtGui, QtWebKit
+
+from openlp.core.lib import OpenLPToolbar, translate
+from openlp.core.lib.mediaplayer import MediaPlayer
+from openlp.core.ui.media import MediaState
+
+log = logging.getLogger(__name__)
+
+VIDEO_CSS = u"""
+#videobackboard {
+ z-index:3;
+ background-color: black;
+}
+#video1 {
+ z-index:4;
+}
+#video2 {
+ z-index:4;
+}
+"""
+
+VIDEO_JS = u"""
+ var video_timer = null;
+ var current_video = '1';
+
+ function show_video(state, path, volume, loop, varVal){
+ // Note, the preferred method for looping would be to use the
+ // video tag loop attribute.
+ // But QtWebKit doesn't support this. Neither does it support the
+ // onended event, hence the setInterval()
+ // In addition, setting the currentTime attribute to zero to restart
+ // the video raises an INDEX_SIZE_ERROR: DOM Exception 1
+ // To complicate it further, sometimes vid.currentTime stops
+ // slightly short of vid.duration and vid.ended is intermittent!
+ //
+ // Note, currently the background may go black between loops. Not
+ // desirable. Need to investigate using two <video>'s, and hiding/
+ // preloading one, and toggle between the two when looping.
+
+ if(current_video=='1'){
+ var vid = document.getElementById('video1');
+ var vid2 = document.getElementById('video2');
+ } else {
+ var vid = document.getElementById('video2');
+ var vid2 = document.getElementById('video1');
+ }
+ if(volume != null){
+ vid.volume = volume;
+ vid2.volume = volume;
+ }
+ switch(state){
+ case 'init':
+ vid.src = 'file:///' + path;
+ vid2.src = 'file:///' + path;
+ if(loop == null) loop = false;
+ vid.looping = loop;
+ vid2.looping = loop;
+ vid.load();
+ break;
+ case 'load':
+ vid2.style.visibility = 'hidden';
+ vid2.load();
+ break;
+ case 'play':
+ vid.play();
+ if(vid.looping){
+ video_timer = setInterval(
+ function() {
+ show_video('poll');
+ }, 200);
+ }
+ break;
+ case 'pause':
+ if(video_timer!=null){
+ clearInterval(video_timer);
+ video_timer = null;
+ }
+ vid.pause();
+ break;
+ case 'stop':
+ show_video('pause');
+ vid.currentTime = 0;
+ break;
+ case 'poll':
+ if(vid.ended||vid.currentTime+0.2>vid.duration)
+ show_video('swap');
+ break;
+ case 'swap':
+ show_video('pause');
+ if(current_video=='1')
+ current_video = '2';
+ else
+ current_video = '1';
+ show_video('load');
+ show_video('play');
+ show_video('setVisible',null,null,null,'visible');
+ break;
+ case 'close':
+ show_video('stop');
+ vid.src = '';
+ vid2.src = '';
+ break;
+ case 'length':
+ return vid.duration;
+ case 'currentTime':
+ return vid.currentTime;
+ case 'seek':
+ // doesnt work currently
+ vid.currentTime = varVal;
+ break;
+ case 'setVisible':
+ vid.style.visibility = varVal;
+ break;
+ case 'setBackBoard':
+ var back = document.getElementById('videobackboard');
+ back.style.visibility = varVal;
+ break;
+ }
+ }
+"""
+
+VIDEO_HTML = u"""
+<div id="videobackboard" class="size" style="visibility:hidden"></div>
+<video id="video1" class="size" style="visibility:hidden" autobuffer preload>
+</video>
+<video id="video2" class="size" style="visibility:hidden" autobuffer preload>
+</video>
+"""
+
+FLASH_CSS = u"""
+#flash {
+ z-index:5;
+}
+"""
+
+FLASH_JS = u"""
+ function getFlashMovieObject(movieName)
+ {
+ if (window.document[movieName])
+ {
+ return window.document[movieName];
+ }
+ if (document.embeds && document.embeds[movieName])
+ return document.embeds[movieName];
+ }
+
+ function show_flash(state, path, volume, varVal){
+ var text = document.getElementById('flash');
+ var flashMovie = getFlashMovieObject("OpenLPFlashMovie");
+ var src = "src = 'file:///" + path + "'";
+ var view_parm = " wmode='opaque'" +
+ " width='100%%'" +
+ " height='100%%'";
+ var swf_parm = " name='OpenLPFlashMovie'" +
+ " autostart='true' loop='false' play='true'" +
+ " hidden='false' swliveconnect='true' allowscriptaccess='always'" +
+ " volume='" + volume + "'";
+
+ switch(state){
+ case 'load':
+ text.innerHTML = "<embed " + src + view_parm + swf_parm + "/>";
+ flashMovie = getFlashMovieObject("OpenLPFlashMovie");
+ flashMovie.Play();
+ break;
+ case 'play':
+ flashMovie.Play();
+ break;
+ case 'pause':
+ flashMovie.StopPlay();
+ break;
+ case 'stop':
+ flashMovie.StopPlay();
+ tempHtml = text.innerHTML;
+ text.innerHTML = '';
+ text.innerHTML = tempHtml;
+ break;
+ case 'close':
+ flashMovie.StopPlay();
+ text.innerHTML = '';
+ break;
+ case 'length':
+ return flashMovie.TotalFrames();
+ case 'currentTime':
+ return flashMovie.CurrentFrame();
+ case 'seek':
+// flashMovie.GotoFrame(varVal);
+ break;
+ case 'setVisible':
+ text.style.visibility = varVal;
+ break;
+ }
+ }
+"""
+
+FLASH_HTML = u"""
+<div id="flash" class="size" style="visibility:hidden"></div>
+"""
+
+VIDEO_EXT = [
+ u'*.3gp'
+ , u'*.3gpp'
+ , u'*.3g2'
+ , u'*.3gpp2'
+ , u'*.aac'
+ , u'*.flv'
+ , u'*.f4a'
+ , u'*.f4b'
+ , u'*.f4p'
+ , u'*.f4v'
+ , u'*.mov'
+ , u'*.m4a'
+ , u'*.m4b'
+ , u'*.m4p'
+ , u'*.m4v'
+ , u'*.mkv'
+ , u'*.mp4'
+ , u'*.ogv'
+ , u'*.webm'
+ , u'*.mpg', u'*.wmv', u'*.mpeg', u'*.avi'
+ , u'*.swf'
+ ]
+
+AUDIO_EXT = [
+ u'*.mp3'
+ , u'*.ogg'
+ ]
+
+
+class WebkitPlayer(MediaPlayer):
+ """
+ A specialised version of the MediaPlayer class, which provides a QtWebKit
+ display.
+ """
+
+ def __init__(self, parent):
+ MediaPlayer.__init__(self, parent, u'webkit')
+ self.parent = parent
+ self.canBackground = True
+ self.audio_extensions_list = AUDIO_EXT
+ self.video_extensions_list = VIDEO_EXT
+
+ def get_media_display_css(self):
+ """
+ Add css style sheets to htmlbuilder
+ """
+ return VIDEO_CSS + FLASH_CSS
+
+ def get_media_display_javascript(self):
+ """
+ Add javascript functions to htmlbuilder
+ """
+ return VIDEO_JS + FLASH_JS
+
+ def get_media_display_html(self):
+ """
+ Add html code to htmlbuilder
+ """
+ return VIDEO_HTML + FLASH_HTML
+
+ def setup(self, display):
+ display.webView.resize(display.size())
+ display.webView.raise_()
+ self.hasOwnWidget = False
+
+ def check_available(self):
+ return True
+
+ def load(self, display):
+ log.debug(u'load vid in Webkit Controller')
+ controller = display.controller
+ if display.hasAudio:
+ volume = controller.media_info.volume
+ vol = float(volume) / float(100)
+ else:
+ vol = 0
+ path = controller.media_info.file_info.absoluteFilePath()
+ if controller.media_info.is_background:
+ loop = u'true'
+ else:
+ loop = u'false'
+ 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'\\\\'))
+ else:
+ 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):
+ controller = display.controller
+ display.webLoaded = True
+ length = 0
+ 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:
+ display.frame.evaluateJavaScript(u'show_flash("play");')
+ else:
+ display.frame.evaluateJavaScript(u'show_video("play");')
+ if start_time > 0:
+ self.seek(display, controller.media_info.start_time*1000)
+ # TODO add playing check and get the correct media length
+ controller.media_info.length = length
+ self.state = MediaState.Playing
+ display.webView.raise_()
+ return True
+
+ def pause(self, display):
+ controller = display.controller
+ if controller.media_info.is_flash:
+ display.frame.evaluateJavaScript(u'show_flash("pause");')
+ else:
+ display.frame.evaluateJavaScript(u'show_video("pause");')
+ self.state = MediaState.Paused
+
+ def stop(self, display):
+ controller = display.controller
+ if controller.media_info.is_flash:
+ display.frame.evaluateJavaScript(u'show_flash("stop");')
+ else:
+ display.frame.evaluateJavaScript(u'show_video("stop");')
+ controller.seekSlider.setSliderPosition(0)
+ self.state = MediaState.Stopped
+
+ def volume(self, display, vol):
+ controller = display.controller
+ # 1.0 is the highest value
+ if display.hasAudio:
+ vol = float(vol) / float(100)
+ if not controller.media_info.is_flash:
+ display.frame.evaluateJavaScript(
+ u'show_video(null, null, %s);' % str(vol))
+
+ def seek(self, display, seekVal):
+ controller = display.controller
+ if controller.media_info.is_flash:
+ seek = seekVal
+ display.frame.evaluateJavaScript( \
+ u'show_flash("seek", null, null, "%s");' % (seek))
+ else:
+ seek = float(seekVal)/1000
+ display.frame.evaluateJavaScript( \
+ u'show_video("seek", null, null, null, "%f");' % (seek))
+
+ def reset(self, display):
+ controller = display.controller
+ if controller.media_info.is_flash:
+ display.frame.evaluateJavaScript(u'show_flash("close");')
+ else:
+ display.frame.evaluateJavaScript(u'show_video("close");')
+ self.state = MediaState.Off
+
+ def set_visible(self, display, status):
+ controller = display.controller
+ if status:
+ is_visible = "visible"
+ else:
+ is_visible = "hidden"
+ if controller.media_info.is_flash:
+ 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))
+
+ def update_ui(self, display):
+ controller = display.controller
+ if controller.media_info.is_flash:
+ currentTime = display.frame.evaluateJavaScript( \
+ u'show_flash("currentTime");').toInt()[0]
+ length = display.frame.evaluateJavaScript( \
+ u'show_flash("length");').toInt()[0]
+ else:
+ (currentTime, ok) = display.frame.evaluateJavaScript( \
+ u'show_video("currentTime");').toFloat()
+ # 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");').toFloat()
+ # check if conversion was ok and value is not 'NaN'
+ if ok and length != float('inf'):
+ length = int(length*1000)
+ if currentTime > 0:
+ controller.media_info.length = length
+ controller.seekSlider.setMaximum(length)
+ if not controller.seekSlider.isSliderDown():
+ controller.seekSlider.setSliderPosition(currentTime)
=== modified file 'openlp/core/ui/slidecontroller.py'
--- openlp/core/ui/slidecontroller.py 2011-11-28 18:03:38 +0000
+++ openlp/core/ui/slidecontroller.py 2011-12-01 18:30:31 +0000
@@ -34,9 +34,9 @@
from PyQt4.phonon import Phonon
from openlp.core.lib import OpenLPToolbar, Receiver, ItemCapabilities, \
- translate, build_icon
+ translate, build_icon, ServiceItem, build_html, PluginManager, ServiceItem
from openlp.core.lib.ui import UiStrings, shortcut_action
-from openlp.core.ui import HideMode, MainDisplay, ScreenList
+from openlp.core.ui import HideMode, MainDisplay, Display, ScreenList
from openlp.core.utils.actions import ActionList, CategoryOrder
log = logging.getLogger(__name__)
@@ -49,8 +49,29 @@
def __init__(self, parent=None, name=None):
QtGui.QTableWidget.__init__(self, parent.controller)
-
-class SlideController(QtGui.QWidget):
+class Controller(QtGui.QWidget):
+ """
+ Controller is a general controller widget.
+ """
+ def __init__(self, parent, isLive=False):
+ """
+ Set up the general Controller.
+ """
+ QtGui.QWidget.__init__(self, parent)
+ self.isLive = isLive
+ self.display = None
+
+ def sendToPlugins(self, *args):
+ """
+ This is the generic function to send signal for control widgets,
+ 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()
+ controller = self
+ Receiver.send_message('%s' % sender, [controller, args])
+
+class SlideController(Controller):
"""
SlideController is the slide controller widget. This widget is what the
user uses to control the displaying of verses/slides/etc on the screen.
@@ -59,13 +80,12 @@
"""
Set up the Slide Controller.
"""
- QtGui.QWidget.__init__(self, parent)
- self.isLive = isLive
- self.display = None
+ Controller.__init__(self, parent, isLive)
self.screens = ScreenList.get_instance()
self.ratio = float(self.screens.current[u'size'].width()) / \
float(self.screens.current[u'size'].height())
self.imageManager = self.parent().imageManager
+ self.mediaController = self.parent().mediaController
self.loopList = [
u'Play Slides Menu',
u'Loop Separator',
@@ -74,7 +94,10 @@
self.songEditList = [
u'Edit Song',
]
- self.volume = 10
+ self.nextPreviousList = [
+ u'Previous Slide',
+ u'Next Slide'
+ ]
self.timer_id = 0
self.songEdit = False
self.selectedRow = 0
@@ -140,14 +163,14 @@
self.toolbar.sizePolicy().hasHeightForWidth())
self.toolbar.setSizePolicy(sizeToolbarPolicy)
self.previousItem = self.toolbar.addToolbarButton(
- translate('OpenLP.SlideController', 'Previous Slide'),
+ u'Previous Slide',
u':/slides/slide_previous.png',
translate('OpenLP.SlideController', 'Move to previous.'),
self.onSlideSelectedPrevious,
shortcuts=[QtCore.Qt.Key_Up, QtCore.Qt.Key_PageUp],
context=QtCore.Qt.WidgetWithChildrenShortcut)
self.nextItem = self.toolbar.addToolbarButton(
- translate('OpenLP.SlideController', 'Next Slide'),
+ u'Next Slide',
u':/slides/slide_next.png',
translate('OpenLP.SlideController', 'Move to next.'),
self.onSlideSelectedNext,
@@ -234,20 +257,8 @@
'Edit and reload song preview.'),
self.onEditSong)
self.controllerLayout.addWidget(self.toolbar)
- # Build a Media ToolBar
- self.mediabar = OpenLPToolbar(self)
- self.mediabar.addToolbarButton(
- u'Media Start', u':/slides/media_playback_start.png',
- translate('OpenLP.SlideController', 'Start playing media.'),
- self.onMediaPlay)
- self.mediabar.addToolbarButton(
- u'Media Pause', u':/slides/media_playback_pause.png',
- translate('OpenLP.SlideController', 'Start playing media.'),
- self.onMediaPause)
- self.mediabar.addToolbarButton(
- u'Media Stop', u':/slides/media_playback_stop.png',
- translate('OpenLP.SlideController', 'Start playing media.'),
- self.onMediaStop)
+ # Build the Media Toolbar
+ self.mediaController.add_controller_items(self, self.controllerLayout)
if self.isLive:
# Build the Song Toolbar
self.songMenu = QtGui.QToolButton(self.toolbar)
@@ -263,23 +274,6 @@
translate('OpenLP.SlideController', 'Pause audio.'),
self.onAudioPauseClicked, True)
self.audioPauseItem.setVisible(False)
- # Build the volumeSlider.
- self.volumeSlider = QtGui.QSlider(QtCore.Qt.Horizontal)
- self.volumeSlider.setTickInterval(1)
- self.volumeSlider.setTickPosition(QtGui.QSlider.TicksAbove)
- self.volumeSlider.setMinimum(0)
- self.volumeSlider.setMaximum(10)
- else:
- # Build the seekSlider.
- self.seekSlider = Phonon.SeekSlider()
- self.seekSlider.setGeometry(QtCore.QRect(90, 260, 221, 24))
- self.seekSlider.setObjectName(u'seekSlider')
- self.mediabar.addToolbarWidget(u'Seek Slider', self.seekSlider)
- self.volumeSlider = Phonon.VolumeSlider()
- self.volumeSlider.setGeometry(QtCore.QRect(90, 260, 221, 24))
- self.volumeSlider.setObjectName(u'volumeSlider')
- self.mediabar.addToolbarWidget(u'Audio Volume', self.volumeSlider)
- self.controllerLayout.addWidget(self.mediabar)
# Screen preview area
self.previewFrame = QtGui.QFrame(self.splitter)
self.previewFrame.setGeometry(QtCore.QRect(0, 0, 300, 300 * self.ratio))
@@ -296,17 +290,13 @@
self.slideLayout = QtGui.QVBoxLayout()
self.slideLayout.setSpacing(0)
self.slideLayout.setMargin(0)
- self.slideLayout.setObjectName(u'slideLayout')
- if not self.isLive:
- self.mediaObject = Phonon.MediaObject(self)
- self.video = Phonon.VideoWidget()
- self.video.setVisible(False)
- self.audio = Phonon.AudioOutput(Phonon.VideoCategory,
- self.mediaObject)
- Phonon.createPath(self.mediaObject, self.video)
- Phonon.createPath(self.mediaObject, self.audio)
- self.video.setGeometry(QtCore.QRect(0, 0, 300, 225))
- self.slideLayout.insertWidget(0, self.video)
+ self.slideLayout.setObjectName(u'SlideLayout')
+ self.previewDisplay = Display(self, self.isLive, self)
+ self.previewDisplay.setGeometry(QtCore.QRect(0, 0, 300, 300))
+ self.previewDisplay.screen = {u'size':self.previewDisplay.geometry()}
+ self.previewDisplay.setup()
+ self.slideLayout.insertWidget(0, self.previewDisplay)
+ self.previewDisplay.hide()
# Actual preview screen
self.slidePreview = QtGui.QLabel(self)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed,
@@ -415,8 +405,6 @@
QtCore.QObject.connect(self.previewListWidget,
QtCore.SIGNAL(u'clicked(QModelIndex)'), self.onSlideSelected)
if self.isLive:
- QtCore.QObject.connect(self.volumeSlider,
- QtCore.SIGNAL(u'sliderReleased()'), self.mediaVolume)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'slidecontroller_live_spin_delay'),
self.receiveSpinDelay)
@@ -426,7 +414,6 @@
QtCore.SIGNAL(u'doubleClicked(QModelIndex)'),
self.onGoLiveClick)
self.toolbar.makeWidgetsInvisible(self.songEditList)
- self.mediabar.setVisible(False)
if self.isLive:
self.setLiveHotkeys(self)
self.__addActionsToWidget(self.previewListWidget)
@@ -577,7 +564,7 @@
def liveEscape(self):
self.display.setVisible(False)
- self.display.videoStop()
+ self.mediaController.video_stop([self])
def servicePrevious(self):
"""
@@ -617,14 +604,22 @@
# rebuild display as screen size changed
if self.display:
self.display.close()
- self.display = MainDisplay(self, self.imageManager, self.isLive)
+ self.display = MainDisplay(self, self.imageManager, self.isLive,
+ self)
self.display.setup()
if self.isLive:
self.__addActionsToWidget(self.display)
# The SlidePreview's ratio.
self.ratio = float(self.screens.current[u'size'].width()) / \
float(self.screens.current[u'size'].height())
+ self.mediaController.setup_display(self.display)
self.previewSizeChanged()
+ self.previewDisplay.setup()
+ serviceItem = ServiceItem()
+ self.previewDisplay.webView.setHtml(build_html(serviceItem,
+ self.previewDisplay.screen, None, self.isLive, None,
+ plugins=PluginManager.get_instance().plugins))
+ self.mediaController.setup_display(self.previewDisplay)
if self.serviceItem:
self.refreshServiceItem()
@@ -646,11 +641,17 @@
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.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.previewDisplay.screen = {u'size':self.previewDisplay.geometry()}
# Make sure that the frames have the correct size.
self.previewListWidget.setColumnWidth(0,
self.previewListWidget.viewport().size().width())
@@ -711,12 +712,13 @@
len(item.get_frames()) > 1:
self.toolbar.makeWidgetsVisible(self.loopList)
if item.is_media():
- self.toolbar.setVisible(False)
self.mediabar.setVisible(True)
+ self.toolbar.makeWidgetsInvisible(self.nextPreviousList)
else:
# Work-around for OS X, hide and then show the toolbar
# See bug #791050
- self.toolbar.show()
+ self.toolbar.makeWidgetsVisible(self.nextPreviousList)
+ self.toolbar.show()
def enablePreviewToolBar(self, item):
"""
@@ -730,13 +732,13 @@
if item.is_capable(ItemCapabilities.CanEdit) and item.from_plugin:
self.toolbar.makeWidgetsVisible(self.songEditList)
elif item.is_media():
- self.toolbar.setVisible(False)
self.mediabar.setVisible(True)
- self.volumeSlider.setAudioOutput(self.audio)
+ self.toolbar.makeWidgetsInvisible(self.nextPreviousList)
if not item.is_media():
# Work-around for OS X, hide and then show the toolbar
# See bug #791050
- self.toolbar.show()
+ self.toolbar.makeWidgetsVisible(self.nextPreviousList)
+ self.toolbar.show()
def refreshServiceItem(self):
"""
@@ -1325,72 +1327,18 @@
"""
log.debug(u'SlideController onMediaStart')
file = os.path.join(item.get_frame_path(), item.get_frame_title())
- if self.isLive:
- self.display.video(file, self.volume)
- self.volumeSlider.setValue(self.volume)
- else:
- self.mediaObject.stop()
- self.mediaObject.clearQueue()
- self.mediaObject.setCurrentSource(Phonon.MediaSource(file))
- self.seekSlider.setMediaObject(self.mediaObject)
- self.seekSlider.show()
- self.onMediaPlay()
-
- def mediaVolume(self):
- """
- Respond to the release of Volume Slider
- """
- log.debug(u'SlideController mediaVolume')
- self.volume = self.volumeSlider.value()
- self.display.videoVolume(self.volume)
-
- def onMediaPause(self):
- """
- Respond to the Pause from the media Toolbar
- """
- log.debug(u'SlideController onMediaPause')
- if self.isLive:
- self.display.videoPause()
- else:
- self.mediaObject.pause()
-
- def onMediaPlay(self):
- """
- Respond to the Play from the media Toolbar
- """
- log.debug(u'SlideController onMediaPlay')
- if self.isLive:
- self.display.videoPlay()
- else:
+ self.mediaController.video(self, file, False, False)
+ if not self.isLive or self.mediaController.withLivePreview:
+ self.previewDisplay.show()
self.slidePreview.hide()
- self.video.show()
- self.mediaObject.play()
-
- def onMediaStop(self):
- """
- Respond to the Stop from the media Toolbar
- """
- log.debug(u'SlideController onMediaStop')
- if self.isLive:
- self.display.videoStop()
- else:
- self.mediaObject.stop()
- self.video.hide()
- self.slidePreview.clear()
- self.slidePreview.show()
def onMediaClose(self):
"""
Respond to a request to close the Video
"""
- log.debug(u'SlideController onMediaStop')
- if self.isLive:
- self.display.resetVideo()
- else:
- self.mediaObject.stop()
- self.mediaObject.clearQueue()
- self.video.hide()
- self.slidePreview.clear()
+ log.debug(u'SlideController onMediaClose')
+ self.mediaController.video_reset(self)
+ self.previewDisplay.hide()
self.slidePreview.show()
def _resetBlank(self):
=== modified file 'openlp/plugins/media/lib/mediaitem.py'
--- openlp/plugins/media/lib/mediaitem.py 2011-10-15 11:30:39 +0000
+++ openlp/plugins/media/lib/mediaitem.py 2011-12-01 18:30:31 +0000
@@ -25,7 +25,6 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
-from datetime import datetime
import logging
import os
import locale
@@ -34,12 +33,17 @@
from PyQt4.phonon import Phonon
from openlp.core.lib import MediaManagerItem, build_icon, ItemCapabilities, \
- SettingsManager, translate, check_item_selected, Receiver, MediaType
-from openlp.core.lib.ui import UiStrings, critical_error_message_box
+ SettingsManager, translate, check_item_selected, Receiver, MediaType, \
+ ServiceItem, build_html
+from openlp.core.lib.ui import UiStrings, critical_error_message_box, \
+ media_item_combo_box
+from openlp.core.ui import Controller, Display
log = logging.getLogger(__name__)
CLAPPERBOARD = QtGui.QImage(u':/media/media_video.png')
+#TODO: Add an appropriate Icon for DVDs, CDs, ...
+DVD_ICON = QtGui.QImage(u':/media/media_video.png')
class MediaMediaItem(MediaManagerItem):
"""
@@ -51,16 +55,40 @@
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()
+
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'video_background_replaced'),
self.videobackgroundReplaced)
QtCore.QObject.connect(Receiver.get_receiver(),
- QtCore.SIGNAL(u'openlp_phonon_creation'),
- self.createPhonon)
+ QtCore.SIGNAL(u'mediaitem_media_rebuild'), self.rebuild)
+ QtCore.QObject.connect(Receiver.get_receiver(),
+ QtCore.SIGNAL(u'config_screen_changed'), self.displaySetup)
# Allow DnD from the desktop
self.listView.activateDnD()
@@ -74,6 +102,10 @@
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:'))
def requiredIcons(self):
MediaManagerItem.requiredIcons(self)
@@ -92,13 +124,34 @@
self.resetAction = self.addToolbarButton(u'', u'',
u':/system/system_close.png', self.onResetClick, False)
self.resetAction.setVisible(False)
+ self.mediaWidget = QtGui.QWidget(self)
+ self.mediaWidget.setObjectName(u'mediaWidget')
+ self.displayLayout = QtGui.QFormLayout(self.mediaWidget)
+ self.displayLayout.setMargin(self.displayLayout.spacing())
+ self.displayLayout.setObjectName(u'displayLayout')
+ self.displayTypeLabel = QtGui.QLabel(self.mediaWidget)
+ self.displayTypeLabel.setObjectName(u'displayTypeLabel')
+ self.displayTypeComboBox = media_item_combo_box(
+ self.mediaWidget, u'displayTypeComboBox')
+ self.displayTypeLabel.setBuddy(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)'), self.overridePlayerChanged)
+
+ def overridePlayerChanged(self, index):
+ Receiver.send_message(u'media_override_player', \
+ u'%s' % self.displayTypeComboBox.currentText())
def onResetClick(self):
"""
- Called to reset the Live backgound with the media selected.
+ Called to reset the Live background with the media selected,
"""
+ self.plugin.liveController.mediaController.video_reset( \
+ self.plugin.liveController)
self.resetAction.setVisible(False)
- self.plugin.liveController.display.resetVideo()
def videobackgroundReplaced(self):
"""
@@ -108,7 +161,7 @@
def onReplaceClick(self):
"""
- Called to replace Live backgound with the media selected.
+ Called to replace Live background with the media selected.
"""
if check_item_selected(self.listView,
translate('MediaPlugin.MediaItem',
@@ -116,8 +169,8 @@
item = self.listView.currentItem()
filename = unicode(item.data(QtCore.Qt.UserRole).toString())
if os.path.exists(filename):
- (path, name) = os.path.split(filename)
- if self.plugin.liveController.display.video(filename, 0, True):
+ if self.plugin.liveController.mediaController.video( \
+ self.plugin.liveController, filename, True, True):
self.resetAction.setVisible(True)
else:
critical_error_message_box(UiStrings().LiveBGError,
@@ -144,30 +197,18 @@
unicode(translate('MediaPlugin.MediaItem',
'The file %s no longer exists.')) % filename)
return False
- self.mediaObject.stop()
- self.mediaObject.clearQueue()
- self.mediaObject.setCurrentSource(Phonon.MediaSource(filename))
- if not self.mediaStateWait(Phonon.StoppedState):
- critical_error_message_box(UiStrings().UnsupportedFile,
- UiStrings().UnsupportedFile)
+ self.mediaLength = 0
+ if self.plugin.mediaController.video( \
+ self.mediaController, filename, False, False):
+ self.mediaLength = self.mediaController.media_info.length
+ service_item.media_length = self.mediaLength
+ self.plugin.mediaController.video_reset(self.mediaController)
+ if self.mediaLength > 0:
+ service_item.add_capability(
+ ItemCapabilities.HasVariableStartTime)
+ else:
return False
- # File too big for processing
- if os.path.getsize(filename) <= 52428800: # 50MiB
- self.mediaObject.play()
- if not self.mediaStateWait(Phonon.PlayingState) \
- or self.mediaObject.currentSource().type() \
- == Phonon.MediaSource.Invalid:
- self.mediaObject.stop()
- critical_error_message_box(
- translate('MediaPlugin.MediaItem', 'File Too Big'),
- translate('MediaPlugin.MediaItem', 'The file you are '
- 'trying to load is too big. Please reduce it to less '
- 'than 50MiB.'))
- return False
- self.mediaObject.stop()
- service_item.media_length = self.mediaObject.totalTime() / 1000
- service_item.add_capability(
- ItemCapabilities.HasVariableStartTime)
+ 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
@@ -177,23 +218,49 @@
service_item.add_from_command(path, name, frame)
return True
- def mediaStateWait(self, mediaState):
- """
- Wait for the video to change its state. Wait no longer than 5 seconds.
- """
- start = datetime.now()
- while self.mediaObject.state() != mediaState:
- if self.mediaObject.state() == Phonon.ErrorState:
- return False
- Receiver.send_message(u'openlp_process_events')
- if (datetime.now() - start).seconds > 5:
- return False
- return True
-
def initialise(self):
self.listView.clear()
self.listView.setIconSize(QtCore.QSize(88, 50))
self.loadList(SettingsManager.load_list(self.settingsSection, u'media'))
+ self.populateDisplayTypes()
+
+ def rebuild(self):
+ """
+ Rebuild the tab in the media manager when changes are made in
+ the settings
+ """
+ self.populateDisplayTypes()
+ self.onNewFileMasks = unicode(translate('MediaPlugin.MediaItem',
+ 'Videos (%s);;Audio (%s);;%s (*)')) % (
+ u' '.join(self.plugin.video_extensions_list),
+ u' '.join(self.plugin.audio_extensions_list), UiStrings().AllFiles)
+
+ def displaySetup(self):
+ self.plugin.mediaController.setup_display( \
+ self.mediaController.previewDisplay)
+
+
+ def populateDisplayTypes(self):
+ """
+ Load the combobox with the enabled media players,
+ allowing user to select a specific player if settings allow
+ """
+ self.displayTypeComboBox.clear()
+ playerSettings = str(QtCore.QSettings().value(u'media/players',
+ QtCore.QVariant(u'webkit')).toString())
+ usedPlayers = playerSettings.split(u',')
+ for title in usedPlayers:
+ # load the drop down selection
+ self.displayTypeComboBox.addItem(title)
+ if self.displayTypeComboBox.count() > 1:
+ self.displayTypeComboBox.insertItem(0, self.Automatic)
+ self.displayTypeComboBox.setCurrentIndex(0)
+ if QtCore.QSettings().value(self.settingsSection + u'/override player',
+ QtCore.QVariant(QtCore.Qt.Unchecked)) == QtCore.Qt.Checked:
+ self.mediaWidget.show()
+ else:
+ self.mediaWidget.hide()
+
def onDeleteClick(self):
"""
@@ -214,10 +281,18 @@
media.sort(cmp=locale.strcoll,
key=lambda filename: os.path.split(unicode(filename))[1].lower())
for track in media:
- filename = os.path.split(unicode(track))[1]
- item_name = QtGui.QListWidgetItem(filename)
- item_name.setIcon(build_icon(CLAPPERBOARD))
- item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(track))
+ track_info = QtCore.QFileInfo(track)
+ if not track_info.isFile():
+ filename = os.path.split(unicode(track))[1]
+ item_name = QtGui.QListWidgetItem(filename)
+ item_name.setIcon(build_icon(CLAPPERBOARD))
+ item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(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.setData(QtCore.Qt.UserRole, QtCore.QVariant(track))
item_name.setToolTip(track)
self.listView.addItem(item_name)
@@ -234,11 +309,6 @@
media = filter(lambda x: os.path.splitext(x)[1] in ext, media)
return media
- def createPhonon(self):
- log.debug(u'CreatePhonon')
- if not self.mediaObject:
- self.mediaObject = Phonon.MediaObject(self)
-
def search(self, string):
files = SettingsManager.load_list(self.settingsSection, u'media')
results = []
=== modified file 'openlp/plugins/media/lib/mediatab.py'
--- openlp/plugins/media/lib/mediatab.py 2011-06-12 16:02:52 +0000
+++ openlp/plugins/media/lib/mediatab.py 2011-12-01 18:30:31 +0000
@@ -28,51 +28,181 @@
from PyQt4 import QtCore, QtGui
from openlp.core.lib import SettingsTab, translate, Receiver
+from openlp.core.lib.ui import UiStrings, critical_error_message_box
class MediaTab(SettingsTab):
"""
MediaTab is the Media settings tab in the settings dialog.
"""
- def __init__(self, parent, title, visible_title, icon_path):
+ def __init__(self, parent, title, visible_title, media_players, icon_path):
+ self.media_players = media_players
SettingsTab.__init__(self, parent, title, visible_title, icon_path)
def setupUi(self):
self.setObjectName(u'MediaTab')
SettingsTab.setupUi(self)
- self.mediaModeGroupBox = QtGui.QGroupBox(self.leftColumn)
- self.mediaModeGroupBox.setObjectName(u'mediaModeGroupBox')
- self.mediaModeLayout = QtGui.QFormLayout(self.mediaModeGroupBox)
- self.mediaModeLayout.setObjectName(u'mediaModeLayout')
- self.usePhononCheckBox = QtGui.QCheckBox(self.mediaModeGroupBox)
- self.usePhononCheckBox.setObjectName(u'usePhononCheckBox')
- self.mediaModeLayout.addRow(self.usePhononCheckBox)
- self.leftLayout.addWidget(self.mediaModeGroupBox)
+ 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 in self.media_players:
+ player = self.media_players[key]
+ checkbox = QtGui.QCheckBox(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.QVBoxLayout(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.orderingButtonsWidget = QtGui.QWidget(self.playerOrderGroupBox)
+ self.orderingButtonsWidget.setObjectName(u'orderingButtonsWidget')
+ self.orderingButtonLayout = QtGui.QHBoxLayout( \
+ self.orderingButtonsWidget)
+ self.orderingButtonLayout.setObjectName(u'orderingButtonLayout')
+ self.orderingDownButton = QtGui.QPushButton(self.orderingButtonsWidget)
+ self.orderingDownButton.setObjectName(u'orderingDownButton')
+ self.orderingButtonLayout.addWidget(self.orderingDownButton)
+ self.orderingUpButton = QtGui.QPushButton(self.playerOrderGroupBox)
+ self.orderingUpButton.setObjectName(u'orderingUpButton')
+ self.orderingButtonLayout.addWidget(self.orderingUpButton)
+ self.playerOrderLayout.addWidget(self.orderingButtonsWidget)
+ self.leftLayout.addWidget(self.playerOrderGroupBox)
+ self.AdvancedGroupBox = QtGui.QGroupBox(self.leftColumn)
+ self.AdvancedGroupBox.setObjectName(u'AdvancedGroupBox')
+ self.AdvancedLayout = QtGui.QVBoxLayout(self.AdvancedGroupBox)
+ self.AdvancedLayout.setObjectName(u'AdvancedLayout')
+ self.OverridePlayerCheckBox = QtGui.QCheckBox(self.AdvancedGroupBox)
+ self.OverridePlayerCheckBox.setObjectName(u'OverridePlayerCheckBox')
+ self.AdvancedLayout.addWidget(self.OverridePlayerCheckBox)
+ self.leftLayout.addWidget(self.AdvancedGroupBox)
self.leftLayout.addStretch()
self.rightLayout.addStretch()
- QtCore.QObject.connect(self.usePhononCheckBox,
- QtCore.SIGNAL(u'stateChanged(int)'),
- self.onUsePhononCheckBoxChanged)
+ for key in self.media_players:
+ player = self.media_players[key]
+ checkbox = self.PlayerCheckBoxes[player.name]
+ QtCore.QObject.connect(checkbox,
+ QtCore.SIGNAL(u'stateChanged(int)'),
+ self.onPlayerCheckBoxChanged)
+ QtCore.QObject.connect(self.orderingUpButton,
+ QtCore.SIGNAL(u'pressed()'), self.onOrderingUpButtonPressed)
+ QtCore.QObject.connect(self.orderingDownButton,
+ QtCore.SIGNAL(u'pressed()'), self.onOrderingDownButtonPressed)
def retranslateUi(self):
- self.mediaModeGroupBox.setTitle(
- translate('MediaPlugin.MediaTab', 'Media Display'))
- self.usePhononCheckBox.setText(
- translate('MediaPlugin.MediaTab', 'Use Phonon for video playback'))
-
- def onUsePhononCheckBoxChanged(self, check_state):
- self.usePhonon = (check_state == QtCore.Qt.Checked)
- self.usePhononChanged = True
+ self.mediaPlayerGroupBox.setTitle(
+ translate('MediaPlugin.MediaTab', 'Available Media Players'))
+ for key in self.media_players:
+ player = self.media_players[key]
+ checkbox = self.PlayerCheckBoxes[player.name]
+ if player.available:
+ checkbox.setText(player.name)
+ else:
+ checkbox.setText(
+ unicode(translate('MediaPlugin.MediaTab',
+ '%s (unavailable)')) % player.name)
+ self.playerOrderGroupBox.setTitle(
+ translate('MediaPlugin.MediaTab', 'Player Order'))
+ self.orderingDownButton.setText(
+ translate('MediaPlugin.MediaTab', 'Down'))
+ self.orderingUpButton.setText(
+ translate('MediaPlugin.MediaTab', 'Up'))
+ self.AdvancedGroupBox.setTitle(UiStrings().Advanced)
+ self.OverridePlayerCheckBox.setText(
+ translate('MediaPlugin.MediaTab',
+ 'Allow media player to be overriden'))
+
+ def onPlayerCheckBoxChanged(self, check_state):
+ player = self.sender().text()
+ if check_state == QtCore.Qt.Checked:
+ if player not in self.usedPlayers:
+ self.usedPlayers.append(player)
+ else:
+ self.usedPlayers.takeAt(self.usedPlayers.indexOf(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 have to stay active
+ self.PlayerCheckBoxes[u'%s' % player].setEnabled(False)
+ else:
+ self.PlayerCheckBoxes[u'%s' % player].setEnabled(True)
+ self.playerOrderlistWidget.addItem(player)
+
+ def onOrderingUpButtonPressed(self):
+ currentRow = self.playerOrderlistWidget.currentRow()
+ if currentRow > 0:
+ item = self.playerOrderlistWidget.takeItem(currentRow)
+ self.playerOrderlistWidget.insertItem(currentRow - 1, item)
+ self.playerOrderlistWidget.setCurrentRow(currentRow - 1)
+ self.usedPlayers.move(currentRow, currentRow - 1)
+
+ def onOrderingDownButtonPressed(self):
+ currentRow = self.playerOrderlistWidget.currentRow()
+ if currentRow < self.playerOrderlistWidget.count() - 1:
+ item = self.playerOrderlistWidget.takeItem(currentRow)
+ self.playerOrderlistWidget.insertItem(currentRow + 1, item)
+ self.playerOrderlistWidget.setCurrentRow(currentRow + 1)
+ self.usedPlayers.move(currentRow, currentRow + 1)
def load(self):
- self.usePhonon = QtCore.QSettings().value(
- self.settingsSection + u'/use phonon',
- QtCore.QVariant(True)).toBool()
- self.usePhononCheckBox.setChecked(self.usePhonon)
+ self.usedPlayers = QtCore.QSettings().value(
+ self.settingsSection + u'/players',
+ QtCore.QVariant(u'webkit')).toString().split(u',')
+ for key in self.media_players:
+ player = self.media_players[key]
+ checkbox = self.PlayerCheckBoxes[player.name]
+ if player.available and player.name in self.usedPlayers:
+ checkbox.setChecked(True)
+ self.updatePlayerList()
+ self.OverridePlayerCheckBox.setChecked(QtCore.QSettings().value(
+ self.settingsSection + u'/override player',
+ QtCore.QVariant(QtCore.Qt.Unchecked)).toInt()[0])
def save(self):
- oldUsePhonon = QtCore.QSettings().value(
- u'media/use phonon', QtCore.QVariant(True)).toBool()
- if oldUsePhonon != self.usePhonon:
- QtCore.QSettings().setValue(self.settingsSection + u'/use phonon',
- QtCore.QVariant(self.usePhonon))
+ override_changed = False
+ player_string_changed = False
+ oldPlayerString = QtCore.QSettings().value(
+ self.settingsSection + u'/players',
+ QtCore.QVariant(u'webkit')).toString()
+ newPlayerString = self.usedPlayers.join(u',')
+ if oldPlayerString != newPlayerString:
+ # clean old Media stuff
+ QtCore.QSettings().setValue(self.settingsSection + u'/players',
+ QtCore.QVariant(newPlayerString))
+ player_string_changed = True
+ override_changed = True
+ setting_key = self.settingsSection + u'/override player'
+ if QtCore.QSettings().value(setting_key) != \
+ self.OverridePlayerCheckBox.checkState():
+ QtCore.QSettings().setValue(setting_key,
+ QtCore.QVariant(self.OverridePlayerCheckBox.checkState()))
+ override_changed = True
+ if override_changed:
+ Receiver.send_message(u'mediaitem_media_rebuild')
+ if player_string_changed:
+ Receiver.send_message(u'mediaitem_media_rebuild')
Receiver.send_message(u'config_screen_changed')
=== modified file 'openlp/plugins/media/mediaplugin.py'
--- openlp/plugins/media/mediaplugin.py 2011-07-23 21:29:24 +0000
+++ openlp/plugins/media/mediaplugin.py 2011-12-01 18:30:31 +0000
@@ -26,9 +26,7 @@
###############################################################################
import logging
-import mimetypes
-
-from PyQt4.phonon import Phonon
+import os
from openlp.core.lib import Plugin, StringContent, build_icon, translate
from openlp.plugins.media.lib import MediaMediaItem, MediaTab
@@ -40,57 +38,28 @@
def __init__(self, plugin_helpers):
Plugin.__init__(self, u'media', plugin_helpers,
- MediaMediaItem, MediaTab)
+ MediaMediaItem)
self.weight = -6
self.icon_path = u':/plugins/plugin_media.png'
self.icon = build_icon(self.icon_path)
# passed with drag and drop messages
self.dnd_id = u'Media'
- self.additional_extensions = {
- u'audio/ac3': [u'.ac3'],
- u'audio/flac': [u'.flac'],
- u'audio/x-m4a': [u'.m4a'],
- u'audio/midi': [u'.mid', u'.midi'],
- u'audio/x-mp3': [u'.mp3'],
- u'audio/mpeg': [u'.mp3', u'.mp2', u'.mpga', u'.mpega', u'.m4a'],
- u'audio/qcelp': [u'.qcp'],
- u'audio/x-wma': [u'.wma'],
- u'audio/x-ms-wma': [u'.wma'],
- u'video/x-flv': [u'.flv'],
- u'video/x-matroska': [u'.mpv', u'.mkv'],
- u'video/x-wmv': [u'.wmv'],
- u'video/x-ms-wmv': [u'.wmv']}
- self.audio_extensions_list = []
- self.video_extensions_list = []
- mimetypes.init()
- for mimetype in Phonon.BackendCapabilities.availableMimeTypes():
- mimetype = unicode(mimetype)
- if mimetype.startswith(u'audio/'):
- self._addToList(self.audio_extensions_list, mimetype)
- elif mimetype.startswith(u'video/'):
- self._addToList(self.video_extensions_list, mimetype)
+ 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 _addToList(self, list, mimetype):
- # Add all extensions which mimetypes provides us for supported types.
- extensions = mimetypes.guess_all_extensions(unicode(mimetype))
- for extension in extensions:
- ext = u'*%s' % extension
- if ext not in list:
- list.append(ext)
- self.serviceManager.supportedSuffixes(extension[1:])
- 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.
- if mimetype in self.additional_extensions.keys():
- for extension in self.additional_extensions[mimetype]:
- ext = u'*%s' % extension
- if ext not in list:
- list.append(ext)
- self.serviceManager.supportedSuffixes(extension[1:])
- log.info(u'MediaPlugin: %s additional extensions: %s' % (mimetype,
- u' '.join(self.additional_extensions[mimetype])))
+ def getSettingsTab(self, parent):
+ """
+ Create the settings Tab
+ """
+ visible_name = self.getString(StringContent.VisibleName)
+ return MediaTab(parent, self.name, visible_name[u'title'],
+ self.mediaController.mediaPlayers, self.icon_path)
def about(self):
about_text = translate('MediaPlugin', '<strong>Media Plugin</strong>'
@@ -123,3 +92,29 @@
'Add the selected media to the service.')
}
self.setPluginUiTextStrings(tooltips)
+
+ def finalise(self):
+ """
+ Time to tidy up on exit
+ """
+ log.info(u'Media Finalising')
+ self.mediaController.finalise()
+ Plugin.finalise(self)
+
+ def getDisplayCss(self):
+ """
+ Add css style sheets to htmlbuilder
+ """
+ return self.mediaController.get_media_display_css()
+
+ def getDisplayJavaScript(self):
+ """
+ Add javascript functions to htmlbuilder
+ """
+ return self.mediaController.get_media_display_javascript()
+
+ def getDisplayHtml(self):
+ """
+ Add html code to htmlbuilder
+ """
+ return self.mediaController.get_media_display_html()
=== removed file 'resources/forms/mediafilesdialog.ui'
--- resources/forms/mediafilesdialog.ui 2011-08-23 21:48:46 +0000
+++ resources/forms/mediafilesdialog.ui 1970-01-01 00:00:00 +0000
@@ -1,95 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>MediaFilesDialog</class>
- <widget class="QDialog" name="MediaFilesDialog">
- <property name="windowModality">
- <enum>Qt::ApplicationModal</enum>
- </property>
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>400</width>
- <height>300</height>
- </rect>
- </property>
- <property name="windowTitle">
- <string>Select Media File(s)</string>
- </property>
- <property name="modal">
- <bool>true</bool>
- </property>
- <layout class="QVBoxLayout" name="filesVerticalLayout">
- <property name="spacing">
- <number>8</number>
- </property>
- <property name="margin">
- <number>8</number>
- </property>
- <item>
- <widget class="QLabel" name="selectLabel">
- <property name="text">
- <string>Select one or more audio files from the list below, and click OK to import them into this song.</string>
- </property>
- <property name="wordWrap">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QListView" name="fileListView">
- <property name="alternatingRowColors">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QDialogButtonBox" name="buttonBox">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="standardButtons">
- <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- <resources>
- <include location="../images/openlp-2.qrc"/>
- </resources>
- <connections>
- <connection>
- <sender>buttonBox</sender>
- <signal>accepted()</signal>
- <receiver>MediaFilesDialog</receiver>
- <slot>accept()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>248</x>
- <y>254</y>
- </hint>
- <hint type="destinationlabel">
- <x>157</x>
- <y>274</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>buttonBox</sender>
- <signal>rejected()</signal>
- <receiver>MediaFilesDialog</receiver>
- <slot>reject()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>316</x>
- <y>260</y>
- </hint>
- <hint type="destinationlabel">
- <x>286</x>
- <y>274</y>
- </hint>
- </hints>
- </connection>
- </connections>
-</ui>
=== added file 'resources/pyinstaller/hook-openlp.core.ui.media.py'
--- resources/pyinstaller/hook-openlp.core.ui.media.py 1970-01-01 00:00:00 +0000
+++ resources/pyinstaller/hook-openlp.core.ui.media.py 2011-12-01 18:30:31 +0000
@@ -0,0 +1,30 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2011 Raoul Snyman #
+# Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael #
+# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, #
+# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, #
+# Jeffrey Smith, Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode #
+# Woldsund #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it #
+# under the terms of the GNU General Public License as published by the Free #
+# Software Foundation; version 2 of the License. #
+# #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
+# more details. #
+# #
+# You should have received a copy of the GNU General Public License along #
+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
+###############################################################################
+
+hiddenimports = ['openlp.core.ui.media.phononplayer',
+ 'openlp.core.ui.media.vlcplayer',
+ 'openlp.core.ui.media.webkitplayer']
=== modified file 'scripts/windows-builder.py'
--- scripts/windows-builder.py 2011-10-28 13:28:57 +0000
+++ scripts/windows-builder.py 2011-12-01 18:30:31 +0000
@@ -233,6 +233,19 @@
copy(os.path.join(root, filename),
os.path.join(dest_path, filename))
+def copy_media_player():
+ print u'Copying media player...'
+ source = os.path.join(source_path, u'core', u'ui', u'media')
+ dest = os.path.join(dist_path, u'core', u'ui', u'media')
+ for root, dirs, files in os.walk(source):
+ for filename in files:
+ if not filename.endswith(u'.pyc'):
+ dest_path = os.path.join(dest, root[len(source)+1:])
+ if not os.path.exists(dest_path):
+ os.makedirs(dest_path)
+ copy(os.path.join(root, filename),
+ os.path.join(dest_path, filename))
+
def copy_windows_files():
print u'Copying extra files for Windows...'
copy(os.path.join(winres_path, u'OpenLP.ico'),
@@ -355,6 +368,7 @@
run_pyinstaller()
write_version_file()
copy_plugins()
+ copy_media_player()
if os.path.exists(manual_path):
run_sphinx()
run_htmlhelp()
Follow ups