forked from openlp/openlp
Rewrite of the multimedia stuff.
bzr-revno: 1810
This commit is contained in:
commit
e8f0bf5cd1
@ -53,8 +53,8 @@ body {
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0px;
|
left: 0px;
|
||||||
top: 0px;
|
top: 0px;
|
||||||
width: %spx;
|
width: 100%%;
|
||||||
height: %spx;
|
height: 100%%;
|
||||||
}
|
}
|
||||||
#black {
|
#black {
|
||||||
z-index: 8;
|
z-index: 8;
|
||||||
@ -67,12 +67,6 @@ body {
|
|||||||
#image {
|
#image {
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
}
|
}
|
||||||
#video1 {
|
|
||||||
z-index: 3;
|
|
||||||
}
|
|
||||||
#video2 {
|
|
||||||
z-index: 3;
|
|
||||||
}
|
|
||||||
%s
|
%s
|
||||||
#footer {
|
#footer {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -90,90 +84,9 @@ sup {
|
|||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
var timer = null;
|
var timer = null;
|
||||||
var video_timer = null;
|
|
||||||
var current_video = '1';
|
|
||||||
var transition = %s;
|
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
|
%s
|
||||||
|
|
||||||
function show_image(src){
|
function show_image(src){
|
||||||
var img = document.getElementById('image');
|
var img = document.getElementById('image');
|
||||||
img.src = src;
|
img.src = src;
|
||||||
@ -186,18 +99,14 @@ sup {
|
|||||||
function show_blank(state){
|
function show_blank(state){
|
||||||
var black = 'none';
|
var black = 'none';
|
||||||
var lyrics = '';
|
var lyrics = '';
|
||||||
var pause = false;
|
|
||||||
switch(state){
|
switch(state){
|
||||||
case 'theme':
|
case 'theme':
|
||||||
lyrics = 'hidden';
|
lyrics = 'hidden';
|
||||||
pause = true;
|
|
||||||
break;
|
break;
|
||||||
case 'black':
|
case 'black':
|
||||||
black = 'block';
|
black = 'block';
|
||||||
pause = true;
|
|
||||||
break;
|
break;
|
||||||
case 'desktop':
|
case 'desktop':
|
||||||
pause = true;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
document.getElementById('black').style.display = black;
|
document.getElementById('black').style.display = black;
|
||||||
@ -210,13 +119,6 @@ sup {
|
|||||||
if(shadow!=null)
|
if(shadow!=null)
|
||||||
shadow.style.visibility = lyrics;
|
shadow.style.visibility = lyrics;
|
||||||
document.getElementById('footer').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){
|
function show_footer(footertext){
|
||||||
@ -277,10 +179,6 @@ sup {
|
|||||||
<body>
|
<body>
|
||||||
<img id="bgimage" class="size" %s />
|
<img id="bgimage" class="size" %s />
|
||||||
<img id="image" 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
|
||||||
%s
|
%s
|
||||||
<div id="footer" class="footer"></div>
|
<div id="footer" class="footer"></div>
|
||||||
@ -336,7 +234,6 @@ def build_html(item, screen, islive, background, image=None,
|
|||||||
js_additions += plugin.getDisplayJavaScript()
|
js_additions += plugin.getDisplayJavaScript()
|
||||||
html_additions += plugin.getDisplayHtml()
|
html_additions += plugin.getDisplayHtml()
|
||||||
html = HTMLSRC % (build_background_css(item, width, height),
|
html = HTMLSRC % (build_background_css(item, width, height),
|
||||||
width, height,
|
|
||||||
css_additions,
|
css_additions,
|
||||||
build_footer_css(item, height),
|
build_footer_css(item, height),
|
||||||
build_lyrics_css(item, webkitvers),
|
build_lyrics_css(item, webkitvers),
|
||||||
@ -609,4 +506,3 @@ def build_footer_css(item, height):
|
|||||||
item.footer.width(), theme.font_footer_name,
|
item.footer.width(), theme.font_footer_name,
|
||||||
theme.font_footer_size, theme.font_footer_color)
|
theme.font_footer_size, theme.font_footer_color)
|
||||||
return lyrics_html
|
return lyrics_html
|
||||||
|
|
||||||
|
137
openlp/core/lib/mediaplayer.py
Normal file
137
openlp/core/lib/mediaplayer.py
Normal file
@ -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''
|
@ -168,6 +168,7 @@ class Plugin(QtCore.QObject):
|
|||||||
self.mediadock = plugin_helpers[u'toolbox']
|
self.mediadock = plugin_helpers[u'toolbox']
|
||||||
self.pluginManager = plugin_helpers[u'pluginmanager']
|
self.pluginManager = plugin_helpers[u'pluginmanager']
|
||||||
self.formparent = plugin_helpers[u'formparent']
|
self.formparent = plugin_helpers[u'formparent']
|
||||||
|
self.mediaController = plugin_helpers[u'mediacontroller']
|
||||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||||
QtCore.SIGNAL(u'%s_add_service_item' % self.name),
|
QtCore.SIGNAL(u'%s_add_service_item' % self.name),
|
||||||
self.processAddServiceEvent)
|
self.processAddServiceEvent)
|
||||||
@ -395,4 +396,3 @@ class Plugin(QtCore.QObject):
|
|||||||
Add html code to htmlbuilder.
|
Add html code to htmlbuilder.
|
||||||
"""
|
"""
|
||||||
return u''
|
return u''
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ class Renderer(object):
|
|||||||
self.theme_data = None
|
self.theme_data = None
|
||||||
self.bg_frame = None
|
self.bg_frame = None
|
||||||
self.force_page = False
|
self.force_page = False
|
||||||
self.display = MainDisplay(None, self.imageManager, False)
|
self.display = MainDisplay(None, self.imageManager, False, self)
|
||||||
self.display.setup()
|
self.display.setup()
|
||||||
|
|
||||||
def update_display(self):
|
def update_display(self):
|
||||||
@ -87,7 +87,7 @@ class Renderer(object):
|
|||||||
self._calculate_default()
|
self._calculate_default()
|
||||||
if self.display:
|
if self.display:
|
||||||
self.display.close()
|
self.display.close()
|
||||||
self.display = MainDisplay(None, self.imageManager, False)
|
self.display = MainDisplay(None, self.imageManager, False, self)
|
||||||
self.display.setup()
|
self.display.setup()
|
||||||
self.bg_frame = None
|
self.bg_frame = None
|
||||||
self.theme_data = None
|
self.theme_data = None
|
||||||
|
@ -77,10 +77,10 @@ from themeform import ThemeForm
|
|||||||
from filerenameform import FileRenameForm
|
from filerenameform import FileRenameForm
|
||||||
from starttimeform import StartTimeForm
|
from starttimeform import StartTimeForm
|
||||||
from screen import ScreenList
|
from screen import ScreenList
|
||||||
from maindisplay import MainDisplay
|
from maindisplay import MainDisplay, Display
|
||||||
from servicenoteform import ServiceNoteForm
|
from servicenoteform import ServiceNoteForm
|
||||||
from serviceitemeditform import ServiceItemEditForm
|
from serviceitemeditform import ServiceItemEditForm
|
||||||
from slidecontroller import SlideController
|
from slidecontroller import SlideController, Controller
|
||||||
from splashscreen import SplashScreen
|
from splashscreen import SplashScreen
|
||||||
from generaltab import GeneralTab
|
from generaltab import GeneralTab
|
||||||
from themestab import ThemesTab
|
from themestab import ThemesTab
|
||||||
|
@ -31,7 +31,7 @@ and play multimedia within OpenLP.
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from PyQt4 import QtCore, QtGui, QtWebKit
|
from PyQt4 import QtCore, QtGui, QtWebKit, QtOpenGL
|
||||||
from PyQt4.phonon import Phonon
|
from PyQt4.phonon import Phonon
|
||||||
|
|
||||||
from openlp.core.lib import Receiver, build_html, ServiceItem, image_to_byte, \
|
from openlp.core.lib import Receiver, build_html, ServiceItem, image_to_byte, \
|
||||||
@ -44,11 +44,13 @@ log = logging.getLogger(__name__)
|
|||||||
#http://www.steveheffernan.com/html5-video-player/demo-video-player.html
|
#http://www.steveheffernan.com/html5-video-player/demo-video-player.html
|
||||||
#http://html5demos.com/two-videos
|
#http://html5demos.com/two-videos
|
||||||
|
|
||||||
class MainDisplay(QtGui.QGraphicsView):
|
class Display(QtGui.QGraphicsView):
|
||||||
"""
|
"""
|
||||||
This is the display screen.
|
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, imageManager, live):
|
def __init__(self, parent, live, controller):
|
||||||
if live:
|
if live:
|
||||||
QtGui.QGraphicsView.__init__(self)
|
QtGui.QGraphicsView.__init__(self)
|
||||||
# Overwrite the parent() method.
|
# Overwrite the parent() method.
|
||||||
@ -56,12 +58,60 @@ class MainDisplay(QtGui.QGraphicsView):
|
|||||||
else:
|
else:
|
||||||
QtGui.QGraphicsView.__init__(self, parent)
|
QtGui.QGraphicsView.__init__(self, parent)
|
||||||
self.isLive = live
|
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.imageManager = imageManager
|
||||||
self.screens = ScreenList.get_instance()
|
self.screens = ScreenList.get_instance()
|
||||||
self.plugins = PluginManager.get_instance().plugins
|
self.plugins = PluginManager.get_instance().plugins
|
||||||
self.rebuildCSS = False
|
self.rebuildCSS = False
|
||||||
self.hideMode = None
|
self.hideMode = None
|
||||||
self.videoHide = False
|
|
||||||
self.override = {}
|
self.override = {}
|
||||||
self.retranslateUi()
|
self.retranslateUi()
|
||||||
self.mediaObject = None
|
self.mediaObject = None
|
||||||
@ -80,9 +130,6 @@ class MainDisplay(QtGui.QGraphicsView):
|
|||||||
QtCore.SIGNAL(u'live_display_hide'), self.hideDisplay)
|
QtCore.SIGNAL(u'live_display_hide'), self.hideDisplay)
|
||||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||||
QtCore.SIGNAL(u'live_display_show'), self.showDisplay)
|
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.QObject.connect(Receiver.get_receiver(),
|
||||||
QtCore.SIGNAL(u'update_display_css'), self.cssChanged)
|
QtCore.SIGNAL(u'update_display_css'), self.cssChanged)
|
||||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||||
@ -115,36 +162,9 @@ class MainDisplay(QtGui.QGraphicsView):
|
|||||||
Set up and build the output screen
|
Set up and build the output screen
|
||||||
"""
|
"""
|
||||||
log.debug(u'Start MainDisplay setup (live = %s)' % self.isLive)
|
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.screen = self.screens.current
|
||||||
self.setVisible(False)
|
self.setVisible(False)
|
||||||
self.setGeometry(self.screen[u'size'])
|
Display.setup(self)
|
||||||
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)
|
|
||||||
if self.isLive:
|
if self.isLive:
|
||||||
# Build the initial frame.
|
# Build the initial frame.
|
||||||
image_file = QtCore.QSettings().value(u'advanced/default image',
|
image_file = QtCore.QSettings().value(u'advanced/default image',
|
||||||
@ -180,24 +200,6 @@ class MainDisplay(QtGui.QGraphicsView):
|
|||||||
self.primary = True
|
self.primary = True
|
||||||
log.debug(u'Finished MainDisplay setup')
|
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):
|
def text(self, slide):
|
||||||
"""
|
"""
|
||||||
Add the slide text from slideController
|
Add the slide text from slideController
|
||||||
@ -221,8 +223,8 @@ class MainDisplay(QtGui.QGraphicsView):
|
|||||||
The text to be displayed.
|
The text to be displayed.
|
||||||
"""
|
"""
|
||||||
log.debug(u'alert to display')
|
log.debug(u'alert to display')
|
||||||
if self.height() != self.screen[u'size'].height() or not \
|
if self.height() != self.screen[u'size'].height() or \
|
||||||
self.isVisible() or self.videoWidget.isVisible():
|
not self.isVisible():
|
||||||
shrink = True
|
shrink = True
|
||||||
js = u'show_alert("%s", "%s")' % (
|
js = u'show_alert("%s", "%s")' % (
|
||||||
text.replace(u'\\', u'\\\\').replace(u'\"', u'\\\"'),
|
text.replace(u'\\', u'\\\\').replace(u'\"', u'\\\"'),
|
||||||
@ -233,22 +235,18 @@ class MainDisplay(QtGui.QGraphicsView):
|
|||||||
text.replace(u'\\', u'\\\\').replace(u'\"', u'\\\"'))
|
text.replace(u'\\', u'\\\\').replace(u'\"', u'\\\"'))
|
||||||
height = self.frame.evaluateJavaScript(js)
|
height = self.frame.evaluateJavaScript(js)
|
||||||
if shrink:
|
if shrink:
|
||||||
if self.phononActive:
|
|
||||||
shrinkItem = self.webView
|
|
||||||
else:
|
|
||||||
shrinkItem = self
|
|
||||||
if text:
|
if text:
|
||||||
alert_height = int(height.toString())
|
alert_height = int(height.toString())
|
||||||
shrinkItem.resize(self.width(), alert_height)
|
self.resize(self.width(), alert_height)
|
||||||
shrinkItem.setVisible(True)
|
self.setVisible(True)
|
||||||
if location == AlertLocation.Middle:
|
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)
|
(self.screen[u'size'].height() - alert_height) / 2)
|
||||||
elif location == AlertLocation.Bottom:
|
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)
|
self.screen[u'size'].height() - alert_height)
|
||||||
else:
|
else:
|
||||||
shrinkItem.setVisible(False)
|
self.setVisible(False)
|
||||||
self.setGeometry(self.screen[u'size'])
|
self.setGeometry(self.screen[u'size'])
|
||||||
|
|
||||||
def directImage(self, name, path, background):
|
def directImage(self, name, path, background):
|
||||||
@ -276,7 +274,7 @@ class MainDisplay(QtGui.QGraphicsView):
|
|||||||
"""
|
"""
|
||||||
log.debug(u'image to display')
|
log.debug(u'image to display')
|
||||||
image = self.imageManager.get_image_bytes(name)
|
image = self.imageManager.get_image_bytes(name)
|
||||||
self.resetVideo()
|
self.controller.mediaController.video_reset(self.controller)
|
||||||
self.displayImage(image)
|
self.displayImage(image)
|
||||||
|
|
||||||
def displayImage(self, image):
|
def displayImage(self, image):
|
||||||
@ -303,135 +301,6 @@ class MainDisplay(QtGui.QGraphicsView):
|
|||||||
# clear the cache
|
# clear the cache
|
||||||
self.override = {}
|
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):
|
def preview(self):
|
||||||
"""
|
"""
|
||||||
Generates a preview of the image displayed.
|
Generates a preview of the image displayed.
|
||||||
@ -511,16 +380,12 @@ class MainDisplay(QtGui.QGraphicsView):
|
|||||||
if serviceItem.foot_text:
|
if serviceItem.foot_text:
|
||||||
self.footer(serviceItem.foot_text)
|
self.footer(serviceItem.foot_text)
|
||||||
# if was hidden keep it hidden
|
# if was hidden keep it hidden
|
||||||
if self.hideMode and self.isLive:
|
if self.hideMode and self.isLive and not serviceItem.is_media():
|
||||||
if QtCore.QSettings().value(u'general/auto unblank',
|
if QtCore.QSettings().value(u'general/auto unblank',
|
||||||
QtCore.QVariant(False)).toBool():
|
QtCore.QVariant(False)).toBool():
|
||||||
Receiver.send_message(u'slidecontroller_live_unblank')
|
Receiver.send_message(u'slidecontroller_live_unblank')
|
||||||
else:
|
else:
|
||||||
self.hideDisplay(self.hideMode)
|
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()
|
self.__hideMouse()
|
||||||
|
|
||||||
def footer(self, text):
|
def footer(self, text):
|
||||||
@ -538,8 +403,6 @@ class MainDisplay(QtGui.QGraphicsView):
|
|||||||
Store the images so they can be replaced when required
|
Store the images so they can be replaced when required
|
||||||
"""
|
"""
|
||||||
log.debug(u'hideDisplay mode = %d', mode)
|
log.debug(u'hideDisplay mode = %d', mode)
|
||||||
if self.phononActive:
|
|
||||||
self.videoPause()
|
|
||||||
if mode == HideMode.Screen:
|
if mode == HideMode.Screen:
|
||||||
self.frame.evaluateJavaScript(u'show_blank("desktop");')
|
self.frame.evaluateJavaScript(u'show_blank("desktop");')
|
||||||
self.setVisible(False)
|
self.setVisible(False)
|
||||||
@ -550,7 +413,6 @@ class MainDisplay(QtGui.QGraphicsView):
|
|||||||
if mode != HideMode.Screen:
|
if mode != HideMode.Screen:
|
||||||
if self.isHidden():
|
if self.isHidden():
|
||||||
self.setVisible(True)
|
self.setVisible(True)
|
||||||
if self.phononActive:
|
|
||||||
self.webView.setVisible(True)
|
self.webView.setVisible(True)
|
||||||
self.hideMode = mode
|
self.hideMode = mode
|
||||||
|
|
||||||
@ -564,9 +426,6 @@ class MainDisplay(QtGui.QGraphicsView):
|
|||||||
self.frame.evaluateJavaScript('show_blank("show");')
|
self.frame.evaluateJavaScript('show_blank("show");')
|
||||||
if self.isHidden():
|
if self.isHidden():
|
||||||
self.setVisible(True)
|
self.setVisible(True)
|
||||||
if self.phononActive:
|
|
||||||
self.webView.setVisible(False)
|
|
||||||
self.videoPlay()
|
|
||||||
self.hideMode = None
|
self.hideMode = None
|
||||||
# Trigger actions when display is active again
|
# Trigger actions when display is active again
|
||||||
if self.isLive:
|
if self.isLive:
|
||||||
|
@ -42,6 +42,7 @@ from openlp.core.lib.ui import UiStrings, base_action, checkable_action, \
|
|||||||
from openlp.core.ui import AboutForm, SettingsForm, ServiceManager, \
|
from openlp.core.ui import AboutForm, SettingsForm, ServiceManager, \
|
||||||
ThemeManager, SlideController, PluginForm, MediaDockManager, \
|
ThemeManager, SlideController, PluginForm, MediaDockManager, \
|
||||||
ShortcutListForm, FormattingTagForm
|
ShortcutListForm, FormattingTagForm
|
||||||
|
from openlp.core.ui.media import MediaController
|
||||||
from openlp.core.utils import AppLocation, add_actions, LanguageManager, \
|
from openlp.core.utils import AppLocation, add_actions, LanguageManager, \
|
||||||
get_application_version, delete_file
|
get_application_version, delete_file
|
||||||
from openlp.core.utils.actions import ActionList, CategoryOrder
|
from openlp.core.utils.actions import ActionList, CategoryOrder
|
||||||
@ -557,6 +558,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
|
|||||||
self.pluginManager = PluginManager(pluginpath)
|
self.pluginManager = PluginManager(pluginpath)
|
||||||
self.pluginHelpers = {}
|
self.pluginHelpers = {}
|
||||||
self.imageManager = ImageManager()
|
self.imageManager = ImageManager()
|
||||||
|
self.mediaController = MediaController(self)
|
||||||
# Set up the interface
|
# Set up the interface
|
||||||
self.setupUi(self)
|
self.setupUi(self)
|
||||||
# Load settings after setupUi so default UI sizes are overwritten
|
# Load settings after setupUi so default UI sizes are overwritten
|
||||||
@ -644,6 +646,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
|
|||||||
self.pluginHelpers[u'toolbox'] = self.mediaDockManager
|
self.pluginHelpers[u'toolbox'] = self.mediaDockManager
|
||||||
self.pluginHelpers[u'pluginmanager'] = self.pluginManager
|
self.pluginHelpers[u'pluginmanager'] = self.pluginManager
|
||||||
self.pluginHelpers[u'formparent'] = self
|
self.pluginHelpers[u'formparent'] = self
|
||||||
|
self.pluginHelpers[u'mediacontroller'] = self.mediaController
|
||||||
self.pluginManager.find_plugins(pluginpath, self.pluginHelpers)
|
self.pluginManager.find_plugins(pluginpath, self.pluginHelpers)
|
||||||
# hook methods have to happen after find_plugins. Find plugins needs
|
# hook methods have to happen after find_plugins. Find plugins needs
|
||||||
# the controllers hence the hooks have moved from setupUI() to here
|
# the controllers hence the hooks have moved from setupUI() to here
|
||||||
|
65
openlp/core/ui/media/__init__.py
Normal file
65
openlp/core/ui/media/__init__.py
Normal file
@ -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
|
576
openlp/core/ui/media/mediacontroller.py
Normal file
576
openlp/core/ui/media/mediacontroller.py
Normal file
@ -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)
|
201
openlp/core/ui/media/phononplayer.py
Normal file
201
openlp/core/ui/media/phononplayer.py
Normal file
@ -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())
|
426
openlp/core/ui/media/webkitplayer.py
Normal file
426
openlp/core/ui/media/webkitplayer.py
Normal file
@ -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)
|
@ -34,9 +34,9 @@ from PyQt4 import QtCore, QtGui
|
|||||||
from PyQt4.phonon import Phonon
|
from PyQt4.phonon import Phonon
|
||||||
|
|
||||||
from openlp.core.lib import OpenLPToolbar, Receiver, ItemCapabilities, \
|
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.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
|
from openlp.core.utils.actions import ActionList, CategoryOrder
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
@ -49,8 +49,29 @@ class SlideList(QtGui.QTableWidget):
|
|||||||
def __init__(self, parent=None, name=None):
|
def __init__(self, parent=None, name=None):
|
||||||
QtGui.QTableWidget.__init__(self, parent.controller)
|
QtGui.QTableWidget.__init__(self, parent.controller)
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
class SlideController(QtGui.QWidget):
|
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
|
SlideController is the slide controller widget. This widget is what the
|
||||||
user uses to control the displaying of verses/slides/etc on the screen.
|
user uses to control the displaying of verses/slides/etc on the screen.
|
||||||
@ -59,13 +80,12 @@ class SlideController(QtGui.QWidget):
|
|||||||
"""
|
"""
|
||||||
Set up the Slide Controller.
|
Set up the Slide Controller.
|
||||||
"""
|
"""
|
||||||
QtGui.QWidget.__init__(self, parent)
|
Controller.__init__(self, parent, isLive)
|
||||||
self.isLive = isLive
|
|
||||||
self.display = None
|
|
||||||
self.screens = ScreenList.get_instance()
|
self.screens = ScreenList.get_instance()
|
||||||
self.ratio = float(self.screens.current[u'size'].width()) / \
|
self.ratio = float(self.screens.current[u'size'].width()) / \
|
||||||
float(self.screens.current[u'size'].height())
|
float(self.screens.current[u'size'].height())
|
||||||
self.imageManager = self.parent().imageManager
|
self.imageManager = self.parent().imageManager
|
||||||
|
self.mediaController = self.parent().mediaController
|
||||||
self.loopList = [
|
self.loopList = [
|
||||||
u'Play Slides Menu',
|
u'Play Slides Menu',
|
||||||
u'Loop Separator',
|
u'Loop Separator',
|
||||||
@ -74,7 +94,10 @@ class SlideController(QtGui.QWidget):
|
|||||||
self.songEditList = [
|
self.songEditList = [
|
||||||
u'Edit Song',
|
u'Edit Song',
|
||||||
]
|
]
|
||||||
self.volume = 10
|
self.nextPreviousList = [
|
||||||
|
u'Previous Slide',
|
||||||
|
u'Next Slide'
|
||||||
|
]
|
||||||
self.timer_id = 0
|
self.timer_id = 0
|
||||||
self.songEdit = False
|
self.songEdit = False
|
||||||
self.selectedRow = 0
|
self.selectedRow = 0
|
||||||
@ -140,14 +163,14 @@ class SlideController(QtGui.QWidget):
|
|||||||
self.toolbar.sizePolicy().hasHeightForWidth())
|
self.toolbar.sizePolicy().hasHeightForWidth())
|
||||||
self.toolbar.setSizePolicy(sizeToolbarPolicy)
|
self.toolbar.setSizePolicy(sizeToolbarPolicy)
|
||||||
self.previousItem = self.toolbar.addToolbarButton(
|
self.previousItem = self.toolbar.addToolbarButton(
|
||||||
translate('OpenLP.SlideController', 'Previous Slide'),
|
u'Previous Slide',
|
||||||
u':/slides/slide_previous.png',
|
u':/slides/slide_previous.png',
|
||||||
translate('OpenLP.SlideController', 'Move to previous.'),
|
translate('OpenLP.SlideController', 'Move to previous.'),
|
||||||
self.onSlideSelectedPrevious,
|
self.onSlideSelectedPrevious,
|
||||||
shortcuts=[QtCore.Qt.Key_Up, QtCore.Qt.Key_PageUp],
|
shortcuts=[QtCore.Qt.Key_Up, QtCore.Qt.Key_PageUp],
|
||||||
context=QtCore.Qt.WidgetWithChildrenShortcut)
|
context=QtCore.Qt.WidgetWithChildrenShortcut)
|
||||||
self.nextItem = self.toolbar.addToolbarButton(
|
self.nextItem = self.toolbar.addToolbarButton(
|
||||||
translate('OpenLP.SlideController', 'Next Slide'),
|
u'Next Slide',
|
||||||
u':/slides/slide_next.png',
|
u':/slides/slide_next.png',
|
||||||
translate('OpenLP.SlideController', 'Move to next.'),
|
translate('OpenLP.SlideController', 'Move to next.'),
|
||||||
self.onSlideSelectedNext,
|
self.onSlideSelectedNext,
|
||||||
@ -234,20 +257,8 @@ class SlideController(QtGui.QWidget):
|
|||||||
'Edit and reload song preview.'),
|
'Edit and reload song preview.'),
|
||||||
self.onEditSong)
|
self.onEditSong)
|
||||||
self.controllerLayout.addWidget(self.toolbar)
|
self.controllerLayout.addWidget(self.toolbar)
|
||||||
# Build a Media ToolBar
|
# Build the Media Toolbar
|
||||||
self.mediabar = OpenLPToolbar(self)
|
self.mediaController.add_controller_items(self, self.controllerLayout)
|
||||||
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)
|
|
||||||
if self.isLive:
|
if self.isLive:
|
||||||
# Build the Song Toolbar
|
# Build the Song Toolbar
|
||||||
self.songMenu = QtGui.QToolButton(self.toolbar)
|
self.songMenu = QtGui.QToolButton(self.toolbar)
|
||||||
@ -263,23 +274,6 @@ class SlideController(QtGui.QWidget):
|
|||||||
translate('OpenLP.SlideController', 'Pause audio.'),
|
translate('OpenLP.SlideController', 'Pause audio.'),
|
||||||
self.onAudioPauseClicked, True)
|
self.onAudioPauseClicked, True)
|
||||||
self.audioPauseItem.setVisible(False)
|
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
|
# Screen preview area
|
||||||
self.previewFrame = QtGui.QFrame(self.splitter)
|
self.previewFrame = QtGui.QFrame(self.splitter)
|
||||||
self.previewFrame.setGeometry(QtCore.QRect(0, 0, 300, 300 * self.ratio))
|
self.previewFrame.setGeometry(QtCore.QRect(0, 0, 300, 300 * self.ratio))
|
||||||
@ -296,17 +290,13 @@ class SlideController(QtGui.QWidget):
|
|||||||
self.slideLayout = QtGui.QVBoxLayout()
|
self.slideLayout = QtGui.QVBoxLayout()
|
||||||
self.slideLayout.setSpacing(0)
|
self.slideLayout.setSpacing(0)
|
||||||
self.slideLayout.setMargin(0)
|
self.slideLayout.setMargin(0)
|
||||||
self.slideLayout.setObjectName(u'slideLayout')
|
self.slideLayout.setObjectName(u'SlideLayout')
|
||||||
if not self.isLive:
|
self.previewDisplay = Display(self, self.isLive, self)
|
||||||
self.mediaObject = Phonon.MediaObject(self)
|
self.previewDisplay.setGeometry(QtCore.QRect(0, 0, 300, 300))
|
||||||
self.video = Phonon.VideoWidget()
|
self.previewDisplay.screen = {u'size':self.previewDisplay.geometry()}
|
||||||
self.video.setVisible(False)
|
self.previewDisplay.setup()
|
||||||
self.audio = Phonon.AudioOutput(Phonon.VideoCategory,
|
self.slideLayout.insertWidget(0, self.previewDisplay)
|
||||||
self.mediaObject)
|
self.previewDisplay.hide()
|
||||||
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)
|
|
||||||
# Actual preview screen
|
# Actual preview screen
|
||||||
self.slidePreview = QtGui.QLabel(self)
|
self.slidePreview = QtGui.QLabel(self)
|
||||||
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed,
|
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed,
|
||||||
@ -415,8 +405,6 @@ class SlideController(QtGui.QWidget):
|
|||||||
QtCore.QObject.connect(self.previewListWidget,
|
QtCore.QObject.connect(self.previewListWidget,
|
||||||
QtCore.SIGNAL(u'clicked(QModelIndex)'), self.onSlideSelected)
|
QtCore.SIGNAL(u'clicked(QModelIndex)'), self.onSlideSelected)
|
||||||
if self.isLive:
|
if self.isLive:
|
||||||
QtCore.QObject.connect(self.volumeSlider,
|
|
||||||
QtCore.SIGNAL(u'sliderReleased()'), self.mediaVolume)
|
|
||||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||||
QtCore.SIGNAL(u'slidecontroller_live_spin_delay'),
|
QtCore.SIGNAL(u'slidecontroller_live_spin_delay'),
|
||||||
self.receiveSpinDelay)
|
self.receiveSpinDelay)
|
||||||
@ -426,7 +414,6 @@ class SlideController(QtGui.QWidget):
|
|||||||
QtCore.SIGNAL(u'doubleClicked(QModelIndex)'),
|
QtCore.SIGNAL(u'doubleClicked(QModelIndex)'),
|
||||||
self.onGoLiveClick)
|
self.onGoLiveClick)
|
||||||
self.toolbar.makeWidgetsInvisible(self.songEditList)
|
self.toolbar.makeWidgetsInvisible(self.songEditList)
|
||||||
self.mediabar.setVisible(False)
|
|
||||||
if self.isLive:
|
if self.isLive:
|
||||||
self.setLiveHotkeys(self)
|
self.setLiveHotkeys(self)
|
||||||
self.__addActionsToWidget(self.previewListWidget)
|
self.__addActionsToWidget(self.previewListWidget)
|
||||||
@ -577,7 +564,7 @@ class SlideController(QtGui.QWidget):
|
|||||||
|
|
||||||
def liveEscape(self):
|
def liveEscape(self):
|
||||||
self.display.setVisible(False)
|
self.display.setVisible(False)
|
||||||
self.display.videoStop()
|
self.mediaController.video_stop([self])
|
||||||
|
|
||||||
def servicePrevious(self):
|
def servicePrevious(self):
|
||||||
"""
|
"""
|
||||||
@ -617,14 +604,22 @@ class SlideController(QtGui.QWidget):
|
|||||||
# rebuild display as screen size changed
|
# rebuild display as screen size changed
|
||||||
if self.display:
|
if self.display:
|
||||||
self.display.close()
|
self.display.close()
|
||||||
self.display = MainDisplay(self, self.imageManager, self.isLive)
|
self.display = MainDisplay(self, self.imageManager, self.isLive,
|
||||||
|
self)
|
||||||
self.display.setup()
|
self.display.setup()
|
||||||
if self.isLive:
|
if self.isLive:
|
||||||
self.__addActionsToWidget(self.display)
|
self.__addActionsToWidget(self.display)
|
||||||
# The SlidePreview's ratio.
|
# The SlidePreview's ratio.
|
||||||
self.ratio = float(self.screens.current[u'size'].width()) / \
|
self.ratio = float(self.screens.current[u'size'].width()) / \
|
||||||
float(self.screens.current[u'size'].height())
|
float(self.screens.current[u'size'].height())
|
||||||
|
self.mediaController.setup_display(self.display)
|
||||||
self.previewSizeChanged()
|
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:
|
if self.serviceItem:
|
||||||
self.refreshServiceItem()
|
self.refreshServiceItem()
|
||||||
|
|
||||||
@ -646,11 +641,17 @@ class SlideController(QtGui.QWidget):
|
|||||||
max_height = self.previewFrame.height() - self.grid.margin() * 2
|
max_height = self.previewFrame.height() - self.grid.margin() * 2
|
||||||
self.slidePreview.setFixedSize(QtCore.QSize(max_height * self.ratio,
|
self.slidePreview.setFixedSize(QtCore.QSize(max_height * self.ratio,
|
||||||
max_height))
|
max_height))
|
||||||
|
self.previewDisplay.setFixedSize(QtCore.QSize(max_height * self.ratio,
|
||||||
|
max_height))
|
||||||
|
self.previewDisplay.screen = {u'size':self.previewDisplay.geometry()}
|
||||||
else:
|
else:
|
||||||
# We have to take the width as limit.
|
# We have to take the width as limit.
|
||||||
max_width = self.previewFrame.width() - self.grid.margin() * 2
|
max_width = self.previewFrame.width() - self.grid.margin() * 2
|
||||||
self.slidePreview.setFixedSize(QtCore.QSize(max_width,
|
self.slidePreview.setFixedSize(QtCore.QSize(max_width,
|
||||||
max_width / self.ratio))
|
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.
|
# Make sure that the frames have the correct size.
|
||||||
self.previewListWidget.setColumnWidth(0,
|
self.previewListWidget.setColumnWidth(0,
|
||||||
self.previewListWidget.viewport().size().width())
|
self.previewListWidget.viewport().size().width())
|
||||||
@ -711,12 +712,13 @@ class SlideController(QtGui.QWidget):
|
|||||||
len(item.get_frames()) > 1:
|
len(item.get_frames()) > 1:
|
||||||
self.toolbar.makeWidgetsVisible(self.loopList)
|
self.toolbar.makeWidgetsVisible(self.loopList)
|
||||||
if item.is_media():
|
if item.is_media():
|
||||||
self.toolbar.setVisible(False)
|
|
||||||
self.mediabar.setVisible(True)
|
self.mediabar.setVisible(True)
|
||||||
|
self.toolbar.makeWidgetsInvisible(self.nextPreviousList)
|
||||||
else:
|
else:
|
||||||
# Work-around for OS X, hide and then show the toolbar
|
# Work-around for OS X, hide and then show the toolbar
|
||||||
# See bug #791050
|
# See bug #791050
|
||||||
self.toolbar.show()
|
self.toolbar.makeWidgetsVisible(self.nextPreviousList)
|
||||||
|
self.toolbar.show()
|
||||||
|
|
||||||
def enablePreviewToolBar(self, item):
|
def enablePreviewToolBar(self, item):
|
||||||
"""
|
"""
|
||||||
@ -730,13 +732,13 @@ class SlideController(QtGui.QWidget):
|
|||||||
if item.is_capable(ItemCapabilities.CanEdit) and item.from_plugin:
|
if item.is_capable(ItemCapabilities.CanEdit) and item.from_plugin:
|
||||||
self.toolbar.makeWidgetsVisible(self.songEditList)
|
self.toolbar.makeWidgetsVisible(self.songEditList)
|
||||||
elif item.is_media():
|
elif item.is_media():
|
||||||
self.toolbar.setVisible(False)
|
|
||||||
self.mediabar.setVisible(True)
|
self.mediabar.setVisible(True)
|
||||||
self.volumeSlider.setAudioOutput(self.audio)
|
self.toolbar.makeWidgetsInvisible(self.nextPreviousList)
|
||||||
if not item.is_media():
|
if not item.is_media():
|
||||||
# Work-around for OS X, hide and then show the toolbar
|
# Work-around for OS X, hide and then show the toolbar
|
||||||
# See bug #791050
|
# See bug #791050
|
||||||
self.toolbar.show()
|
self.toolbar.makeWidgetsVisible(self.nextPreviousList)
|
||||||
|
self.toolbar.show()
|
||||||
|
|
||||||
def refreshServiceItem(self):
|
def refreshServiceItem(self):
|
||||||
"""
|
"""
|
||||||
@ -1325,72 +1327,18 @@ class SlideController(QtGui.QWidget):
|
|||||||
"""
|
"""
|
||||||
log.debug(u'SlideController onMediaStart')
|
log.debug(u'SlideController onMediaStart')
|
||||||
file = os.path.join(item.get_frame_path(), item.get_frame_title())
|
file = os.path.join(item.get_frame_path(), item.get_frame_title())
|
||||||
if self.isLive:
|
self.mediaController.video(self, file, False, False)
|
||||||
self.display.video(file, self.volume)
|
if not self.isLive or self.mediaController.withLivePreview:
|
||||||
self.volumeSlider.setValue(self.volume)
|
self.previewDisplay.show()
|
||||||
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.slidePreview.hide()
|
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):
|
def onMediaClose(self):
|
||||||
"""
|
"""
|
||||||
Respond to a request to close the Video
|
Respond to a request to close the Video
|
||||||
"""
|
"""
|
||||||
log.debug(u'SlideController onMediaStop')
|
log.debug(u'SlideController onMediaClose')
|
||||||
if self.isLive:
|
self.mediaController.video_reset(self)
|
||||||
self.display.resetVideo()
|
self.previewDisplay.hide()
|
||||||
else:
|
|
||||||
self.mediaObject.stop()
|
|
||||||
self.mediaObject.clearQueue()
|
|
||||||
self.video.hide()
|
|
||||||
self.slidePreview.clear()
|
|
||||||
self.slidePreview.show()
|
self.slidePreview.show()
|
||||||
|
|
||||||
def _resetBlank(self):
|
def _resetBlank(self):
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
from datetime import datetime
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import locale
|
import locale
|
||||||
@ -34,12 +33,17 @@ from PyQt4 import QtCore, QtGui
|
|||||||
from PyQt4.phonon import Phonon
|
from PyQt4.phonon import Phonon
|
||||||
|
|
||||||
from openlp.core.lib import MediaManagerItem, build_icon, ItemCapabilities, \
|
from openlp.core.lib import MediaManagerItem, build_icon, ItemCapabilities, \
|
||||||
SettingsManager, translate, check_item_selected, Receiver, MediaType
|
SettingsManager, translate, check_item_selected, Receiver, MediaType, \
|
||||||
from openlp.core.lib.ui import UiStrings, critical_error_message_box
|
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__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
CLAPPERBOARD = QtGui.QImage(u':/media/media_video.png')
|
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):
|
class MediaMediaItem(MediaManagerItem):
|
||||||
"""
|
"""
|
||||||
@ -51,16 +55,40 @@ class MediaMediaItem(MediaManagerItem):
|
|||||||
self.iconPath = u'images/image'
|
self.iconPath = u'images/image'
|
||||||
self.background = False
|
self.background = False
|
||||||
self.previewFunction = CLAPPERBOARD
|
self.previewFunction = CLAPPERBOARD
|
||||||
|
self.Automatic = u''
|
||||||
MediaManagerItem.__init__(self, parent, plugin, icon)
|
MediaManagerItem.__init__(self, parent, plugin, icon)
|
||||||
self.singleServiceItem = False
|
self.singleServiceItem = False
|
||||||
self.hasSearch = True
|
self.hasSearch = True
|
||||||
self.mediaObject = None
|
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.QObject.connect(Receiver.get_receiver(),
|
||||||
QtCore.SIGNAL(u'video_background_replaced'),
|
QtCore.SIGNAL(u'video_background_replaced'),
|
||||||
self.videobackgroundReplaced)
|
self.videobackgroundReplaced)
|
||||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||||
QtCore.SIGNAL(u'openlp_phonon_creation'),
|
QtCore.SIGNAL(u'mediaitem_media_rebuild'), self.rebuild)
|
||||||
self.createPhonon)
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||||
|
QtCore.SIGNAL(u'config_screen_changed'), self.displaySetup)
|
||||||
# Allow DnD from the desktop
|
# Allow DnD from the desktop
|
||||||
self.listView.activateDnD()
|
self.listView.activateDnD()
|
||||||
|
|
||||||
@ -74,6 +102,10 @@ class MediaMediaItem(MediaManagerItem):
|
|||||||
self.replaceAction.setToolTip(UiStrings().ReplaceLiveBG)
|
self.replaceAction.setToolTip(UiStrings().ReplaceLiveBG)
|
||||||
self.resetAction.setText(UiStrings().ResetBG)
|
self.resetAction.setText(UiStrings().ResetBG)
|
||||||
self.resetAction.setToolTip(UiStrings().ResetLiveBG)
|
self.resetAction.setToolTip(UiStrings().ResetLiveBG)
|
||||||
|
self.Automatic = translate('MediaPlugin.MediaItem',
|
||||||
|
'Automatic')
|
||||||
|
self.displayTypeLabel.setText(
|
||||||
|
translate('MediaPlugin.MediaItem', 'Use Player:'))
|
||||||
|
|
||||||
def requiredIcons(self):
|
def requiredIcons(self):
|
||||||
MediaManagerItem.requiredIcons(self)
|
MediaManagerItem.requiredIcons(self)
|
||||||
@ -92,13 +124,34 @@ class MediaMediaItem(MediaManagerItem):
|
|||||||
self.resetAction = self.addToolbarButton(u'', u'',
|
self.resetAction = self.addToolbarButton(u'', u'',
|
||||||
u':/system/system_close.png', self.onResetClick, False)
|
u':/system/system_close.png', self.onResetClick, False)
|
||||||
self.resetAction.setVisible(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):
|
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.resetAction.setVisible(False)
|
||||||
self.plugin.liveController.display.resetVideo()
|
|
||||||
|
|
||||||
def videobackgroundReplaced(self):
|
def videobackgroundReplaced(self):
|
||||||
"""
|
"""
|
||||||
@ -108,7 +161,7 @@ class MediaMediaItem(MediaManagerItem):
|
|||||||
|
|
||||||
def onReplaceClick(self):
|
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,
|
if check_item_selected(self.listView,
|
||||||
translate('MediaPlugin.MediaItem',
|
translate('MediaPlugin.MediaItem',
|
||||||
@ -116,8 +169,8 @@ class MediaMediaItem(MediaManagerItem):
|
|||||||
item = self.listView.currentItem()
|
item = self.listView.currentItem()
|
||||||
filename = unicode(item.data(QtCore.Qt.UserRole).toString())
|
filename = unicode(item.data(QtCore.Qt.UserRole).toString())
|
||||||
if os.path.exists(filename):
|
if os.path.exists(filename):
|
||||||
(path, name) = os.path.split(filename)
|
if self.plugin.liveController.mediaController.video( \
|
||||||
if self.plugin.liveController.display.video(filename, 0, True):
|
self.plugin.liveController, filename, True, True):
|
||||||
self.resetAction.setVisible(True)
|
self.resetAction.setVisible(True)
|
||||||
else:
|
else:
|
||||||
critical_error_message_box(UiStrings().LiveBGError,
|
critical_error_message_box(UiStrings().LiveBGError,
|
||||||
@ -144,30 +197,18 @@ class MediaMediaItem(MediaManagerItem):
|
|||||||
unicode(translate('MediaPlugin.MediaItem',
|
unicode(translate('MediaPlugin.MediaItem',
|
||||||
'The file %s no longer exists.')) % filename)
|
'The file %s no longer exists.')) % filename)
|
||||||
return False
|
return False
|
||||||
self.mediaObject.stop()
|
self.mediaLength = 0
|
||||||
self.mediaObject.clearQueue()
|
if self.plugin.mediaController.video( \
|
||||||
self.mediaObject.setCurrentSource(Phonon.MediaSource(filename))
|
self.mediaController, filename, False, False):
|
||||||
if not self.mediaStateWait(Phonon.StoppedState):
|
self.mediaLength = self.mediaController.media_info.length
|
||||||
critical_error_message_box(UiStrings().UnsupportedFile,
|
service_item.media_length = self.mediaLength
|
||||||
UiStrings().UnsupportedFile)
|
self.plugin.mediaController.video_reset(self.mediaController)
|
||||||
|
if self.mediaLength > 0:
|
||||||
|
service_item.add_capability(
|
||||||
|
ItemCapabilities.HasVariableStartTime)
|
||||||
|
else:
|
||||||
return False
|
return False
|
||||||
# File too big for processing
|
service_item.media_length = self.mediaLength
|
||||||
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.title = unicode(self.plugin.nameStrings[u'singular'])
|
service_item.title = unicode(self.plugin.nameStrings[u'singular'])
|
||||||
service_item.add_capability(ItemCapabilities.RequiresMedia)
|
service_item.add_capability(ItemCapabilities.RequiresMedia)
|
||||||
# force a non-existent theme
|
# force a non-existent theme
|
||||||
@ -177,23 +218,49 @@ class MediaMediaItem(MediaManagerItem):
|
|||||||
service_item.add_from_command(path, name, frame)
|
service_item.add_from_command(path, name, frame)
|
||||||
return True
|
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):
|
def initialise(self):
|
||||||
self.listView.clear()
|
self.listView.clear()
|
||||||
self.listView.setIconSize(QtCore.QSize(88, 50))
|
self.listView.setIconSize(QtCore.QSize(88, 50))
|
||||||
self.loadList(SettingsManager.load_list(self.settingsSection, u'media'))
|
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):
|
def onDeleteClick(self):
|
||||||
"""
|
"""
|
||||||
@ -214,10 +281,18 @@ class MediaMediaItem(MediaManagerItem):
|
|||||||
media.sort(cmp=locale.strcoll,
|
media.sort(cmp=locale.strcoll,
|
||||||
key=lambda filename: os.path.split(unicode(filename))[1].lower())
|
key=lambda filename: os.path.split(unicode(filename))[1].lower())
|
||||||
for track in media:
|
for track in media:
|
||||||
filename = os.path.split(unicode(track))[1]
|
track_info = QtCore.QFileInfo(track)
|
||||||
item_name = QtGui.QListWidgetItem(filename)
|
if not track_info.isFile():
|
||||||
item_name.setIcon(build_icon(CLAPPERBOARD))
|
filename = os.path.split(unicode(track))[1]
|
||||||
item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(track))
|
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)
|
item_name.setToolTip(track)
|
||||||
self.listView.addItem(item_name)
|
self.listView.addItem(item_name)
|
||||||
|
|
||||||
@ -234,11 +309,6 @@ class MediaMediaItem(MediaManagerItem):
|
|||||||
media = filter(lambda x: os.path.splitext(x)[1] in ext, media)
|
media = filter(lambda x: os.path.splitext(x)[1] in ext, media)
|
||||||
return media
|
return media
|
||||||
|
|
||||||
def createPhonon(self):
|
|
||||||
log.debug(u'CreatePhonon')
|
|
||||||
if not self.mediaObject:
|
|
||||||
self.mediaObject = Phonon.MediaObject(self)
|
|
||||||
|
|
||||||
def search(self, string):
|
def search(self, string):
|
||||||
files = SettingsManager.load_list(self.settingsSection, u'media')
|
files = SettingsManager.load_list(self.settingsSection, u'media')
|
||||||
results = []
|
results = []
|
||||||
|
@ -28,51 +28,181 @@
|
|||||||
from PyQt4 import QtCore, QtGui
|
from PyQt4 import QtCore, QtGui
|
||||||
|
|
||||||
from openlp.core.lib import SettingsTab, translate, Receiver
|
from openlp.core.lib import SettingsTab, translate, Receiver
|
||||||
|
from openlp.core.lib.ui import UiStrings, critical_error_message_box
|
||||||
|
|
||||||
class MediaTab(SettingsTab):
|
class MediaTab(SettingsTab):
|
||||||
"""
|
"""
|
||||||
MediaTab is the Media settings tab in the settings dialog.
|
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)
|
SettingsTab.__init__(self, parent, title, visible_title, icon_path)
|
||||||
|
|
||||||
def setupUi(self):
|
def setupUi(self):
|
||||||
self.setObjectName(u'MediaTab')
|
self.setObjectName(u'MediaTab')
|
||||||
SettingsTab.setupUi(self)
|
SettingsTab.setupUi(self)
|
||||||
self.mediaModeGroupBox = QtGui.QGroupBox(self.leftColumn)
|
self.mediaPlayerGroupBox = QtGui.QGroupBox(self.leftColumn)
|
||||||
self.mediaModeGroupBox.setObjectName(u'mediaModeGroupBox')
|
self.mediaPlayerGroupBox.setObjectName(u'mediaPlayerGroupBox')
|
||||||
self.mediaModeLayout = QtGui.QFormLayout(self.mediaModeGroupBox)
|
self.mediaPlayerLayout = QtGui.QVBoxLayout(self.mediaPlayerGroupBox)
|
||||||
self.mediaModeLayout.setObjectName(u'mediaModeLayout')
|
self.mediaPlayerLayout.setObjectName(u'mediaPlayerLayout')
|
||||||
self.usePhononCheckBox = QtGui.QCheckBox(self.mediaModeGroupBox)
|
self.PlayerCheckBoxes = {}
|
||||||
self.usePhononCheckBox.setObjectName(u'usePhononCheckBox')
|
for key in self.media_players:
|
||||||
self.mediaModeLayout.addRow(self.usePhononCheckBox)
|
player = self.media_players[key]
|
||||||
self.leftLayout.addWidget(self.mediaModeGroupBox)
|
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.leftLayout.addStretch()
|
||||||
self.rightLayout.addStretch()
|
self.rightLayout.addStretch()
|
||||||
QtCore.QObject.connect(self.usePhononCheckBox,
|
for key in self.media_players:
|
||||||
QtCore.SIGNAL(u'stateChanged(int)'),
|
player = self.media_players[key]
|
||||||
self.onUsePhononCheckBoxChanged)
|
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):
|
def retranslateUi(self):
|
||||||
self.mediaModeGroupBox.setTitle(
|
self.mediaPlayerGroupBox.setTitle(
|
||||||
translate('MediaPlugin.MediaTab', 'Media Display'))
|
translate('MediaPlugin.MediaTab', 'Available Media Players'))
|
||||||
self.usePhononCheckBox.setText(
|
for key in self.media_players:
|
||||||
translate('MediaPlugin.MediaTab', 'Use Phonon for video playback'))
|
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 onUsePhononCheckBoxChanged(self, check_state):
|
def onPlayerCheckBoxChanged(self, check_state):
|
||||||
self.usePhonon = (check_state == QtCore.Qt.Checked)
|
player = self.sender().text()
|
||||||
self.usePhononChanged = True
|
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):
|
def load(self):
|
||||||
self.usePhonon = QtCore.QSettings().value(
|
self.usedPlayers = QtCore.QSettings().value(
|
||||||
self.settingsSection + u'/use phonon',
|
self.settingsSection + u'/players',
|
||||||
QtCore.QVariant(True)).toBool()
|
QtCore.QVariant(u'webkit')).toString().split(u',')
|
||||||
self.usePhononCheckBox.setChecked(self.usePhonon)
|
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):
|
def save(self):
|
||||||
oldUsePhonon = QtCore.QSettings().value(
|
override_changed = False
|
||||||
u'media/use phonon', QtCore.QVariant(True)).toBool()
|
player_string_changed = False
|
||||||
if oldUsePhonon != self.usePhonon:
|
oldPlayerString = QtCore.QSettings().value(
|
||||||
QtCore.QSettings().setValue(self.settingsSection + u'/use phonon',
|
self.settingsSection + u'/players',
|
||||||
QtCore.QVariant(self.usePhonon))
|
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')
|
Receiver.send_message(u'config_screen_changed')
|
||||||
|
@ -26,9 +26,7 @@
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import mimetypes
|
import os
|
||||||
|
|
||||||
from PyQt4.phonon import Phonon
|
|
||||||
|
|
||||||
from openlp.core.lib import Plugin, StringContent, build_icon, translate
|
from openlp.core.lib import Plugin, StringContent, build_icon, translate
|
||||||
from openlp.plugins.media.lib import MediaMediaItem, MediaTab
|
from openlp.plugins.media.lib import MediaMediaItem, MediaTab
|
||||||
@ -40,57 +38,28 @@ class MediaPlugin(Plugin):
|
|||||||
|
|
||||||
def __init__(self, plugin_helpers):
|
def __init__(self, plugin_helpers):
|
||||||
Plugin.__init__(self, u'media', plugin_helpers,
|
Plugin.__init__(self, u'media', plugin_helpers,
|
||||||
MediaMediaItem, MediaTab)
|
MediaMediaItem)
|
||||||
self.weight = -6
|
self.weight = -6
|
||||||
self.icon_path = u':/plugins/plugin_media.png'
|
self.icon_path = u':/plugins/plugin_media.png'
|
||||||
self.icon = build_icon(self.icon_path)
|
self.icon = build_icon(self.icon_path)
|
||||||
# passed with drag and drop messages
|
# passed with drag and drop messages
|
||||||
self.dnd_id = u'Media'
|
self.dnd_id = u'Media'
|
||||||
self.additional_extensions = {
|
self.audio_extensions_list = \
|
||||||
u'audio/ac3': [u'.ac3'],
|
self.mediaController.get_audio_extensions_list()
|
||||||
u'audio/flac': [u'.flac'],
|
for ext in self.audio_extensions_list:
|
||||||
u'audio/x-m4a': [u'.m4a'],
|
self.serviceManager.supportedSuffixes(ext[2:])
|
||||||
u'audio/midi': [u'.mid', u'.midi'],
|
self.video_extensions_list = \
|
||||||
u'audio/x-mp3': [u'.mp3'],
|
self.mediaController.get_video_extensions_list()
|
||||||
u'audio/mpeg': [u'.mp3', u'.mp2', u'.mpga', u'.mpega', u'.m4a'],
|
for ext in self.video_extensions_list:
|
||||||
u'audio/qcelp': [u'.qcp'],
|
self.serviceManager.supportedSuffixes(ext[2:])
|
||||||
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)
|
|
||||||
|
|
||||||
def _addToList(self, list, mimetype):
|
def getSettingsTab(self, parent):
|
||||||
# Add all extensions which mimetypes provides us for supported types.
|
"""
|
||||||
extensions = mimetypes.guess_all_extensions(unicode(mimetype))
|
Create the settings Tab
|
||||||
for extension in extensions:
|
"""
|
||||||
ext = u'*%s' % extension
|
visible_name = self.getString(StringContent.VisibleName)
|
||||||
if ext not in list:
|
return MediaTab(parent, self.name, visible_name[u'title'],
|
||||||
list.append(ext)
|
self.mediaController.mediaPlayers, self.icon_path)
|
||||||
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 about(self):
|
def about(self):
|
||||||
about_text = translate('MediaPlugin', '<strong>Media Plugin</strong>'
|
about_text = translate('MediaPlugin', '<strong>Media Plugin</strong>'
|
||||||
@ -123,3 +92,29 @@ class MediaPlugin(Plugin):
|
|||||||
'Add the selected media to the service.')
|
'Add the selected media to the service.')
|
||||||
}
|
}
|
||||||
self.setPluginUiTextStrings(tooltips)
|
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()
|
||||||
|
@ -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>
|
|
30
resources/pyinstaller/hook-openlp.core.ui.media.py
Normal file
30
resources/pyinstaller/hook-openlp.core.ui.media.py
Normal file
@ -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']
|
@ -233,6 +233,19 @@ def copy_plugins():
|
|||||||
copy(os.path.join(root, filename),
|
copy(os.path.join(root, filename),
|
||||||
os.path.join(dest_path, 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():
|
def copy_windows_files():
|
||||||
print u'Copying extra files for Windows...'
|
print u'Copying extra files for Windows...'
|
||||||
copy(os.path.join(winres_path, u'OpenLP.ico'),
|
copy(os.path.join(winres_path, u'OpenLP.ico'),
|
||||||
@ -355,6 +368,7 @@ def main():
|
|||||||
run_pyinstaller()
|
run_pyinstaller()
|
||||||
write_version_file()
|
write_version_file()
|
||||||
copy_plugins()
|
copy_plugins()
|
||||||
|
copy_media_player()
|
||||||
if os.path.exists(manual_path):
|
if os.path.exists(manual_path):
|
||||||
run_sphinx()
|
run_sphinx()
|
||||||
run_htmlhelp()
|
run_htmlhelp()
|
||||||
|
Loading…
Reference in New Issue
Block a user