From 51a3eb39be5f4a8d5b8a76c23c592a7226ae944f Mon Sep 17 00:00:00 2001
From: Christian Muehlhaeuser <muesli@gmail.com>
Date: Wed, 6 Apr 2011 07:26:57 +0200
Subject: [PATCH] * Fixed page-history related crash when deleting / creating
 playlists.

---
 .../dynamic/widgets/DynamicWidget.cpp         | 145 +++++++++---------
 .../playlist/dynamic/widgets/DynamicWidget.h  |  46 +++---
 src/libtomahawk/playlist/playlistmanager.cpp  |  51 +++---
 src/libtomahawk/playlist/playlistmanager.h    |  22 ++-
 src/libtomahawk/playlist/playlistmodel.cpp    |  18 ++-
 src/libtomahawk/playlist/playlistmodel.h      |   6 +-
 src/libtomahawk/playlist/playlistview.cpp     |  12 +-
 src/libtomahawk/playlist/playlistview.h       |   7 +-
 src/libtomahawk/viewpage.h                    |  12 +-
 src/libtomahawk/widgets/newplaylistwidget.h   |   4 +-
 10 files changed, 176 insertions(+), 147 deletions(-)

diff --git a/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.cpp b/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.cpp
index d63fe718f..bd76b5683 100644
--- a/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.cpp
+++ b/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.cpp
@@ -1,5 +1,5 @@
 /* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
- * 
+ *
  *   Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
  *
  *   Tomahawk is free software: you can redistribute it and/or modify
@@ -58,30 +58,30 @@ DynamicWidget::DynamicWidget( const Tomahawk::dynplaylist_ptr& playlist, QWidget
     , m_controls( 0 )
     , m_view( 0 )
     , m_model()
-{   
+{
     m_controls = new CollapsibleControls( this );
     m_layout->addWidget( m_controls );
     setContentsMargins( 0, 0, 0, 1 ); // to align the bottom with the bottom of the sourcelist
-    
+
     m_model = new DynamicModel( this );
     m_view = new DynamicView( this );
     m_view->setModel( m_model );
     m_view->setContentsMargins( 0, 0, 0, 0 );
     m_layout->addWidget( m_view, 1 );
-    
+
     connect( m_model, SIGNAL( collapseFromTo( int, int ) ), m_view, SLOT( collapseEntries( int, int ) ) );
-    connect( m_model, SIGNAL( trackGenerationFailure( QString ) ), this, SLOT( stationFailed( QString ) ) );    
-    
-    m_loading = new LoadingSpinner( m_view ); 
+    connect( m_model, SIGNAL( trackGenerationFailure( QString ) ), this, SLOT( stationFailed( QString ) ) );
+
+    m_loading = new LoadingSpinner( m_view );
     connect( m_model, SIGNAL( tracksAdded() ), m_loading, SLOT( fadeOut() ) );
-    
+
     m_setup = new DynamicSetupWidget( playlist, this );
     m_setup->fadeIn();
-    
+
     connect( m_model, SIGNAL( tracksAdded() ), this, SLOT( tracksAdded() ) );
-    
+
     loadDynamicPlaylist( playlist );
-    
+
     m_layout->setContentsMargins( 0, 0, 0, 0 );
     m_layout->setMargin( 0 );
     m_layout->setSpacing( 0 );
@@ -103,7 +103,7 @@ DynamicWidget::~DynamicWidget()
 {
 }
 
-void 
+void
 DynamicWidget::loadDynamicPlaylist( const Tomahawk::dynplaylist_ptr& playlist )
 {
     // special case: if we have launched multiple setRevision calls, and the number of controls is different, it means that we're getting an intermediate setRevision
@@ -114,61 +114,61 @@ DynamicWidget::loadDynamicPlaylist( const Tomahawk::dynplaylist_ptr& playlist )
         return;
     }
     m_seqRevLaunched = 0;
-    
+
     // if we're being told to load the same dynamic playlist over again, only do it if the controls have a different number
     if( !m_playlist.isNull() && ( m_playlist.data() == playlist.data() ) // same playlist pointer
         && m_playlist->generator()->controls().size() == playlist->generator()->controls().size() ) {
         // we can skip our work. just let the dynamiccontrollist show the difference
         m_controls->setControls( m_playlist, m_playlist->author()->isLocal() );
-    
+
         m_playlist = playlist;
-        
+
         if( !m_runningOnDemand ) {
             m_model->loadPlaylist( m_playlist );
         } else if( !m_controlsChanged ) { // if the controls changed, we already dealt with that and don't want to change station yet
             m_model->changeStation();
         }
         m_controlsChanged = false;
-        
+
         return;
     }
-    
+
     if( !m_playlist.isNull() ) {
         disconnect( m_playlist->generator().data(), SIGNAL( generated( QList<Tomahawk::query_ptr> ) ), this, SLOT( tracksGenerated( QList<Tomahawk::query_ptr> ) ) );
         disconnect( m_playlist.data(), SIGNAL( dynamicRevisionLoaded( Tomahawk::DynamicPlaylistRevision) ), this, SLOT(onRevisionLoaded( Tomahawk::DynamicPlaylistRevision) ) );
         disconnect( m_playlist->generator().data(), SIGNAL( error( QString, QString ) ), this, SLOT( generatorError( QString, QString ) ) );
-        disconnect( m_playlist.data(), SIGNAL( deleted( Tomahawk::dynplaylist_ptr ) ), this, SLOT( deleteLater() ) );
+        disconnect( m_playlist.data(), SIGNAL( deleted( Tomahawk::dynplaylist_ptr ) ), this, SLOT( onDeleted() ) );
     }
-    
-    
+
+
     m_playlist = playlist;
     m_view->setOnDemand( m_playlist->mode() == OnDemand );
     m_view->setReadOnly( !m_playlist->author()->isLocal() );
     m_model->loadPlaylist( m_playlist );
     m_controlsChanged = false;
     m_setup->setPlaylist( m_playlist );
-        
-    
+
+
     if( !m_playlist->author()->isLocal() ) { // hide controls, as we show the description in the summary
             m_layout->removeWidget( m_controls );
     } else if( m_layout->indexOf( m_controls ) == -1 ) {
         m_layout->insertWidget( 0, m_controls );
-    } 
-    
+    }
+
     if( m_playlist->mode() == OnDemand && !m_playlist->generator()->controls().isEmpty() )
         showPreview();
-    
+
     if( !m_playlist.isNull() )
         m_controls->setControls( m_playlist, m_playlist->author()->isLocal() );
-    
+
     connect( m_playlist->generator().data(), SIGNAL( generated( QList<Tomahawk::query_ptr> ) ), this, SLOT( tracksGenerated( QList<Tomahawk::query_ptr> ) ) );
     connect( m_playlist.data(), SIGNAL( dynamicRevisionLoaded( Tomahawk::DynamicPlaylistRevision ) ), this, SLOT( onRevisionLoaded( Tomahawk::DynamicPlaylistRevision ) ) );
     connect( m_playlist->generator().data(), SIGNAL( error( QString, QString ) ), this, SLOT( generatorError( QString, QString ) ) );
-    connect( m_playlist.data(), SIGNAL( deleted( Tomahawk::dynplaylist_ptr ) ), this, SLOT( deleteLater() ) );
+    connect( m_playlist.data(), SIGNAL( deleted( Tomahawk::dynplaylist_ptr ) ), this, SLOT( onDeleted() ) );
 }
 
 
-void 
+void
 DynamicWidget::onRevisionLoaded( const Tomahawk::DynamicPlaylistRevision& rev )
 {
     qDebug() << "DynamicWidget::onRevisionLoaded";
@@ -180,7 +180,7 @@ DynamicWidget::onRevisionLoaded( const Tomahawk::DynamicPlaylistRevision& rev )
     }
 }
 
-PlaylistInterface* 
+PlaylistInterface*
 DynamicWidget::playlistInterface() const
 {
     return m_view->proxyModel();
@@ -194,36 +194,36 @@ DynamicWidget::sizeHint() const
     return QSize( 5000, 5000 );
 }
 
-void 
+void
 DynamicWidget::resizeEvent(QResizeEvent* )
 {
     layoutFloatingWidgets();
 }
 
-void 
+void
 DynamicWidget::layoutFloatingWidgets()
 {
     if( !m_runningOnDemand ) {
         int x = ( width() / 2 ) - ( m_setup->size().width() / 2 );
         int y = height() - m_setup->size().height() - 40; // padding
-        
+
         m_setup->move( x, y );
     } else if( m_runningOnDemand && m_steering ) {
         int x = ( width() / 2 ) - ( m_steering->size().width() / 2 );
         int y = height() - m_steering->size().height() - 40; // padding
-        
+
         m_steering->move( x, y );
     }
 }
 
-void 
+void
 DynamicWidget::playlistChanged( PlaylistInterface* pl )
 {
     if( pl == static_cast< PlaylistInterface* >( m_view->proxyModel() ) ) { // same playlist
         m_activePlaylist = true;
     } else {
         m_activePlaylist = false;
-        
+
         // user started playing something somewhere else, so give it a rest
         if( m_runningOnDemand ) {
             stopStation( false );
@@ -231,7 +231,7 @@ DynamicWidget::playlistChanged( PlaylistInterface* pl )
     }
 }
 
-void 
+void
 DynamicWidget::showEvent(QShowEvent* )
 {
     if( !m_playlist.isNull() && !m_runningOnDemand ) {
@@ -240,7 +240,7 @@ DynamicWidget::showEvent(QShowEvent* )
 }
 
 
-void 
+void
 DynamicWidget::generate( int num )
 {
     // get the items from the generator, and put them in the playlist
@@ -249,27 +249,27 @@ DynamicWidget::generate( int num )
     m_playlist->generator()->generate( num );
 }
 
-void 
+void
 DynamicWidget::stationFailed( const QString& msg )
 {
     m_view->setDynamicWorking( false );
     m_view->showMessage( msg );
     m_loading->fadeOut();
-    
+
     stopStation( false );
 }
 
-void 
+void
 DynamicWidget::trackStarted()
-{    
+{
     if( m_activePlaylist && !m_playlist.isNull() &&
         m_playlist->mode() == OnDemand && !m_runningOnDemand ) {
-        
+
         startStation();
     }
 }
 
-void 
+void
 DynamicWidget::tracksAdded()
 {
     if( m_playlist->mode() == OnDemand && m_runningOnDemand && m_setup->isVisible() )
@@ -277,94 +277,94 @@ DynamicWidget::tracksAdded()
 }
 
 
-void 
+void
 DynamicWidget::stopStation( bool stopPlaying )
 {
     m_model->stopOnDemand( stopPlaying );
     m_runningOnDemand = false;
-    
+
     // TODO until i add a qwidget interface
     QMetaObject::invokeMethod( m_steering, "fadeOut", Qt::DirectConnection );
     m_setup->fadeIn();
 }
 
-void 
+void
 DynamicWidget::startStation()
 {
     m_runningOnDemand = true;
     m_model->startOnDemand();
-    
+
     m_setup->fadeOut();
     // show the steering controls
     if( m_playlist->generator()->onDemandSteerable() ) {
         // position it horizontally centered, above the botton.
         m_steering = m_playlist->generator()->steeringWidget();
         Q_ASSERT( m_steering );
-        
+
         int x = ( width() / 2 ) - ( m_steering->size().width() / 2 );
         int y = height() - m_steering->size().height() - 40; // padding
-        
+
         m_steering->setParent( this );
         m_steering->move( x, y );
-        
+
         // TODO until i add a qwidget interface
         QMetaObject::invokeMethod( m_steering, "fadeIn", Qt::DirectConnection );
-        
+
         connect( m_steering, SIGNAL( resized() ), this, SLOT( layoutFloatingWidgets() ) );
     }
 }
 
-void 
+void
 DynamicWidget::playlistTypeChanged( QString )
 {
     // TODO
 }
 
-void 
+void
 DynamicWidget::tracksGenerated( const QList< query_ptr >& queries )
-{   
+{
     int limit = -1; // only limit the "preview" of a station
     if( m_playlist->author()->isLocal() && m_playlist->mode() == Static ) {
         m_resolveOnNextLoad = true;
     } else if( m_playlist->mode() == OnDemand )
         limit = 5;
-    
+
     if( m_playlist->mode() != OnDemand )
         m_loading->fadeOut();
     m_model->tracksGenerated( queries, limit );
 }
 
 
-void 
+void
 DynamicWidget::controlsChanged()
 {
     // controlsChanged() is emitted when a control is added or removed
     // in the case of addition, it's blank by default... so to avoid an error
     // when playing a station just ignore it till we're ready and get a controlChanged()
     m_controlsChanged = true;
-    
+
     if( !m_playlist->author()->isLocal() )
         return;
     m_playlist->createNewRevision();
     m_seqRevLaunched++;
-    
+
     emit descriptionChanged( m_playlist->generator()->sentenceSummary() );
 }
 
-void 
+void
 DynamicWidget::controlChanged( const Tomahawk::dyncontrol_ptr& control )
-{   
+{
     if( !m_playlist->author()->isLocal() )
-        return;       
+        return;
     m_playlist->createNewRevision();
     m_seqRevLaunched++;
-    
+
     showPreview();
-    
+
     emit descriptionChanged( m_playlist->generator()->sentenceSummary() );
 }
 
-void 
+void
 DynamicWidget::showPreview()
 {
     if( m_playlist->mode() == OnDemand && !m_runningOnDemand && m_model->rowCount( QModelIndex() ) == 0 ) { // if this is a not running station, preview matching tracks
@@ -373,7 +373,7 @@ DynamicWidget::showPreview()
 }
 
 
-void 
+void
 DynamicWidget::generatorError( const QString& title, const QString& content )
 {
     if( m_runningOnDemand ) {
@@ -386,17 +386,17 @@ DynamicWidget::generatorError( const QString& title, const QString& content )
 
 void
 DynamicWidget::paintRoundedFilledRect( QPainter& p, QPalette& pal, QRect& r, qreal opacity )
-{   
+{
     p.setBackgroundMode( Qt::TransparentMode );
     p.setRenderHint( QPainter::Antialiasing );
     p.setOpacity( opacity );
-    
+
     QPen pen( pal.dark().color(), .5 );
     p.setPen( pen );
     p.setBrush( pal.highlight() );
-    
+
     p.drawRoundedRect( r, 10, 10 );
-    
+
     p.setOpacity( opacity + .2 );
     p.setBrush( QBrush() );
     p.setPen( pen );
@@ -409,3 +409,10 @@ DynamicWidget::jumpToCurrentTrack()
     m_view->scrollTo( m_view->proxyModel()->currentItem(), QAbstractItemView::PositionAtCenter );
     return true;
 }
+
+void
+DynamicWidget::onDeleted()
+{
+    emit destroyed( widget() );
+    deleteLater();
+}
diff --git a/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.h b/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.h
index 1771fd07b..6b8ef96e3 100644
--- a/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.h
+++ b/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.h
@@ -1,5 +1,5 @@
 /* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
- * 
+ *
  *   Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
  *
  *   Tomahawk is free software: you can redistribute it and/or modify
@@ -58,57 +58,59 @@ class CollapsibleControls;
  */
 class DynamicWidget : public QWidget, public Tomahawk::ViewPage
 {
-Q_OBJECT 
+Q_OBJECT
 public:
     explicit DynamicWidget( const dynplaylist_ptr& playlist, QWidget* parent = 0);
     virtual ~DynamicWidget();
-    
+
     void loadDynamicPlaylist( const dynplaylist_ptr& playlist );
-    
+
     virtual PlaylistInterface* playlistInterface() const;
-    
+
     virtual QSize sizeHint() const;
     virtual void resizeEvent( QResizeEvent* );
     virtual void showEvent(QShowEvent* );
-    
+
     static void paintRoundedFilledRect( QPainter& p, QPalette& pal, QRect& r, qreal opacity = .95 );
 
     virtual QWidget* widget() { return this; }
-    
+
     virtual QString title() const { return m_model->title(); }
     virtual QString description() const { return m_model->description(); }
     virtual QPixmap pixmap() const { return QPixmap( RESPATH "images/playlist-icon.png" ); }
-    
+
     virtual bool jumpToCurrentTrack();
-    
+
 public slots:
     void onRevisionLoaded( const Tomahawk::DynamicPlaylistRevision& rev );
     void playlistTypeChanged(QString);
-    
+
     void startStation();
     void stopStation( bool stopPlaying = true );
-    
+
     void trackStarted();
     void stationFailed( const QString& );
-    
+
     void playlistChanged( PlaylistInterface* );
     void tracksAdded();
-    
+
 signals:
     void descriptionChanged( const QString& caption );
-    
+    void destroyed( QWidget* widget );
+
 private slots:
     void generate( int = -1 );
     void tracksGenerated( const QList< Tomahawk::query_ptr>& queries );
     void generatorError( const QString& title, const QString& content );
-    
+
     void controlsChanged();
     void controlChanged( const Tomahawk::dyncontrol_ptr& control );
     void showPreview();
-    
-    void layoutFloatingWidgets();
 
-private:    
+    void layoutFloatingWidgets();
+    void onDeleted();
+
+private:
     dynplaylist_ptr m_playlist;
     QVBoxLayout* m_layout;
     bool m_resolveOnNextLoad;
@@ -117,17 +119,17 @@ private:
 
     // loading animation
     LoadingSpinner* m_loading;
-    
+
     // setup controls
     DynamicSetupWidget* m_setup;
-    
+
     // used in OnDemand mode
     bool m_runningOnDemand;
     bool m_controlsChanged;
     QWidget* m_steering;
-        
+
     CollapsibleControls* m_controls;
-    
+
     DynamicView* m_view;
     DynamicModel* m_model;
 };
diff --git a/src/libtomahawk/playlist/playlistmanager.cpp b/src/libtomahawk/playlist/playlistmanager.cpp
index eac12794f..657f75645 100644
--- a/src/libtomahawk/playlist/playlistmanager.cpp
+++ b/src/libtomahawk/playlist/playlistmanager.cpp
@@ -163,8 +163,6 @@ PlaylistManager::show( const Tomahawk::playlist_ptr& playlist )
         playlist->resolve();
 
         m_playlistViews.insert( playlist, view );
-
-        connect( playlist.data(), SIGNAL( deleted( Tomahawk::playlist_ptr ) ), this, SLOT( onPlaylistDeleted( Tomahawk::playlist_ptr ) ) );
     }
     else
     {
@@ -540,11 +538,11 @@ PlaylistManager::setPage( ViewPage* page, bool trackHistory )
         setHistoryPosition( m_pageHistory.count() - 1 );
     }
 
-    if ( playlistForInterface( currentPlaylistInterface() ) )
+    if ( !playlistForInterface( currentPlaylistInterface() ).isNull() )
         emit playlistActivated( playlistForInterface( currentPlaylistInterface() ) );
-    if ( dynamicPlaylistForInterface( currentPlaylistInterface() ) )
+    if ( !dynamicPlaylistForInterface( currentPlaylistInterface() ).isNull() )
         emit dynamicPlaylistActivated( dynamicPlaylistForInterface( currentPlaylistInterface() ) );
-    if ( collectionForInterface( currentPlaylistInterface() ) )
+    if ( !collectionForInterface( currentPlaylistInterface() ).isNull() )
         emit collectionActivated( collectionForInterface( currentPlaylistInterface() ) );
     if ( isSuperCollectionVisible() )
         emit superCollectionActivated();
@@ -555,10 +553,17 @@ PlaylistManager::setPage( ViewPage* page, bool trackHistory )
         AudioEngine::instance()->setPlaylist( currentPlaylistInterface() );
 
     // UGH!
-    if( QObject* obj = dynamic_cast< QObject* >( currentPage() ) ) {
+    if ( QObject* obj = dynamic_cast< QObject* >( currentPage() ) )
+    {
         // if the signal exists (just to hide the qobject runtime warning...)
         if( obj->metaObject()->indexOfSignal( "descriptionChanged(QString)" ) > -1 )
-            connect( obj, SIGNAL( descriptionChanged( QString ) ), m_infobar, SLOT( setDescription( QString ) ) );
+            connect( obj, SIGNAL( descriptionChanged( QString ) ), m_infobar, SLOT( setDescription( QString ) ), Qt::UniqueConnection );
+    }
+    if ( QObject* obj = dynamic_cast< QObject* >( currentPage() ) )
+    {
+        // if the signal exists (just to hide the qobject runtime warning...)
+        if( obj->metaObject()->indexOfSignal( "destroyed(QWidget*)" ) > -1 )
+            connect( obj, SIGNAL( destroyed( QWidget* ) ), SLOT( onWidgetDestroyed( QWidget* ) ), Qt::UniqueConnection );
     }
 
     m_stack->setCurrentWidget( page->widget() );
@@ -638,24 +643,6 @@ PlaylistManager::updateView()
     m_infobar->setPixmap( currentPage()->pixmap() );
 }
 
-void
-PlaylistManager::onDynamicDeleted( const Tomahawk::dynplaylist_ptr& pl )
-{
-    QWidget* w = m_dynamicWidgets.value( pl );
-    m_dynamicWidgets.remove( pl );
-
-    onWidgetDestroyed( w );
-}
-
-void
-PlaylistManager::onPlaylistDeleted( const Tomahawk::playlist_ptr& pl )
-{
-    QWidget* w = m_playlistViews.value( pl );
-    m_playlistViews.remove( pl );
-
-    onWidgetDestroyed( w );
-}
-
 
 void
 PlaylistManager::onWidgetDestroyed( QWidget* widget )
@@ -663,11 +650,20 @@ PlaylistManager::onWidgetDestroyed( QWidget* widget )
     qDebug() << "Destroyed child:" << widget << widget->metaObject()->className();
 
     bool resetWidget = ( m_stack->currentWidget() == widget );
-    m_stack->removeWidget( widget );
 
     for ( int i = 0; i < m_pageHistory.count(); i++ )
     {
         ViewPage* page = m_pageHistory.at( i );
+
+        if ( !playlistForInterface( page->playlistInterface() ).isNull() )
+        {
+            m_playlistViews.remove( playlistForInterface( page->playlistInterface() ) );
+        }
+        if ( !dynamicPlaylistForInterface( page->playlistInterface() ).isNull() )
+        {
+            m_dynamicWidgets.remove( dynamicPlaylistForInterface( page->playlistInterface() ) );
+        }
+
         if ( page->widget() == widget )
         {
             m_pageHistory.removeAt( i );
@@ -677,6 +673,8 @@ PlaylistManager::onWidgetDestroyed( QWidget* widget )
         }
     }
 
+    m_stack->removeWidget( widget );
+
     if ( resetWidget )
     {
         if ( m_pageHistory.count() )
@@ -783,6 +781,7 @@ PlaylistManager::playlistForInterface( PlaylistInterface* interface ) const
 {
     foreach ( PlaylistView* view, m_playlistViews.values() )
     {
+        qDebug() << "LAAAA:" << view;
         if ( view->playlistInterface() == interface )
         {
             return m_playlistViews.key( view );
diff --git a/src/libtomahawk/playlist/playlistmanager.h b/src/libtomahawk/playlist/playlistmanager.h
index fc86acf66..6c7f66578 100644
--- a/src/libtomahawk/playlist/playlistmanager.h
+++ b/src/libtomahawk/playlist/playlistmanager.h
@@ -1,5 +1,5 @@
 /* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
- * 
+ *
  *   Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
  *
  *   Tomahawk is free software: you can redistribute it and/or modify
@@ -104,7 +104,7 @@ signals:
     void collectionActivated( const Tomahawk::collection_ptr& collection );
     void playlistActivated( const Tomahawk::playlist_ptr& playlist );
     void dynamicPlaylistActivated( const Tomahawk::dynplaylist_ptr& playlist );
-    
+
 public slots:
     bool showSuperCollection();
     void showWelcomePage();
@@ -123,21 +123,19 @@ public slots:
 
     void setRepeatMode( PlaylistInterface::RepeatMode mode );
     void setShuffled( bool enabled );
-    
+
     // called by the playlist creation dbcmds
     void createPlaylist( const Tomahawk::source_ptr& src, const QVariant& contents );
     void createDynamicPlaylist( const Tomahawk::source_ptr& src, const QVariant& contents );
-    
+
     // ugh need to set up the connection in tomahawk to libtomahawk
     void onPlayClicked();
     void onPauseClicked();
-    
+
 private slots:
     void setFilter( const QString& filter );
     void applyFilter();
-    
-    void onPlaylistDeleted( const Tomahawk::playlist_ptr& pl );
-    void onDynamicDeleted( const Tomahawk::dynplaylist_ptr& pl );
+
     void onWidgetDestroyed( QWidget* widget );
 
 private:
@@ -149,7 +147,7 @@ private:
     Tomahawk::playlist_ptr playlistForInterface( PlaylistInterface* interface ) const;
     Tomahawk::dynplaylist_ptr dynamicPlaylistForInterface( PlaylistInterface* interface ) const;
     Tomahawk::collection_ptr collectionForInterface( PlaylistInterface* interface ) const;
-    
+
     QWidget* m_widget;
     InfoBar* m_infobar;
     TopBar* m_topbar;
@@ -164,7 +162,7 @@ private:
     CollectionFlatModel* m_superCollectionFlatModel;
     CollectionView* m_superCollectionView;
     WelcomeWidget* m_welcomeWidget;
-    
+
     QList< Tomahawk::collection_ptr > m_superCollections;
 
     QHash< Tomahawk::dynplaylist_ptr, Tomahawk::DynamicWidget* > m_dynamicWidgets;
@@ -174,13 +172,13 @@ private:
     QHash< Tomahawk::album_ptr, PlaylistView* > m_albumViews;
     QHash< Tomahawk::playlist_ptr, PlaylistView* > m_playlistViews;
     QHash< Tomahawk::source_ptr, SourceInfoWidget* > m_sourceViews;
-    
+
     QList<Tomahawk::ViewPage*> m_pageHistory;
     int m_historyPosition;
 
     Tomahawk::collection_ptr m_currentCollection;
     int m_currentMode;
-    
+
     QTimer m_filterTimer;
     QString m_filter;
 
diff --git a/src/libtomahawk/playlist/playlistmodel.cpp b/src/libtomahawk/playlist/playlistmodel.cpp
index cdcad71aa..9f95c554b 100644
--- a/src/libtomahawk/playlist/playlistmodel.cpp
+++ b/src/libtomahawk/playlist/playlistmodel.cpp
@@ -1,5 +1,5 @@
 /* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
- * 
+ *
  *   Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
  *
  *   Tomahawk is free software: you can redistribute it and/or modify
@@ -71,7 +71,10 @@ void
 PlaylistModel::loadPlaylist( const Tomahawk::playlist_ptr& playlist, bool loadEntries )
 {
     if ( !m_playlist.isNull() )
+    {
         disconnect( m_playlist.data(), SIGNAL( revisionLoaded( Tomahawk::PlaylistRevision ) ), this, SLOT( onRevisionLoaded( Tomahawk::PlaylistRevision ) ) );
+        disconnect( m_playlist.data(), SIGNAL( deleted( Tomahawk::playlist_ptr ) ), this, SIGNAL( playlistDeleted() ) );
+    }
 
     if ( rowCount( QModelIndex() ) && loadEntries )
     {
@@ -80,6 +83,7 @@ PlaylistModel::loadPlaylist( const Tomahawk::playlist_ptr& playlist, bool loadEn
 
     m_playlist = playlist;
     connect( playlist.data(), SIGNAL( revisionLoaded( Tomahawk::PlaylistRevision ) ), SLOT( onRevisionLoaded( Tomahawk::PlaylistRevision ) ) );
+    connect( playlist.data(), SIGNAL( deleted( Tomahawk::playlist_ptr ) ), this, SIGNAL( playlistDeleted() ) );
 
     setReadOnly( !m_playlist->author()->isLocal() );
     setTitle( playlist->title() );
@@ -105,7 +109,7 @@ PlaylistModel::loadPlaylist( const Tomahawk::playlist_ptr& playlist, bool loadEn
             plitem->index = createIndex( m_rootItem->children.count() - 1, 0, plitem );
 
             connect( plitem, SIGNAL( dataChanged() ), SLOT( onDataChanged() ) );
-            
+
             if( !entry->query()->resolvingFinished() && entry->query()->playable() ) {
                 m_waitingForResolved.append( entry->query().data() );
                 connect( entry->query().data(), SIGNAL( resolvingFinished( bool ) ), this, SLOT( trackResolved( bool ) ) );
@@ -119,7 +123,7 @@ PlaylistModel::loadPlaylist( const Tomahawk::playlist_ptr& playlist, bool loadEn
 
     if( !m_waitingForResolved.isEmpty() )
         emit loadingStarted();
-    
+
     emit trackCountChanged( rowCount( QModelIndex() ) );
 }
 
@@ -145,7 +149,7 @@ PlaylistModel::loadHistory( const Tomahawk::source_ptr& source, unsigned int amo
 }
 
 
-void 
+void
 PlaylistModel::clear()
 {
     if ( rowCount( QModelIndex() ) )
@@ -210,15 +214,15 @@ PlaylistModel::insert( unsigned int row, const Tomahawk::query_ptr& query )
     onTracksInserted( row, ql );
 }
 
-void 
+void
 PlaylistModel::trackResolved( bool )
 {
     Tomahawk::Query* q = qobject_cast< Query* >( sender() );
     Q_ASSERT( q );
-    
+
     m_waitingForResolved.removeAll( q );
     disconnect( q, SIGNAL( resolvingFinished( bool ) ), this, SLOT( trackResolved( bool ) ) );
-    
+
     if( m_waitingForResolved.isEmpty() )
         emit loadingFinished();
 }
diff --git a/src/libtomahawk/playlist/playlistmodel.h b/src/libtomahawk/playlist/playlistmodel.h
index e5ce24ae4..ad9bd9411 100644
--- a/src/libtomahawk/playlist/playlistmodel.h
+++ b/src/libtomahawk/playlist/playlistmodel.h
@@ -1,5 +1,5 @@
 /* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
- * 
+ *
  *   Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
  *
  *   Tomahawk is free software: you can redistribute it and/or modify
@@ -70,6 +70,9 @@ signals:
     void shuffleModeChanged( bool enabled );
 
     void itemSizeChanged( const QModelIndex& index );
+
+    void playlistDeleted();
+
 private slots:
     void onDataChanged();
 
@@ -80,6 +83,7 @@ private slots:
     void onTracksInserted( unsigned int row, const QList<Tomahawk::query_ptr>& tracks );
 
     void trackResolved( bool );
+
 private:
     QList<Tomahawk::plentry_ptr> playlistEntries() const;
 
diff --git a/src/libtomahawk/playlist/playlistview.cpp b/src/libtomahawk/playlist/playlistview.cpp
index 9b66257ad..79026e872 100644
--- a/src/libtomahawk/playlist/playlistview.cpp
+++ b/src/libtomahawk/playlist/playlistview.cpp
@@ -1,5 +1,5 @@
 /* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
- * 
+ *
  *   Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
  *
  *   Tomahawk is free software: you can redistribute it and/or modify
@@ -58,6 +58,7 @@ PlaylistView::setModel( PlaylistModel* model )
         setGuid( "playlistview" );
 
     connect( model, SIGNAL( trackCountChanged( unsigned int ) ), SLOT( onTrackCountChanged( unsigned int ) ) );
+    connect( model, SIGNAL( playlistDeleted() ), SLOT( onDeleted() ) );
 }
 
 
@@ -154,3 +155,12 @@ PlaylistView::jumpToCurrentTrack()
     scrollTo( proxyModel()->currentItem(), QAbstractItemView::PositionAtCenter );
     return true;
 }
+
+
+void
+PlaylistView::onDeleted()
+{
+    qDebug() << Q_FUNC_INFO;
+    emit destroyed( widget() );
+    deleteLater();
+}
diff --git a/src/libtomahawk/playlist/playlistview.h b/src/libtomahawk/playlist/playlistview.h
index 3629099b1..5fa0d3a51 100644
--- a/src/libtomahawk/playlist/playlistview.h
+++ b/src/libtomahawk/playlist/playlistview.h
@@ -1,5 +1,5 @@
 /* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
- * 
+ *
  *   Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
  *
  *   Tomahawk is free software: you can redistribute it and/or modify
@@ -50,6 +50,9 @@ public:
 
     virtual bool jumpToCurrentTrack();
 
+signals:
+    void destroyed( QWidget* widget );
+
 protected:
     void keyPressEvent( QKeyEvent* event );
 
@@ -60,6 +63,8 @@ private slots:
     void addItemsToPlaylist();
     void deleteItems();
 
+    void onDeleted();
+
 private:
     void setupMenus();
 
diff --git a/src/libtomahawk/viewpage.h b/src/libtomahawk/viewpage.h
index d775f451d..a515c47e6 100644
--- a/src/libtomahawk/viewpage.h
+++ b/src/libtomahawk/viewpage.h
@@ -1,5 +1,5 @@
 /* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
- * 
+ *
  *   Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
  *
  *   Tomahawk is free software: you can redistribute it and/or modify
@@ -29,7 +29,7 @@
 
 namespace Tomahawk
 {
-    
+
 class DLLEXPORT ViewPage
 {
 public:
@@ -45,18 +45,18 @@ public:
     virtual bool showStatsBar() const { return true; }
     virtual bool showModes() const { return false; }
     virtual bool queueVisible() const { return true; }
-    
+
     virtual bool jumpToCurrentTrack() = 0;
 
     /** subclasses implementing ViewPage can emit the following signals:
      * descriptionChanged( const QString& )
-     * deleted()
-     * 
+     * destroyed( QWidget* widget );
+     *
      * See DynamicWidget for an example
      */
 private:
 };
-    
+
 }; // ns
 
 #endif //VIEWPAGE_H
diff --git a/src/libtomahawk/widgets/newplaylistwidget.h b/src/libtomahawk/widgets/newplaylistwidget.h
index bb6c27629..61799ffd6 100644
--- a/src/libtomahawk/widgets/newplaylistwidget.h
+++ b/src/libtomahawk/widgets/newplaylistwidget.h
@@ -1,5 +1,5 @@
 /* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
- * 
+ *
  *   Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
  *
  *   Tomahawk is free software: you can redistribute it and/or modify
@@ -47,7 +47,7 @@ public:
 
     virtual QWidget* widget() { return this; }
     virtual PlaylistInterface* playlistInterface() const { return 0; }
-    
+
     virtual QString title() const { return tr( "Create a new playlist" ); }
     virtual QString description() const { return QString(); }