diff --git a/openlp/core/lib/__init__.py b/openlp/core/lib/__init__.py index 0aac8dd16..189718d47 100644 --- a/openlp/core/lib/__init__.py +++ b/openlp/core/lib/__init__.py @@ -137,7 +137,7 @@ from settingstab import SettingsTab from mediamanageritem import MediaManagerItem from xmlrootclass import XmlRootClass from serviceitem import ServiceItem -from serviceitem import ServiceType +from serviceitem import ServiceItemType from serviceitem import ServiceItem from toolbar import OpenLPToolbar from dockwidget import OpenLPDockWidget diff --git a/openlp/core/lib/mediamanageritem.py b/openlp/core/lib/mediamanageritem.py index 14606a948..325eb72d3 100644 --- a/openlp/core/lib/mediamanageritem.py +++ b/openlp/core/lib/mediamanageritem.py @@ -388,7 +388,8 @@ class MediaManagerItem(QtGui.QWidget): if self.ServiceItemIconName is not None: service_item.addIcon(self.ServiceItemIconName) else: - service_item.addIcon(self.icon) + service_item.addIcon( + u':/media/media_' + self.PluginNameShort.lower() + u'.png') if self.generateSlideData(service_item): self.ListView.clearSelection() return service_item diff --git a/openlp/core/lib/serviceitem.py b/openlp/core/lib/serviceitem.py index b9c82c798..7fab33ea3 100644 --- a/openlp/core/lib/serviceitem.py +++ b/openlp/core/lib/serviceitem.py @@ -30,13 +30,14 @@ from PyQt4 import QtGui from openlp.core.lib import buildIcon -class ServiceType(object): +class ServiceItemType(object): """ Defines the type of service item """ Text = 1 Image = 2 Command = 3 + Video = 4 class ServiceItem(object): """ @@ -91,7 +92,7 @@ class ServiceItem(object): """ log.debug(u'Render called') self.frames = [] - if self.service_item_type == ServiceType.Text: + if self.service_item_type == ServiceItemType.Text: log.debug(u'Formatting slides') if self.theme is None: self.RenderManager.set_override_theme(None) @@ -109,9 +110,9 @@ class ServiceItem(object): self.frames.append({u'title': title, u'text': lines, u'image': frame}) log.info(u'Formatting took %4s' % (time.time() - before)) - elif self.service_item_type == ServiceType.Command: + elif self.service_item_type == ServiceItemType.Command: self.frames = self.service_frames - elif self.service_item_type == ServiceType.Image: + elif self.service_item_type == ServiceItemType.Image: for slide in self.service_frames: slide[u'image'] = \ self.RenderManager.resize_image(slide[u'image']) @@ -148,10 +149,16 @@ class ServiceItem(object): ``image`` The actual image file name. """ - self.service_item_type = ServiceType.Image + self.service_item_type = ServiceItemType.Image self.service_item_path = path self.service_frames.append( - {u'title': frame_title, u'text':None, u'image': image}) + {u'title': frame_title, u'text': None, u'image': image}) + + def add_from_media(self, path, frame_title, image): + self.service_item_type = ServiceItemType.Video + self.service_item_path = path + self.service_frames.append( + {u'title': frame_title, u'text': None, u'image': image}) def add_from_text(self, frame_title, raw_slide): """ @@ -163,7 +170,7 @@ class ServiceItem(object): ``raw_slide`` The raw text of the slide. """ - self.service_item_type = ServiceType.Text + self.service_item_type = ServiceItemType.Text frame_title = frame_title.split(u'\n')[0] self.service_frames.append( {u'title': frame_title, u'raw_slide': raw_slide}) @@ -178,7 +185,7 @@ class ServiceItem(object): ``command`` The command of/for the slide. """ - self.service_item_type = ServiceType.Command + self.service_item_type = ServiceItemType.Command self.service_item_path = path self.service_frames.append( {u'title': frame_title, u'command': None, u'text':None, u'image': image}) @@ -199,13 +206,16 @@ class ServiceItem(object): u'audit':self.audit } service_data = [] - if self.service_item_type == ServiceType.Text: + if self.service_item_type == ServiceItemType.Text: for slide in self.service_frames: service_data.append(slide) - elif self.service_item_type == ServiceType.Image: + elif self.service_item_type == ServiceItemType.Image: for slide in self.service_frames: service_data.append(slide[u'title']) - elif self.service_item_type == ServiceType.Command: + elif self.service_item_type == ServiceItemType.Command: + for slide in self.service_frames: + service_data.append(slide[u'title']) + elif self.service_item_type == ServiceItemType.Video: for slide in self.service_frames: service_data.append(slide[u'title']) return {u'header': service_header, u'data': service_data} @@ -230,15 +240,17 @@ class ServiceItem(object): self.addIcon(header[u'icon']) self.raw_footer = header[u'footer'] self.audit = header[u'audit'] - if self.service_item_type == ServiceType.Text: + if self.service_item_type == ServiceItemType.Text: for slide in serviceitem[u'serviceitem'][u'data']: self.service_frames.append(slide) - elif self.service_item_type == ServiceType.Image: + elif self.service_item_type == ServiceItemType.Image: for text_image in serviceitem[u'serviceitem'][u'data']: filename = os.path.join(path, text_image) real_image = QtGui.QImage(unicode(filename)) self.add_from_image(path, text_image, real_image) - elif self.service_item_type == ServiceType.Command: + elif self.service_item_type == ServiceItemType.Command: for text_image in serviceitem[u'serviceitem'][u'data']: filename = os.path.join(path, text_image) self.add_from_command(path, text_image) + elif self.service_item_type == ServiceItemType.Video: + pass diff --git a/openlp/core/ui/maindisplay.py b/openlp/core/ui/maindisplay.py index 6f3bf910d..e59f399b4 100644 --- a/openlp/core/ui/maindisplay.py +++ b/openlp/core/ui/maindisplay.py @@ -23,7 +23,10 @@ ############################################################################### import logging +import os + from PyQt4 import QtCore, QtGui +from PyQt4.phonon import Phonon from openlp.core.lib import Receiver, str_to_bool @@ -85,15 +88,23 @@ class MainDisplay(DisplayLabel): self.layout.setSpacing(0) self.layout.setMargin(0) self.layout.setObjectName(u'layout') + self.mediaObject = Phonon.MediaObject(self) + self.video = Phonon.VideoWidget() + self.audio = Phonon.AudioOutput(Phonon.VideoCategory, self.mediaObject) + self.video.setFullScreen(True) + Phonon.createPath(self.mediaObject, self.video) + Phonon.createPath(self.mediaObject, self.audio) + self.layout.insertWidget(0, self.video) self.display = QtGui.QLabel(self) self.display.setScaledContents(True) - self.layout.addWidget(self.display) + self.layout.insertWidget(0, self.display) self.displayBlank = False self.blankFrame = None self.frame = None self.alertactive = False self.alertTab = None self.timer_id = 0 + self.firstTime = True QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'live_slide_blank'), self.blankDisplay) QtCore.QObject.connect(Receiver.get_receiver(), @@ -102,6 +113,17 @@ class MainDisplay(DisplayLabel): QtCore.SIGNAL(u'presentations_start'), self.hideDisplay) QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'presentations_stop'), self.showDisplay) + QtCore.QObject.connect(self.mediaObject, + QtCore.SIGNAL(u'finished()'), self.onMediaFinish) + QtCore.QObject.connect(Receiver.get_receiver(), + QtCore.SIGNAL(u'media_start'), self.onMediaQueue) + QtCore.QObject.connect(Receiver.get_receiver(), + QtCore.SIGNAL(u'media_play'), self.onMediaPlay) + QtCore.QObject.connect(Receiver.get_receiver(), + QtCore.SIGNAL(u'media_pause'), self.onMediaPaws) + QtCore.QObject.connect(Receiver.get_receiver(), + QtCore.SIGNAL(u'media_stop'), self.onMediaFinish) + def setup(self, screenNumber): """ @@ -221,3 +243,28 @@ class MainDisplay(DisplayLabel): self.display.setPixmap(QtGui.QPixmap.fromImage(self.frame)) self.killTimer(self.timer_id) self.timer_id = 0 + + def onMediaQueue(self, message): + self.display.close() + file = os.path.join(message[1], message[2]) + if self.firstTime: + self.mediaObject.setCurrentSource(Phonon.MediaSource(file)) + self.firstTime = False + else: + self.mediaObject.enqueue(Phonon.MediaSource(file)) + self.onMediaPlay() + + def onMediaPlay(self): + self.display.hide() + self.mediaObject.play() + self.setVisible(True) + + def onMediaPaws(self): + self.mediaObject.pause() + + def onMediaFinish(self): + self.setVisible(False) + self.mediaObject.stop() + self.mediaObject.clearQueue() + self.video.close() + self.display.show() diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index 278896e9e..68dc2bd62 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -30,8 +30,8 @@ import zipfile from PyQt4 import QtCore, QtGui from openlp.core.lib import PluginConfig, OpenLPToolbar, ServiceItem, \ - ServiceType, contextMenuAction, contextMenuSeparator, Receiver, \ - contextMenu, str_to_bool + ServiceItemType, contextMenuAction, contextMenuSeparator, contextMenu, \ + Receiver, contextMenu, str_to_bool class ServiceManagerList(QtGui.QTreeWidget): @@ -443,8 +443,8 @@ class ServiceManager(QtGui.QWidget): for item in self.serviceItems: service.append( {u'serviceitem':item[u'data'].get_service_repr()}) - if item[u'data'].service_item_type == ServiceType.Image or \ - item[u'data'].service_item_type == ServiceType.Command: + if item[u'data'].service_item_type == ServiceItemType.Image or \ + item[u'data'].service_item_type == ServiceItemType.Command: for frame in item[u'data'].frames: path_from = unicode(os.path.join( item[u'data'].service_item_path, frame[u'title'])) diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py index d00c045d4..557b468aa 100644 --- a/openlp/core/ui/slidecontroller.py +++ b/openlp/core/ui/slidecontroller.py @@ -26,7 +26,8 @@ import logging import time from PyQt4 import QtCore, QtGui -from openlp.core.lib import OpenLPToolbar, Receiver, ServiceType, str_to_bool, PluginConfig +from openlp.core.lib import OpenLPToolbar, Receiver, ServiceItemType, \ + str_to_bool, PluginConfig class SlideList(QtGui.QTableWidget): """ @@ -79,6 +80,11 @@ class SlideController(QtGui.QWidget): u'Loop Separator', u'Image SpinBox' ] + self.media_list = [ + u'Media Start', + u'Media Stop', + u'Media Pause' + ] self.song_list = [ u'Edit Song', ] @@ -171,6 +177,16 @@ class SlideController(QtGui.QWidget): u'Image SpinBox', self.DelaySpinBox) self.DelaySpinBox.setSuffix(self.trUtf8(u's')) self.DelaySpinBox.setToolTip(self.trUtf8(u'Delay between slides in seconds')) + self.Toolbar.addToolbarButton( + u'Media Start', u':/slides/media_playback_start.png', + self.trUtf8(u'Start playing media'), self.onMediaPlay) + self.Toolbar.addToolbarButton( + u'Media Pause', u':/slides/media_playback_pause.png', + self.trUtf8(u'Start playing media'), self.onMediaPause) + self.Toolbar.addToolbarButton( + u'Media Stop', u':/slides/media_playback_stop.png', + self.trUtf8(u'Start playing media'), self.onMediaStop) + self.ControllerLayout.addWidget(self.Toolbar) # Build the Song Toolbar if isLive: @@ -231,6 +247,7 @@ class SlideController(QtGui.QWidget): Receiver().send_message(u'request_spin_delay') if isLive: self.Toolbar.makeWidgetsInvisible(self.image_list) + self.Toolbar.makeWidgetsInvisible(self.media_list) else: self.Toolbar.makeWidgetsInvisible(self.song_list) QtCore.QObject.connect(Receiver.get_receiver(), @@ -278,7 +295,8 @@ class SlideController(QtGui.QWidget): """ self.Songbar.setVisible(False) self.Toolbar.makeWidgetsInvisible(self.image_list) - if item.service_item_type == ServiceType.Text: + self.Toolbar.makeWidgetsInvisible(self.media_list) + if item.service_item_type == ServiceItemType.Text: self.Toolbar.makeWidgetsInvisible(self.image_list) if item.name == u'Songs' and \ str_to_bool(self.songsconfig.get_config(u'display songbar', True)): @@ -293,10 +311,13 @@ class SlideController(QtGui.QWidget): #More than 20 verses hard luck pass self.Songbar.setVisible(True) - elif item.service_item_type == ServiceType.Image: + elif item.service_item_type == ServiceItemType.Image: #Not sensible to allow loops with 1 frame if len(item.frames) > 1: self.Toolbar.makeWidgetsVisible(self.image_list) + elif item.service_item_type == ServiceItemType.Command and \ + item.name == u'Media': + self.Toolbar.makeWidgetsVisible(self.media_list) def enablePreviewToolBar(self, item): """ @@ -316,14 +337,14 @@ class SlideController(QtGui.QWidget): log.debug(u'addServiceItem') #If old item was a command tell it to stop if self.commandItem is not None and \ - self.commandItem.service_item_type == ServiceType.Command: + self.commandItem.service_item_type == ServiceItemType.Command: Receiver().send_message(u'%s_stop'% self.commandItem.name.lower()) self.commandItem = item before = time.time() item.render() log.info(u'Rendering took %4s' % (time.time() - before)) self.enableToolBar(item) - if item.service_item_type == ServiceType.Command: + if item.service_item_type == ServiceItemType.Command: Receiver().send_message(u'%s_start' % item.name.lower(), \ [item.shortname, item.service_item_path, item.service_frames[0][u'title']]) @@ -350,11 +371,11 @@ class SlideController(QtGui.QWidget): log.debug(u'addServiceManagerItem') #If old item was a command tell it to stop if self.commandItem is not None and \ - self.commandItem.service_item_type == ServiceType.Command: + self.commandItem.service_item_type == ServiceItemType.Command: Receiver().send_message(u'%s_stop'% self.commandItem.name.lower()) self.commandItem = item self.enableToolBar(item) - if item.service_item_type == ServiceType.Command: + if item.service_item_type == ServiceItemType.Command: Receiver().send_message(u'%s_start' % item.name.lower(), \ [item.shortname, item.service_item_path, item.service_frames[0][u'title'], slideno]) @@ -413,7 +434,7 @@ class SlideController(QtGui.QWidget): Go to the first slide. """ if self.commandItem is not None and \ - self.commandItem.service_item_type == ServiceType.Command: + self.commandItem.service_item_type == ServiceItemType.Command: Receiver().send_message(u'%s_first'% self.commandItem.name.lower()) QtCore.QTimer.singleShot(0.5, self.grabMainDisplay) else: @@ -425,7 +446,7 @@ class SlideController(QtGui.QWidget): Blank the screen. """ if self.commandItem is not None and \ - self.commandItem.service_item_type == ServiceType.Command: + self.commandItem.service_item_type == ServiceItemType.Command: if blanked: Receiver().send_message(u'%s_blank'% self.commandItem.name.lower()) else: @@ -441,9 +462,9 @@ class SlideController(QtGui.QWidget): row = self.PreviewListWidget.currentRow() self.row = 0 if row > -1 and row < self.PreviewListWidget.rowCount(): - if self.commandItem.service_item_type == ServiceType.Command: + if self.commandItem.service_item_type == ServiceItemType.Command: Receiver().send_message(u'%s_slide'% self.commandItem.name.lower(), [row]) - if isLive: + if self.isLive: QtCore.QTimer.singleShot(0.5, self.grabMainDisplay) else: frame = self.serviceitem.frames[row][u'image'] @@ -479,7 +500,7 @@ class SlideController(QtGui.QWidget): Go to the next slide. """ if self.commandItem is not None and \ - self.commandItem.service_item_type == ServiceType.Command: + self.commandItem.service_item_type == ServiceItemType.Command: Receiver().send_message(u'%s_next'% self.commandItem.name.lower()) QtCore.QTimer.singleShot(0.5, self.grabMainDisplay) else: @@ -494,7 +515,7 @@ class SlideController(QtGui.QWidget): Go to the previous slide. """ if self.commandItem is not None and \ - self.commandItem.service_item_type == ServiceType.Command: + self.commandItem.service_item_type == ServiceItemType.Command: Receiver().send_message( u'%s_previous'% self.commandItem.name.lower()) QtCore.QTimer.singleShot(0.5, self.grabMainDisplay) @@ -510,7 +531,7 @@ class SlideController(QtGui.QWidget): Go to the last slide. """ if self.commandItem is not None and \ - self.commandItem.service_item_type == ServiceType.Command: + self.commandItem.service_item_type == ServiceItemType.Command: Receiver().send_message(u'%s_last'% self.commandItem.name.lower()) QtCore.QTimer.singleShot(0.5, self.grabMainDisplay) else: @@ -550,3 +571,12 @@ class SlideController(QtGui.QWidget): if row > -1 and row < self.PreviewListWidget.rowCount(): self.parent.LiveController.addServiceManagerItem( self.commandItem, row) + + def onMediaPause(self): + Receiver().send_message(u'%s_pause'% self.commandItem.name.lower()) + + def onMediaPlay(self): + Receiver().send_message(u'%s_play'% self.commandItem.name.lower()) + + def onMediaStop(self): + Receiver().send_message(u'%s_stop'% self.commandItem.name.lower()) diff --git a/openlp/plugins/media/lib/mediaitem.py b/openlp/plugins/media/lib/mediaitem.py index 544e5d767..2a98f78b7 100644 --- a/openlp/plugins/media/lib/mediaitem.py +++ b/openlp/plugins/media/lib/mediaitem.py @@ -45,14 +45,15 @@ class MediaMediaItem(MediaManagerItem): def __init__(self, parent, icon, title): self.PluginNameShort = u'Media' self.IconPath = u'images/image' + self.ConfigSection = u'media' self.ConfigSection = title - self.OnNewFileMasks = \ - u'Videos (*.avi *.mpeg *.mpg *.mp4);;Audio (*.ogg *.mp3 *.wma);;All files (*)' # this next is a class, not an instance of a class - it will # be instanced by the base MediaManagerItem self.ListViewWithDnD_class = MediaListView + self.ServiceItemIconName = u':/media/media_video.png' self.PreviewFunction = self.video_get_preview MediaManagerItem.__init__(self, parent, icon, title) + self.MainDisplay = self.parent.live_controller.parent.mainDisplay def initPluginNameVisible(self): self.PluginNameVisible = self.trUtf8(u'Media') @@ -60,40 +61,61 @@ class MediaMediaItem(MediaManagerItem): def retranslateUi(self): self.OnNewPrompt = self.trUtf8(u'Select Media') + def reTranslateUI(self): + self.OnNewPrompt = self.trUtf8(u'Select Media') + self.OnNewFileMasks = self.trUtf8(u'Videos (*.avi *.mpeg *.mpg' + '*.mp4);;Audio (*.ogg *.mp3 *.wma);;All files (*)') + def requiredIcons(self): MediaManagerItem.requiredIcons(self) self.hasFileIcon = True self.hasNewIcon = False self.hasEditIcon = False - def video_get_preview(self, filename): + def video_get_preview(self): # For now cross platform is an icon. Phonon does not support # individual frame access (yet?) and GStreamer is not available # on Windows return QtGui.QPixmap(u':/media/media_video.png').toImage() def generateSlideData(self, service_item): - indexes = self.ListView.selectedIndexes() - if len(indexes) > 1: + items = self.ListView.selectedIndexes() + if len(items) > 1: return False - service_item.title = u'Media' - for index in indexes: - filename = self.ListData.getFilename(index) - frame = QtGui.QImage(unicode(filename)) + service_item.title = self.trUtf8(u'Media') + for item in items: + bitem = self.ListView.item(item.row()) + filename = unicode((bitem.data(QtCore.Qt.UserRole)).toString()) + frame = u':/media/media_video.png' (path, name) = os.path.split(filename) - service_item.add_from_image(path, name, frame) + #service_item.add_from_image(path, name, frame) + print path + print name + service_item.add_from_command(path, name, frame) return True - def onPreviewClick(self): - log.debug(u'Media Preview Button pressed') - items = self.ListView.selectedIndexes() - for item in items: - text = self.ListData.getValue(item) - print text - - def onMediaLiveClick(self): - log.debug(u'Media Live Button pressed') - pass +# def onPreviewClick(self): +# log.debug(u'Media Preview Button pressed') +# items = self.ListView.selectedIndexes() +# for item in items: +# baseItem = self.ListView.item(item.row()) +# itemText = unicode(baseItem.data(QtCore.Qt.UserRole).toString()) +# print itemText +# +# def onLiveClick(self): +# log.debug(u'Media Live Button pressed') +# items = self.ListView.selectedIndexes() +# if len(items) > 0: +# firstPass = True +# for item in items: +# baseItem = self.ListView.item(item.row()) +# filename = unicode(baseItem.data(QtCore.Qt.UserRole).toString()) +# if firstPass: +# self.MainDisplay.queueMedia(filename, firstPass) +# firstPass = False +# else: +# self.MainDisplay.queueMedia(filename, firstPass) +# self.MainDisplay.playMedia() def initialise(self): self.ListView.setSelectionMode( @@ -113,7 +135,7 @@ class MediaMediaItem(MediaManagerItem): for file in list: (path, filename) = os.path.split(unicode(file)) item_name = QtGui.QListWidgetItem(filename) - img = self.video_get_preview(file) + img = self.video_get_preview() item_name.setIcon(buildIcon(img)) item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(file)) self.ListView.addItem(item_name) diff --git a/openlp/plugins/presentations/lib/mediaitem.py b/openlp/plugins/presentations/lib/mediaitem.py index 550c15b60..b49b37627 100644 --- a/openlp/plugins/presentations/lib/mediaitem.py +++ b/openlp/plugins/presentations/lib/mediaitem.py @@ -51,7 +51,6 @@ class PresentationMediaItem(MediaManagerItem): self.PluginNameShort = u'Presentation' self.ConfigSection = title self.IconPath = u'presentations/presentation' - self.OnNewFileMasks = u'Presentations (*.ppt *.pps *.odp)' # this next is a class, not an instance of a class - it will # be instanced by the base MediaManagerItem self.ListViewWithDnD_class = PresentationListView @@ -64,6 +63,10 @@ class PresentationMediaItem(MediaManagerItem): def retranslateUi(self): self.OnNewPrompt = self.trUtf8(u'Select Presentation(s)') + def reTranslateUI(self): + self.OnNewPrompt = self.trUtf8(u'Select Presentation(s)') + self.OnNewFileMasks = self.trUtf8(u'Presentations (*.ppt *.pps *.odp)') + def requiredIcons(self): MediaManagerItem.requiredIcons(self) self.hasFileIcon = True diff --git a/resources/images/media_playback_pause.png b/resources/images/media_playback_pause.png new file mode 100644 index 000000000..a9b3113fb Binary files /dev/null and b/resources/images/media_playback_pause.png differ diff --git a/resources/images/media_playback_start.png b/resources/images/media_playback_start.png new file mode 100644 index 000000000..80ff3a1d5 Binary files /dev/null and b/resources/images/media_playback_start.png differ diff --git a/resources/images/media_playback_stop.png b/resources/images/media_playback_stop.png new file mode 100644 index 000000000..180280e8b Binary files /dev/null and b/resources/images/media_playback_stop.png differ diff --git a/resources/images/openlp-2.qrc b/resources/images/openlp-2.qrc index 83c88c3e5..f7e6f095f 100644 --- a/resources/images/openlp-2.qrc +++ b/resources/images/openlp-2.qrc @@ -27,6 +27,9 @@ slide_last.png slide_next.png slide_previous.png + media_playback_start.png + media_playback_stop.png + media_playback_pause.png openlp-logo-16x16.png diff --git a/version.txt b/version.txt index 412d069e4..02bb4725f 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.9.0-645 +1.9.0-646