[amarok] /: Fix Saved Playlists and Podcasts actions

Matěj Laitl matej at laitl.cz
Mon May 6 21:52:55 UTC 2013


Git commit d3982dc6c2fa2953c37d4864bca61e73aff19a52 by Matěj Laitl.
Committed on 06/05/2013 at 22:48.
Pushed by laitl into branch 'master'.

Fix Saved Playlists and Podcasts actions

After 2 failed attempts to solve this non-intrusively, I realized the
obvious: the actions belong to the view, not the model! (Qt has no
Model/View/Controller, it has Model/View+Controller)

After this it was "easy", just a fair bit of work to move relevant
actions to PlaylistBrowserModel and ensure they work correctly. Some
playlist (and podcast) actions weren't really appropriate for
PlaylistBrowserModel. Methods to get actions from these needed to be
changed, because the old way simply didn't allow reliable action
execution.

When I was at it, I cleaned up a fair bit of things in podcasts (and
playlist providers) - I haven't seen such code bloat in a while -
100-line-long unused function isn't anything surprising there. I'm
pointing at you, Bart. :-)

This regression exists since Ralf's cleanups, although Ralf certainly
didn't introduce it - he just broke the delicate equilibrium of hacks
that kept it working. (and I still think it was working just by chance)

This doesn't go into ChangeLog as it was introduced post-2.7. The code
is not perfect yet (we have lost "Create Empty Playlist" if you clink
into empty space), but the bug this fixes is much more critical.

BUG: 318782
FIXED-IN: 2.8
CCMAIL: amarok-devel at kde.org

M  +12   -103  src/browsers/playlistbrowser/PlaylistBrowserModel.cpp
M  +6    -14   src/browsers/playlistbrowser/PlaylistBrowserModel.h
M  +351  -69   src/browsers/playlistbrowser/PlaylistBrowserView.cpp
M  +36   -21   src/browsers/playlistbrowser/PlaylistBrowserView.h
M  +13   -68   src/browsers/playlistbrowser/PodcastModel.cpp
M  +2    -9    src/browsers/playlistbrowser/PodcastModel.h
M  +13   -30   src/core-impl/collections/ipodcollection/IpodPlaylistProvider.cpp
M  +4    -5    src/core-impl/collections/ipodcollection/IpodPlaylistProvider.h
M  +2    -62   src/core-impl/collections/mediadevicecollection/playlist/MediaDeviceUserPlaylistProvider.cpp
M  +3    -18   src/core-impl/collections/mediadevicecollection/playlist/MediaDeviceUserPlaylistProvider.h
M  +48   -46   src/core-impl/collections/umscollection/podcasts/UmsPodcastProvider.cpp
M  +4    -6    src/core-impl/collections/umscollection/podcasts/UmsPodcastProvider.h
M  +1    -218  src/core-impl/playlists/providers/user/UserPlaylistProvider.cpp
M  +17   -64   src/core-impl/playlists/providers/user/UserPlaylistProvider.h
M  +1    -1    src/core-impl/playlists/types/file/PlaylistFile.h
M  +83   -283  src/core-impl/podcasts/sql/SqlPodcastProvider.cpp
M  +3    -6    src/core-impl/podcasts/sql/SqlPodcastProvider.h
M  +0    -17   src/core/playlists/Playlist.cpp
M  +0    -12   src/core/playlists/Playlist.h
M  +43   -4    src/core/playlists/PlaylistProvider.cpp
M  +50   -19   src/core/playlists/PlaylistProvider.h
M  +1    -26   src/core/podcasts/PodcastProvider.h
M  +1    -1    src/playlistmanager/PlaylistManager.cpp
M  +0    -18   src/playlistmanager/SyncedPlaylist.cpp
M  +0    -3    src/playlistmanager/SyncedPlaylist.h
M  +7    -2    src/playlistmanager/file/PlaylistFileProvider.cpp
M  +3    -9    src/playlistmanager/file/PlaylistFileProvider.h
M  +2    -34   src/playlistmanager/sql/SqlUserPlaylistProvider.cpp
M  +2    -8    src/playlistmanager/sql/SqlUserPlaylistProvider.h
M  +17   -29   src/services/gpodder/GpodderProvider.cpp
M  +3    -2    src/services/gpodder/GpodderProvider.h
M  +1    -1    tests/playlistmanager/file/TestPlaylistFileProvider.cpp
M  +1    -1    tests/playlistmanager/sql/TestSqlUserPlaylistProvider.cpp

http://commits.kde.org/amarok/d3982dc6c2fa2953c37d4864bca61e73aff19a52

diff --git a/src/browsers/playlistbrowser/PlaylistBrowserModel.cpp b/src/browsers/playlistbrowser/PlaylistBrowserModel.cpp
index 6ee3db3..d2b55ff 100644
--- a/src/browsers/playlistbrowser/PlaylistBrowserModel.cpp
+++ b/src/browsers/playlistbrowser/PlaylistBrowserModel.cpp
@@ -41,29 +41,6 @@ lessThanPlaylistTitles( const Playlists::PlaylistPtr &lhs, const Playlists::Play
 PlaylistBrowserModel::PlaylistBrowserModel( int playlistCategory )
     : m_playlistCategory( playlistCategory )
 {
-    m_createEmptyPlaylistAction = new QAction( KIcon( "media-track-add-amarok" ),
-                                               i18n( "Create empty playlist" ),
-                                               this );
-    connect( m_createEmptyPlaylistAction, SIGNAL(triggered()), SLOT(slotCreateEmptyPlaylist()) );
-
-    //common, unconditional actions
-    m_appendAction = new QAction( KIcon( "media-track-add-amarok" ), i18n( "&Add to Playlist" ),
-                                  this );
-    // object name must match one in PlaylistBrowserNS::PlaylistBrowserView
-    m_appendAction->setObjectName( "appendAction" );
-    // key shortcut is only for display purposes here, actual one is determined by View in Model/View classes
-    m_appendAction->setShortcut( Qt::Key_Enter );
-    m_appendAction->setProperty( "popupdropper_svg_id", "append" );
-    connect( m_appendAction, SIGNAL(triggered()), this, SLOT(slotAppend()) );
-
-    m_loadAction = new QAction( KIcon( "folder-open" ),
-                                i18nc( "Replace the currently loaded tracks with these",
-                                       "&Replace Playlist" ),
-                                this );
-    m_loadAction->setObjectName( "loadAction" );
-    m_loadAction->setProperty( "popupdropper_svg_id", "load" );
-    connect( m_loadAction, SIGNAL(triggered()), this, SLOT(slotLoad()) );
-
     connect( The::playlistManager(), SIGNAL(updated(int)), SLOT(slotUpdate(int)) );
 
     connect( The::playlistManager(), SIGNAL(playlistAdded(Playlists::PlaylistPtr,int)),
@@ -93,6 +70,7 @@ PlaylistBrowserModel::data( const QModelIndex &index, int role ) const
     QList<Playlists::PlaylistProvider *> providers =
         The::playlistManager()->getProvidersForPlaylist( playlist );
     Playlists::PlaylistProvider *provider = providers.count() == 1 ? providers.first() : 0;
+    Meta::TrackPtr track;
 
     switch( index.column() )
     {
@@ -100,7 +78,7 @@ PlaylistBrowserModel::data( const QModelIndex &index, int role ) const
         {
             if( IS_TRACK(index) )
             {
-                Meta::TrackPtr track = playlist->tracks()[index.row()];
+                track = playlist->tracks()[index.row()];
                 name = track->prettyName();
                 icon = KIcon( "amarok_track" );
             }
@@ -190,17 +168,17 @@ PlaylistBrowserModel::data( const QModelIndex &index, int role ) const
             if( IS_TRACK(index) )
                 return QVariant();
             else
-                return i18ncp( "number of playlists from one source",
-                               "One playlist", "%1 playlists",
-                               playlistCount );
-        case PrettyTreeRoles::DecoratorRole:
-            return QVariant::fromValue( actionsFor( index ) );
-        case PrettyTreeRoles::DecoratorRoleCount:
-            return actionsFor( index ).count();
+                return i18ncp( "number of playlists from one source", "One playlist",
+                               "%1 playlists", playlistCount );
         case PlaylistBrowserModel::ProviderRole:
-            return provider ? QVariant::fromValue<Playlists::PlaylistProvider *>( provider ) : QVariant();
-
-        default: return QVariant();
+            return provider ? QVariant::fromValue( provider ) : QVariant();
+        case PlaylistBrowserModel::PlaylistRole:
+            return playlist ? QVariant::fromValue( playlist ) : QVariant();
+        case PlaylistBrowserModel::TrackRole:
+            return track ? QVariant::fromValue( track ) : QVariant();
+
+        default:
+            return QVariant();
     }
 }
 
@@ -618,34 +596,6 @@ PlaylistBrowserModel::loadPlaylists()
 }
 
 void
-PlaylistBrowserModel::slotLoad()
-{
-    QAction *action = qobject_cast<QAction *>( QObject::sender() );
-    if( action == 0 )
-        return;
-
-    QModelIndexList indexes = action->data().value<QModelIndexList>();
-
-    Meta::TrackList tracks = tracksFromIndexes( indexes );
-    if( !tracks.isEmpty() )
-        The::playlistController()->insertOptioned( tracks, Playlist::LoadAndPlay );
-}
-
-void
-PlaylistBrowserModel::slotAppend()
-{
-    QAction *action = qobject_cast<QAction *>( QObject::sender() );
-    if( action == 0 )
-        return;
-
-    QModelIndexList indexes = action->data().value<QModelIndexList>();
-
-    Meta::TrackList tracks = tracksFromIndexes( indexes );
-    if( !tracks.isEmpty() )
-        The::playlistController()->insertOptioned( tracks, Playlist::AppendAndPlay );
-}
-
-void
 PlaylistBrowserModel::slotPlaylistAdded( Playlists::PlaylistPtr playlist, int category )
 {
     //ignore playlists of a different category
@@ -709,13 +659,6 @@ PlaylistBrowserModel::slotPlaylistUpdated( Playlists::PlaylistPtr playlist, int
     endInsertRows();
 }
 
-void
-PlaylistBrowserModel::slotCreateEmptyPlaylist()
-{
-    The::playlistManager()->save( Meta::TrackList(),
-                                  Amarok::generatePlaylistName( Meta::TrackList() ) );
-}
-
 Meta::TrackList
 PlaylistBrowserModel::tracksFromIndexes( const QModelIndexList &list ) const
 {
@@ -779,40 +722,6 @@ PlaylistBrowserModel::providerForIndex( const QModelIndex &idx ) const
     return m_playlists.at( playlistRow )->provider();
 }
 
-QActionList
-PlaylistBrowserModel::actionsFor( const QModelIndex &idx ) const
-{
-    if( !idx.isValid() )
-    {
-        QActionList emptyActions;
-        emptyActions << m_createEmptyPlaylistAction;
-        return emptyActions;
-    }
-    //whether we use the list from m_appendAction of m_loadAction does not matter they are the same
-    QModelIndexList actionList = m_appendAction->data().value<QModelIndexList>();
-
-    actionList << idx;
-    QVariant value = QVariant::fromValue( actionList );
-    m_appendAction->setData( value );
-    m_loadAction->setData( value );
-
-    QActionList actions;
-    actions << m_appendAction << m_loadAction;
-
-    if( !IS_TRACK(idx) )
-    {
-        Playlists::PlaylistPtr playlist = m_playlists.value( idx.internalId() );
-        actions << playlist->actions();
-    }
-    else
-    {
-        Playlists::PlaylistPtr playlist = m_playlists.value( idx.parent().internalId() );
-        actions << playlist->trackActions( idx.row() );
-    }
-
-    return actions;
-}
-
 Playlists::PlaylistProvider *
 PlaylistBrowserModel::getProviderByName( const QString &name )
 {
diff --git a/src/browsers/playlistbrowser/PlaylistBrowserModel.h b/src/browsers/playlistbrowser/PlaylistBrowserModel.h
index d507793..6f3d584 100644
--- a/src/browsers/playlistbrowser/PlaylistBrowserModel.h
+++ b/src/browsers/playlistbrowser/PlaylistBrowserModel.h
@@ -39,8 +39,7 @@ namespace PlaylistBrowserNS {
 /**
     @author Bart Cerneels <bart.cerneels at kde.org>
 */
-class PlaylistBrowserModel : public QAbstractItemModel,
-                          public Playlists::PlaylistObserver
+class PlaylistBrowserModel : public QAbstractItemModel, public Playlists::PlaylistObserver
 {
     Q_OBJECT
     public:
@@ -53,8 +52,11 @@ class PlaylistBrowserModel : public QAbstractItemModel,
 
         enum
         {
-            ProviderRole = Qt::UserRole + 21,  // pointer to associated PlaylistProvider
-            CustomRoleOffset = Qt::UserRole + 22 //first role that can be used by sublasses for their own data
+            ProviderRole = Qt::UserRole + 21, // pointer to associated PlaylistProvider
+            PlaylistRole = Qt::UserRole + 22, // PlaylistPtr for associated playlist or null
+            TrackRole = Qt::UserRole + 23, // TrackPtr for associated track or null
+            EpisodeIsNewRole = Qt::UserRole + 24, // for podcast episodes, supports setting, type: bool
+            CustomRoleOffset = Qt::UserRole + 25 //first role that can be used by sublasses for their own data
         };
 
         PlaylistBrowserModel( int PlaylistCategory );
@@ -97,7 +99,6 @@ class PlaylistBrowserModel : public QAbstractItemModel,
 
     protected:
         virtual Playlists::PlaylistList loadPlaylists();
-        virtual QActionList actionsFor( const QModelIndex &idx ) const;
 
         Meta::TrackList tracksFromIndexes( const QModelIndexList &list ) const;
         Meta::TrackPtr trackFromIndex( const QModelIndex &index ) const;
@@ -110,23 +111,14 @@ class PlaylistBrowserModel : public QAbstractItemModel,
         Playlists::PlaylistProvider *getProviderByName( const QString &name );
 
     private slots:
-        void slotLoad();
-        void slotAppend();
         void slotPlaylistAdded( Playlists::PlaylistPtr playlist, int category );
         void slotPlaylistRemoved( Playlists::PlaylistPtr playlist, int category );
         void slotPlaylistUpdated( Playlists::PlaylistPtr playlist, int category );
-        void slotCreateEmptyPlaylist();
 
     private:
         int m_playlistCategory;
-        QAction *m_appendAction;
-        QAction *m_loadAction;
-        QAction *m_createEmptyPlaylistAction;
 };
 
 }
 
-//we store these in a QVariant for the load and append actions
-Q_DECLARE_METATYPE( QModelIndexList )
-
 #endif //AMAROK_PLAYLISTBROWSERMODEL_H
diff --git a/src/browsers/playlistbrowser/PlaylistBrowserView.cpp b/src/browsers/playlistbrowser/PlaylistBrowserView.cpp
index c0e1d1d..4418a06 100644
--- a/src/browsers/playlistbrowser/PlaylistBrowserView.cpp
+++ b/src/browsers/playlistbrowser/PlaylistBrowserView.cpp
@@ -17,11 +17,10 @@
 
 #include "PlaylistBrowserView.h"
 
-#define DEBUG_PREFIX "PlaylistBrowserView"
-
 #include "PaletteHandler.h"
 #include "PopupDropperFactory.h"
 #include "SvgHandler.h"
+#include "amarokconfig.h"
 #include "browsers/playlistbrowser/PlaylistBrowserModel.h"
 #include "browsers/playlistbrowser/PlaylistsByProviderProxy.h"
 #include "browsers/playlistbrowser/PlaylistsInFoldersProxy.h"
@@ -29,22 +28,31 @@
 #include "context/popupdropper/libpud/PopupDropperItem.h"
 #include "context/popupdropper/libpud/PopupDropper.h"
 #include "core/support/Debug.h"
+#include "core-impl/playlists/types/file/PlaylistFileSupport.h"
 #include "playlist/PlaylistModel.h"
 #include "playlist/PlaylistController.h"
+#include "playlistmanager/PlaylistManager.h"
 #include "widgets/PrettyTreeRoles.h"
 
-#include <KAction>
+#include <KFileDialog>
 #include <KGlobalSettings>
 #include <KMenu>
 
 #include <QKeyEvent>
 #include <QMouseEvent>
+#include <QCheckBox>
+#include <QLabel>
+
+#define DEBUG_PREFIX "PlaylistBrowserView"
+
+Q_DECLARE_METATYPE( QModelIndexList )
+
+using namespace PlaylistBrowserNS;
 
 PlaylistBrowserNS::PlaylistBrowserView::PlaylistBrowserView( QAbstractItemModel *model,
                                                              QWidget *parent )
     : Amarok::PrettyTreeView( parent )
     , m_pd( 0 )
-    , m_addFolderAction( 0 )
     , m_ongoingDrag( false )
 {
     DEBUG_BLOCK
@@ -55,10 +63,56 @@ PlaylistBrowserNS::PlaylistBrowserView::PlaylistBrowserView( QAbstractItemModel
     setAcceptDrops( true );
     setEditTriggers( QAbstractItemView::EditKeyPressed );
     setMouseTracking( true ); // needed for highlighting provider action icons
-}
 
-PlaylistBrowserNS::PlaylistBrowserView::~PlaylistBrowserView()
-{
+    m_createEmptyPlaylistAction = new QAction( KIcon( "media-track-add-amarok" ),
+                                               i18n( "Create an Empty Playlist" ), this );
+    connect( m_createEmptyPlaylistAction, SIGNAL(triggered()), SLOT(slotCreateEmptyPlaylist()) );
+
+    m_appendAction = new QAction( KIcon( "media-track-add-amarok" ),
+            i18n( "&Add to Playlist" ), this );
+    // key shortcut is only for display purposes here, actual one is determined by View in Model/View classes
+    m_appendAction->setShortcut( Qt::Key_Enter );
+    m_appendAction->setProperty( "popupdropper_svg_id", "append" );
+    connect( m_appendAction, SIGNAL(triggered()), this, SLOT(slotAppend()) );
+
+    m_loadAction = new QAction( KIcon( "folder-open" ), i18nc( "Replace the currently "
+            "loaded tracks with these", "&Replace Playlist" ), this );
+    m_loadAction->setProperty( "popupdropper_svg_id", "load" );
+    connect( m_loadAction, SIGNAL(triggered()), this, SLOT(slotLoad()) );
+
+    m_setNewAction = new QAction( KIcon( "rating" ), i18nc( "toggle the \"new\" status "
+            " of this podcast episode", "&New" ), this );
+    m_setNewAction->setProperty( "popupdropper_svg_id", "new" );
+    m_setNewAction->setCheckable( true );
+    connect( m_setNewAction, SIGNAL(triggered(bool)), SLOT(slotSetNew(bool)) );
+
+    m_renamePlaylistAction = new QAction( KIcon( "media-track-edit-amarok" ),
+            i18n( "&Rename..." ), this );
+    m_renamePlaylistAction->setProperty( "popupdropper_svg_id", "edit" );
+    // key shortcut is only for display purposes here, actual one is determined by View in Model/View classes
+    m_renamePlaylistAction->setShortcut( Qt::Key_F2 );
+    connect( m_renamePlaylistAction, SIGNAL(triggered()), this, SLOT(slotRename()) );
+
+    m_deletePlaylistAction = new QAction( KIcon( "media-track-remove-amarok" ),
+            i18n( "&Delete..." ), this );
+    m_deletePlaylistAction->setProperty( "popupdropper_svg_id", "delete" );
+    // key shortcut is only for display purposes here, actual one is determined by View in Model/View classes
+    m_deletePlaylistAction->setShortcut( Qt::Key_Delete );
+    connect( m_deletePlaylistAction, SIGNAL(triggered()), SLOT(slotDelete()) );
+
+    m_removeTracksAction = new QAction( KIcon( "media-track-remove-amarok" ),
+            QString( "<placeholder>" ), this );
+    m_removeTracksAction->setProperty( "popupdropper_svg_id", "delete" );
+    // key shortcut is only for display purposes here, actual one is determined by View in Model/View classes
+    m_removeTracksAction->setShortcut( Qt::Key_Delete );
+    connect( m_removeTracksAction, SIGNAL(triggered()), SLOT(slotRemoveTracks()) );
+
+    m_exportAction = new QAction( KIcon( "document-export-amarok" ),
+            i18n( "&Export As..." ), this );
+    connect( m_exportAction, SIGNAL(triggered()), this, SLOT(slotExport()) );
+
+    m_separatorAction = new QAction( this );
+    m_separatorAction->setSeparator( true );
 }
 
 void
@@ -100,7 +154,7 @@ PlaylistBrowserNS::PlaylistBrowserView::mouseReleaseEvent( QMouseEvent *event )
 
 void PlaylistBrowserNS::PlaylistBrowserView::startDrag( Qt::DropActions supportedActions )
 {
-    //Waah? when a parent item is dragged, startDrag is called a bunch of times
+    // Waah? when a parent item is dragged, startDrag is called a bunch of times
     if( m_ongoingDrag )
         return;
     m_ongoingDrag = true;
@@ -108,12 +162,9 @@ void PlaylistBrowserNS::PlaylistBrowserView::startDrag( Qt::DropActions supporte
     if( !m_pd )
         m_pd = The::popupDropperFactory()->createPopupDropper( Context::ContextView::self() );
 
-    QList<QAction *> actions;
-
     if( m_pd && m_pd->isHidden() )
     {
-        actions = actionsFor( selectedIndexes() );
-
+        QActionList actions = actionsFor( selectedIndexes() );
         foreach( QAction *action, actions )
             m_pd->addItem( The::popupDropperFactory()->createItem( action ) );
 
@@ -121,16 +172,13 @@ void PlaylistBrowserNS::PlaylistBrowserView::startDrag( Qt::DropActions supporte
     }
 
     QTreeView::startDrag( supportedActions );
-    debug() << "After the drag!";
 
-    //We keep the items that the actions need to be applied to in the actions private data.
-    //Clear the data from all actions now that the PUD has executed.
-    foreach( QAction *action, actions )
-        action->setData( QVariant() );
+    // We keep the items that the actions need to be applied to.
+    // Clear the data from all actions now that the PUD has executed.
+    resetActionTargets();
 
     if( m_pd )
     {
-        debug() << "clearing PUD";
         connect( m_pd, SIGNAL(fadeHideFinished()), m_pd, SLOT(clear()) );
         m_pd->hide();
     }
@@ -141,7 +189,8 @@ void
 PlaylistBrowserNS::PlaylistBrowserView::keyPressEvent( QKeyEvent *event )
 {
     QModelIndexList indices = selectedIndexes();
-    if( indices.isEmpty() )
+    // mind bug 305203
+    if( indices.isEmpty() || state() != QAbstractItemView::NoState )
     {
         Amarok::PrettyTreeView::keyPressEvent( event );
         return;
@@ -152,20 +201,21 @@ PlaylistBrowserNS::PlaylistBrowserView::keyPressEvent( QKeyEvent *event )
         //activated() only works for current index, not all selected
         case Qt::Key_Enter:
         case Qt::Key_Return:
-            if( state() != EditingState )
-            {
-                //Why do we even get in this state? Shouldn't the editor consume the
-                //keypress? The delete works. see bug 305203
-                appendAndPlay( indices );
-                return;
-            }
-            break;
+            appendAndPlay( indices );
+            return;
         case Qt::Key_Delete:
-            deletePlaylistsTracks( indices );
+        {
+            QActionList actions = actionsFor( indices ); // sets action targets
+            if( actions.contains( m_removeTracksAction ) )
+                m_removeTracksAction->trigger();
+            else if( actions.contains( m_deletePlaylistAction ) )
+                m_deletePlaylistAction->trigger();
+            resetActionTargets();
             return;
+        }
         default:
             break;
-     }
+    }
     Amarok::PrettyTreeView::keyPressEvent( event );
 }
 
@@ -207,56 +257,146 @@ void PlaylistBrowserNS::PlaylistBrowserView::contextMenuEvent( QContextMenuEvent
     QModelIndex clickedIdx = indexAt( event->pos() );
 
     QModelIndexList indices;
-    if( selectedIndexes().contains( clickedIdx ) )
+    if( clickedIdx.isValid() && selectedIndexes().contains( clickedIdx ) )
         indices << selectedIndexes();
-    else
+    else if( clickedIdx.isValid() )
         indices << clickedIdx;
 
     QActionList actions = actionsFor( indices );
-
     if( actions.isEmpty() )
+    {
+        resetActionTargets();
         return;
+    }
 
     KMenu menu;
     foreach( QAction *action, actions )
-    {
-        if( action )
-            menu.addAction( action );
-    }
-
-    if( indices.count() == 0 )
-        menu.addAction( m_addFolderAction );
-
+        menu.addAction( action );
     menu.exec( mapToGlobal( event->pos() ) );
 
-    //We keep the items that the action need to be applied to in the action's private data.
-    //Clear the data from all actions now that the context menu has executed.
-    foreach( QAction *action, actions )
-        action->setData( QVariant() );
+    // We keep the items that the action need to be applied to.
+    // Clear the data from all actions now that the context menu has executed.
+    resetActionTargets();
 }
 
 QList<QAction *>
-PlaylistBrowserNS::PlaylistBrowserView::actionsFor( QModelIndexList indexes )
+PlaylistBrowserNS::PlaylistBrowserView::actionsFor( const QModelIndexList &indexes )
 {
+    resetActionTargets();
+    if( indexes.isEmpty() )
+        return QActionList();
+
+    using namespace Playlists;
+    QSet<PlaylistProvider *> providers, writableProviders;
     QActionList actions;
-    foreach( QModelIndex idx, indexes )
+    QModelIndexList newPodcastEpisodes, oldPodcastEpisodes;
+    foreach( const QModelIndex &idx, indexes )
     {
-        QActionList idxActions = model()->data( idx,
-                PrettyTreeRoles::DecoratorRole ).value<QActionList>();
-        //only add unique actions model is responsible for making them unique
-        foreach( QAction *action, idxActions )
+        // direct provider actions:
+        actions << idx.data( PrettyTreeRoles::DecoratorRole ).value<QActionList>();
+
+        PlaylistProvider *provider = idx.data( PlaylistBrowserModel::ProviderRole ).value<PlaylistProvider *>();
+        if( provider )
+            providers << provider;
+        bool isWritable =  provider ? provider->isWritable() : false;
+        if( isWritable )
+            writableProviders |= provider;
+        Meta::TrackPtr track = idx.data( PlaylistBrowserModel::TrackRole ).value<Meta::TrackPtr>();
+        PlaylistPtr playlist = idx.data( PlaylistBrowserModel::PlaylistRole ).value<PlaylistPtr>();
+        if( !track && playlist ) // a playlist (must check it is not a track)
         {
-            if( !actions.contains( action ) )
-                actions << action;
+            m_actionPlaylists << playlist;
+            if( isWritable )
+                m_writableActionPlaylists << playlist;
+        }
+        if( track )
+        {
+            m_actionTracks.insert( playlist, idx.row() );
+            if( isWritable )
+                m_writableActionTracks.insert( playlist, idx.row() );
+        }
+
+        QVariant episodeIsNew = idx.data( PlaylistBrowserModel::EpisodeIsNewRole );
+        if( episodeIsNew.type() == QVariant::Bool )
+        {
+            if( episodeIsNew.toBool() )
+                newPodcastEpisodes << idx;
+            else
+                oldPodcastEpisodes << idx;
         }
     }
-    return actions;
+    // all actions taking provider have only sense with one provider
+    if( writableProviders.count() == 1 )
+        m_writableActionProvider = writableProviders.toList().first();
+
+    // process per-provider actions
+    foreach( PlaylistProvider *provider, providers )
+    {
+        // prepare arguments and get relevant actions
+        PlaylistList providerPlaylists;
+        foreach( const PlaylistPtr &playlist, m_actionPlaylists )
+        {
+            if( playlist->provider() == provider )
+                providerPlaylists << playlist;
+        }
+        actions << provider->playlistActions( providerPlaylists );
+
+        QMultiHash<PlaylistPtr, int> playlistTracks;
+        QHashIterator<PlaylistPtr, int> it( m_actionTracks );
+        while( it.hasNext() )
+        {
+            it.next();
+            if( it.key()->provider() == provider )
+                playlistTracks.insert( it.key(), it.value() );
+        }
+        actions << provider->trackActions( playlistTracks );
+    }
+
+    // separate model actions from standard actions we provide (at the top)
+    QActionList standardActions;
+    if( m_actionPlaylists.isEmpty() && m_actionTracks.isEmpty() && m_writableActionProvider )
+        standardActions << m_createEmptyPlaylistAction;
+    if( !m_actionPlaylists.isEmpty() || !m_actionTracks.isEmpty() )
+        standardActions << m_appendAction << m_loadAction;
+    if( !newPodcastEpisodes.isEmpty() || !oldPodcastEpisodes.isEmpty() )
+    {
+        m_setNewAction->setChecked( oldPodcastEpisodes.isEmpty() );
+        m_setNewAction->setData( QVariant::fromValue( newPodcastEpisodes + oldPodcastEpisodes ) );
+        standardActions << m_setNewAction;
+    }
+    if( m_writableActionPlaylists.count() == 1 && m_actionTracks.isEmpty() )
+        standardActions << m_renamePlaylistAction;
+    if( !m_writableActionPlaylists.isEmpty() && m_actionTracks.isEmpty() )
+        standardActions << m_deletePlaylistAction;
+    if( m_actionPlaylists.isEmpty() && !m_writableActionTracks.isEmpty() )
+    {
+        const int actionTrackCount = m_writableActionTracks.count();
+        const int playlistCount = m_writableActionTracks.uniqueKeys().count();
+        if( playlistCount > 1 )
+            m_removeTracksAction->setText( i18ncp( "Number of playlists is >= 2",
+                "Remove a Track From %2 Playlists", "Remove %1 Tracks From %2 Playlists",
+                actionTrackCount, playlistCount ) );
+        else
+            m_removeTracksAction->setText( i18ncp( "%2 is saved playlist name",
+                "Remove a Track From %2", "Remove %1 Tracks From %2", actionTrackCount,
+                m_writableActionTracks.uniqueKeys().first()->prettyName() ) );
+        standardActions << m_removeTracksAction;
+    }
+    if( m_actionPlaylists.count() == 1 && m_actionTracks.isEmpty() )
+        standardActions << m_exportAction;
+    standardActions << m_separatorAction;
+
+    return standardActions + actions;
 }
 
 void
-PlaylistBrowserNS::PlaylistBrowserView::setNewFolderAction( KAction *action )
+PlaylistBrowserView::resetActionTargets()
 {
-    m_addFolderAction = action;
+    m_writableActionProvider = 0;
+    m_actionPlaylists.clear();
+    m_writableActionPlaylists.clear();
+    m_actionTracks.clear();
+    m_writableActionTracks.clear();
 }
 
 void
@@ -269,35 +409,177 @@ PlaylistBrowserNS::PlaylistBrowserView::currentChanged( const QModelIndex &curre
 }
 
 void
-PlaylistBrowserNS::PlaylistBrowserView::appendAndPlay( const QModelIndex &index )
+PlaylistBrowserView::slotCreateEmptyPlaylist()
 {
-    appendAndPlay( QModelIndexList() << index );
+    // m_actionProvider may be null, which is fine
+    The::playlistManager()->save( Meta::TrackList(), Amarok::generatePlaylistName(
+            Meta::TrackList() ), m_writableActionProvider );
 }
 
 void
-PlaylistBrowserNS::PlaylistBrowserView::appendAndPlay( const QModelIndexList &list )
+PlaylistBrowserView::slotAppend()
 {
-    performActionNamed( "appendAction", list );
+    insertToPlayQueue( Playlist::AppendAndPlay );
 }
 
 void
-PlaylistBrowserNS::PlaylistBrowserView::deletePlaylistsTracks( const QModelIndexList &list )
+PlaylistBrowserView::slotLoad()
 {
-    performActionNamed( "deleteAction", list );
+    insertToPlayQueue( Playlist::LoadAndPlay );
 }
 
 void
-PlaylistBrowserNS::PlaylistBrowserView::performActionNamed( const QString &name,
-                                                            const QModelIndexList &list )
+PlaylistBrowserView::slotSetNew( bool newState )
 {
-    QActionList actions = actionsFor( list );
+    QModelIndexList indices = m_setNewAction->data().value<QModelIndexList>();
+    foreach( const QModelIndex &idx, indices )
+        model()->setData( idx, newState, PlaylistBrowserModel::EpisodeIsNewRole );
+}
 
-    foreach( QAction *action, actions )
+void
+PlaylistBrowserView::slotRename()
+{
+    if( m_writableActionPlaylists.count() != 1 )
     {
-        if( action->objectName() == name )
-            action->trigger();
-        action->setData( QVariant() );  // reset data of all actions
+        warning() << __PRETTY_FUNCTION__ << "m_writableActionPlaylists.count() is not 1";
+        return;
+    }
+    Playlists::PlaylistPtr playlist = m_writableActionPlaylists.at( 0 );
+
+    // TODO: this makes a rather complicated round-trip and ends up in edit(QModelIndex)
+    // here -- simplify that
+    The::playlistManager()->rename( playlist );
+}
+
+void
+PlaylistBrowserView::slotDelete()
+{
+    if( m_writableActionPlaylists.isEmpty() )
+        return;
+
+    using namespace Playlists;
+    QHash<PlaylistProvider *, PlaylistList> providerPlaylists;
+    foreach( const PlaylistPtr &playlist, m_writableActionPlaylists )
+    {
+        if( playlist->provider() )
+            providerPlaylists[ playlist->provider() ] << playlist;
+    }
+    QStringList providerNames;
+    foreach( const PlaylistProvider *provider, providerPlaylists.keys() )
+        providerNames << provider->prettyName();
+
+    KDialog dialog;
+    dialog.setCaption( i18n( "Confirm Playlist Deletion" ) );
+    dialog.setButtons( KDialog::Ok | KDialog::Cancel );
+    QLabel *label = new QLabel( i18np( "Are you sure you want to delete this playlist?",
+            "Are you sure you want to delete these %1 playlists?",
+            m_writableActionPlaylists.count() ), &dialog );
+    // TODO: include a text area with all the names of the playlists
+    dialog.setButtonText( KDialog::Ok, i18nc( "%1 is playlist provider pretty name",
+            "Yes, delete from %1.", providerNames.join( ", " ) ) );
+    dialog.setMainWidget( label );
+    if( dialog.exec() == QDialog::Accepted )
+    {
+        foreach( PlaylistProvider *provider, providerPlaylists.keys() )
+            provider->deletePlaylists( providerPlaylists.value( provider ) );
+    }
+}
+
+void
+PlaylistBrowserView::slotRemoveTracks()
+{
+    foreach( Playlists::PlaylistPtr playlist, m_writableActionTracks.uniqueKeys() )
+    {
+        QList<int> trackIndices = m_writableActionTracks.values( playlist );
+        qSort( trackIndices );
+        int removed = 0;
+        foreach( int trackIndex, trackIndices )
+        {
+            playlist->removeTrack( trackIndex - removed /* account for already removed */ );
+            removed++;
+        }
     }
 }
 
-#include "PlaylistBrowserView.moc"
+void
+PlaylistBrowserView::slotExport()
+{
+    if( m_actionPlaylists.count() != 1 )
+    {
+        warning() << __PRETTY_FUNCTION__ << "m_actionPlaylists.count() is not 1";
+        return;
+    }
+    Playlists::PlaylistPtr playlist = m_actionPlaylists.at( 0 );
+
+    // --- display save location dialog
+    // compare with MainWindow::exportPlaylist
+    // TODO: have this code only once
+    QCheckBox *saveRelativeCheck = new QCheckBox( i18n("Use relative path for &saving") );
+    saveRelativeCheck->setChecked( AmarokConfig::relativePlaylist() );
+    KFileDialog fileDialog( KUrl( "kfiledialog:///amarok-playlist-export" ), QString(), 0, saveRelativeCheck );
+
+    QStringList supportedMimeTypes;
+    supportedMimeTypes << "video/x-ms-asf"; // ASX
+    supportedMimeTypes << "audio/x-mpegurl"; // M3U
+    supportedMimeTypes << "audio/x-scpls"; // PLS
+    supportedMimeTypes << "application/xspf+xml"; // XSPF
+
+    fileDialog.setSelection( playlist->name() );
+    fileDialog.setMimeFilter( supportedMimeTypes, supportedMimeTypes.value( 1 ) );
+    fileDialog.setOperationMode( KFileDialog::Saving );
+    fileDialog.setMode( KFile::File );
+    fileDialog.setCaption( i18n("Save As") );
+    fileDialog.setObjectName( "PlaylistExport" );
+
+    fileDialog.exec();
+    QString playlistPath = fileDialog.selectedFile();
+
+    // --- actually save the playlist
+    if( !playlistPath.isEmpty() )
+        Playlists::exportPlaylistFile( playlist->tracks(), playlistPath, saveRelativeCheck->isChecked() );
+}
+
+void
+PlaylistBrowserNS::PlaylistBrowserView::appendAndPlay( const QModelIndex &index )
+{
+    appendAndPlay( QModelIndexList() << index );
+}
+
+void
+PlaylistBrowserNS::PlaylistBrowserView::appendAndPlay( const QModelIndexList &list )
+{
+    actionsFor( list ); // sets action targets
+    insertToPlayQueue( Playlist::AppendAndPlay );
+    resetActionTargets();
+}
+
+void
+PlaylistBrowserView::insertToPlayQueue( int options )
+{
+    Meta::TrackList tracks;
+
+    // add tracks for fully-selected playlists:
+    foreach( Playlists::PlaylistPtr playlist, m_actionPlaylists )
+    {
+        tracks << playlist->tracks();
+    }
+
+    // filter-out tracks from playlists that are selected, add lone tracks:
+    foreach( Playlists::PlaylistPtr playlist, m_actionTracks.uniqueKeys() )
+    {
+        if( m_actionPlaylists.contains( playlist ) )
+            continue;
+
+        Meta::TrackList playlistTracks = playlist->tracks();
+        QList<int> positions = m_actionTracks.values( playlist );
+        qSort( positions );
+        foreach( int position, positions )
+        {
+            if( position >= 0 && position < playlistTracks.count() )
+                tracks << playlistTracks.at( position );
+        }
+    }
+
+    if( !tracks.isEmpty() )
+        The::playlistController()->insertOptioned( tracks, options );
+}
diff --git a/src/browsers/playlistbrowser/PlaylistBrowserView.h b/src/browsers/playlistbrowser/PlaylistBrowserView.h
index b0d72bd..e2bb3b2 100644
--- a/src/browsers/playlistbrowser/PlaylistBrowserView.h
+++ b/src/browsers/playlistbrowser/PlaylistBrowserView.h
@@ -18,12 +18,12 @@
 #ifndef PLAYLISTBROWSERVIEW_H
 #define PLAYLISTBROWSERVIEW_H
 
+#include "core/playlists/Playlist.h"
 #include "widgets/PrettyTreeView.h"
 
 #include <QMutex>
 
 class PopupDropper;
-class KAction;
 class QKeyEvent;
 class QMouseEvent;
 class QContextMenuEvent;
@@ -35,54 +35,69 @@ class PlaylistBrowserView : public Amarok::PrettyTreeView
 Q_OBJECT
 public:
     explicit PlaylistBrowserView( QAbstractItemModel *model, QWidget *parent = 0 );
-    ~PlaylistBrowserView();
 
     virtual void setModel( QAbstractItemModel *model );
 
-    void setNewFolderAction( KAction *action );
-
 signals:
     void currentItemChanged( const QModelIndex &current );
 
 protected:
-    //TODO:re-implement QWidget::dragEnterEvent() to show drop-not-allowed indicator
+    // TODO: re-implement QWidget::dragEnterEvent() to show drop-not-allowed indicator
 
     virtual void keyPressEvent( QKeyEvent *event );
     virtual void mouseDoubleClickEvent( QMouseEvent *event );
     virtual void mouseReleaseEvent( QMouseEvent *event );
     virtual void startDrag( Qt::DropActions supportedActions );
 
-    virtual void contextMenuEvent( QContextMenuEvent* event );
+    virtual void contextMenuEvent( QContextMenuEvent *event );
 
 protected slots:
     /** reimplemented to emit a signal */
     void currentChanged( const QModelIndex &current, const QModelIndex &previous );
 
+private slots:
+    // these are connected to m_*Actions:
+    void slotCreateEmptyPlaylist();
+    void slotAppend();
+    void slotLoad();
+    void slotSetNew( bool newState );
+    void slotRename();
+    void slotDelete();
+    void slotRemoveTracks();
+    void slotExport();
+
 private:
-    /**
-     * Execute all actions that are named appendAction
-     */
     void appendAndPlay( const QModelIndex &index );
     void appendAndPlay( const QModelIndexList &list );
+    void insertToPlayQueue( int options );
 
     /**
-     * Execute all actions that are named deleteAction
-     */
-    void deletePlaylistsTracks( const QModelIndexList &list );
-
-    /**
-     * Executes all actions that are named @param name
+     * Gets action for a list of indices and sets internal action targets to these.
+     *
+     * After you have processed/triggered the actions, you should call
+     * resetActionTargets() to prevent stale targets laying around.
      */
-    void performActionNamed( const QString &name, const QModelIndexList &list );
-
-    QAction *decoratorActionAt( const QModelIndex &idx, const QPoint position );
-    QList<QAction *> actionsFor( QModelIndexList indexes );
+    QList<QAction *> actionsFor( const QModelIndexList &indexes );
+    void resetActionTargets();
 
     PopupDropper* m_pd;
 
-    KAction *m_addFolderAction;
-
+    QAction *m_createEmptyPlaylistAction;
+    QAction *m_appendAction;
+    QAction *m_loadAction;
+    QAction *m_setNewAction; // for podcasts
+    QAction *m_renamePlaylistAction;
+    QAction *m_deletePlaylistAction;
+    QAction *m_removeTracksAction;
+    QAction *m_exportAction;
+    QAction *m_separatorAction;
     bool m_ongoingDrag;
+
+    Playlists::PlaylistProvider *m_writableActionProvider;
+    Playlists::PlaylistList m_actionPlaylists;
+    Playlists::PlaylistList m_writableActionPlaylists;
+    QMultiHash<Playlists::PlaylistPtr, int> m_actionTracks; // maps playlists to track positions
+    QMultiHash<Playlists::PlaylistPtr, int> m_writableActionTracks;
 };
 
 } // namespace PlaylistBrowserNS
diff --git a/src/browsers/playlistbrowser/PodcastModel.cpp b/src/browsers/playlistbrowser/PodcastModel.cpp
index 5f277aa..6f9b935 100644
--- a/src/browsers/playlistbrowser/PodcastModel.cpp
+++ b/src/browsers/playlistbrowser/PodcastModel.cpp
@@ -66,17 +66,8 @@ PlaylistBrowserNS::PodcastModel::destroy()
 
 PlaylistBrowserNS::PodcastModel::PodcastModel()
     : PlaylistBrowserModel( PlaylistManager::PodcastChannel )
-    , m_setNewAction( 0 )
 {
     s_instance = this;
-    m_setNewAction = new QAction( KIcon( "rating" ),
-                                  i18nc( "toggle the \"new\" status of this podcast episode",
-                                         "&New" ),
-                                  this
-                                );
-    m_setNewAction->setProperty( "popupdropper_svg_id", "new" );
-    m_setNewAction->setCheckable( true );
-    connect( m_setNewAction, SIGNAL(triggered(bool)), SLOT(slotSetNew(bool)) );
 }
 
 bool
@@ -267,6 +258,8 @@ PlaylistBrowserNS::PodcastModel::episodeData( const PodcastEpisodePtr &episode,
             if( idx.column() == PlaylistBrowserModel::PlaylistItemColumn )
                 return icon( episode );
             break;
+        case EpisodeIsNewRole:
+            return episode->isNew();
     }
 
     return PlaylistBrowserModel::data( idx, role );
@@ -275,10 +268,18 @@ PlaylistBrowserNS::PodcastModel::episodeData( const PodcastEpisodePtr &episode,
 bool
 PlaylistBrowserNS::PodcastModel::setData( const QModelIndex &idx, const QVariant &value, int role )
 {
-    DEBUG_BLOCK
+    PodcastEpisodePtr episode = episodeForIndex( idx );
+    if( !episode || !value.canConvert<bool>() || role != EpisodeIsNewRole )
+    {
+        return PlaylistBrowserModel::setData( idx, value, role );
+    }
 
-    //TODO: implement setNew.
-    return PlaylistBrowserModel::setData( idx, value, role );
+    bool checked = value.toBool();
+    episode->setNew( checked );
+    if( checked )
+        emit episodeMarkedAsNew( episode );
+    emit dataChanged( idx, idx );
+    return true;
 }
 
 int
@@ -353,62 +354,6 @@ PlaylistBrowserNS::PodcastModel::refreshPodcasts()
     }
 }
 
-QActionList
-PlaylistBrowserNS::PodcastModel::actionsFor( const QModelIndex &idx ) const
-{
-    if( !idx.isValid() )
-    {
-        //TODO: add podcast action
-        return QActionList();
-    }
-
-    QActionList actions = PlaylistBrowserModel::actionsFor( idx );
-
-    /* by default a list of podcast episodes can only be changed to isNew = false or
-       isKeep = false, except when all selected episodes are the same state */
-    m_setNewAction->setChecked( false );
-
-    Podcasts::PodcastEpisodeList episodes = m_setNewAction->data().value<Podcasts::PodcastEpisodeList>();
-    if( IS_TRACK(idx) )
-        episodes << episodeForIndex( idx );
-    else
-        episodes << channelForIndex( idx )->episodes();
-
-    foreach( const Podcasts::PodcastEpisodePtr episode, episodes )
-    {
-        if( episode->isNew() )
-            m_setNewAction->setChecked( true );
-    }
-
-    m_setNewAction->setData( QVariant::fromValue( episodes ) );
-
-    actions << m_setNewAction;
-
-    return actions;
-}
-
-void
-PlaylistBrowserNS::PodcastModel::slotSetNew( bool newState )
-{
-    Q_UNUSED( newState );
-    QAction *action = qobject_cast<QAction *>( QObject::sender() );
-    if( action == 0 )
-        return;
-
-    Podcasts::PodcastEpisodeList episodes = action->data().value<Podcasts::PodcastEpisodeList>();
-
-    foreach( Podcasts::PodcastEpisodePtr episode, episodes )
-    {
-        if( !episode.isNull() )
-        {
-            episode->setNew( action->isChecked() );
-
-            if( action->isChecked() )
-                emit episodeMarkedAsNew( episode );
-        }
-    }
-}
-
 Podcasts::PodcastChannelPtr
 PlaylistBrowserNS::PodcastModel::channelForIndex( const QModelIndex &idx ) const
 {
diff --git a/src/browsers/playlistbrowser/PodcastModel.h b/src/browsers/playlistbrowser/PodcastModel.h
index 0f0b3b5..4d8eb41 100644
--- a/src/browsers/playlistbrowser/PodcastModel.h
+++ b/src/browsers/playlistbrowser/PodcastModel.h
@@ -50,6 +50,7 @@ enum
 class PodcastModel : public PlaylistBrowserModel
 {
     Q_OBJECT
+
     public:
         static PodcastModel *instance();
         static void destroy();
@@ -77,14 +78,8 @@ class PodcastModel : public PlaylistBrowserModel
         void addPodcast();
         void refreshPodcasts();
 
-    private slots:
-        void slotSetNew( bool newState );
-
-    protected:
-        virtual QActionList actionsFor( const QModelIndex &idx ) const;
-
     private:
-        static PodcastModel* s_instance;
+        static PodcastModel *s_instance;
         PodcastModel();
 
         QVariant channelData( const Podcasts::PodcastChannelPtr &channel,
@@ -97,8 +92,6 @@ class PodcastModel : public PlaylistBrowserModel
 
         Q_DISABLE_COPY( PodcastModel )
 
-        QAction *m_setNewAction;
-
         /**
          * A convenience function to convert a PodcastEpisodeList into a TrackList.
          */
diff --git a/src/core-impl/collections/ipodcollection/IpodPlaylistProvider.cpp b/src/core-impl/collections/ipodcollection/IpodPlaylistProvider.cpp
index abf0fae..ff9e4ad 100644
--- a/src/core-impl/collections/ipodcollection/IpodPlaylistProvider.cpp
+++ b/src/core-impl/collections/ipodcollection/IpodPlaylistProvider.cpp
@@ -101,45 +101,28 @@ IpodPlaylistProvider::providerActions()
 }
 
 QActionList
-IpodPlaylistProvider::playlistActions( Playlists::PlaylistPtr playlist )
+IpodPlaylistProvider::playlistActions( const Playlists::PlaylistList &playlists )
 {
-    QList<QAction *> actions;
-    if( !m_playlists.contains( playlist ) )  // make following static cast safe
-        return actions;
-    KSharedPtr<IpodPlaylist> ipodPlaylist = KSharedPtr<IpodPlaylist>::staticCast( playlist );
-    switch( ipodPlaylist->type() )
+    QActionList actions;
+    foreach( const Playlists::PlaylistPtr &playlist, playlists )
     {
-        case IpodPlaylist::Normal:
-            actions << Playlists::UserPlaylistProvider::playlistActions( playlist );
-            break;
-        case IpodPlaylist::Stale:
-        case IpodPlaylist::Orphaned:
+        if( !m_playlists.contains( playlist ) )  // make following static cast safe
+            continue;
+        IpodPlaylist::Type type = KSharedPtr<IpodPlaylist>::staticCast( playlist )->type();
+        if( type == IpodPlaylist::Stale || type == IpodPlaylist::Orphaned )
+        {
             actions << m_coll->m_consolidateAction;
             break;
+        }
     }
 
     return actions;
 }
 
 QActionList
-IpodPlaylistProvider::trackActions( Playlists::PlaylistPtr playlist, int trackIndex )
+IpodPlaylistProvider::trackActions( const QMultiHash<Playlists::PlaylistPtr, int> &playlistTracks )
 {
-    QList<QAction *> actions;
-    if( !m_playlists.contains( playlist ) )  // make following static cast safe
-        return actions;
-    KSharedPtr<IpodPlaylist> ipodPlaylist = KSharedPtr<IpodPlaylist>::staticCast( playlist );
-    switch( ipodPlaylist->type() )
-    {
-        case IpodPlaylist::Normal:
-            actions << Playlists::UserPlaylistProvider::trackActions( playlist, trackIndex );
-            break;
-        case IpodPlaylist::Stale:
-        case IpodPlaylist::Orphaned:
-            actions << m_coll->m_consolidateAction;
-            break;
-    }
-
-    return actions;
+    return playlistActions( playlistTracks.uniqueKeys() );
 }
 
 bool
@@ -149,7 +132,7 @@ IpodPlaylistProvider::isWritable()
 }
 
 void
-IpodPlaylistProvider::rename( Playlists::PlaylistPtr playlist, const QString &newName )
+IpodPlaylistProvider::renamePlaylist( Playlists::PlaylistPtr playlist, const QString &newName )
 {
     if( !m_playlists.contains( playlist ) )  // make following static cast safe
         return;
@@ -163,7 +146,7 @@ IpodPlaylistProvider::rename( Playlists::PlaylistPtr playlist, const QString &ne
 }
 
 bool
-IpodPlaylistProvider::deletePlaylists( Playlists::PlaylistList playlistlist )
+IpodPlaylistProvider::deletePlaylists( const Playlists::PlaylistList &playlistlist )
 {
     if( !isWritable() )
         return false;
diff --git a/src/core-impl/collections/ipodcollection/IpodPlaylistProvider.h b/src/core-impl/collections/ipodcollection/IpodPlaylistProvider.h
index 990d423..0ba2d15 100644
--- a/src/core-impl/collections/ipodcollection/IpodPlaylistProvider.h
+++ b/src/core-impl/collections/ipodcollection/IpodPlaylistProvider.h
@@ -49,13 +49,12 @@ class IpodPlaylistProvider : public Playlists::UserPlaylistProvider, private Pla
                                              const QString& name = QString() );
 
         virtual QActionList providerActions();
-        virtual QActionList playlistActions( Playlists::PlaylistPtr playlist );
-        virtual QActionList trackActions( Playlists::PlaylistPtr playlist,
-                                               int trackIndex );
+        virtual QActionList playlistActions( const Playlists::PlaylistList &playlists );
+        virtual QActionList trackActions( const QMultiHash<Playlists::PlaylistPtr, int> &playlistTracks );
 
         virtual bool isWritable();
-        virtual void rename( Playlists::PlaylistPtr playlist, const QString &newName );
-        virtual bool deletePlaylists( Playlists::PlaylistList playlistlist );
+        virtual void renamePlaylist( Playlists::PlaylistPtr playlist, const QString &newName );
+        virtual bool deletePlaylists( const Playlists::PlaylistList &playlistlist );
 
         // PlaylistObserver methods:
         virtual void metadataChanged( Playlists::PlaylistPtr playlist );
diff --git a/src/core-impl/collections/mediadevicecollection/playlist/MediaDeviceUserPlaylistProvider.cpp b/src/core-impl/collections/mediadevicecollection/playlist/MediaDeviceUserPlaylistProvider.cpp
index f49a9f6..e6d52e1 100644
--- a/src/core-impl/collections/mediadevicecollection/playlist/MediaDeviceUserPlaylistProvider.cpp
+++ b/src/core-impl/collections/mediadevicecollection/playlist/MediaDeviceUserPlaylistProvider.cpp
@@ -33,7 +33,6 @@
 #include <KInputDialog>
 #include <KUrl>
 
-#include <QAction>
 #include <QMap>
 
 static const int USERPLAYLIST_DB_VERSION = 2;
@@ -43,7 +42,6 @@ namespace Playlists {
 
 MediaDeviceUserPlaylistProvider::MediaDeviceUserPlaylistProvider( Collections::MediaDeviceCollection *collection )
     : Playlists::UserPlaylistProvider()
-    , m_renameAction( 0 )
     , m_collection( collection )
 {
     DEBUG_BLOCK
@@ -79,65 +77,7 @@ MediaDeviceUserPlaylistProvider::playlists()
 
     return playlists;
 }
-#if 0
-void
-SqlPlaylists::UserPlaylistProvider::slotDelete()
-{
-    DEBUG_BLOCK
-
-    //TODO FIXME Confirmation of delete
-    foreach( Playlists::PlaylistPtr playlist, The::userPlaylistModel()->selectedPlaylists() )
-    {
-        Meta::SqlPlaylistPtr sqlPlaylist =
-                Meta::SqlPlaylistPtr::dynamicCast( playlist );
-        if( sqlPlaylist )
-        {
-            debug() << "deleting " << sqlPlaylist->name();
-            sqlPlaylist->removeFromDb();
-        }
-    }
-    reloadFromDb();
-}
-#endif
-
-#if 0
-void
-MediaDeviceUserPlaylistProvider::slotRename()
-{
-    DEBUG_BLOCK
-    //only one playlist can be selected at this point
-    Playlists::MediaDevicePlaylistPtr playlist = selectedPlaylists().first();
-    if( playlist.isNull() )
-        return;
-
-    bool ok;
-    const QString newName = KInputDialog::getText( i18n("Change playlist"),
-                i18n("Enter new name for playlist:"), playlist->name(),
-                                                   &ok );
-    if ( ok )
-    {
-        playlist->setName( newName.trimmed() );
-        emit( updated() );
-    }
-}
-#endif
-#if 0
-void
-SqlPlaylists::UserPlaylistProvider::slotRemove()
-{
-    QAction *action = qobject_cast<QAction *>( QObject::sender() );
-    if( action == 0 )
-        return;
 
-    PlaylistTrackMap playlistMap = action->data().value<PlaylistTrackMap>();
-    foreach( Playlists::PlaylistPtr playlist, playlistMap.keys() )
-        foreach( Meta::TrackPtr track, playlistMap.values( playlist ) )
-            playlist->removeTrack( playlist->tracks().indexOf( track ) );
-
-    //clear the data
-    action->setData( QVariant() );
-}
-#endif
 Playlists::PlaylistPtr
 MediaDeviceUserPlaylistProvider::save( const Meta::TrackList &tracks )
 {
@@ -169,7 +109,7 @@ MediaDeviceUserPlaylistProvider::save( const Meta::TrackList &tracks, const QStr
 }
 
 void
-MediaDeviceUserPlaylistProvider::rename( Playlists::PlaylistPtr playlist, const QString &newName )
+MediaDeviceUserPlaylistProvider::renamePlaylist( Playlists::PlaylistPtr playlist, const QString &newName )
 {
     DEBUG_BLOCK
     Playlists::MediaDevicePlaylistPtr pl = Playlists::MediaDevicePlaylistPtr::staticCast( playlist );
@@ -183,7 +123,7 @@ MediaDeviceUserPlaylistProvider::rename( Playlists::PlaylistPtr playlist, const
 }
 
 bool
-MediaDeviceUserPlaylistProvider::deletePlaylists( Playlists::PlaylistList playlistlist )
+MediaDeviceUserPlaylistProvider::deletePlaylists( const Playlists::PlaylistList &playlistlist )
 {
     Playlists::MediaDevicePlaylistList pllist;
     foreach( Playlists::PlaylistPtr playlist, playlistlist )
diff --git a/src/core-impl/collections/mediadevicecollection/playlist/MediaDeviceUserPlaylistProvider.h b/src/core-impl/collections/mediadevicecollection/playlist/MediaDeviceUserPlaylistProvider.h
index 3a1572f..d86decc 100644
--- a/src/core-impl/collections/mediadevicecollection/playlist/MediaDeviceUserPlaylistProvider.h
+++ b/src/core-impl/collections/mediadevicecollection/playlist/MediaDeviceUserPlaylistProvider.h
@@ -23,8 +23,6 @@
 #include <klocale.h>
 #include <kicon.h>
 
-class QAction;
-
 namespace Collections {
     class MediaDeviceCollection;
 }
@@ -39,7 +37,7 @@ class AMAROK_EXPORT MediaDeviceUserPlaylistProvider : public Playlists::UserPlay
         ~MediaDeviceUserPlaylistProvider();
 
         /* PlaylistProvider functions */
-        virtual QString prettyName() const { return i18n("Media Device playlists"); };
+        virtual QString prettyName() const { return i18n( "Media Device playlists" ); };
         virtual KIcon icon() const { return KIcon( "multimedia-player" ); }
 
         /* Playlists::UserPlaylistProvider functions */
@@ -48,15 +46,9 @@ class AMAROK_EXPORT MediaDeviceUserPlaylistProvider : public Playlists::UserPlay
         virtual Playlists::PlaylistPtr save( const Meta::TrackList &tracks );
         virtual Playlists::PlaylistPtr save( const Meta::TrackList &tracks, const QString& name );
 
-        //      virtual bool supportsEmptyGroups() { return true; }
-
-        //virtual QList<QAction *> playlistActions( Meta::PlaylistList list );
-
         virtual bool isWritable() { return true; }
-
-        virtual void rename( Playlists::PlaylistPtr playlist, const QString &newName );
-
-        virtual bool deletePlaylists( Playlists::PlaylistList playlistlist );
+        virtual void renamePlaylist( Playlists::PlaylistPtr playlist, const QString &newName );
+        virtual bool deletePlaylists( const Playlists::PlaylistList &playlistlist );
 
         /// MediaDevice-specific Functions
 
@@ -71,16 +63,9 @@ class AMAROK_EXPORT MediaDeviceUserPlaylistProvider : public Playlists::UserPlay
             void playlistRenamed( const Playlists::MediaDevicePlaylistPtr &playlist );
             void playlistsDeleted( const Playlists::MediaDevicePlaylistList &playlistlist );
 
-        private slots:
-        //void slotDelete();
-        //void slotRename();
-        //void slotRemove();
-
  private:
-
     MediaDevicePlaylistList m_playlists;
 
-    QAction *m_renameAction;
     Collections::MediaDeviceCollection *m_collection;
 };
 
diff --git a/src/core-impl/collections/umscollection/podcasts/UmsPodcastProvider.cpp b/src/core-impl/collections/umscollection/podcasts/UmsPodcastProvider.cpp
index e8af676..7579ba2 100644
--- a/src/core-impl/collections/umscollection/podcasts/UmsPodcastProvider.cpp
+++ b/src/core-impl/collections/umscollection/podcasts/UmsPodcastProvider.cpp
@@ -174,28 +174,23 @@ UmsPodcastProvider::playlists()
     return playlists;
 }
 
-QList<QAction *>
+QActionList
 UmsPodcastProvider::episodeActions( PodcastEpisodeList episodes )
 {
-    QList<QAction *> actions;
+    QActionList actions;
+    if( episodes.isEmpty() )
+        return actions;
+
     if( m_deleteEpisodeAction == 0 )
     {
-        m_deleteEpisodeAction = new QAction(
-            KIcon( "edit-delete" ),
-            i18n( "&Delete Episode" ),
-            this
-        );
+        m_deleteEpisodeAction = new QAction( KIcon( "edit-delete" ), i18n( "&Delete Episode" ), this );
         m_deleteEpisodeAction->setProperty( "popupdropper_svg_id", "delete" );
-        connect( m_deleteEpisodeAction, SIGNAL(triggered()),
-                 SLOT(slotDeleteEpisodes()) );
+        connect( m_deleteEpisodeAction, SIGNAL(triggered()), SLOT(slotDeleteEpisodes()) );
     }
-    //set the episode list as data that we'll retrieve in the slot
-    PodcastEpisodeList actionList =
-            m_deleteEpisodeAction->data().value<PodcastEpisodeList>();
-
-    actionList << episodes;
-    m_deleteEpisodeAction->setData( QVariant::fromValue( actionList ) );
+    // set the episode list as data that we'll retrieve in the slot
+    m_deleteEpisodeAction->setData( QVariant::fromValue( episodes ) );
     actions << m_deleteEpisodeAction;
+
     return actions;
 }
 
@@ -318,29 +313,24 @@ UmsPodcastProvider::deleteJobComplete( KJob *job )
     }
 }
 
-QList<QAction *>
+QActionList
 UmsPodcastProvider::channelActions( PodcastChannelList channels )
 {
-    QList<QAction *> actions;
+    QActionList actions;
+    if( channels.isEmpty() )
+        return actions;
+
     if( m_deleteChannelAction == 0 )
     {
-        m_deleteChannelAction = new QAction(
-            KIcon( "edit-delete" ),
-            i18n( "&Delete Channel and Episodes" ),
-            this
-        );
+        m_deleteChannelAction = new QAction( KIcon( "edit-delete" ), i18n( "&Delete "
+                "Channel and Episodes" ), this );
         m_deleteChannelAction->setProperty( "popupdropper_svg_id", "delete" );
-        connect( m_deleteChannelAction, SIGNAL(triggered()),
-                 SLOT(slotDeleteChannels()) );
+        connect( m_deleteChannelAction, SIGNAL(triggered()), SLOT(slotDeleteChannels()) );
     }
-    //set the episode list as data that we'll retrieve in the slot
-    PodcastChannelList actionList =
-            m_deleteChannelAction->data().value<PodcastChannelList>();
-
-    actionList << channels;
-    m_deleteChannelAction->setData( QVariant::fromValue( actionList ) );
-
+    // set the episode list as data that we'll retrieve in the slot
+    m_deleteChannelAction->setData( QVariant::fromValue( channels ) );
     actions << m_deleteChannelAction;
+
     return actions;
 }
 
@@ -372,29 +362,41 @@ UmsPodcastProvider::slotDeleteChannels()
     }
 }
 
-QList<QAction *>
-UmsPodcastProvider::playlistActions( Playlists::PlaylistPtr playlist )
+QActionList
+UmsPodcastProvider::playlistActions( const Playlists::PlaylistList &playlists )
 {
     PodcastChannelList channels;
-    PodcastChannelPtr channel = PodcastChannelPtr::dynamicCast( playlist );
-    if( channel.isNull() )
-        return QList<QAction *>();
+    foreach( const Playlists::PlaylistPtr &playlist, playlists )
+    {
+        PodcastChannelPtr channel = PodcastChannelPtr::dynamicCast( playlist );
+        if( channel )
+            channels << channel;
+    }
 
-    return channelActions( channels << channel );
+    return channelActions( channels );
 }
 
-QList<QAction *>
-UmsPodcastProvider::trackActions( Playlists::PlaylistPtr playlist, int trackIndex )
+QActionList
+UmsPodcastProvider::trackActions( const QMultiHash<Playlists::PlaylistPtr, int> &playlistTracks )
 {
-    if( playlist->tracks().count() > trackIndex )
+    PodcastEpisodeList episodes;
+    foreach( const Playlists::PlaylistPtr &playlist, playlistTracks.uniqueKeys() )
     {
-        PodcastEpisodeList episodes;
-        episodes << UmsPodcastEpisode::toPodcastEpisodePtr(
-                    UmsPodcastEpisode::fromTrackPtr( playlist->tracks()[trackIndex] )
-                );
-        return episodeActions( episodes );
+        PodcastChannelPtr channel = PodcastChannelPtr::dynamicCast( playlist );
+        if( !channel )
+            continue;
+
+        PodcastEpisodeList channelEpisodes = channel->episodes();
+        QList<int> trackPositions = playlistTracks.values( playlist );
+        qSort( trackPositions );
+        foreach( int trackPosition, trackPositions )
+        {
+            if( trackPosition >= 0 && trackPosition < channelEpisodes.count() )
+                episodes << channelEpisodes.at( trackPosition );
+        }
     }
-    return QList<QAction *>();
+
+    return episodeActions( episodes );
 }
 
 void
diff --git a/src/core-impl/collections/umscollection/podcasts/UmsPodcastProvider.h b/src/core-impl/collections/umscollection/podcasts/UmsPodcastProvider.h
index d46f63d..18f29f6 100644
--- a/src/core-impl/collections/umscollection/podcasts/UmsPodcastProvider.h
+++ b/src/core-impl/collections/umscollection/podcasts/UmsPodcastProvider.h
@@ -57,12 +57,8 @@ class UmsPodcastProvider : public PodcastProvider
 
         virtual Playlists::PlaylistList playlists();
 
-        virtual QList<QAction *> episodeActions( Podcasts::PodcastEpisodeList );
-        virtual QList<QAction *> channelActions( Podcasts::PodcastChannelList );
-
-        virtual QList<QAction *> playlistActions( Playlists::PlaylistPtr playlist );
-        virtual QList<QAction *> trackActions( Playlists::PlaylistPtr playlist,
-                                                  int trackIndex );
+        virtual QActionList playlistActions( const Playlists::PlaylistList &playlists );
+        virtual QActionList trackActions( const QMultiHash<Playlists::PlaylistPtr, int> &playlistTracks );
 
         virtual void completePodcastDownloads();
 
@@ -84,6 +80,8 @@ class UmsPodcastProvider : public PodcastProvider
         void slotCopyComplete( KJob *job );
 
     private:
+        QList<QAction *> episodeActions( Podcasts::PodcastEpisodeList );
+        QList<QAction *> channelActions( Podcasts::PodcastChannelList );
         void deleteEpisodes( UmsPodcastEpisodeList umsEpisodes );
 
         KUrl m_scanDirectory;
diff --git a/src/core-impl/playlists/providers/user/UserPlaylistProvider.cpp b/src/core-impl/playlists/providers/user/UserPlaylistProvider.cpp
index d9d066c..abcd1d4 100644
--- a/src/core-impl/playlists/providers/user/UserPlaylistProvider.cpp
+++ b/src/core-impl/playlists/providers/user/UserPlaylistProvider.cpp
@@ -15,56 +15,11 @@
  * this program.  If not, see <http://www.gnu.org/licenses/>.                           *
  ****************************************************************************************/
 
-#include "core-impl/playlists/providers/user/UserPlaylistProvider.h"
-#include "core-impl/playlists/types/file/PlaylistFileSupport.h"
-
-#include "playlistmanager/PlaylistManager.h"
-#include "amarokconfig.h"
-
-#include <KDialog>
-#include <KFileDialog>
-#include <kabstractfilewidget.h> // KFileDialog needs this. It's a scandal.
-#include <KLocalizedString>
-
-#include <QAction>
-#include <QCheckBox>
-#include <QLabel>
-
-// For removing multiple tracks from different playlists with one QAction
-typedef QMultiMap<Playlists::PlaylistPtr, int> PlaylistTrackMap;
-Q_DECLARE_METATYPE( PlaylistTrackMap )
+#include "UserPlaylistProvider.h"
 
 Playlists::UserPlaylistProvider::UserPlaylistProvider( QObject *parent )
     : PlaylistProvider( parent )
 {
-    m_deleteAction = new QAction( KIcon( "media-track-remove-amarok" ), i18n( "&Delete..." ), this );
-    m_deleteAction->setProperty( "popupdropper_svg_id", "delete" );
-    // object name must match one in PlaylistBrowserNS::PlaylistBrowserView
-    m_deleteAction->setObjectName( "deleteAction" );
-    // key shortcut is only for display purposes here, actual one is determined by View in Model/View classes
-    m_deleteAction->setShortcut( Qt::Key_Delete );
-    connect( m_deleteAction, SIGNAL(triggered()), SLOT(slotDelete()) );
-
-    m_renameAction =  new QAction( KIcon( "media-track-edit-amarok" ), i18n( "&Rename..." ), this );
-    m_renameAction->setProperty( "popupdropper_svg_id", "edit" );
-    // key shortcut is only for display purposes here, actual one is determined by View in Model/View classes
-    m_renameAction->setShortcut( Qt::Key_F2 );
-    connect( m_renameAction, SIGNAL(triggered()), this, SLOT(slotRename()) );
-
-    m_exportAction = new QAction( KIcon( "document-export-amarok" ), i18n("&Export Playlist As..."), this );
-    connect( m_exportAction, SIGNAL(triggered()), this, SLOT(slotExport()) );
-
-    m_removeTrackAction = new QAction( KIcon( "media-track-remove-amarok" ), QString( "Placeholder" ), this );
-    m_removeTrackAction->setProperty( "popupdropper_svg_id", "delete" );
-    // object name must match one in PlaylistBrowserNS::PlaylistBrowserView
-    m_removeTrackAction->setObjectName( "deleteAction" );
-    // key shortcut is only for display purposes here, actual one is determined by View in Model/View classes
-    m_removeTrackAction->setShortcut( Qt::Key_Delete );
-    connect( m_removeTrackAction, SIGNAL(triggered()), SLOT(slotRemoveTrack()) );
-}
-
-Playlists::UserPlaylistProvider::~UserPlaylistProvider()
-{
 }
 
 int
@@ -72,175 +27,3 @@ Playlists::UserPlaylistProvider::category() const
 {
      return Playlists::UserPlaylist;
 }
-
-QList<QAction *>
-Playlists::UserPlaylistProvider::playlistActions( Playlists::PlaylistPtr playlist )
-{
-    QList<QAction *> actions;
-
-    Playlists::PlaylistList actionList = m_deleteAction->data().value<Playlists::PlaylistList>();
-    actionList << playlist;
-    m_deleteAction->setData( QVariant::fromValue( actionList ) );
-    actions << m_deleteAction;
-
-    m_renameAction->setData( QVariant::fromValue( playlist ) );
-    actions << m_renameAction;
-
-    m_exportAction->setData( QVariant::fromValue( playlist ) );
-    actions << m_exportAction;
-
-    return actions;
-}
-
-QList<QAction *>
-Playlists::UserPlaylistProvider::trackActions( Playlists::PlaylistPtr playlist, int trackIndex )
-{
-    Q_UNUSED( trackIndex );
-    QList<QAction *> actions;
-
-    if( trackIndex < 0 )
-        return actions;
-    int trackCount = playlist->trackCount();
-    if( trackCount == -1 )
-        trackCount = playlist->tracks().size();
-    if( trackIndex >= trackCount )
-        return actions;
-
-    // Add the playlist/track combination to a QMultiMap that is stored in the action.
-    // In the slot we use this data to remove that track from the playlist.
-    PlaylistTrackMap playlistMap = m_removeTrackAction->data().value<PlaylistTrackMap>();
-
-    //only add action to map if playlist/track combo is not in there yet.
-    if( !playlistMap.keys().contains( playlist ) ||
-        !playlistMap.values( playlist ).contains( trackIndex ) )
-    {
-        playlistMap.insert( playlist, trackIndex );
-    }
-    m_removeTrackAction->setData( QVariant::fromValue( playlistMap ) );
-
-    const int actionTrackCount = playlistMap.count();
-    const int playlistCount = playlistMap.uniqueKeys().count();
-    if( playlistCount > 1 )
-    {
-        m_removeTrackAction->setText( i18ncp( "Number of playlists is >= 2",
-            "Remove a track from %2 playlists", "Remove %1 tracks from %2 playlists",
-            actionTrackCount, playlistCount ) );
-    }
-    else
-    {
-        m_removeTrackAction->setText( i18ncp( "%2 is saved playlist name",
-            "Remove a track from %2", "Remove %1 tracks from %2", actionTrackCount,
-            playlist->name() ) );
-    }
-    actions << m_removeTrackAction;
-
-    return actions;
-}
-
-void
-Playlists::UserPlaylistProvider::slotDelete()
-{
-    QAction *action = qobject_cast<QAction *>( QObject::sender() );
-    if( action == 0 )
-        return;
-
-    Playlists::PlaylistList playlists = action->data().value<Playlists::PlaylistList>();
-    if( playlists.count() == 0 )
-        return;
-
-    KDialog dialog;
-    dialog.setCaption( i18n( "Confirm Delete" ) );
-    dialog.setButtons( KDialog::Ok | KDialog::Cancel );
-    QLabel label( i18np( "Are you sure you want to delete this playlist?",
-                         "Are you sure you want to delete these %1 playlists?",
-                         playlists.count() )
-                    , &dialog
-                  );
-    //TODO:include a text area with all the names of the playlists
-    dialog.setButtonText( KDialog::Ok, i18nc( "%1 is playlist provider pretty name",
-                                              "Yes, delete from %1.", prettyName() ) );
-    dialog.setMainWidget( &label );
-    if( dialog.exec() == QDialog::Accepted )
-        deletePlaylists( playlists );
-}
-
-void
-Playlists::UserPlaylistProvider::slotRename()
-{
-    QAction *action = qobject_cast<QAction *>( QObject::sender() );
-    if( action == 0 )
-        return;
-
-    Playlists::PlaylistPtr playlist = action->data().value<Playlists::PlaylistPtr>();
-    if( playlist.isNull() )
-        return;
-
-    The::playlistManager()->rename( playlist );  // initiates inline rename of the playlist
-}
-
-void
-Playlists::UserPlaylistProvider::slotExport()
-{
-    QAction *action = qobject_cast<QAction *>( QObject::sender() );
-    if( action == 0 )
-        return;
-
-    Playlists::PlaylistPtr playlist = action->data().value<Playlists::PlaylistPtr>();
-    if( playlist.isNull() )
-        return;
-
-    // --- display save location dialog
-    // compare with MainWindow::exportPlaylist
-    // TODO: have this code only once
-    KFileDialog fileDialog( KUrl("kfiledialog:///amarok-playlist-export"), QString(), 0 );
-    QCheckBox *saveRelativeCheck = new QCheckBox( i18n("Use relative path for &saving") );
-    saveRelativeCheck->setChecked( AmarokConfig::relativePlaylist() );
-
-    QStringList supportedMimeTypes;
-
-    supportedMimeTypes << "video/x-ms-asf"; //ASX
-    supportedMimeTypes << "audio/x-mpegurl"; //M3U
-    supportedMimeTypes << "audio/x-scpls"; //PLS
-    supportedMimeTypes << "application/xspf+xml"; //XSPF
-
-    fileDialog.setMimeFilter( supportedMimeTypes, supportedMimeTypes.first() );
-    fileDialog.fileWidget()->setCustomWidget( saveRelativeCheck );
-    fileDialog.setOperationMode( KFileDialog::Saving );
-    fileDialog.setMode( KFile::File );
-    fileDialog.setCaption( i18n("Save As") );
-    fileDialog.setObjectName( "PlaylistExport" );
-
-    fileDialog.exec();
-
-    QString playlistPath = fileDialog.selectedFile();
-
-    // --- actually save the playlist
-    if( !playlistPath.isEmpty() )
-        exportPlaylistFile( playlist->tracks(), playlistPath, saveRelativeCheck->isChecked() );
-}
-
-void
-Playlists::UserPlaylistProvider::slotRemoveTrack()
-{
-    QAction *action = qobject_cast<QAction *>( QObject::sender() );
-    if( action == 0 )
-        return;
-
-    PlaylistTrackMap playlistMap = action->data().value<PlaylistTrackMap>();
-    foreach( Playlists::PlaylistPtr playlist, playlistMap.uniqueKeys() )
-    {
-        QList<int> trackIndices = playlistMap.values( playlist );
-        qSort( trackIndices );
-        int removed = 0;
-        foreach( int trackIndex, trackIndices )
-        {
-            playlist->removeTrack( trackIndex - removed /* account for already removed */ );
-            removed++;
-        }
-    }
-
-    //clear the data
-    action->setData( QVariant() );
-}
-
-#include "UserPlaylistProvider.moc"
diff --git a/src/core-impl/playlists/providers/user/UserPlaylistProvider.h b/src/core-impl/playlists/providers/user/UserPlaylistProvider.h
index 38a3cd9..b72ead5 100644
--- a/src/core-impl/playlists/providers/user/UserPlaylistProvider.h
+++ b/src/core-impl/playlists/providers/user/UserPlaylistProvider.h
@@ -20,73 +20,26 @@
 #define USERPLAYLISTPROVIDER_H
 
 #include "amarok_export.h"
-#include "core/playlists/Playlist.h"
 #include "core/playlists/PlaylistProvider.h"
 
-class QAction;
-
 namespace Playlists {
-
-/**
-    @author Bart Cerneels <bart.cerneels at kde.org>
-*/
-class AMAROK_EXPORT UserPlaylistProvider : public PlaylistProvider
-{
-    Q_OBJECT
-    public:
-        explicit UserPlaylistProvider( QObject *parent = 0 );
-        virtual ~UserPlaylistProvider();
-
-        /* PlaylistProvider functions */
-        virtual int category() const;
-
-        /* UserPlaylistProvider functions */
-        virtual Playlists::PlaylistPtr save( const Meta::TrackList &tracks,
-                                             const QString& name = QString() ) = 0;
-
-        virtual QList<QAction *> playlistActions( Playlists::PlaylistPtr playlist );
-        virtual QList<QAction *> trackActions( Playlists::PlaylistPtr playlist,
-                                                  int trackIndex );
-
-        // UserPlaylistProvider-specific
-        virtual bool isWritable() { return false; }
-        virtual void rename( Playlists::PlaylistPtr playlist, const QString &newName )
-                { Q_UNUSED( playlist ) Q_UNUSED(newName) }
-        virtual bool deletePlaylists( Playlists::PlaylistList playlistlist )
-                { Q_UNUSED( playlistlist ) return false; }
-
-    protected slots:
-        /**
-         * Delete selected playlists.
-         * Will only work if the sender is a QAction with a PlaylistPtr as data.
-         */
-        virtual void slotDelete();
-
-        /**
-         * Rename selected playlist.
-         * Will only work if the sender is a QAction with a PlaylistPtr as data.
-         */
-        virtual void slotRename();
-
-        /**
-         * Export the selected playlist.
-         * Will only work if the sender is a QAction with a PlaylistPtr as data.
-         */
-        virtual void slotExport();
-
-        /**
-         * Remove a track (or tracks) from a playlist.
-         * Will only work if the sender is a QAction with a PlaylistTrackMap as data.
-         */
-        virtual void slotRemoveTrack();
-
-    protected:
-        QAction *m_deleteAction;
-        QAction *m_renameAction;
-        QAction *m_exportAction;
-        QAction *m_removeTrackAction;
-};
-
+    /**
+     * @author Bart Cerneels <bart.cerneels at kde.org>
+     */
+    class AMAROK_EXPORT UserPlaylistProvider : public PlaylistProvider
+    {
+        Q_OBJECT
+
+        public:
+            explicit UserPlaylistProvider( QObject *parent = 0 );
+
+            /* PlaylistProvider functions */
+            virtual int category() const;
+
+            /* UserPlaylistProvider functions */
+            virtual PlaylistPtr save( const Meta::TrackList &tracks,
+                                      const QString &name = QString() ) = 0;
+    };
 } //namespace Playlists
 
 #endif
diff --git a/src/core-impl/playlists/types/file/PlaylistFile.h b/src/core-impl/playlists/types/file/PlaylistFile.h
index de71057..bd88199 100644
--- a/src/core-impl/playlists/types/file/PlaylistFile.h
+++ b/src/core-impl/playlists/types/file/PlaylistFile.h
@@ -25,11 +25,11 @@
 #include <QMutex>
 #include <QSemaphore>
 
-class PlaylistProvider;
 class QFile;
 
 namespace Playlists
 {
+    class PlaylistProvider;
     class PlaylistFile;
     class PlaylistFileLoaderJob;
 
diff --git a/src/core-impl/podcasts/sql/SqlPodcastProvider.cpp b/src/core-impl/podcasts/sql/SqlPodcastProvider.cpp
index ad60e2b..ba7387b 100644
--- a/src/core-impl/podcasts/sql/SqlPodcastProvider.cpp
+++ b/src/core-impl/podcasts/sql/SqlPodcastProvider.cpp
@@ -280,31 +280,25 @@ SqlPodcastProvider::playlists()
     return playlistList;
 }
 
-QList<QAction *>
+QActionList
 SqlPodcastProvider::providerActions()
 {
     if( m_providerActions.isEmpty() )
     {
         QAction *updateAllAction = new QAction( KIcon( "view-refresh-amarok" ),
-                                         i18n( "&Update All Channels" ),
-                                         this
-                                       );
+                i18n( "&Update All Channels" ), this );
         updateAllAction->setProperty( "popupdropper_svg_id", "update" );
         connect( updateAllAction, SIGNAL(triggered()), this, SLOT(updateAll()) );
         m_providerActions << updateAllAction;
 
         QAction *configureAction = new QAction( KIcon( "configure" ),
-            i18n( "&Configure General Settings" ),
-            this
-        );
+                i18n( "&Configure General Settings" ), this );
         configureAction->setProperty( "popupdropper_svg_id", "configure" );
         connect( configureAction, SIGNAL(triggered()), this, SLOT(slotConfigureProvider()) );
         m_providerActions << configureAction;
 
         QAction *exportOpmlAction = new QAction( KIcon( "document-export" ),
-                                                 i18n( "&Export subscriptions to OPML file" ),
-                                                 this
-                                               );
+                i18n( "&Export subscriptions to OPML file" ), this );
         connect( exportOpmlAction, SIGNAL(triggered()), SLOT(slotExportOpml()) );
         m_providerActions << exportOpmlAction;
     }
@@ -312,114 +306,100 @@ SqlPodcastProvider::providerActions()
     return m_providerActions;
 }
 
-QList<QAction *>
-SqlPodcastProvider::playlistActions( Playlists::PlaylistPtr playlist )
+QActionList
+SqlPodcastProvider::playlistActions( const Playlists::PlaylistList &playlists )
 {
-    QList<QAction *> actions;
+    QActionList actions;
+    SqlPodcastChannelList sqlChannels;
+    foreach( const Playlists::PlaylistPtr &playlist, playlists )
+    {
+        SqlPodcastChannelPtr sqlChannel = SqlPodcastChannel::fromPlaylistPtr( playlist );
+        if( sqlChannel )
+            sqlChannels << sqlChannel;
+    }
 
-    Podcasts::SqlPodcastChannelPtr sqlChannel = Podcasts::SqlPodcastChannel::fromPlaylistPtr( playlist );
-    if( sqlChannel.isNull() )
+    if( sqlChannels.isEmpty() )
         return actions;
 
     //TODO: add export OPML action for selected playlists only. Use the QAction::data() trick.
     if( m_configureChannelAction == 0 )
     {
-        m_configureChannelAction = new QAction(
-            KIcon( "configure" ),
-            i18n( "&Configure" ),
-            this
-        );
+        m_configureChannelAction = new QAction( KIcon( "configure" ), i18n( "&Configure" ), this );
         m_configureChannelAction->setProperty( "popupdropper_svg_id", "configure" );
         connect( m_configureChannelAction, SIGNAL(triggered()), SLOT(slotConfigureChannel()) );
     }
-
     //only one channel can be configured at a time.
-    if( m_configureChannelAction->data().isNull() )
-        m_configureChannelAction->setData( QVariant::fromValue( sqlChannel ) );
-
-    actions << m_configureChannelAction;
+    if( sqlChannels.count() == 1 )
+    {
+        m_configureChannelAction->setData( QVariant::fromValue( sqlChannels.first() ) );
+        actions << m_configureChannelAction;
+    }
 
-    Podcasts::SqlPodcastChannelList actionChannels;
     if( m_removeAction == 0 )
     {
-        m_removeAction = new QAction(
-            KIcon( "news-unsubscribe" ),
-            i18n( "&Remove Subscription" ),
-            this
-        );
+        m_removeAction = new QAction( KIcon( "news-unsubscribe" ), i18n( "&Remove Subscription" ), this );
         m_removeAction->setProperty( "popupdropper_svg_id", "remove" );
         connect( m_removeAction, SIGNAL(triggered()), SLOT(slotRemoveChannels()) );
     }
-    else
-    {
-        actionChannels = m_removeAction->data().value<Podcasts::SqlPodcastChannelList>();
-    }
-    m_removeAction->setObjectName( "deleteAction" );
-
-    actionChannels << sqlChannel;
-    m_removeAction->setData( QVariant::fromValue( actionChannels ) );
-
+    m_removeAction->setData( QVariant::fromValue( sqlChannels ) );
     actions << m_removeAction;
 
-    actionChannels.clear();
     if( m_updateAction == 0 )
     {
-        m_updateAction = new QAction(
-            KIcon( "view-refresh-amarok" ),
-            i18n( "&Update Channel" ),
-            this
-        );
+        m_updateAction = new QAction( KIcon( "view-refresh-amarok" ), i18n( "&Update Channel" ), this );
         m_updateAction->setProperty( "popupdropper_svg_id", "update" );
         connect( m_updateAction, SIGNAL(triggered()), SLOT(slotUpdateChannels()) );
     }
-    else
-    {
-        actionChannels = m_updateAction->data().value<Podcasts::SqlPodcastChannelList>();
-    }
-
-    actionChannels << sqlChannel;
-    m_updateAction->setData( QVariant::fromValue( actionChannels ) );
-
+    m_updateAction->setData( QVariant::fromValue( sqlChannels ) );
     actions << m_updateAction;
 
     return actions;
 }
 
-QList<QAction *>
-SqlPodcastProvider::trackActions( Playlists::PlaylistPtr playlist, int trackIndex )
+QActionList
+SqlPodcastProvider::trackActions( const QMultiHash<Playlists::PlaylistPtr, int> &playlistTracks )
 {
-    QList<QAction *> actions;
-    Podcasts::SqlPodcastChannelPtr sqlChannel = Podcasts::SqlPodcastChannel::fromPlaylistPtr( playlist );
-    if( sqlChannel.isNull() )
-        return actions;
+    SqlPodcastEpisodeList episodes;
+    foreach( const Playlists::PlaylistPtr &playlist, playlistTracks.uniqueKeys() )
+    {
+        SqlPodcastChannelPtr sqlChannel = SqlPodcastChannel::fromPlaylistPtr( playlist );
+        if( !sqlChannel )
+            continue;
 
-    Podcasts::SqlPodcastEpisodeList sqlEpisodes = sqlChannel->sqlEpisodes();
-    if( trackIndex >= sqlEpisodes.count() )
-        return actions;
+        SqlPodcastEpisodeList channelEpisodes = sqlChannel->sqlEpisodes();
+        QList<int> trackPositions = playlistTracks.values( playlist );
+        qSort( trackPositions );
+        foreach( int trackPosition, trackPositions )
+        {
+            if( trackPosition >= 0 && trackPosition < channelEpisodes.count() )
+                episodes << channelEpisodes.at( trackPosition );
+        }
+    }
 
-    Podcasts::SqlPodcastEpisodePtr sqlEpisode = sqlEpisodes.at( trackIndex );
-    if( sqlEpisode.isNull() )
+    QActionList actions;
+    if( episodes.isEmpty() )
         return actions;
 
+    if( m_downloadAction == 0 )
+    {
+        m_downloadAction = new QAction( KIcon( "go-down" ), i18n( "&Download Episode" ), this );
+        m_downloadAction->setProperty( "popupdropper_svg_id", "download" );
+        connect( m_downloadAction, SIGNAL(triggered()), SLOT(slotDownloadEpisodes()) );
+    }
+
     if( m_deleteAction == 0 )
     {
-        m_deleteAction = new QAction(
-            KIcon( "edit-delete" ),
-            i18n( "&Delete Downloaded Episode" ),
-            this
-        );
+        m_deleteAction = new QAction( KIcon( "edit-delete" ),
+            i18n( "&Delete Downloaded Episode" ), this );
         m_deleteAction->setProperty( "popupdropper_svg_id", "delete" );
+        m_deleteAction->setObjectName( "deleteAction" );
         connect( m_deleteAction, SIGNAL(triggered()), SLOT(slotDeleteDownloadedEpisodes()) );
     }
-    m_deleteAction->setObjectName( "deleteAction" );
 
     if( m_writeTagsAction == 0 )
     {
-        m_writeTagsAction = new QAction(
-            KIcon( "media-track-edit-amarok" ),
-            i18n( "&Write Feed Information to File" ),
-            this
-        );
+        m_writeTagsAction = new QAction( KIcon( "media-track-edit-amarok" ),
+            i18n( "&Write Feed Information to File" ), this );
         m_writeTagsAction->setProperty( "popupdropper_svg_id", "edit" );
         connect( m_writeTagsAction, SIGNAL(triggered()), SLOT(slotWriteTagsToFiles()) );
     }
@@ -427,51 +407,44 @@ SqlPodcastProvider::trackActions( Playlists::PlaylistPtr playlist, int trackInde
     if( m_keepAction == 0 )
     {
         m_keepAction = new QAction( KIcon( "podcast-amarok" ),
-                                       i18nc( "toggle the \"keep\" downloaded file status of this podcast episode. "
-                                              "Notice that downloaded files with this status wouldn't be deleted if we apply a purge.",
-                                              "&Keep downloaded file" ),
-                                       this
-                                       );
+                i18n( "&Keep downloaded file" ), this );
+        m_keepAction->setToolTip( i18n( "Toggle the \"keep\" downloaded file status of "
+                "this podcast episode. Downloaded files with this status wouldn't be "
+                "deleted even if we apply a purge." ) );
         m_keepAction->setProperty( "popupdropper_svg_id", "keep" );
         m_keepAction->setCheckable( true );
-
         connect( m_keepAction, SIGNAL(triggered(bool)), SLOT(slotSetKeep()) );
     }
 
-    Podcasts::SqlPodcastEpisodeList actionEpisodes;
-    if( !sqlEpisode->localUrl().isEmpty() )
-    {
-        actionEpisodes = m_deleteAction->data().value<Podcasts::SqlPodcastEpisodeList>();
-        actionEpisodes << sqlEpisode;
-        m_keepAction->setChecked( sqlEpisode->isKeep() );
-        m_keepAction->setData( QVariant::fromValue( actionEpisodes ) );
-        m_deleteAction->setData( QVariant::fromValue( actionEpisodes ) );
-        //these lists are the same anyway
-        m_writeTagsAction->setData( QVariant::fromValue( actionEpisodes ) );
-        actions << m_keepAction;
-        actions << m_deleteAction;
-        actions << m_writeTagsAction;
-    }
-    else
+    SqlPodcastEpisodeList remoteEpisodes;
+    SqlPodcastEpisodeList keptDownloadedEpisodes, unkeptDownloadedEpisodes;
+    foreach( const SqlPodcastEpisodePtr &episode, episodes )
     {
-        if( m_downloadAction == 0 )
-        {
-            m_downloadAction = new QAction(
-                KIcon( "go-down" ),
-                i18n( "&Download Episode" ),
-                this
-            );
-            m_downloadAction->setProperty( "popupdropper_svg_id", "download" );
-            connect( m_downloadAction, SIGNAL(triggered()), SLOT(slotDownloadEpisodes()) );
-        }
+        if( episode->localUrl().isEmpty() )
+            remoteEpisodes << episode;
         else
         {
-            actionEpisodes = m_downloadAction->data().value<Podcasts::SqlPodcastEpisodeList>();
+            if( episode->isKeep() )
+                keptDownloadedEpisodes << episode;
+            else
+                unkeptDownloadedEpisodes << episode;
         }
-        actionEpisodes << sqlEpisode;
-        m_downloadAction->setData( QVariant::fromValue( actionEpisodes ) );
+    }
+
+    if( !remoteEpisodes.isEmpty() )
+    {
+        m_downloadAction->setData( QVariant::fromValue( remoteEpisodes ) );
         actions << m_downloadAction;
     }
+    if( !( keptDownloadedEpisodes + unkeptDownloadedEpisodes ).isEmpty() )
+    {
+        m_deleteAction->setData( QVariant::fromValue( keptDownloadedEpisodes + unkeptDownloadedEpisodes ) );
+        actions << m_deleteAction;
+
+        m_keepAction->setChecked( unkeptDownloadedEpisodes.isEmpty() );
+        m_keepAction->setData( QVariant::fromValue( keptDownloadedEpisodes + unkeptDownloadedEpisodes ) );
+        actions << m_keepAction;
+    }
 
     return actions;
 }
@@ -806,179 +779,6 @@ SqlPodcastProvider::configureChannel( Podcasts::SqlPodcastChannelPtr sqlChannel
         startTimer();
 }
 
-QList<QAction *>
-SqlPodcastProvider::episodeActions( Podcasts::PodcastEpisodeList episodes )
-{
-    QList< QAction * > actions;
-    if( episodes.isEmpty() )
-        return actions;
-
-    Podcasts::PodcastEpisodeList actionEpisodes;
-    if( m_deleteAction == 0 )
-    {
-        m_deleteAction = new QAction(
-            KIcon( "edit-delete" ),
-            i18n( "&Delete Downloaded Episode" ),
-            this
-        );
-        m_deleteAction->setProperty( "popupdropper_svg_id", "delete" );
-        connect( m_deleteAction, SIGNAL(triggered()), SLOT(slotDeleteDownloadedEpisodes()) );
-    }
-
-    actionEpisodes.clear();
-    if( m_writeTagsAction == 0 )
-    {
-        m_writeTagsAction = new QAction(
-            KIcon( "media-track-edit-amarok" ),
-            i18n( "&Write Feed Information to File" ),
-            this
-        );
-        m_writeTagsAction->setProperty( "popupdropper_svg_id", "edit" );
-        connect( m_writeTagsAction, SIGNAL(triggered()), SLOT(slotWriteTagsToFiles()) );
-    }
-
-    if( m_keepAction == 0 )
-    {
-        m_keepAction = new QAction( KIcon( "podcast-amarok" ),
-                                       i18nc( "toggle the \"keep\" downloaded file status of this podcast episode. "
-                                              "Notice that downloaded files with this status wouldn't be deleted if we apply a purge.",
-                                              "&Keep downloaded file" ),
-                                       this
-                                       );
-        m_keepAction->setProperty( "popupdropper_svg_id", "keep" );
-        m_keepAction->setCheckable( true );
-
-        connect( m_keepAction, SIGNAL(triggered(bool)), SLOT(slotSetKeep()) );
-    }
-
-    bool hasDownloaded = false;
-    bool hasKeep = false;
-    foreach( Podcasts::PodcastEpisodePtr episode, episodes )
-    {
-        Podcasts::SqlPodcastEpisodePtr sqlEpisode
-                = Podcasts::SqlPodcastEpisodePtr::dynamicCast( episode );
-        if( sqlEpisode.isNull() )
-            break;
-
-        if( !sqlEpisode->localUrl().isEmpty() )
-        {
-            hasDownloaded = true;
-
-            if ( sqlEpisode->isKeep() )
-                hasKeep = true;
-
-            break;
-        }
-    }
-    if( hasDownloaded )
-    {
-        Podcasts::PodcastEpisodeList actionEpisodes = m_deleteAction->data().value<Podcasts::PodcastEpisodeList>();
-        actionEpisodes << episodes;
-        //these lists are the same anyway
-        m_keepAction->setData( QVariant::fromValue( actionEpisodes ) );
-        m_deleteAction->setData( QVariant::fromValue( actionEpisodes ) );
-        m_writeTagsAction->setData( QVariant::fromValue( actionEpisodes ) );
-
-        m_keepAction->setChecked( hasKeep );
-
-        actions << m_keepAction;
-        actions << m_deleteAction;
-        actions << m_writeTagsAction;
-    }
-    else
-    {
-        if( m_downloadAction == 0 )
-        {
-            m_downloadAction = new QAction(
-                KIcon( "go-down" ),
-                i18n( "&Download Episode" ),
-                this
-            );
-            m_downloadAction->setProperty( "popupdropper_svg_id", "download" );
-            connect( m_downloadAction, SIGNAL(triggered()), SLOT(slotDownloadEpisodes()) );
-        }
-        else
-        {
-            actionEpisodes = m_downloadAction->data().value<Podcasts::PodcastEpisodeList>();
-        }
-        actionEpisodes << episodes;
-        m_downloadAction->setData( QVariant::fromValue( actionEpisodes ) );
-        actions << m_downloadAction;
-    }
-
-    return actions;
-}
-
-QList<QAction *>
-SqlPodcastProvider::channelActions( Podcasts::PodcastChannelList channels )
-{
-    QList< QAction * > actions;
-
-    if( channels.isEmpty() )
-        return actions;
-
-    if( m_configureChannelAction == 0 )
-    {
-        m_configureChannelAction = new QAction(
-            KIcon( "configure" ),
-            i18n( "&Configure" ),
-            this
-        );
-        m_configureChannelAction->setProperty( "popupdropper_svg_id", "configure" );
-        connect( m_configureChannelAction, SIGNAL(triggered()), SLOT(slotConfigureChannel()) );
-    }
-
-    //only one playlist can be renamed at a time.
-    if( m_configureChannelAction->data().isNull() )
-        m_configureChannelAction->setData( QVariant::fromValue( channels.first() ) );
-
-    actions << m_configureChannelAction;
-
-    Podcasts::PodcastChannelList actionChannels;
-    if( m_removeAction == 0 )
-    {
-        m_removeAction = new QAction(
-            KIcon( "news-unsubscribe" ),
-            i18n( "&Remove Subscription" ),
-            this
-        );
-        m_removeAction->setProperty( "popupdropper_svg_id", "remove" );
-        connect( m_removeAction, SIGNAL(triggered()), SLOT(slotRemoveChannels()) );
-    }
-    else
-    {
-        actionChannels = m_removeAction->data().value<Podcasts::PodcastChannelList>();
-    }
-
-    actionChannels << channels;
-    m_removeAction->setData( QVariant::fromValue( actionChannels ) );
-
-    actions << m_removeAction;
-
-    actionChannels.clear();
-    if( m_updateAction == 0 )
-    {
-        m_updateAction = new QAction(
-            KIcon( "view-refresh-amarok" ),
-            i18n( "&Update Channel" ),
-            this
-        );
-        m_updateAction->setProperty( "popupdropper_svg_id", "update" );
-        connect( m_updateAction, SIGNAL(triggered()), SLOT(slotUpdateChannels()) );
-    }
-    else
-    {
-        actionChannels = m_updateAction->data().value<Podcasts::PodcastChannelList>();
-    }
-
-    actionChannels << channels;
-    m_updateAction->setData( QVariant::fromValue( actionChannels ) );
-
-    actions << m_updateAction;
-
-    return actions;
-}
-
 void
 SqlPodcastProvider::deleteDownloadedEpisodes( Podcasts::SqlPodcastEpisodeList &episodes )
 {
diff --git a/src/core-impl/podcasts/sql/SqlPodcastProvider.h b/src/core-impl/podcasts/sql/SqlPodcastProvider.h
index 6d341ca..2e590b4 100644
--- a/src/core-impl/podcasts/sql/SqlPodcastProvider.h
+++ b/src/core-impl/podcasts/sql/SqlPodcastProvider.h
@@ -59,9 +59,9 @@ class AMAROK_EXPORT SqlPodcastProvider : public Podcasts::PodcastProvider
         virtual Playlists::PlaylistList playlists();
 
         //PlaylistProvider methods
-        virtual QList<QAction *> providerActions();
-        virtual QList<QAction *> playlistActions( Playlists::PlaylistPtr playlist );
-        virtual QList<QAction *> trackActions( Playlists::PlaylistPtr playlist, int trackIndex );
+        virtual QActionList providerActions();
+        virtual QActionList playlistActions( const Playlists::PlaylistList &playlists );
+        virtual QActionList trackActions( const QMultiHash<Playlists::PlaylistPtr, int> &playlistTracks );
 
         //PodcastProvider methods
         virtual Podcasts::PodcastEpisodePtr episodeForGuid( const QString &guid );
@@ -73,9 +73,6 @@ class AMAROK_EXPORT SqlPodcastProvider : public Podcasts::PodcastProvider
 
         virtual Podcasts::PodcastChannelList channels();
 
-        virtual QList<QAction *> episodeActions( Podcasts::PodcastEpisodeList );
-        virtual QList<QAction *> channelActions( Podcasts::PodcastChannelList );
-
         virtual void completePodcastDownloads();
 
         //SqlPodcastProvider specific methods
diff --git a/src/core/playlists/Playlist.cpp b/src/core/playlists/Playlist.cpp
index 2677c78..401d728 100644
--- a/src/core/playlists/Playlist.cpp
+++ b/src/core/playlists/Playlist.cpp
@@ -96,23 +96,6 @@ Playlist::syncTrackStatus( int, Meta::TrackPtr )
 {
 }
 
-QActionList
-Playlist::actions()
-{
-    if( provider() )
-        return provider()->playlistActions( PlaylistPtr( this ) );
-
-    return QActionList();
-}
-
-QActionList
-Playlist::trackActions( int trackIndex )
-{
-    if( provider() )
-        return provider()->trackActions( PlaylistPtr( this ), trackIndex );
-    return QActionList();
-}
-
 QStringList
 Playlist::groups()
 {
diff --git a/src/core/playlists/Playlist.h b/src/core/playlists/Playlist.h
index 9fa854f..8543b9c 100644
--- a/src/core/playlists/Playlist.h
+++ b/src/core/playlists/Playlist.h
@@ -206,18 +206,6 @@ namespace Playlists
             virtual void syncTrackStatus( int position, Meta::TrackPtr otherTrack );
 
             /**
-             * Return user-actionable actions for this playlist. Default implementation
-             * just returns provider actions for this playlist.
-             */
-            virtual QActionList actions();
-
-            /**
-             * Return actions for track at position @trackIndex for this playlist. Default
-             * implementation returns provider()'s trackActions().
-             */
-            virtual QActionList trackActions( int trackIndex );
-
-            /**
              * A list of groups or labels this playlist belongs to.
              *
              * Can be used for grouping in folders (use ex. '/' as separator) or for
diff --git a/src/core/playlists/PlaylistProvider.cpp b/src/core/playlists/PlaylistProvider.cpp
index 545a11e..b42061f 100644
--- a/src/core/playlists/PlaylistProvider.cpp
+++ b/src/core/playlists/PlaylistProvider.cpp
@@ -19,16 +19,55 @@
 
 using namespace Playlists;
 
+PlaylistProvider::PlaylistProvider( QObject *parent)
+    : QObject( parent )
+{
+}
+
+QActionList
+PlaylistProvider::providerActions()
+{
+    return QActionList();
+}
+
+QActionList
+PlaylistProvider::playlistActions( const PlaylistList & )
+{
+    return QActionList();
+
+}
+
+QActionList
+PlaylistProvider::trackActions( const QMultiHash<PlaylistPtr, int> & )
+{
+    return QActionList();
+}
+
+bool
+PlaylistProvider::isWritable()
+{
+    return false;
+}
+
 PlaylistPtr
-PlaylistProvider::addPlaylist( Playlists::PlaylistPtr playlist )
+PlaylistProvider::addPlaylist( Playlists::PlaylistPtr )
 {
-    Q_UNUSED( playlist );
     return PlaylistPtr();
 }
 
+void
+PlaylistProvider::renamePlaylist( PlaylistPtr, const QString & )
+{
+}
+
+bool
+PlaylistProvider::deletePlaylists( const PlaylistList & )
+{
+    return false;
+}
+
 Meta::TrackPtr
-PlaylistProvider::addTrack( Meta::TrackPtr track )
+PlaylistProvider::addTrack( Meta::TrackPtr )
 {
-    Q_UNUSED( track );
     return Meta::TrackPtr();
 }
diff --git a/src/core/playlists/PlaylistProvider.h b/src/core/playlists/PlaylistProvider.h
index 4752225..95cafb3 100644
--- a/src/core/playlists/PlaylistProvider.h
+++ b/src/core/playlists/PlaylistProvider.h
@@ -20,9 +20,6 @@
 #include "core/amarokcore_export.h"
 #include "core/playlists/Playlist.h"
 
-#include <QString>
-
-class QAction;
 class KIcon;
 
 namespace Playlists {
@@ -32,14 +29,16 @@ class AMAROK_CORE_EXPORT PlaylistProvider : public QObject
     Q_OBJECT
 
     public:
-        PlaylistProvider( QObject *parent = 0 ) : QObject( parent ) {}
-        virtual ~PlaylistProvider() {}
+        explicit PlaylistProvider( QObject *parent = 0 );
 
         /**
-        * @returns A translated string to identify this Provider.
-        */
+         * A translated string to identify this Provider.
+         */
         virtual QString prettyName() const = 0;
 
+        /**
+         * A nice icon for this playlist provider.
+         */
         virtual KIcon icon() const = 0;
 
         /**
@@ -48,24 +47,56 @@ class AMAROK_CORE_EXPORT PlaylistProvider : public QObject
          */
         virtual int category() const = 0;
 
-        /** @returns the number of playlists this provider has or a negative value if it
+        /**
+         * @returns the number of playlists this provider has or a negative value if it
          * can not determine that before loading them all.
+         *
+         * Default implementation returns -1.
          */
         virtual int playlistCount() const { return -1; }
-        virtual Playlists::PlaylistList playlists() = 0;
 
-        virtual QActionList providerActions() { return QList<QAction *>(); }
-        virtual QActionList playlistActions( Playlists::PlaylistPtr playlist ) = 0;
-        virtual QActionList trackActions( Playlists::PlaylistPtr playlist, int trackIndex ) = 0;
+        /**
+         * Return a list of plyalists of this provider. If playlistCount() is negative,
+         * this list may be incomplete.
+         */
+        virtual PlaylistList playlists() = 0;
 
-        /** Copy a playlist to the provider.
-          */
-        virtual Playlists::PlaylistPtr addPlaylist( Playlists::PlaylistPtr playlist );
+        virtual QActionList providerActions();
+        virtual QActionList playlistActions( const PlaylistList &playlists );
+        virtual QActionList trackActions( const QMultiHash<PlaylistPtr, int> &playlistTracks );
 
-        /** Copy a track directly to a playlist provider without being in a playlist.
-          * It's up to the implementation to decide what to do but could for instance allow the
-          * creation of a new playlist from scratch.
-          */
+        /**
+         * Return true if this providers supports modification made by the user.
+         *
+         * I.e. whether addPlaylist(), renamePlaylist(), deletePlaylists() make sense
+         * to be triggered by user action.
+         *
+         * Default implementation returns false.
+         */
+        virtual bool isWritable();
+
+        /**
+         * Copy a playlist to the provider.
+         */
+        virtual PlaylistPtr addPlaylist( PlaylistPtr playlist );
+
+        /**
+         * Rename a playlist of this provider.
+         */
+        virtual void renamePlaylist( PlaylistPtr playlist, const QString &newName );
+
+        /**
+         * Deletes a list of playlists. Returns true of successful, false otherwise.
+         *
+         * Default implementation does nothing and returns false.
+         */
+        virtual bool deletePlaylists( const PlaylistList &playlistlist );
+
+        /**
+         * Copy a track directly to a playlist provider without being in a playlist.
+         * It's up to the implementation to decide what to do but could for instance allow the
+         * creation of a new playlist from scratch.
+         */
         virtual Meta::TrackPtr addTrack( Meta::TrackPtr track );
 
     signals:
diff --git a/src/core/podcasts/PodcastProvider.h b/src/core/podcasts/PodcastProvider.h
index 257aaee..f126ebe 100644
--- a/src/core/podcasts/PodcastProvider.h
+++ b/src/core/podcasts/PodcastProvider.h
@@ -21,12 +21,6 @@
 #include "core/playlists/PlaylistProvider.h"
 #include "core/podcasts/PodcastMeta.h"
 
-#include <kio/jobclasses.h>
-#include <KLocale>
-
-class KUrl;
-class QAction;
-
 namespace Podcasts {
 
 /**
@@ -38,8 +32,6 @@ class AMAROK_CORE_EXPORT PodcastProvider : public Collections::TrackProvider, pu
         static bool couldBeFeed( const QString &urlString );
         static KUrl toFeedUrl( const QString &urlString );
 
-        virtual ~PodcastProvider() {}
-
         virtual bool possiblyContainsTrack( const KUrl &url ) const = 0;
         virtual Meta::TrackPtr trackForUrl( const KUrl &url ) = 0;
 
@@ -59,29 +51,12 @@ class AMAROK_CORE_EXPORT PodcastProvider : public Collections::TrackProvider, pu
 
         virtual Podcasts::PodcastChannelList channels() = 0;
 
-        virtual QList<QAction *> episodeActions( Podcasts::PodcastEpisodeList )
-            { return QList<QAction *>(); }
-        virtual QList<QAction *> channelActions( Podcasts::PodcastChannelList )
-            { return QList<QAction *>(); }
-
         //TODO: need to move this to SqlPodcastProvider since it's provider specific.
         //perhaps use a more general transferprogress for playlists
         virtual void completePodcastDownloads() = 0;
 
         // PlaylistProvider methods
-        virtual QString prettyName() const = 0;
-        virtual KIcon icon() const = 0;
-
-        virtual int category() const { return (int)Playlists::PodcastChannelPlaylist; }
-
-        virtual Playlists::PlaylistList playlists() = 0;
-
-        virtual QList<QAction *> providerActions() { return QList<QAction *>(); }
-        virtual QList<QAction *> playlistActions( Playlists::PlaylistPtr playlist )
-                { Q_UNUSED( playlist ) return QList<QAction *>(); }
-        virtual QList<QAction *> trackActions( Playlists::PlaylistPtr playlist,
-                                                  int trackIndex )
-                { Q_UNUSED( playlist) Q_UNUSED( trackIndex ) return QList<QAction *>(); }
+        virtual int category() const { return Playlists::PodcastChannelPlaylist; }
 
         /** convenience function that downcast the argument to PodcastChannel and calls addChannel()
           */
diff --git a/src/playlistmanager/PlaylistManager.cpp b/src/playlistmanager/PlaylistManager.cpp
index 281215e..860a8da 100644
--- a/src/playlistmanager/PlaylistManager.cpp
+++ b/src/playlistmanager/PlaylistManager.cpp
@@ -359,7 +359,7 @@ PlaylistManager::rename( PlaylistPtr playlist, const QString &newName )
     if( !provider || !provider->isWritable() )
         return false;
 
-    provider->rename( playlist, newName );
+    provider->renamePlaylist( playlist, newName );
     return true;
 }
 
diff --git a/src/playlistmanager/SyncedPlaylist.cpp b/src/playlistmanager/SyncedPlaylist.cpp
index ae6f9ab..985f087 100644
--- a/src/playlistmanager/SyncedPlaylist.cpp
+++ b/src/playlistmanager/SyncedPlaylist.cpp
@@ -104,24 +104,6 @@ SyncedPlaylist::removeTrack( int position )
     m_playlists.first()->removeTrack( position );
 }
 
-QActionList
-SyncedPlaylist::actions()
-{
-    QActionList actions;
-    //only add actions from the master playlist
-    actions << playlists().first()->actions();
-    return actions;
-}
-
-QActionList
-SyncedPlaylist::trackActions( int trackIndex )
-{
-    QActionList actions;
-    //only add actions from the master playlist
-    actions << playlists().first()->trackActions( trackIndex );
-    return actions;
-}
-
 void
 SyncedPlaylist::metadataChanged( Playlists::PlaylistPtr playlist )
 {
diff --git a/src/playlistmanager/SyncedPlaylist.h b/src/playlistmanager/SyncedPlaylist.h
index 214bb5c..fd2f966 100644
--- a/src/playlistmanager/SyncedPlaylist.h
+++ b/src/playlistmanager/SyncedPlaylist.h
@@ -43,9 +43,6 @@ class SyncedPlaylist : public Playlists::Playlist, public Playlists::PlaylistObs
         virtual void addTrack( Meta::TrackPtr track, int position = -1 );
         virtual void removeTrack( int position );
 
-        virtual QActionList actions();
-        virtual QActionList trackActions( int trackIndex );
-
         //PlaylistObserver methods
         virtual void metadataChanged( Playlists::PlaylistPtr playlist );
         virtual void tracksLoaded( Playlists::PlaylistPtr);
diff --git a/src/playlistmanager/file/PlaylistFileProvider.cpp b/src/playlistmanager/file/PlaylistFileProvider.cpp
index 5126c62..cd35efa 100644
--- a/src/playlistmanager/file/PlaylistFileProvider.cpp
+++ b/src/playlistmanager/file/PlaylistFileProvider.cpp
@@ -97,6 +97,11 @@ PlaylistFileProvider::prettyName() const
     return i18n( "Playlist Files on Disk" );
 }
 
+KIcon PlaylistFileProvider::icon() const
+{
+    return KIcon( "folder-documents" );
+}
+
 int
 PlaylistFileProvider::playlistCount() const
 {
@@ -229,14 +234,14 @@ PlaylistFileProvider::import( const KUrl &path )
 }
 
 void
-PlaylistFileProvider::rename( Playlists::PlaylistPtr playlist, const QString &newName )
+PlaylistFileProvider::renamePlaylist( Playlists::PlaylistPtr playlist, const QString &newName )
 {
     DEBUG_BLOCK
     playlist->setName( newName );
 }
 
 bool
-PlaylistFileProvider::deletePlaylists( Playlists::PlaylistList playlists )
+PlaylistFileProvider::deletePlaylists( const Playlists::PlaylistList &playlists )
 {
     Playlists::PlaylistFileList playlistFiles;
     foreach( Playlists::PlaylistPtr playlist, playlists )
diff --git a/src/playlistmanager/file/PlaylistFileProvider.h b/src/playlistmanager/file/PlaylistFileProvider.h
index b15437a..58b2f41 100644
--- a/src/playlistmanager/file/PlaylistFileProvider.h
+++ b/src/playlistmanager/file/PlaylistFileProvider.h
@@ -22,12 +22,6 @@
 #include "core-impl/playlists/providers/user/UserPlaylistProvider.h"
 #include "core-impl/playlists/types/file/PlaylistFileSupport.h"
 
-#include <kicon.h>
-
-class KConfigGroup;
-class KUrl;
-
-class QAction;
 class QTimer;
 
 namespace Playlists {
@@ -43,7 +37,7 @@ class PlaylistFileProvider : public Playlists::UserPlaylistProvider
         virtual ~PlaylistFileProvider();
 
         virtual QString prettyName() const;
-        virtual KIcon icon() const { return KIcon( "folder-documents" ); }
+        virtual KIcon icon() const;
 
         virtual int category() const { return Playlists::UserPlaylist; }
 
@@ -62,8 +56,8 @@ class PlaylistFileProvider : public Playlists::UserPlaylistProvider
         virtual bool import( const KUrl &path );
 
         virtual bool isWritable() { return true; }
-        virtual void rename( Playlists::PlaylistPtr playlist, const QString &newName );
-        virtual bool deletePlaylists( Playlists::PlaylistList playlistList );
+        virtual void renamePlaylist( Playlists::PlaylistPtr playlist, const QString &newName );
+        virtual bool deletePlaylists( const Playlists::PlaylistList &playlists );
 
         /* PlaylistFileProvider methods */
         /** Schedules a PlaylistFile to be saved on the next iteration of the mainloop.
diff --git a/src/playlistmanager/sql/SqlUserPlaylistProvider.cpp b/src/playlistmanager/sql/SqlUserPlaylistProvider.cpp
index 0ffb3d6..d9209d2 100644
--- a/src/playlistmanager/sql/SqlUserPlaylistProvider.cpp
+++ b/src/playlistmanager/sql/SqlUserPlaylistProvider.cpp
@@ -76,43 +76,11 @@ SqlUserPlaylistProvider::playlists()
 }
 
 void
-SqlUserPlaylistProvider::rename( Playlists::PlaylistPtr playlist, const QString &newName )
+SqlUserPlaylistProvider::renamePlaylist( Playlists::PlaylistPtr playlist, const QString &newName )
 {
     playlist->setName( newName.trimmed() );
 }
 
-void
-SqlUserPlaylistProvider::slotDelete()
-{
-    QAction *action = qobject_cast<QAction *>( QObject::sender() );
-    if( action == 0 )
-        return;
-
-    Playlists::PlaylistList playlists = action->data().value<Playlists::PlaylistList>();
-    if( playlists.count() == 0 )
-        return;
-
-    if( !m_debug )
-    {
-        KDialog dialog;
-        dialog.setCaption( i18n( "Confirm Delete" ) );
-        dialog.setButtons( KDialog::Ok | KDialog::Cancel );
-        QLabel label( i18np( "Are you sure you want to delete this playlist?",
-                             "Are you sure you want to delete these %1 playlists?",
-                             playlists.count() )
-                      , &dialog
-                    );
-        //TODO:include a text area with all the names of the playlists
-        dialog.setButtonText( KDialog::Ok, i18nc( "%1 is playlist provider pretty name",
-                                                  "Yes, delete from %1.", prettyName() ) );
-        dialog.setMainWidget( &label );
-        if( dialog.exec() != QDialog::Accepted )
-            return;
-    }
-
-    deletePlaylists( playlists );
-}
-
 bool
 SqlUserPlaylistProvider::isWritable()
 {
@@ -120,7 +88,7 @@ SqlUserPlaylistProvider::isWritable()
 }
 
 bool
-SqlUserPlaylistProvider::deletePlaylists( Playlists::PlaylistList playlistList )
+SqlUserPlaylistProvider::deletePlaylists( const Playlists::PlaylistList &playlistList )
 {
     Playlists::SqlPlaylistList sqlPlaylists;
     foreach( Playlists::PlaylistPtr playlist, playlistList )
diff --git a/src/playlistmanager/sql/SqlUserPlaylistProvider.h b/src/playlistmanager/sql/SqlUserPlaylistProvider.h
index 2ff9fda..273a050 100644
--- a/src/playlistmanager/sql/SqlUserPlaylistProvider.h
+++ b/src/playlistmanager/sql/SqlUserPlaylistProvider.h
@@ -53,19 +53,13 @@ class AMAROK_EXPORT SqlUserPlaylistProvider : public UserPlaylistProvider
 
         /* UserPlaylistProvider functions */
         virtual bool isWritable();
-        virtual bool deletePlaylists( Playlists::PlaylistList playlistlist );
-        virtual void rename( Playlists::PlaylistPtr playlist, const QString &newName );
+        virtual bool deletePlaylists( const Playlists::PlaylistList &playlistlist );
+        virtual void renamePlaylist( Playlists::PlaylistPtr playlist, const QString &newName );
 
         Playlists::SqlPlaylistGroupPtr group( const QString &name );
 
         static Playlists::SqlPlaylistList toSqlPlaylists( Playlists::PlaylistList playlists );
 
-    private slots:
-        /**
-         * Overridden only bacause of the m_debug flag
-         */
-        void slotDelete();
-
     private:
         void reloadFromDb();
         Playlists::SqlPlaylistGroupPtr m_root;
diff --git a/src/services/gpodder/GpodderProvider.cpp b/src/services/gpodder/GpodderProvider.cpp
index 28102a5..d7ae60f 100644
--- a/src/services/gpodder/GpodderProvider.cpp
+++ b/src/services/gpodder/GpodderProvider.cpp
@@ -343,51 +343,39 @@ GpodderProvider::removeChannel( const QUrl &url )
     }
 }
 
-QList<QAction *>
+QActionList
 GpodderProvider::channelActions( PodcastChannelList channels )
 {
-    DEBUG_BLOCK
-
-    QList<QAction *> actions;
+    QActionList actions;
+    if( channels.isEmpty() )
+        return actions;
 
     if( m_removeAction == 0 )
     {
-        m_removeAction = new QAction(
-            KIcon( "edit-delete" ),
-            i18n( "&Delete Channel and Episodes" ),
-            this
-        );
-
+        m_removeAction = new QAction( KIcon( "edit-delete" ),
+                i18n( "&Delete Channel and Episodes" ), this );
         m_removeAction->setProperty( "popupdropper_svg_id", "delete" );
-        connect( m_removeAction, 
-                 SIGNAL(triggered()),
-                 SLOT(slotRemoveChannels()) );
+        connect( m_removeAction,  SIGNAL(triggered()), SLOT(slotRemoveChannels()) );
     }
-
     //Set the episode list as data that we'll retrieve in the slot
-    PodcastChannelList actionList =
-        m_removeAction->data().value<PodcastChannelList>();
-
-    actionList << channels;
-    m_removeAction->setData( QVariant::fromValue( actionList ) );
-
+    m_removeAction->setData( QVariant::fromValue( channels ) );
     actions << m_removeAction;
 
     return actions;
 }
 
-QList<QAction *>
-GpodderProvider::playlistActions( Playlists::PlaylistPtr playlist )
+QActionList
+GpodderProvider::playlistActions( const Playlists::PlaylistList &playlists )
 {
-    DEBUG_BLOCK
-
     PodcastChannelList channels;
-    PodcastChannelPtr channel = PodcastChannelPtr::dynamicCast( playlist );
-
-    if( channel.isNull() )
-        return QList<QAction *>();
+    foreach( const Playlists::PlaylistPtr &playlist, playlists )
+    {
+        PodcastChannelPtr channel = PodcastChannelPtr::dynamicCast( playlist );
+        if( channel )
+            channels << channel;
+    }
 
-    return channelActions( channels << channel );
+    return channelActions( channels );
 }
 
 void
diff --git a/src/services/gpodder/GpodderProvider.h b/src/services/gpodder/GpodderProvider.h
index a259d5d..f5dc268 100644
--- a/src/services/gpodder/GpodderProvider.h
+++ b/src/services/gpodder/GpodderProvider.h
@@ -77,8 +77,7 @@ public:
     /** Copy a playlist to the provider.
     */
     virtual Playlists::PlaylistPtr addPlaylist( Playlists::PlaylistPtr playlist );
-    QList<QAction *> channelActions( PodcastChannelList episodes );
-    QList<QAction *> playlistActions( Playlists::PlaylistPtr playlist );
+    virtual QActionList playlistActions( const Playlists::PlaylistList &playlists );
 
 private slots:
     void requestDeviceUpdates();
@@ -120,6 +119,8 @@ private slots:
     void slotEpisodeMarkedAsNew( Podcasts::PodcastEpisodePtr episode );
 
 private:
+    QActionList channelActions( PodcastChannelList episodes );
+
     ApiRequest *m_apiRequest;
     const QString m_username;
     const QString m_deviceName;
diff --git a/tests/playlistmanager/file/TestPlaylistFileProvider.cpp b/tests/playlistmanager/file/TestPlaylistFileProvider.cpp
index 2d97ee2..d8723a9 100644
--- a/tests/playlistmanager/file/TestPlaylistFileProvider.cpp
+++ b/tests/playlistmanager/file/TestPlaylistFileProvider.cpp
@@ -125,7 +125,7 @@ void TestPlaylistFileProvider::testRename()
     tempList = m_testPlaylistFileProvider->playlists();
     QCOMPARE( tempList.size(), 1 );
 
-    m_testPlaylistFileProvider->rename( tempList.at( 0 ), "New Test Name" );
+    m_testPlaylistFileProvider->renamePlaylist( tempList.at( 0 ), "New Test Name" );
     tempList = m_testPlaylistFileProvider->playlists();
     QCOMPARE( tempList.at( 0 )->name(), QString( "New Test Name.m3u" ) );
 
diff --git a/tests/playlistmanager/sql/TestSqlUserPlaylistProvider.cpp b/tests/playlistmanager/sql/TestSqlUserPlaylistProvider.cpp
index b1a1f9d..83ea2bc 100644
--- a/tests/playlistmanager/sql/TestSqlUserPlaylistProvider.cpp
+++ b/tests/playlistmanager/sql/TestSqlUserPlaylistProvider.cpp
@@ -79,7 +79,7 @@ void TestSqlUserPlaylistProvider::testSave()
 void TestSqlUserPlaylistProvider::testRename()
 {
     Playlists::PlaylistList tempList = m_testSqlUserPlaylistProvider->playlists();
-    m_testSqlUserPlaylistProvider->rename( tempList.at( 0 ), "New Test Name" );
+    m_testSqlUserPlaylistProvider->renamePlaylist( tempList.at( 0 ), "New Test Name" );
     QCOMPARE( tempList.at( 0 )->name(), QString( "New Test Name" ) );
 }
 


More information about the Amarok-devel mailing list