# -*- coding: utf-8 -*- # vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4 ############################################################################### # OpenLP - Open Source Lyrics Projection # # --------------------------------------------------------------------------- # # Copyright (c) 2008-2010 Raoul Snyman # # Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael # # Gorven, Scott Guerrieri, Meinert Jordan, Andreas Preikschat, Christian # # Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon Tibble, # # Carsten Tinggaard, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # # Software Foundation; version 2 of the License. # # # # This program is distributed in the hope that it will be useful, but WITHOUT # # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # # more details. # # # # You should have received a copy of the GNU General Public License along # # with this program; if not, write to the Free Software Foundation, Inc., 59 # # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### """ Provides the generic functions for interfacing plugins with the Media Manager. """ import logging import os from PyQt4 import QtCore, QtGui from openlp.core.lib import context_menu_action, context_menu_separator, \ SettingsManager, OpenLPToolbar, ServiceItem, build_icon, translate log = logging.getLogger(__name__) class MediaManagerItem(QtGui.QWidget): """ MediaManagerItem is a helper widget for plugins. None of the following *need* to be used, feel free to override them completely in your plugin's implementation. Alternatively, call them from your plugin before or after you've done extra things that you need to. **Constructor Parameters** ``parent`` The parent widget. Usually this will be the *Media Manager* itself. This needs to be a class descended from ``QWidget``. ``icon`` Either a ``QIcon``, a resource path, or a file name. This is the icon which is displayed in the *Media Manager*. ``title`` The title visible on the item in the *Media Manager*. **Member Variables** When creating a descendant class from this class for your plugin, the following member variables should be set. ``self.PluginNameShort`` The shortened (usually singular) name for the plugin e.g. *'Song'* for the Songs plugin. ``self.pluginNameVisible`` The user visible name for a plugin which should use a suitable translation function. ``self.OnNewPrompt`` Defaults to *'Select Image(s)'*. ``self.OnNewFileMasks`` Defaults to *'Images (*.jpg *jpeg *.gif *.png *.bmp)'*. This assumes that the new action is to load a file. If not, you need to override the ``OnNew`` method. ``self.ListViewWithDnD_class`` This must be a **class**, not an object, descended from ``openlp.core.lib.BaseListWithDnD`` that is not used in any other part of OpenLP. ``self.PreviewFunction`` This must be a method which returns a QImage to represent the item (usually a preview). No scaling is required, that is performed automatically by OpenLP when necessary. If this method is not defined, a default will be used (treat the filename as an image). """ log.info(u'Media Item loaded') def __init__(self, parent=None, icon=None, title=None): """ Constructor to create the media manager item. """ QtGui.QWidget.__init__(self) self.parent = parent self.settingsSection = title.lower() if isinstance(icon, QtGui.QIcon): self.icon = icon elif isinstance(icon, basestring): self.icon.addPixmap(QtGui.QPixmap.fromImage(QtGui.QImage(icon)), QtGui.QIcon.Normal, QtGui.QIcon.Off) else: self.icon = None if title: self.title = title self.toolbar = None self.remoteTriggered = None self.serviceItemIconName = None self.singleServiceItem = True self.pageLayout = QtGui.QVBoxLayout(self) self.pageLayout.setSpacing(0) self.pageLayout.setContentsMargins(4, 0, 4, 0) self.requiredIcons() self.setupUi() self.retranslateUi() def requiredIcons(self): """ This method is called to define the icons for the plugin. It provides a default set and the plugin is able to override the if required. """ self.hasImportIcon = False self.hasNewIcon = True self.hasEditIcon = True self.hasFileIcon = False self.hasDeleteIcon = True self.addToServiceItem = False def retranslateUi(self): """ This method is called automatically to provide OpenLP with the opportunity to translate the ``MediaManagerItem`` to another language. """ pass def addToolbar(self): """ A method to help developers easily add a toolbar to the media manager item. """ if self.toolbar is None: self.toolbar = OpenLPToolbar(self) self.pageLayout.addWidget(self.toolbar) def addToolbarButton( self, title, tooltip, icon, slot=None, checkable=False): """ A method to help developers easily add a button to the toolbar. ``title`` The title of the button. ``tooltip`` The tooltip to be displayed when the mouse hovers over the button. ``icon`` The icon of the button. This can be an instance of QIcon, or a string cotaining either the absolute path to the image, or an internal resource path starting with ':/'. ``slot`` The method to call when the button is clicked. ``objectname`` The name of the button. """ # NB different order (when I broke this out, I didn't want to # break compatability), but it makes sense for the icon to # come before the tooltip (as you have to have an icon, but # not neccesarily a tooltip) self.toolbar.addToolbarButton(title, icon, tooltip, slot, checkable) def addToolbarSeparator(self): """ A very simple method to add a separator to the toolbar. """ self.toolbar.addSeparator() def setupUi(self): """ This method sets up the interface on the button. Plugin developers use this to add and create toolbars, and the rest of the interface of the media manager item. """ # Add a toolbar self.addToolbar() #Allow the plugin to define buttons at start of bar self.addStartHeaderBar() #Add the middle of the tool bar (pre defined) self.addMiddleHeaderBar() #Allow the plugin to define buttons at end of bar self.addEndHeaderBar() #Add the list view self.addListViewToToolBar() def addMiddleHeaderBar(self): """ Create buttons for the media item toolbar """ ## Import Button ## if self.hasImportIcon: self.addToolbarButton( unicode(translate('OpenLP.MediaManagerItem', 'Import %s')) % self.PluginNameShort, unicode(translate('OpenLP.MediaManagerItem', 'Import a %s')) % self.pluginNameVisible, u':/general/general_import.png', self.onImportClick) ## File Button ## if self.hasFileIcon: self.addToolbarButton( unicode(translate('OpenLP.MediaManagerItem', 'Load %s')) % self.PluginNameShort, unicode(translate('OpenLP.MediaManagerItem', 'Load a new %s')) % self.pluginNameVisible, u':/general/general_open.png', self.onFileClick) ## New Button ## if self.hasNewIcon: self.addToolbarButton( unicode(translate('OpenLP.MediaManagerItem', 'New %s')) % self.PluginNameShort, unicode(translate('OpenLP.MediaManagerItem', 'Add a new %s')) % self.pluginNameVisible, u':/general/general_new.png', self.onNewClick) ## Edit Button ## if self.hasEditIcon: self.addToolbarButton( unicode(translate('OpenLP.MediaManagerItem', 'Edit %s')) % self.PluginNameShort, unicode(translate( 'OpenLP.MediaManagerItem', 'Edit the selected %s')) % self.pluginNameVisible, u':/general/general_edit.png', self.onEditClick) ## Delete Button ## if self.hasDeleteIcon: self.addToolbarButton( unicode(translate('OpenLP.MediaManagerItem', 'Delete %s')) % self.PluginNameShort, translate('OpenLP.MediaManagerItem', 'Delete the selected item'), u':/general/general_delete.png', self.onDeleteClick) ## Separator Line ## self.addToolbarSeparator() ## Preview ## self.addToolbarButton( unicode(translate('OpenLP.MediaManagerItem', 'Preview %s')) % self.PluginNameShort, translate('OpenLP.MediaManagerItem', 'Preview the selected item'), u':/general/general_preview.png', self.onPreviewClick) ## Live Button ## self.addToolbarButton( u'Go Live', translate('OpenLP.MediaManagerItem', 'Send the selected item live'), u':/general/general_live.png', self.onLiveClick) ## Add to service Button ## self.addToolbarButton( unicode(translate('OpenLP.MediaManagerItem', 'Add %s to Service')) % self.PluginNameShort, translate('OpenLP.MediaManagerItem', 'Add the selected item(s) to the service'), u':/general/general_add.png', self.onAddClick) def addListViewToToolBar(self): """ Creates the main widget for listing items the media item is tracking """ #Add the List widget self.listView = self.ListViewWithDnD_class(self) self.listView.uniformItemSizes = True self.listView.setGeometry(QtCore.QRect(10, 100, 256, 591)) self.listView.setSpacing(1) self.listView.setSelectionMode( QtGui.QAbstractItemView.ExtendedSelection) self.listView.setAlternatingRowColors(True) self.listView.setDragEnabled(True) self.listView.setObjectName(u'%sListView' % self.PluginNameShort) #Add to pageLayout self.pageLayout.addWidget(self.listView) #define and add the context menu self.listView.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu) if self.hasEditIcon: self.listView.addAction( context_menu_action( self.listView, u':/general/general_edit.png', unicode(translate('OpenLP.MediaManagerItem', '&Edit %s')) % self.pluginNameVisible, self.onEditClick)) self.listView.addAction(context_menu_separator(self.listView)) if self.hasDeleteIcon: self.listView.addAction( context_menu_action( self.listView, u':/general/general_delete.png', unicode(translate('OpenLP.MediaManagerItem', '&Delete %s')) % self.pluginNameVisible, self.onDeleteClick)) self.listView.addAction(context_menu_separator(self.listView)) self.listView.addAction( context_menu_action( self.listView, u':/general/general_preview.png', unicode(translate('OpenLP.MediaManagerItem', '&Preview %s')) % self.pluginNameVisible, self.onPreviewClick)) self.listView.addAction( context_menu_action( self.listView, u':/general/general_live.png', translate('OpenLP.MediaManagerItem', '&Show Live'), self.onLiveClick)) self.listView.addAction( context_menu_action( self.listView, u':/general/general_add.png', translate('OpenLP.MediaManagerItem', '&Add to Service'), self.onAddClick)) if self.addToServiceItem: self.listView.addAction( context_menu_action( self.listView, u':/general/general_add.png', translate('OpenLP.MediaManagerItem', '&Add to selected Service Item'), self.onAddEditClick)) if QtCore.QSettings().value(u'advanced/double click live', QtCore.QVariant(False)).toBool(): QtCore.QObject.connect(self.listView, QtCore.SIGNAL(u'doubleClicked(QModelIndex)'), self.onLiveClick) else: QtCore.QObject.connect(self.listView, QtCore.SIGNAL(u'doubleClicked(QModelIndex)'), self.onPreviewClick) def initialise(self): """ Implement this method in your descendent media manager item to do any UI or other initialisation. This method is called automatically. """ pass def addStartHeaderBar(self): """ Slot at start of toolbar for plugin to addwidgets """ pass def addEndHeaderBar(self): """ Slot at end of toolbar for plugin to add widgets """ pass def onFileClick(self): """ Add a file to the list widget to make it available for showing """ files = QtGui.QFileDialog.getOpenFileNames( self, self.OnNewPrompt, SettingsManager.get_last_dir(self.settingsSection), self.OnNewFileMasks) log.info(u'New files(s) %s', unicode(files)) if files: self.loadList(files) lastDir = os.path.split(unicode(files[0]))[0] SettingsManager.set_last_dir(self.settingsSection, lastDir) SettingsManager.set_list(self.settingsSection, self.settingsSection, self.getFileList()) def getFileList(self): """ Return the current list of files """ count = 0 filelist = [] while count < self.listView.count(): bitem = self.listView.item(count) filename = unicode(bitem.data(QtCore.Qt.UserRole).toString()) filelist.append(filename) count += 1 return filelist def validate(self, file, thumb): """ Validates to see if the file still exists or thumbnail is up to date """ if not os.path.exists(file): return False if os.path.exists(thumb): filedate = os.stat(file).st_mtime thumbdate = os.stat(thumb).st_mtime #if file updated rebuild icon if filedate > thumbdate: self.iconFromFile(file, thumb) else: self.iconFromFile(file, thumb) return True def iconFromFile(self, file, thumb): """ Create a thumbnail icon from a given file ``file`` The file to create the icon from ``thumb`` The filename to save the thumbnail to """ icon = build_icon(unicode(file)) pixmap = icon.pixmap(QtCore.QSize(88, 50)) ext = os.path.splitext(thumb)[1].lower() pixmap.save(thumb, ext[1:]) return icon def loadList(self, list): raise NotImplementedError(u'MediaManagerItem.loadList needs to be ' u'defined by the plugin') def onNewClick(self): raise NotImplementedError(u'MediaManagerItem.onNewClick needs to be ' u'defined by the plugin') def onEditClick(self): raise NotImplementedError(u'MediaManagerItem.onEditClick needs to be ' u'defined by the plugin') def onDeleteClick(self): raise NotImplementedError(u'MediaManagerItem.onDeleteClick needs to ' u'be defined by the plugin') def generateSlideData(self, service_item, item=None): raise NotImplementedError(u'MediaManagerItem.generateSlideData needs ' u'to be defined by the plugin') def onPreviewClick(self): """ Preview an item by building a service item then adding that service item to the preview slide controller. """ if not self.listView.selectedIndexes() and not self.remoteTriggered: QtGui.QMessageBox.information(self, translate('OpenLP.MediaManagerItem', 'No Items Selected'), translate('OpenLP.MediaManagerItem', 'You must select one or more items to preview.')) else: log.debug(self.PluginNameShort + u' Preview requested') service_item = self.buildServiceItem() if service_item: service_item.from_plugin = True self.parent.previewController.addServiceItem(service_item) def onLiveClick(self): """ Send an item live by building a service item then adding that service item to the live slide controller. """ if not self.listView.selectedIndexes(): QtGui.QMessageBox.information(self, translate('OpenLP.MediaManagerItem', 'No Items Selected'), translate('OpenLP.MediaManagerItem', 'You must select one or more items to send live.')) else: log.debug(self.PluginNameShort + u' Live requested') service_item = self.buildServiceItem() if service_item: service_item.from_plugin = True self.parent.liveController.addServiceItem(service_item) def onAddClick(self): """ Add a selected item to the current service """ if not self.listView.selectedIndexes() and not self.remoteTriggered: QtGui.QMessageBox.information(self, translate('OpenLP.MediaManagerItem', 'No Items Selected'), translate('OpenLP.MediaManagerItem', 'You must select one or more items.')) else: #Is it posssible to process multiple list items to generate multiple #service items? if self.singleServiceItem or self.remoteTriggered: log.debug(self.PluginNameShort + u' Add requested') service_item = self.buildServiceItem() if service_item: service_item.from_plugin = False self.parent.serviceManager.addServiceItem(service_item, replace=self.remoteTriggered) else: items = self.listView.selectedIndexes() for item in items: service_item = self.buildServiceItem(item) if service_item: service_item.from_plugin = False self.parent.serviceManager.addServiceItem(service_item) def onAddEditClick(self): """ Add a selected item to an existing item in the current service. """ if not self.listView.selectedIndexes() and not self.remoteTriggered: QtGui.QMessageBox.information(self, translate('OpenLP.MediaManagerItem', 'No items selected'), translate('OpenLP.MediaManagerItem', 'You must select one or more items')) else: log.debug(self.PluginNameShort + u' Add requested') service_item = self.parent.serviceManager.getServiceItem() if not service_item: QtGui.QMessageBox.information(self, translate('OpenLP.MediaManagerItem', 'No Service Item Selected'), translate('OpenLP.MediaManagerItem', 'You must select an existing service item to add to.')) elif self.title.lower() == service_item.name.lower(): self.generateSlideData(service_item) self.parent.serviceManager.addServiceItem(service_item, replace=True) else: #Turn off the remote edit update message indicator QtGui.QMessageBox.information(self, translate('OpenLP.MediaManagerItem', 'Invalid Service Item'), unicode(translate('OpenLP.MediaManagerItem', 'You must select a %s service item.')) % self.title) def buildServiceItem(self, item=None): """ Common method for generating a service item """ service_item = ServiceItem(self.parent) if self.serviceItemIconName: service_item.add_icon(self.serviceItemIconName) else: service_item.add_icon(self.parent.icon_path) if self.generateSlideData(service_item, item): return service_item else: return None