Added Martin's changes to my tree

Resolve confilcts
Get plugins working again and clean up duplicate code
Remove the references to listwithpreviews
This commit is contained in:
Tim Bentley 2009-07-04 06:52:30 +01:00
commit e5a33d2f30
9 changed files with 163 additions and 242 deletions

View File

@ -35,14 +35,18 @@ class ListWithPreviews(QtCore.QAbstractListModel):
self.items = []
self.rowheight = 50
self.maximagewidth = self.rowheight * 16 / 9.0;
if new_preview_function is not None:
self.make_preview=new_preview_function
else:
self.make_preview=self.preview_function
self.preview_function = new_preview_function
def preview_function(self, filename):
def make_preview(self, filename):
if os.path.exists(filename):
preview = QtGui.QImage(filename)
if self.preview_function is not None:
preview=self.preview_function(filename)
else:
preview = QtGui.QImage(filename)
else:
preview = None
if preview is not None:
w = self.maximagewidth;
h = self.rowheight
preview = preview.scaled(w, h, QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation)

View File

@ -23,14 +23,38 @@ import os
from PyQt4 import QtCore, QtGui
from openlp.core.lib.toolbar import *
from openlp.core.lib import translate
from listwithpreviews import ListWithPreviews
from openlp.core.lib import translate, contextMenuAction, contextMenuSeparator
from serviceitem import ServiceItem
class MediaManagerItem(QtGui.QWidget):
"""
MediaManagerItem is a helper widget for plugins.
None of the following *need* to be used, feel free to override
them cmopletely in your plugin's implementation. Alternatively, call them from your
plugin before or after you've done etra things that you need to.
The plugin will be assigned an icon called u':/media/media_' + 'self.ShortPluginName + u'image.png'
which needs to be available in the main resources in order for them to work, you need to have setup
self.TranslationContext
self.PluginTextShort # eg 'Image' for the image plugin
self.ConfigSection - where the items in the media manager are stored
this could potentially be self.PluginTextShort.lower()
self.OnNewPrompt=u'Select Image(s)'
self.OnNewFileMasks=u'Images (*.jpg *jpeg *.gif *.png *.bmp)'
assumes that the new action is to load a file. If not, override onnew
self.ListViewWithDnD_class - there is a base list class with DnD assigned to it (openlp.core.lib.BaseListWithDnD())
each plugin needs to inherit a class from this and pass that *class* (not an instance) to here
via the ListViewWithDnD_class member
self.PreviewFunction - a function which returns a QImage to represent the item (a preview usually)
- no scaling required - that's done later
If this fn is not defined, a default will be used (treat the filename as an image)
"""
global log
log = logging.getLogger(u'MediaManagerItem')
log.info(u'Media Item loaded')
@ -84,61 +108,6 @@ class MediaManagerItem(QtGui.QWidget):
"""
self.Toolbar.addSeparator()
def contextMenuSeparator(self, base):
action = QtGui.QAction(u'', base)
action.setSeparator(True)
return action
def contextMenuAction(self, base, icon, text, slot):
"""
Utility method to help build context menus for plugins
"""
if type(icon) is QtGui.QIcon:
ButtonIcon = icon
elif type(icon) is types.StringType or type(icon) is types.UnicodeType:
ButtonIcon = QtGui.QIcon()
if icon.startswith(u':/'):
ButtonIcon.addPixmap(QtGui.QPixmap(icon), QtGui.QIcon.Normal,
QtGui.QIcon.Off)
else:
ButtonIcon.addPixmap(QtGui.QPixmap.fromImage(QtGui.QImage(icon)),
QtGui.QIcon.Normal, QtGui.QIcon.Off)
action = QtGui.QAction(text, base)
action .setIcon(ButtonIcon)
QtCore.QObject.connect(action, QtCore.SIGNAL(u'triggered()'), slot)
return action
###########################################################################
### None of the following *need* to be used, feel free to override
### them cmopletely in your plugin's implementation. Alternatively, call them from your
### plugin before or after you've done etra things that you need to.
### in order for them to work, you need to have setup
# self.TranslationContext
# self.PluginTextShort # eg "Image" for the image plugin
# self.ConfigSection - where the items in the media manager are stored
# this could potentially be self.PluginTextShort.lower()
# self.IconPath=u'images/images' - allows specific icons to be used
# self.hasFileIcon - Is the file Icon required
# self.hasEditIcon - Is the edit Icon required
# self.hasNewIcon - Is the new Icon required
#
# self.OnNewPrompt=u'Select Image(s)'
# self.OnNewFileMasks=u'Images (*.jpg *jpeg *.gif *.png *.bmp)'
# assumes that the new action is to load a file. If not, override onnew
# self.ListViewWithDnD_class - there is a base list class with DnD assigned to it (openlp.core.lib.BaseListWithDnD())
# each plugin needs to inherit a class from this and pass that *class* (not an instance) to here
# via the ListViewWithDnD_class member
# The assumption is that given that at least two plugins are of the form
# "text with an icon" then all this will help
# even for plugins of another sort, the setup of the right-click menu, common toolbar
# will help to keep things consistent and ease the creation of new plugins
# also a set of completely consistent action anesm then exist
# (onPreviewClick() is always called that, rather than having the
# name of the plugin added in as well... I regard that as a
# feature, I guess others might differ!)
def setupUi(self):
# Add a toolbar
self.addToolbar()
@ -168,7 +137,7 @@ class MediaManagerItem(QtGui.QWidget):
u':'+self.IconPath+ u'_delete.png', self.onDeleteClick, self.PluginTextShort+u'DeleteItem')
## Separator Line ##
self.addToolbarSeparator()
## Preview Button ##
## Preview ##
self.addToolbarButton(
translate(self.TranslationContext, u'Preview '+self.PluginTextShort),
translate(self.TranslationContext, u'Preview the selected item'),
@ -178,7 +147,7 @@ class MediaManagerItem(QtGui.QWidget):
translate(self.TranslationContext, u'Go Live'),
translate(self.TranslationContext, u'Send the selected item live'),
u':/system/system_live.png', self.onLiveClick, u'LiveItem')
## Add Button ##
## Add to service Button ##
self.addToolbarButton(
translate(self.TranslationContext, u'Add '+self.PluginTextShort+u' To Service'),
translate(self.TranslationContext, u'Add the selected item(s) to the service'),
@ -199,26 +168,29 @@ class MediaManagerItem(QtGui.QWidget):
#define and add the context menu
self.ListView.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
if self.hasEditIcon:
self.ListView.addAction(self.contextMenuAction(self.ListView,
self.ListView.addAction(contextMenuAction(self.ListView,
':' +self.IconPath+u'_new.png',
translate(self.TranslationContext, u'&Edit '+self.PluginTextShort),
self.onEditClick))
self.ListView.addAction(self.contextMenuSeparator(self.SongListWidget))
self.ListView.addAction(self.contextMenuAction(
self.ListView.addAction(contextMenuAction(
self.ListView, ':/system/system_preview.png',
translate(self.TranslationContext, u'&Preview '+self.PluginTextShort),
self.onPreviewClick))
self.ListView.addAction(self.contextMenuAction(
self.ListView.addAction(contextMenuAction(
self.ListView, ':/system/system_live.png',
translate(self.TranslationContext, u'&Show Live'),
self.onLiveClick))
self.ListView.addAction(self.contextMenuAction(
self.ListView.addAction(contextMenuAction(
self.ListView, ':/system/system_add.png',
translate(self.TranslationContext, u'&Add to Service'),
self.onAddClick))
QtCore.QObject.connect(self.ListView,
QtCore.SIGNAL(u'doubleClicked(QModelIndex)'), self.onPreviewClick)
def initialise(self):
pass
def addHeaderBar(self):
pass
@ -232,12 +204,15 @@ class MediaManagerItem(QtGui.QWidget):
self.loadList(files)
dir, filename = os.path.split(unicode(files[0]))
self.parent.config.set_last_dir(dir)
#self.parent.config.set_list(self.ConfigSection, self.ListData.getFileList())
self.parent.config.set_list(self.ConfigSection, self.getFileList())
def getFileList(self):
count = 0
while count < len(self.ListView):
filelist = [set.ListView.item(count).text()]
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

View File

@ -21,7 +21,7 @@ import logging
from PyQt4 import QtCore, QtGui
from openlp.core.lib import ServiceItem, MediaManagerItem, Receiver, translate
from openlp.core.lib import ServiceItem, MediaManagerItem, Receiver, translate, contextMenuAction, contextMenuSeparator
from openlp.plugins.bibles.forms import BibleImportForm
class BibleList(QtGui.QListWidget):
@ -215,13 +215,13 @@ class BibleMediaItem(MediaManagerItem):
QtCore.SIGNAL(u'doubleClicked(QModelIndex)'), self.onPreviewClick)
# Context Menus
self.ListView.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
self.ListView.addAction(self.contextMenuAction(
self.ListView.addAction(contextMenuAction(
self.ListView, u':/system/system_preview.png',
translate(u'BibleMediaItem',u'&Preview Verse'), self.onPreviewClick))
self.ListView.addAction(self.contextMenuAction(
self.ListView.addAction(contextMenuAction(
self.ListView, u':/system/system_live.png',
translate(u'BibleMediaItem',u'&Show Live'), self.onLiveClick))
self.ListView.addAction(self.contextMenuAction(
self.ListView.addAction(contextMenuAction(
self.ListView, u':/system/system_add.png',
translate(u'BibleMediaItem',u'&Add to Service'), self.onAddClick))

View File

@ -21,7 +21,7 @@ import logging
from PyQt4 import QtCore, QtGui
from openlp.core.lib import MediaManagerItem, SongXMLParser, ServiceItem, translate
from openlp.core.lib import MediaManagerItem, SongXMLParser, ServiceItem, translate, contextMenuAction, contextMenuSeparator
class CustomList(QtGui.QListWidget):
@ -114,17 +114,17 @@ class CustomMediaItem(MediaManagerItem):
QtCore.SIGNAL(u'doubleClicked(QModelIndex)'), self.onCustomPreviewClick)
#define and add the context menu
self.ListView.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
self.ListView.addAction(self.contextMenuAction(self.ListView,
self.ListView.addAction(contextMenuAction(self.ListView,
':/custom/custom_edit.png', translate(u'CustomMediaItem', u'&Edit Custom'),
self.onCustomEditClick))
self.ListView.addAction(self.contextMenuSeparator(self.ListView))
self.ListView.addAction(self.contextMenuAction(
self.ListView.addAction(contextMenuSeparator(self.ListView))
self.ListView.addAction(contextMenuAction(
self.ListView, ':/system/system_preview.png',
translate(u'CustomMediaItem',u'&Preview Custom'), self.onCustomPreviewClick))
self.ListView.addAction(self.contextMenuAction(
self.ListView.addAction(contextMenuAction(
self.ListView, ':/system/system_live.png',
translate(u'CustomMediaItem',u'&Show Live'), self.onCustomLiveClick))
self.ListView.addAction(self.contextMenuAction(
self.ListView.addAction(contextMenuAction(
self.ListView, ':/system/system_add.png',
translate(u'CustomMediaItem',u'&Add to Service'), self.onCustomAddClick))

View File

@ -53,6 +53,8 @@ class ImageMediaItem(MediaManagerItem):
# this next is a class, not an instance of a class - it will
# be instanced by the base MediaManagerItem
self.ListViewWithDnD_class = ImageListView
self.ServiceItemIconName = u':/media/media_image.png'
MediaManagerItem.__init__(self, parent, icon, title)
#create and install our own slide controller toolbar
imageToolbar = ImageToolbar(self, True)

View File

@ -19,6 +19,12 @@ Place, Suite 330, Boston, MA 02111-1307 USA
"""
import logging
import os
import tempfile
try:
import gst
except:
log = logging.getLogger(u'MediaMediaItemSetup')
log.warning(u'Can\'t generate Videos previews - import gst failed');
from PyQt4 import QtCore, QtGui
@ -26,6 +32,13 @@ from openlp.core.lib import MediaManagerItem, translate
from openlp.plugins.media.lib import MediaTab
from openlp.plugins.media.lib import FileListData
# from listwithpreviews import ListWithPreviews
from openlp.core.lib import MediaManagerItem, ServiceItem, translate, BaseListWithDnD, buildIcon
class MediaListView(BaseListWithDnD):
def __init__(self, parent=None):
self.PluginName = u'Media'
BaseListWithDnD.__init__(self, parent)
class MediaMediaItem(MediaManagerItem):
"""
@ -36,100 +49,98 @@ class MediaMediaItem(MediaManagerItem):
log.info(u'Media Media Item loaded')
def __init__(self, parent, icon, title):
self.TranslationContext = u'MediaPlugin'
self.hasFileIcon = True
self.hasNewIcon = False
self.hasEditIcon = False
self.IconPath = u'images/image'
self.PluginTextShort = u'Media'
self.ConfigSection = u'images'
self.OnNewPrompt = u'Select Media(s)'
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_image.png'
self.PreviewFunction = self.video_get_preview
MediaManagerItem.__init__(self, parent, icon, title)
def setupUi(self):
# Add a toolbar
self.addToolbar()
# Create buttons for the toolbar
## New Media Button ##
self.addToolbarButton(
translate(u'MediaMediaItem',u'New Media'),
translate(u'MediaMediaItem',u'Load Media into openlp.org'),
':/videos/video_load.png', self.onMediaNewClick, 'MediaNewItem')
## Delete Media Button ##
self.addToolbarButton(
translate(u'MediaMediaItem',u'Delete Media'),
translate(u'MediaMediaItem',u'Delete the selected Media item'),
':/videos/video_delete.png', self.onMediaDeleteClick, 'MediaDeleteItem')
## Separator Line ##
self.addToolbarSeparator()
## Preview Media Button ##
self.addToolbarButton(
translate(u'MediaMediaItem',u'Preview Media'),
translate(u'MediaMediaItem',u'Preview the selected Media item'),
':/system/system_preview.png', self.onMediaPreviewClick, 'MediaPreviewItem')
## Live Media Button ##
self.addToolbarButton(
translate(u'MediaMediaItem',u'Go Live'),
translate(u'MediaMediaItem',u'Send the selected Media item live'),
':/system/system_live.png', self.onMediaLiveClick, 'MediaLiveItem')
## Add Media Button ##
self.addToolbarButton(
translate(u'MediaMediaItem',u'Add Media To Service'),
translate(u'MediaMediaItem',u'Add the selected Media items(s) to the service'),
':/system/system_add.png',self.onMediaAddClick, 'MediaAddItem')
## Add the Medialist widget ##
def video_get_preview(self, filename):
"""Gets a preview of the first frame of a video file using
GSTREAMER (non-portable??? - Can't figure out how to do with
Phonon - returns a QImage"""
try:
# Define your pipeline, just as you would at the command prompt.
# This is much easier than trying to create and link each gstreamer element in Python.
# This is great for pipelines that end with a filesink (i.e. there is no audible or visual output)
log.info ("Video preview %s"%( filename))
outfile=tempfile.NamedTemporaryFile(suffix='.png')
cmd=u'filesrc location="%s" ! decodebin ! ffmpegcolorspace ! pngenc ! filesink location="%s"'% (filename, outfile.name)
pipe = gst.parse_launch(cmd)
# Get a reference to the pipeline's bus
bus = pipe.get_bus()
self.MediaListView = QtGui.QListView()
self.MediaListView.setAlternatingRowColors(True)
self.MediaListData = FileListData()
self.MediaListView.setModel(self.MediaListData)
# Set the pipeline's state to PLAYING
pipe.set_state(gst.STATE_PLAYING)
self.PageLayout.addWidget(self.MediaListView)
# Listen to the pipeline's bus indefinitely until we receive a EOS (end of stream) message.
# This is a super important step, or the pipeline might not work as expected. For example,
# in my example pipeline above, the pngenc will not export an actual image unless you have
# this line of code. It just exports a 0 byte png file. So... don't forget this step.
bus.poll(gst.MESSAGE_EOS, -1)
img = QtGui.QImage(outfile.name)
outfile.close()
# os.unlink(outfile.name)
pipe.set_state(gst.STATE_NULL)
return img
except:
log.info("Can't generate video preview for some reason");
import sys
print sys.exc_info()
return None
#define and add the context menu
self.MediaListView.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
self.MediaListView.addAction(self.contextMenuAction(
self.MediaListView, ':/system/system_preview.png',
translate(u'MediaMediaItem',u'&Preview Media'), self.onMediaPreviewClick))
self.MediaListView.addAction(self.contextMenuAction(
self.MediaListView, ':/system/system_live.png',
translate(u'MediaMediaItem',u'&Show Live'), self.onMediaLiveClick))
self.MediaListView.addAction(self.contextMenuAction(
self.MediaListView, ':/system/system_add.png',
translate(u'MediaMediaItem',u'&Add to Service'), self.onMediaAddClick))
def initialise(self):
list = self.parent.config.load_list(u'Media')
self.loadMediaList(list)
def onMediaNewClick(self):
files = QtGui.QFileDialog.getOpenFileNames(None,
translate(u'MediaMediaItem', u'Select Media(s) items'),
self.parent.config.get_last_dir(),
u'Videos (*.avi *.mpeg);;Audio (*.mp3 *.ogg *.wma);;All files (*)')
if len(files) > 0:
self.loadMediaList(files)
dir, filename = os.path.split(unicode(files[0]))
self.parent.config.set_last_dir(dir)
self.parent.config.set_list(u'media', self.MediaListData.getFileList())
def getFileList(self):
filelist = [item[0] for item in self.MediaListView];
return filelist
def loadMediaList(self, list):
for files in list:
self.MediaListData.addRow(files)
def onMediaDeleteClick(self):
indexes = self.MediaListView.selectedIndexes()
def generateSlideData(self, service_item):
indexes = self.ListView.selectedIndexes()
service_item.title = u'Media'
for index in indexes:
current_row = int(index.row())
self.MediaListData.removeRow(current_row)
self.parent.config.set_list(u'media', self.MediaListData.getFileList())
filename = self.ListData.getFilename(index)
frame = QtGui.QImage(unicode(filename))
(path, name) = os.path.split(filename)
service_item.add_from_image(path, name, frame)
def onMediaPreviewClick(self):
def onPreviewClick(self):
log.debug(u'Media Preview Button pressed')
items = self.MediaListView.selectedIndexes()
items = self.ListView.selectedIndexes()
for item in items:
text = self.MediaListData.getValue(item)
text = self.ListData.getValue(item)
print text
def onMediaLiveClick(self):
log.debug(u'Media Live Button pressed')
pass
def onMediaAddClick(self):
pass
def initialise(self):
self.ListView.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
self.ListView.setIconSize(QtCore.QSize(88,50))
self.loadList(self.parent.config.load_list(self.ConfigSection))
def onDeleteClick(self):
item = self.ListView.currentItem()
if item is not None:
item_id = (item.data(QtCore.Qt.UserRole)).toInt()[0]
row = self.ListView.row(item)
self.ListView.takeItem(row)
self.parent.config.set_list(self.ConfigSection, self.ListData.getFileList())
def loadList(self, list):
for file in list:
(path, filename) = os.path.split(unicode(file))
item_name = QtGui.QListWidgetItem(filename)
img = self.video_get_preview(file)
#item_name.setIcon(buildIcon(file))
item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(file))
self.ListView.addItem(item_name)
# def onMediaAddClick(self):
# log.debug(u'Media Add Button pressed')
# pass

View File

@ -22,7 +22,6 @@ from PyQt4 import QtCore, QtGui
from openlp.core.lib import Plugin, MediaManagerItem, SettingsTab
from openlp.plugins.media.lib import MediaTab,MediaMediaItem
class MediaPlugin(Plugin):
def __init__(self, plugin_helpers):

View File

@ -1,70 +0,0 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
"""
OpenLP - Open Source Lyrics Projection
Copyright (c) 2008 Raoul Snyman
Portions copyright (c) 2008 Martin Thompson, Tim Bentley,
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 os
from PyQt4 import QtCore, QtGui
# xxx this needs a try, except once we've decided what to do if it fails
from PyQt4.phonon import Phonon
# from openlp.core.lib import Plugin, MediaManagerItem, SettingsTab
# from openlp.plugins.media.lib import MediaTab,MediaMediaItem
"""Renders a video to some surface or other """
class w(QtGui.QMainWindow):
def __init__(self, parent=None):
super(QtGui.QMainWindow, self).__init__(parent)
self.resize(640,480)
self.setWindowTitle(u'simple media player')
self.show()
if __name__==u'__main__':
app = QtGui.QApplication([])
# widget = QtGui.QWidget()
# widget.resize(320, 240)
# widget.setWindowTitle(u'simple')
# widget.show()
# QCore.QCoreApplication.setApplicationName(u'OpenLP')
mainwindow=w()
widget=QtGui.QWidget(mainwindow)
mainwindow.setCentralWidget(widget)
widget.setLayout(QtGui.QVBoxLayout(widget))
# videofile=u'r-128.rm'
videofile=u'/extra_space/Download/coa360download56Kbps240x160.mpg'
source=Phonon.MediaSource(videofile)
media=Phonon.MediaObject(widget)
media.setCurrentSource(source)
video=Phonon.VideoWidget(widget)
audio=Phonon.AudioOutput(Phonon.MusicCategory)
# controller=Phonon.MediaController(media)
Phonon.createPath(media, video);
Phonon.createPath(media, audio);
# player=Phonon.VideoPlayer(Phonon.VideoCategory, widget)
slider=Phonon.SeekSlider(media, mainwindow)
widget.layout().addWidget(slider)
widget.layout().addWidget(video)
slider.show()
video.show()
media.play()
app.exec_()

View File

@ -20,7 +20,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
import logging
from PyQt4 import QtCore, QtGui
from openlp.core.lib import MediaManagerItem, translate, ServiceItem, SongXMLParser
from openlp.core.lib import MediaManagerItem, translate, ServiceItem, SongXMLParser , contextMenuAction, contextMenuSeparator
from openlp.plugins.songs.forms import EditSongForm
@ -138,17 +138,17 @@ class SongMediaItem(MediaManagerItem):
QtCore.SIGNAL(u'doubleClicked(QModelIndex)'), self.onSongPreviewClick)
#define and add the context menu
self.ListView.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
self.ListView.addAction(self.contextMenuAction(self.ListView,
self.ListView.addAction(contextMenuAction(self.ListView,
':/songs/song_new.png', translate(u'SongMediaItem', u'&Edit Song'),
self.onSongEditClick))
self.ListView.addAction(self.contextMenuSeparator(self.ListView))
self.ListView.addAction(self.contextMenuAction(self.ListView,
self.ListView.addAction(contextMenuSeparator(self.ListView))
self.ListView.addAction(contextMenuAction(self.ListView,
':/system/system_preview.png', translate(u'SongMediaItem', u'&Preview Song'),
self.onSongPreviewClick))
self.ListView.addAction(self.contextMenuAction(self.ListView,
self.ListView.addAction(contextMenuAction(self.ListView,
':/system/system_live.png', translate(u'SongMediaItem', u'&Show Live'),
self.onSongLiveClick))
self.ListView.addAction(self.contextMenuAction(self.ListView,
self.ListView.addAction(contextMenuAction(self.ListView,
':/system/system_add.png', translate(u'SongMediaItem', u'&Add to Service'),
self.onSongAddClick))