From 44585933dc8d727561ceac01e485ac92b7627f7b Mon Sep 17 00:00:00 2001
From: Christian Muehlhaeuser <muesli@gmail.com>
Date: Thu, 12 May 2011 00:35:05 +0200
Subject: [PATCH] * Auto advance to the next track in TreeView. * Show proper
 icon for TreeView. * Drag operations for tracks in TreeView / -Model. *
 Various shutdown fixes. * Properly hook up SipHandler signals again.

---
 include/tomahawk/tomahawkapp.h                |  1 -
 src/libtomahawk/network/controlconnection.cpp |  9 ++-
 src/libtomahawk/pipeline.cpp                  | 30 +++++++--
 src/libtomahawk/pipeline.h                    |  8 ++-
 src/libtomahawk/playlist/artistview.cpp       | 66 ++++++++++---------
 src/libtomahawk/playlist/artistview.h         |  8 +--
 src/libtomahawk/playlist/playlistmodel.cpp    | 25 ++++++-
 src/libtomahawk/playlist/trackproxymodel.cpp  |  1 -
 src/libtomahawk/playlist/trackview.cpp        | 14 ++++
 src/libtomahawk/playlist/treemodel.cpp        | 57 ++++++++++++----
 src/libtomahawk/playlist/treemodel.h          |  4 ++
 src/libtomahawk/playlist/treeproxymodel.cpp   | 23 ++++++-
 src/libtomahawk/playlist/treeproxymodel.h     |  5 ++
 src/libtomahawk/result.cpp                    | 22 +++++--
 src/libtomahawk/result.h                      |  4 +-
 src/libtomahawk/sip/SipHandler.cpp            | 24 +++++--
 src/libtomahawk/sip/SipPlugin.h               |  2 +-
 src/libtomahawk/sourcelist.cpp                |  1 -
 src/libtomahawk/sourcelist.h                  |  2 +-
 src/resolvers/qtscriptresolver.cpp            |  2 +-
 src/sip/jreen/jabber.cpp                      | 29 ++++++--
 src/sourcetree/items/playlistitems.cpp        | 66 ++++++++++++-------
 src/sourcetree/sourcesmodel.cpp               | 21 ++++++
 src/sourcetree/sourcetreeview.cpp             | 14 ++--
 src/tomahawkapp.cpp                           | 16 +++--
 src/tomahawkwindow.cpp                        | 10 +--
 26 files changed, 341 insertions(+), 123 deletions(-)

diff --git a/include/tomahawk/tomahawkapp.h b/include/tomahawk/tomahawkapp.h
index d814ea32d..ea51dfa12 100644
--- a/include/tomahawk/tomahawkapp.h
+++ b/include/tomahawk/tomahawkapp.h
@@ -82,7 +82,6 @@ public:
     void init();
     static TomahawkApp* instance();
 
-    SipHandler* sipHandler();
     XMPPBot* xmppBot() { return m_xmppBot; }
 
 #ifndef TOMAHAWK_HEADLESS
diff --git a/src/libtomahawk/network/controlconnection.cpp b/src/libtomahawk/network/controlconnection.cpp
index 1982ee8d7..2d143d0f7 100644
--- a/src/libtomahawk/network/controlconnection.cpp
+++ b/src/libtomahawk/network/controlconnection.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
@@ -53,11 +53,10 @@ ControlConnection::~ControlConnection()
 
     if ( !m_source.isNull() )
         m_source->setOffline();
-    
+
     delete m_pingtimer;
-    m_servent->unregisterControlConnection(this);
-    if( m_dbsyncconn )
-        m_dbsyncconn->deleteLater();
+    m_servent->unregisterControlConnection( this );
+    delete m_dbsyncconn;
 }
 
 
diff --git a/src/libtomahawk/pipeline.cpp b/src/libtomahawk/pipeline.cpp
index 97606389f..a996ef24f 100644
--- a/src/libtomahawk/pipeline.cpp
+++ b/src/libtomahawk/pipeline.cpp
@@ -41,29 +41,43 @@ Pipeline::instance()
 
 Pipeline::Pipeline( QObject* parent )
     : QObject( parent )
-    , m_index_ready( false )
+    , m_running( false )
 {
     s_instance = this;
 }
 
 
+Pipeline::~Pipeline()
+{
+    m_running = false;
+}
+
+
 void
 Pipeline::databaseReady()
 {
-    connect( Database::instance(), SIGNAL( indexReady() ), this, SLOT( indexReady() ), Qt::QueuedConnection );
+    connect( Database::instance(), SIGNAL( indexReady() ), this, SLOT( start() ), Qt::QueuedConnection );
     Database::instance()->loadIndex();
 }
 
 
-void Pipeline::indexReady()
+void
+Pipeline::start()
 {
     qDebug() << Q_FUNC_INFO << "shunting this many pending queries:" << m_queries_pending.size();
-    m_index_ready = true;
+    m_running = true;
 
     shuntNext();
 }
 
 
+void
+Pipeline::stop()
+{
+    m_running = false;
+}
+
+
 void
 Pipeline::removeResolver( Resolver* r )
 {
@@ -210,7 +224,7 @@ Pipeline::reportResults( QID qid, const QList< result_ptr >& results )
 void
 Pipeline::shuntNext()
 {
-    if ( !m_index_ready )
+    if ( !m_running )
         return;
 
     query_ptr q;
@@ -245,6 +259,9 @@ Pipeline::shuntNext()
 void
 Pipeline::timeoutShunt( const query_ptr& q )
 {
+    if ( !m_running )
+        return;
+
     // are we still waiting for a timeout?
     if ( m_qidsTimeout.contains( q->id() ) )
     {
@@ -259,6 +276,9 @@ Pipeline::timeoutShunt( const query_ptr& q )
 void
 Pipeline::shunt( const query_ptr& q )
 {
+    if ( !m_running )
+        return;
+
     qDebug() << Q_FUNC_INFO << q->solved() << q->toString() << q->id();
     unsigned int lastweight = 0;
     unsigned int lasttimeout = 0;
diff --git a/src/libtomahawk/pipeline.h b/src/libtomahawk/pipeline.h
index 7f845f2e9..d07608747 100644
--- a/src/libtomahawk/pipeline.h
+++ b/src/libtomahawk/pipeline.h
@@ -44,6 +44,7 @@ public:
     static Pipeline* instance();
 
     explicit Pipeline( QObject* parent = 0 );
+    virtual ~Pipeline();
 
     void reportResults( QID qid, const QList< result_ptr >& results );
 
@@ -67,6 +68,9 @@ public slots:
     void resolve( const query_ptr& q, bool prioritized = false );
     void resolve( const QList<query_ptr>& qlist, bool prioritized = false );
     void resolve( QID qid, bool prioritized = false );
+
+    void start();
+    void stop();
     void databaseReady();
 
 signals:
@@ -77,8 +81,6 @@ private slots:
     void shunt( const query_ptr& q );
     void shuntNext();
 
-    void indexReady();
-
 private:
     void setQIDState( const Tomahawk::query_ptr& query, int state );
     int incQIDState( const Tomahawk::query_ptr& query );
@@ -95,7 +97,7 @@ private:
 
     // store queries here until DB index is loaded, then shunt them all
     QList< query_ptr > m_queries_pending;
-    bool m_index_ready;
+    bool m_running;
 
     static Pipeline* s_instance;
 };
diff --git a/src/libtomahawk/playlist/artistview.cpp b/src/libtomahawk/playlist/artistview.cpp
index a3ae3232b..8d558f8fe 100644
--- a/src/libtomahawk/playlist/artistview.cpp
+++ b/src/libtomahawk/playlist/artistview.cpp
@@ -125,33 +125,14 @@ ArtistView::onItemActivated( const QModelIndex& index )
         else if ( !item->album().isNull() )
             ViewManager::instance()->show( item->album() );
         else if ( !item->result().isNull() )
-            AudioEngine::instance()->playItem( 0, item->result() );
+        {
+            m_model->setCurrentItem( item->index );
+            AudioEngine::instance()->playItem( m_proxyModel, item->result() );
+        }
     }
 }
 
 
-void
-ArtistView::dragEnterEvent( QDragEnterEvent* event )
-{
-    qDebug() << Q_FUNC_INFO;
-    QTreeView::dragEnterEvent( event );
-}
-
-
-void
-ArtistView::dragMoveEvent( QDragMoveEvent* event )
-{
-    QTreeView::dragMoveEvent( event );
-}
-
-
-void
-ArtistView::dropEvent( QDropEvent* event )
-{
-    QTreeView::dropEvent( event );
-}
-
-
 void
 ArtistView::paintEvent( QPaintEvent* event )
 {
@@ -178,15 +159,32 @@ ArtistView::onFilterChanged( const QString& )
 void
 ArtistView::startDrag( Qt::DropActions supportedActions )
 {
-    Q_UNUSED( supportedActions );
-}
+    QList<QPersistentModelIndex> pindexes;
+    QModelIndexList indexes;
+    foreach( const QModelIndex& idx, selectedIndexes() )
+    {
+        if ( ( m_proxyModel->flags( idx ) & Qt::ItemIsDragEnabled ) )
+        {
+            indexes << idx;
+            pindexes << idx;
+        }
+    }
 
+    if ( indexes.count() == 0 )
+        return;
 
-QPixmap
-ArtistView::createDragPixmap( int itemCount ) const
-{
-    Q_UNUSED( itemCount );
-    return QPixmap();
+    qDebug() << "Dragging" << indexes.count() << "indexes";
+    QMimeData* data = m_proxyModel->mimeData( indexes );
+    if ( !data )
+        return;
+
+    QDrag* drag = new QDrag( this );
+    drag->setMimeData( data );
+    const QPixmap p = TomahawkUtils::createDragPixmap( indexes.count() );
+    drag->setPixmap( p );
+    drag->setHotSpot( QPoint( -20, -20 ) );
+
+    drag->exec( supportedActions, Qt::CopyAction );
 }
 
 
@@ -232,3 +230,11 @@ ArtistView::onScrollTimeout()
             QVariant::fromValue< Tomahawk::InfoSystem::InfoCriteriaHash >( trackInfo ), Tomahawk::InfoSystem::InfoCustomData() );
     }
 }
+
+
+bool
+ArtistView::jumpToCurrentTrack()
+{
+    scrollTo( m_proxyModel->currentItem(), QAbstractItemView::PositionAtCenter );
+    return true;
+}
diff --git a/src/libtomahawk/playlist/artistview.h b/src/libtomahawk/playlist/artistview.h
index e02107cbb..6123905ec 100644
--- a/src/libtomahawk/playlist/artistview.h
+++ b/src/libtomahawk/playlist/artistview.h
@@ -51,11 +51,12 @@ public:
 
     virtual QString title() const { return m_model->title(); }
     virtual QString description() const { return m_model->description(); }
+    virtual QPixmap pixmap() const { return QPixmap( RESPATH "images/music-icon.png" ); }
 
     virtual bool showStatsBar() const { return false; }
     virtual bool showModes() const { return true; }
 
-    virtual bool jumpToCurrentTrack() { return false; }
+    virtual bool jumpToCurrentTrack();
 
     QString guid() const { return QString( "ArtistView" ); }
 
@@ -64,9 +65,6 @@ public slots:
 
 protected:
     virtual void startDrag( Qt::DropActions supportedActions );
-    virtual void dragEnterEvent( QDragEnterEvent* event );
-    virtual void dragMoveEvent( QDragMoveEvent* event );
-    virtual void dropEvent( QDropEvent* event );
     virtual void resizeEvent( QResizeEvent* event );
 
     void paintEvent( QPaintEvent* event );
@@ -77,8 +75,6 @@ private slots:
     void onScrollTimeout();
 
 private:
-    QPixmap createDragPixmap( int itemCount ) const;
-
     TreeHeader* m_header;
     TreeModel* m_model;
     TreeProxyModel* m_proxyModel;
diff --git a/src/libtomahawk/playlist/playlistmodel.cpp b/src/libtomahawk/playlist/playlistmodel.cpp
index 2d7e5ab1a..c6b246749 100644
--- a/src/libtomahawk/playlist/playlistmodel.cpp
+++ b/src/libtomahawk/playlist/playlistmodel.cpp
@@ -300,6 +300,7 @@ PlaylistModel::onRevisionLoaded( Tomahawk::PlaylistRevision revision )
 bool
 PlaylistModel::dropMimeData( const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent )
 {
+    qDebug() << "LALALA";
     Q_UNUSED( column );
     if ( action == Qt::IgnoreAction || isReadOnly() )
         return true;
@@ -319,11 +320,30 @@ PlaylistModel::dropMimeData( const QMimeData* data, Qt::DropAction action, int r
 
     qDebug() << data->formats();
 
+    QList<Tomahawk::query_ptr> queries;
+    if ( data->hasFormat( "application/tomahawk.result.list" ) )
+    {
+        QByteArray itemData = data->data( "application/tomahawk.result.list" );
+        QDataStream stream( &itemData, QIODevice::ReadOnly );
+
+        while ( !stream.atEnd() )
+        {
+            qlonglong qptr;
+            stream >> qptr;
+
+            Tomahawk::result_ptr* result = reinterpret_cast<Tomahawk::result_ptr*>(qptr);
+            if ( result && !result->isNull() )
+            {
+                qDebug() << "Dropped result item:" << result->data()->artist() << "-" << result->data()->track() << action;
+                queries << result->data()->toQuery();
+            }
+        }
+    }
+
     if ( data->hasFormat( "application/tomahawk.query.list" ) )
     {
         QByteArray itemData = data->data( "application/tomahawk.query.list" );
         QDataStream stream( &itemData, QIODevice::ReadOnly );
-        QList<Tomahawk::query_ptr> queries;
 
         while ( !stream.atEnd() )
         {
@@ -337,7 +357,10 @@ PlaylistModel::dropMimeData( const QMimeData* data, Qt::DropAction action, int r
                 queries << *query;
             }
         }
+    }
 
+    if ( queries.count() )
+    {
         emit beginInsertRows( QModelIndex(), beginRow, beginRow + queries.count() - 1 );
         foreach( const Tomahawk::query_ptr& query, queries )
         {
diff --git a/src/libtomahawk/playlist/trackproxymodel.cpp b/src/libtomahawk/playlist/trackproxymodel.cpp
index 2ed2c94b1..91f082ecd 100644
--- a/src/libtomahawk/playlist/trackproxymodel.cpp
+++ b/src/libtomahawk/playlist/trackproxymodel.cpp
@@ -143,7 +143,6 @@ TrackProxyModel::siblingItem( int itemsAway )
     if ( idx.isValid() ) do
     {
         TrackModelItem* item = itemFromIndex( mapToSource( idx ) );
-        qDebug() << item->query()->toString();
         if ( item && item->query()->playable() )
         {
             qDebug() << "Next PlaylistItem found:" << item->query()->toString() << item->query()->results().at( 0 )->url();
diff --git a/src/libtomahawk/playlist/trackview.cpp b/src/libtomahawk/playlist/trackview.cpp
index db7a619f4..daf3627f0 100644
--- a/src/libtomahawk/playlist/trackview.cpp
+++ b/src/libtomahawk/playlist/trackview.cpp
@@ -285,6 +285,19 @@ TrackView::dropEvent( QDropEvent* event )
             qDebug() << "Drop Event accepted at row:" << index.row();
             event->acceptProposedAction();
 
+            if ( !model()->isReadOnly() )
+            {
+                model()->dropMimeData( event->mimeData(), event->proposedAction(), index.row(), 0, index.parent() );
+            }
+        }
+        else if ( event->mimeData()->hasFormat( "application/tomahawk.result.list" ) )
+        {
+            const QPoint pos = event->pos();
+            const QModelIndex index = indexAt( pos );
+
+            qDebug() << "Drop Event accepted at row:" << index.row();
+            event->acceptProposedAction();
+
             if ( !model()->isReadOnly() )
             {
                 model()->dropMimeData( event->mimeData(), event->proposedAction(), index.row(), 0, index.parent() );
@@ -345,6 +358,7 @@ TrackView::onFilterChanged( const QString& )
             m_overlay->hide();
 }
 
+
 void
 TrackView::copyLink()
 {
diff --git a/src/libtomahawk/playlist/treemodel.cpp b/src/libtomahawk/playlist/treemodel.cpp
index 8830e0bfe..28feb59d8 100644
--- a/src/libtomahawk/playlist/treemodel.cpp
+++ b/src/libtomahawk/playlist/treemodel.cpp
@@ -55,6 +55,29 @@ TreeModel::~TreeModel()
 }
 
 
+void
+TreeModel::setCurrentItem( const QModelIndex& index )
+{
+    qDebug() << Q_FUNC_INFO;
+    TreeModelItem* oldEntry = itemFromIndex( m_currentIndex );
+    if ( oldEntry )
+    {
+//        oldEntry->setIsPlaying( false );
+    }
+
+    TreeModelItem* entry = itemFromIndex( index );
+    if ( entry )
+    {
+        m_currentIndex = index;
+//        entry->setIsPlaying( true );
+    }
+    else
+    {
+        m_currentIndex = QModelIndex();
+    }
+}
+
+
 QModelIndex
 TreeModel::index( int row, int column, const QModelIndex& parent ) const
 {
@@ -257,9 +280,13 @@ TreeModel::flags( const QModelIndex& index ) const
     Qt::ItemFlags defaultFlags = QAbstractItemModel::flags( index );
 
     if ( index.isValid() && index.column() == 0 )
-        return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags;
-    else
-        return defaultFlags;
+    {
+        TreeModelItem* item = itemFromIndex( index );
+        if ( item && !item->result().isNull() )
+            return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags;
+    }
+
+    return defaultFlags;
 }
 
 
@@ -267,7 +294,7 @@ QStringList
 TreeModel::mimeTypes() const
 {
     QStringList types;
-    types << "application/tomahawk.query.list";
+    types << "application/tomahawk.result.list";
     return types;
 }
 
@@ -277,8 +304,8 @@ TreeModel::mimeData( const QModelIndexList &indexes ) const
 {
     qDebug() << Q_FUNC_INFO;
 
-    QByteArray queryData;
-    QDataStream queryStream( &queryData, QIODevice::WriteOnly );
+    QByteArray resultData;
+    QDataStream resultStream( &resultData, QIODevice::WriteOnly );
 
     foreach ( const QModelIndex& i, indexes )
     {
@@ -287,15 +314,15 @@ TreeModel::mimeData( const QModelIndexList &indexes ) const
 
         QModelIndex idx = index( i.row(), 0, i.parent() );
         TreeModelItem* item = itemFromIndex( idx );
-        if ( item )
+        if ( item && !item->result().isNull() )
         {
-            const album_ptr& album = item->album();
-            queryStream << qlonglong( &album );
+            const result_ptr& result = item->result();
+            resultStream << qlonglong( &result );
         }
     }
 
     QMimeData* mimeData = new QMimeData();
-    mimeData->setData( "application/tomahawk.query.list", queryData );
+    mimeData->setData( "application/tomahawk.result.list", resultData );
 
     return mimeData;
 }
@@ -396,7 +423,10 @@ TreeModel::addCollection( const collection_ptr& collection )
 
     Database::instance()->enqueue( QSharedPointer<DatabaseCommand>( cmd ) );
 
-    m_title = tr( "All Artists from %1" ).arg( collection->source()->friendlyName() );
+    if ( collection->source()->isLocal() )
+        setTitle( tr( "Your Collection" ) );
+    else
+        setTitle( tr( "Collection of %1" ).arg( collection->source()->friendlyName() ) );
 }
 
 
@@ -418,7 +448,10 @@ TreeModel::addFilteredCollection( const collection_ptr& collection, unsigned int
 
     Database::instance()->enqueue( QSharedPointer<DatabaseCommand>( cmd ) );
 
-    m_title = tr( "All albums from %1" ).arg( collection->source()->friendlyName() );
+    if ( collection->source()->isLocal() )
+        setTitle( tr( "Your Collection" ) );
+    else
+        setTitle( tr( "Collection of %1" ).arg( collection->source()->friendlyName() ) );
 }
 
 
diff --git a/src/libtomahawk/playlist/treemodel.h b/src/libtomahawk/playlist/treemodel.h
index 68f23bd98..002471f1b 100644
--- a/src/libtomahawk/playlist/treemodel.h
+++ b/src/libtomahawk/playlist/treemodel.h
@@ -74,6 +74,8 @@ public:
     virtual QStringList mimeTypes() const;
     virtual Qt::ItemFlags flags( const QModelIndex& index ) const;
 
+    virtual QPersistentModelIndex currentItem() { return m_currentIndex; }
+
     void addAllCollections();
     void addCollection( const Tomahawk::collection_ptr& collection );
     void addFilteredCollection( const Tomahawk::collection_ptr& collection, unsigned int amount, DatabaseCommand_AllArtists::SortOrder order );
@@ -97,6 +99,8 @@ public:
     }
 
 public slots:
+    virtual void setCurrentItem( const QModelIndex& index );
+
     virtual void setRepeatMode( PlaylistInterface::RepeatMode /*mode*/ ) {}
     virtual void setShuffled( bool /*shuffled*/ ) {}
 
diff --git a/src/libtomahawk/playlist/treeproxymodel.cpp b/src/libtomahawk/playlist/treeproxymodel.cpp
index 3f8b86b16..82570805d 100644
--- a/src/libtomahawk/playlist/treeproxymodel.cpp
+++ b/src/libtomahawk/playlist/treeproxymodel.cpp
@@ -140,7 +140,28 @@ Tomahawk::result_ptr
 TreeProxyModel::siblingItem( int itemsAway )
 {
     qDebug() << Q_FUNC_INFO;
-    return Tomahawk::result_ptr( 0 );
+
+    QModelIndex idx = currentItem();
+
+    // Try to find the next available PlaylistItem (with results)
+    if ( idx.isValid() ) do
+    {
+        idx = index( idx.row() + ( itemsAway > 0 ? 1 : -1 ), 0, idx.parent() );
+        if ( !idx.isValid() )
+            break;
+
+        TreeModelItem* item = itemFromIndex( mapToSource( idx ) );
+        if ( item && item->result()->isOnline() )
+        {
+            qDebug() << "Next PlaylistItem found:" << item->result()->url();
+            setCurrentItem( idx );
+            return item->result();
+        }
+    }
+    while ( idx.isValid() );
+
+    setCurrentItem( QModelIndex() );
+    return Tomahawk::result_ptr();
 }
 
 
diff --git a/src/libtomahawk/playlist/treeproxymodel.h b/src/libtomahawk/playlist/treeproxymodel.h
index b441e155b..34444dc6e 100644
--- a/src/libtomahawk/playlist/treeproxymodel.h
+++ b/src/libtomahawk/playlist/treeproxymodel.h
@@ -36,6 +36,9 @@ public:
     virtual TreeModel* sourceModel() const { return m_model; }
     virtual void setSourceModel( TreeModel* sourceModel );
 
+    virtual QPersistentModelIndex currentItem() const { return mapFromSource( m_model->currentItem() ); }
+    virtual void setCurrentItem( const QModelIndex& index ) { m_model->setCurrentItem( mapToSource( index ) ); }
+
     virtual QList<Tomahawk::query_ptr> tracks() { Q_ASSERT( FALSE ); QList<Tomahawk::query_ptr> queries; return queries; }
 
     virtual int unfilteredTrackCount() const { return sourceModel()->rowCount( QModelIndex() ); }
@@ -53,6 +56,8 @@ public:
     virtual bool shuffled() const { return m_shuffled; }
     virtual PlaylistInterface::ViewMode viewMode() const { return PlaylistInterface::Tree; }
 
+    TreeModelItem* itemFromIndex( const QModelIndex& index ) const { return sourceModel()->itemFromIndex( index ); }
+
 signals:
     void repeatModeChanged( PlaylistInterface::RepeatMode mode );
     void shuffleModeChanged( bool enabled );
diff --git a/src/libtomahawk/result.cpp b/src/libtomahawk/result.cpp
index 9f655f149..9bfae38f7 100644
--- a/src/libtomahawk/result.cpp
+++ b/src/libtomahawk/result.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
@@ -30,7 +30,14 @@ using namespace Tomahawk;
 
 Result::Result()
     : QObject()
+    , m_duration( 0 )
+    , m_bitrate( 0 )
+    , m_size( 0 )
+    , m_albumpos( 0 )
+    , m_modtime( 0 )
     , m_year( 0 )
+    , m_score( 0 )
+    , m_id( 0 )
 {
 }
 
@@ -40,21 +47,21 @@ Result::~Result()
 }
 
 
-artist_ptr 
+artist_ptr
 Result::artist() const
 {
     return m_artist;
 }
 
 
-album_ptr 
+album_ptr
 Result::album() const
 {
     return m_album;
 }
 
 
-collection_ptr 
+collection_ptr
 Result::collection() const
 {
     return m_collection;
@@ -87,6 +94,13 @@ Result::id() const
 }
 
 
+bool
+Result::isOnline() const
+{
+    return ( !collection().isNull() && collection()->source()->isOnline() );
+}
+
+
 QVariant
 Result::toVariant() const
 {
diff --git a/src/libtomahawk/result.h b/src/libtomahawk/result.h
index aff9604ba..ce2c69542 100644
--- a/src/libtomahawk/result.h
+++ b/src/libtomahawk/result.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
@@ -55,6 +55,8 @@ public:
 
     float score() const;
     RID id() const;
+    bool isOnline() const;
+
     collection_ptr collection() const;
     Tomahawk::artist_ptr artist() const;
     Tomahawk::album_ptr album() const;
diff --git a/src/libtomahawk/sip/SipHandler.cpp b/src/libtomahawk/sip/SipHandler.cpp
index 3ff86aa7b..e106f21f5 100644
--- a/src/libtomahawk/sip/SipHandler.cpp
+++ b/src/libtomahawk/sip/SipHandler.cpp
@@ -40,13 +40,16 @@
 
 SipHandler* SipHandler::s_instance = 0;
 
-SipHandler* SipHandler::instance()
+SipHandler*
+SipHandler::instance()
 {
-    if( s_instance == 0 )
-        s_instance = new SipHandler( 0 );
+    if ( !s_instance )
+        new SipHandler( 0 );
+
     return s_instance;
 }
 
+
 SipHandler::SipHandler( QObject* parent )
     : QObject( parent )
     , m_connected( false )
@@ -61,10 +64,14 @@ SipHandler::SipHandler( QObject* parent )
 
 SipHandler::~SipHandler()
 {
+    qDebug() << Q_FUNC_INFO;
     disconnectAll();
+    qDeleteAll( m_allPlugins );
 }
 
-const QPixmap SipHandler::avatar( const QString& name ) const
+
+const QPixmap
+SipHandler::avatar( const QString& name ) const
 {
     qDebug() << Q_FUNC_INFO << "Getting avatar" << name << m_usernameAvatars.keys();
     if( m_usernameAvatars.keys().contains( name ) )
@@ -80,12 +87,14 @@ const QPixmap SipHandler::avatar( const QString& name ) const
     }
 }
 
+
 const SipInfo
 SipHandler::sipInfo(const QString& peerId) const
 {
     return m_peersSipInfos.value( peerId );
 }
 
+
 void
 SipHandler::onSettingsChanged()
 {
@@ -554,10 +563,11 @@ SipHandler::onStateChanged( SipPlugin::ConnectionState state )
     {
         m_connectedPlugins.removeAll( sip );
         emit disconnected( sip );
-    } else if ( sip->connectionState() == SipPlugin::Connected )
+    }
+    else if ( sip->connectionState() == SipPlugin::Connected )
     {
-        m_connectedPlugins.removeAll( sip );
-        emit disconnected( sip );
+        m_connectedPlugins << sip;
+        emit connected( sip );
     }
 
     emit stateChanged( sip, state );
diff --git a/src/libtomahawk/sip/SipPlugin.h b/src/libtomahawk/sip/SipPlugin.h
index 3ac9fd2cc..dc1b4a9e8 100644
--- a/src/libtomahawk/sip/SipPlugin.h
+++ b/src/libtomahawk/sip/SipPlugin.h
@@ -59,7 +59,7 @@ class DLLEXPORT SipPlugin : public QObject
 
 public:
     enum SipErrorCode { AuthError, ConnectionError }; // Placeholder for errors, to be defined
-    enum ConnectionState { Disconnected, Connecting, Connected };
+    enum ConnectionState { Disconnected, Connecting, Connected, Disconnecting };
 
     explicit SipPlugin( const QString& pluginId, QObject* parent = 0 );
     virtual ~SipPlugin() {}
diff --git a/src/libtomahawk/sourcelist.cpp b/src/libtomahawk/sourcelist.cpp
index 0f3576808..44ba6d8af 100644
--- a/src/libtomahawk/sourcelist.cpp
+++ b/src/libtomahawk/sourcelist.cpp
@@ -45,7 +45,6 @@ SourceList::instance()
 SourceList::SourceList( QObject* parent )
     : QObject( parent )
 {
-    loadSources();
 }
 
 
diff --git a/src/libtomahawk/sourcelist.h b/src/libtomahawk/sourcelist.h
index 7073f713d..d4757095b 100644
--- a/src/libtomahawk/sourcelist.h
+++ b/src/libtomahawk/sourcelist.h
@@ -43,6 +43,7 @@ public:
     void setWebSource( const Tomahawk::source_ptr& websrc );
     const Tomahawk::source_ptr webSource() const;
 
+    void loadSources();
     void removeAllRemote();
 
     QList<Tomahawk::source_ptr> sources( bool onlyOnline = false ) const;
@@ -62,7 +63,6 @@ private slots:
     void sourceSynced();
 
 private:
-    void loadSources();
     void add( const Tomahawk::source_ptr& source );
 
     QMap< QString, Tomahawk::source_ptr > m_sources;
diff --git a/src/resolvers/qtscriptresolver.cpp b/src/resolvers/qtscriptresolver.cpp
index 78375c522..53debfafc 100644
--- a/src/resolvers/qtscriptresolver.cpp
+++ b/src/resolvers/qtscriptresolver.cpp
@@ -60,7 +60,7 @@ QtScriptResolver::QtScriptResolver( const QString& scriptPath )
 QtScriptResolver::~QtScriptResolver()
 {
     Tomahawk::Pipeline::instance()->removeResolver( this );
-    delete m_engine;
+//    delete m_engine;
 }
 
 
diff --git a/src/sip/jreen/jabber.cpp b/src/sip/jreen/jabber.cpp
index 392da18fe..fabcd9846 100644
--- a/src/sip/jreen/jabber.cpp
+++ b/src/sip/jreen/jabber.cpp
@@ -96,7 +96,7 @@ JabberPlugin::JabberPlugin( const QString& pluginId )
     // instantiate XmlConsole
     if( readXmlConsoleEnabled() )
     {
-        m_xmlConsole =  new XmlConsole( m_client );
+        m_xmlConsole = new XmlConsole( m_client );
         m_xmlConsole->show();
     }
 
@@ -141,7 +141,11 @@ JabberPlugin::JabberPlugin( const QString& pluginId )
 
 JabberPlugin::~JabberPlugin()
 {
-
+    delete m_avatarManager;
+    delete m_roster;
+    delete m_client;
+    delete m_xmlConsole;
+    delete m_ui;
 }
 
 void
@@ -222,7 +226,6 @@ JabberPlugin::connectPlugin( bool startup )
     //FIXME: we're badly workarounding some missing reconnection api here, to be fixed soon
     QTimer::singleShot( 1000, m_client, SLOT( connectToServer() ) );
 
-
     connect(m_client->connection(), SIGNAL(error(Jreen::Connection::SocketError)), SLOT(onError(Jreen::Connection::SocketError)));
 
     m_state = Connecting;
@@ -251,7 +254,9 @@ JabberPlugin::disconnectPlugin()
     m_peers.clear();
     m_legacy_peers.clear();
 
-    m_client->disconnectFromServer(true);
+    m_client->disconnectFromServer( true );
+    m_state = Disconnecting;
+    emit stateChanged( m_state );
 }
 
 void
@@ -572,6 +577,11 @@ void JabberPlugin::removeMenuHelper()
 
 void JabberPlugin::onNewMessage(const Jreen::Message& message)
 {
+    if ( m_state != Connected )
+        return;
+
+    qDebug() << Q_FUNC_INFO << "message type" << message.subtype();
+
     QString from = message.from().full();
     QString msg = message.body();
 
@@ -608,6 +618,8 @@ void JabberPlugin::onNewMessage(const Jreen::Message& message)
 void JabberPlugin::onPresenceReceived( const Jreen::RosterItem::Ptr &item, const Jreen::Presence& presence )
 {
     Q_UNUSED(item);
+    if ( m_state != Connected )
+        return;
 
     Jreen::JID jid = presence.from();
     QString fulljid( jid.full() );
@@ -652,6 +664,9 @@ void JabberPlugin::onPresenceReceived( const Jreen::RosterItem::Ptr &item, const
 
 void JabberPlugin::onSubscriptionReceived(const Jreen::RosterItem::Ptr& item, const Jreen::Presence& presence)
 {
+    if ( m_state != Connected )
+        return;
+
     qDebug() << Q_FUNC_INFO << "presence type: " << presence.subtype();
     if(item)
         qDebug() << Q_FUNC_INFO << presence.from().full() << "subs" << item->subscription() << "ask" << item->ask();
@@ -739,6 +754,9 @@ JabberPlugin::onSubscriptionRequestConfirmed( int result )
 
 void JabberPlugin::onNewIq(const Jreen::IQ& iq, int context)
 {
+    if ( m_state != Connected )
+        return;
+
     if( context == RequestDisco )
     {
         qDebug() << Q_FUNC_INFO << "Received disco IQ...";
@@ -885,6 +903,9 @@ void JabberPlugin::handlePeerStatus(const Jreen::JID& jid, Jreen::Presence::Type
 void JabberPlugin::onNewAvatar(const QString& jid)
 {
     qDebug() << Q_FUNC_INFO << jid;
+    if ( m_state != Connected )
+        return;
+
     Q_ASSERT(!m_avatarManager->avatar( jid ).isNull());
 
     // find peers for the jid
diff --git a/src/sourcetree/items/playlistitems.cpp b/src/sourcetree/items/playlistitems.cpp
index ce5de4277..d73d6ada0 100644
--- a/src/sourcetree/items/playlistitems.cpp
+++ b/src/sourcetree/items/playlistitems.cpp
@@ -111,36 +111,56 @@ PlaylistItem::willAcceptDrag( const QMimeData* data ) const
 bool
 PlaylistItem::dropMimeData( const QMimeData* data, Qt::DropAction action )
 {
-    if( data->hasFormat( "application/tomahawk.query.list" ) ) {
-        if ( !m_playlist.isNull() && m_playlist->author()->isLocal() ) {
+    QList< Tomahawk::query_ptr > queries;
+    if ( data->hasFormat( "application/tomahawk.result.list" ) )
+    {
+        QByteArray itemData = data->data( "application/tomahawk.result.list" );
+        QDataStream stream( &itemData, QIODevice::ReadOnly );
 
-            QByteArray itemData = data->data( "application/tomahawk.query.list" );
-            QDataStream stream( &itemData, QIODevice::ReadOnly );
-            QList< Tomahawk::query_ptr > queries;
+        while ( !stream.atEnd() )
+        {
+            qlonglong qptr;
+            stream >> qptr;
 
-            while ( !stream.atEnd() )
+            Tomahawk::result_ptr* result = reinterpret_cast<Tomahawk::result_ptr*>(qptr);
+            if ( result && !result->isNull() )
             {
-                qlonglong qptr;
-                stream >> qptr;
-
-                Tomahawk::query_ptr* query = reinterpret_cast<Tomahawk::query_ptr*>(qptr);
-                if ( query && !query->isNull() )
-                {
-                    qDebug() << "Dropped query item:" << query->data()->artist() << "-" << query->data()->track();
-                    queries << *query;
-                }
+                qDebug() << "Dropped result item:" << result->data()->artist() << "-" << result->data()->track();
+                queries << result->data()->toQuery();
             }
-
-            qDebug() << "on playlist:" << m_playlist->title() << m_playlist->guid();
-
-            // TODO do we need to use this in the refactor?
-            //                     QString rev = item->currentlyLoadedPlaylistRevision( playlist->guid() );
-            m_playlist->addEntries( queries, m_playlist->currentrevision() );
-
-            return true;
         }
     }
 
+    if ( data->hasFormat( "application/tomahawk.query.list" ) )
+    {
+        QByteArray itemData = data->data( "application/tomahawk.query.list" );
+        QDataStream stream( &itemData, QIODevice::ReadOnly );
+
+        while ( !stream.atEnd() )
+        {
+            qlonglong qptr;
+            stream >> qptr;
+
+            Tomahawk::query_ptr* query = reinterpret_cast<Tomahawk::query_ptr*>(qptr);
+            if ( query && !query->isNull() )
+            {
+                qDebug() << "Dropped query item:" << query->data()->artist() << "-" << query->data()->track();
+                queries << *query;
+            }
+        }
+    }
+
+    if ( queries.count() && !m_playlist.isNull() && m_playlist->author()->isLocal() )
+    {
+        qDebug() << "on playlist:" << m_playlist->title() << m_playlist->guid();
+
+        // TODO do we need to use this in the refactor?
+        //                     QString rev = item->currentlyLoadedPlaylistRevision( playlist->guid() );
+        m_playlist->addEntries( queries, m_playlist->currentrevision() );
+
+        return true;
+    }
+
     return false;
 }
 
diff --git a/src/sourcetree/sourcesmodel.cpp b/src/sourcetree/sourcesmodel.cpp
index 61adc5f0b..e152d29b9 100644
--- a/src/sourcetree/sourcesmodel.cpp
+++ b/src/sourcetree/sourcesmodel.cpp
@@ -87,12 +87,14 @@ SourcesModel::data( const QModelIndex& index, int role ) const
     return QVariant();
 }
 
+
 int
 SourcesModel::columnCount( const QModelIndex& parent ) const
 {
     return 1;
 }
 
+
 int
 SourcesModel::rowCount( const QModelIndex& parent ) const
 {
@@ -103,6 +105,7 @@ SourcesModel::rowCount( const QModelIndex& parent ) const
     return itemFromIndex( parent )->children().count();
 }
 
+
 QModelIndex
 SourcesModel::parent( const QModelIndex& child ) const
 {
@@ -119,6 +122,7 @@ SourcesModel::parent( const QModelIndex& child ) const
     return createIndex( rowForItem( parent ), 0, parent );
 }
 
+
 QModelIndex
 SourcesModel::index( int row, int column, const QModelIndex& parent ) const
 {
@@ -137,6 +141,7 @@ SourcesModel::index( int row, int column, const QModelIndex& parent ) const
 
 }
 
+
 bool
 SourcesModel::setData( const QModelIndex& index, const QVariant& value, int role )
 {
@@ -144,14 +149,17 @@ SourcesModel::setData( const QModelIndex& index, const QVariant& value, int role
     return item->setData( value, role );
 }
 
+
 QStringList
 SourcesModel::mimeTypes() const
 {
     QStringList types;
     types << "application/tomahawk.query.list";
+    types << "application/tomahawk.result.list";
     return types;
 }
 
+
 QMimeData*
 SourcesModel::mimeData( const QModelIndexList& indexes ) const
 {
@@ -159,6 +167,7 @@ SourcesModel::mimeData( const QModelIndexList& indexes ) const
     return new QMimeData();
 }
 
+
 bool
 SourcesModel::dropMimeData( const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent )
 {
@@ -173,12 +182,14 @@ SourcesModel::dropMimeData( const QMimeData* data, Qt::DropAction action, int ro
     return item->dropMimeData( data, action );
 }
 
+
 Qt::DropActions
 SourcesModel::supportedDropActions() const
 {
     return Qt::CopyAction;
 }
 
+
 Qt::ItemFlags
 SourcesModel::flags( const QModelIndex& index ) const
 {
@@ -200,6 +211,7 @@ SourcesModel::appendItem( const Tomahawk::source_ptr& source )
     endInsertRows();
 }
 
+
 bool
 SourcesModel::removeItem( const Tomahawk::source_ptr& source )
 {
@@ -228,6 +240,7 @@ SourcesModel::removeItem( const Tomahawk::source_ptr& source )
     return false;
 }
 
+
 void
 SourcesModel::viewPageActivated( Tomahawk::ViewPage* page )
 {
@@ -244,6 +257,7 @@ SourcesModel::viewPageActivated( Tomahawk::ViewPage* page )
     }
 }
 
+
 void
 SourcesModel::loadSources()
 {
@@ -275,6 +289,7 @@ SourcesModel::onSourceRemoved( const source_ptr& source )
     removeItem( source );
 }
 
+
 void
 SourcesModel::itemUpdated()
 {
@@ -303,6 +318,7 @@ SourcesModel::onItemRowsAddedBegin( int first, int last )
     beginInsertRows( idx, first, last );
 }
 
+
 void
 SourcesModel::onItemRowsAddedDone()
 {
@@ -311,6 +327,7 @@ SourcesModel::onItemRowsAddedDone()
     endInsertRows();
 }
 
+
 void
 SourcesModel::onItemRowsRemovedBegin( int first, int last )
 {
@@ -324,6 +341,7 @@ SourcesModel::onItemRowsRemovedBegin( int first, int last )
     beginRemoveRows( idx, first, last );
 }
 
+
 void
 SourcesModel::onItemRowsRemovedDone()
 {
@@ -332,6 +350,7 @@ SourcesModel::onItemRowsRemovedDone()
     endRemoveRows();
 }
 
+
 void
 SourcesModel::linkSourceItemToPage( SourceTreeItem* item, ViewPage* p )
 {
@@ -356,6 +375,7 @@ SourcesModel::itemFromIndex( const QModelIndex& idx ) const
     return reinterpret_cast< SourceTreeItem* >( idx.internalPointer() );
 }
 
+
 QModelIndex
 SourcesModel::indexFromItem( SourceTreeItem* item ) const
 {
@@ -396,6 +416,7 @@ SourcesModel::indexFromItem( SourceTreeItem* item ) const
     return idx;
 }
 
+
 int
 SourcesModel::rowForItem( SourceTreeItem* item ) const
 {
diff --git a/src/sourcetree/sourcetreeview.cpp b/src/sourcetree/sourcetreeview.cpp
index a504126ed..5ff59ead9 100644
--- a/src/sourcetree/sourcetreeview.cpp
+++ b/src/sourcetree/sourcetreeview.cpp
@@ -160,6 +160,7 @@ SourceTreeView::hideOfflineSources()
     m_proxyModel->hideOfflineSources();
 }
 
+
 void
 SourceTreeView::onItemActivated( const QModelIndex& index )
 {
@@ -182,6 +183,7 @@ SourceTreeView::onItemExpanded( const QModelIndex& idx )
     }
 }
 
+
 void
 SourceTreeView::selectRequest( const QModelIndex& idx )
 {
@@ -260,7 +262,8 @@ SourceTreeView::dragEnterEvent( QDragEnterEvent* event )
     qDebug() << Q_FUNC_INFO;
     QTreeView::dragEnterEvent( event );
 
-    if ( event->mimeData()->hasFormat( "application/tomahawk.query.list" ) )
+    if ( event->mimeData()->hasFormat( "application/tomahawk.query.list" )
+      || event->mimeData()->hasFormat( "application/tomahawk.result.list" ) )
     {
         m_dragging = true;
         m_dropRect = QRect();
@@ -278,7 +281,8 @@ SourceTreeView::dragMoveEvent( QDragMoveEvent* event )
     bool accept = false;
     QTreeView::dragMoveEvent( event );
 
-    if ( event->mimeData()->hasFormat( "application/tomahawk.query.list" ) )
+    if ( event->mimeData()->hasFormat( "application/tomahawk.query.list" )
+      || event->mimeData()->hasFormat( "application/tomahawk.result.list" ) )
     {
         setDirtyRegion( m_dropRect );
         const QPoint pos = event->pos();
@@ -292,7 +296,9 @@ SourceTreeView::dragMoveEvent( QDragMoveEvent* event )
             const SourceTreeItem* item = itemFromIndex< SourceTreeItem >( index );
             if( item->willAcceptDrag( event->mimeData() ) )
                 accept = true;
-        } else {
+        }
+        else
+        {
             m_dropRect = QRect();
         }
 
@@ -344,6 +350,7 @@ SourceTreeView::drawRow( QPainter* painter, const QStyleOptionViewItem& option,
     QTreeView::drawRow( painter, option, index );
 }
 
+
 template< typename T > T*
 SourceTreeView::itemFromIndex( const QModelIndex& index ) const
 {
@@ -389,7 +396,6 @@ SourceDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, co
         }
     }
 
-
     SourcesModel::RowType type = static_cast< SourcesModel::RowType >( index.data( SourcesModel::SourceTreeItemTypeRole ).toInt() );
     SourceTreeItem* item = index.data( SourcesModel::SourceTreeItemRole ).value< SourceTreeItem* >();
     Q_ASSERT( item );
diff --git a/src/tomahawkapp.cpp b/src/tomahawkapp.cpp
index 1fcac1d34..c0ffad1c2 100644
--- a/src/tomahawkapp.cpp
+++ b/src/tomahawkapp.cpp
@@ -323,8 +323,14 @@ TomahawkApp::~TomahawkApp()
     delete m_mainwindow;
     delete m_audioEngine;
 #endif
-    delete m_infoSystem;
+
+    delete SipHandler::instance();
+    Pipeline::instance()->stop();
+
     delete m_database;
+    delete m_infoSystem;
+
+    qDebug() << "Finished shutdown.";
 }
 
 
@@ -343,11 +349,6 @@ TomahawkApp::audioControls()
 }
 #endif
 
-SipHandler*
-TomahawkApp::sipHandler()
-{
-    return SipHandler::instance();
-}
 
 void
 TomahawkApp::registerMetaTypes()
@@ -476,6 +477,7 @@ TomahawkApp::disableScriptResolver( const QString& path )
     }
 }
 
+
 Tomahawk::ExternalResolver*
 TomahawkApp::resolverForPath( const QString& scriptPath )
 {
@@ -499,6 +501,7 @@ TomahawkApp::initLocalCollection()
     collection_ptr dummycol( new WebCollection( dummy ) );
     dummy->addCollection( dummycol );
     SourceList::instance()->setWebSource( dummy );
+    SourceList::instance()->loadSources();
 
     // to make the stats signal be emitted by our local source
     // this will update the sidebar, etc.
@@ -521,6 +524,7 @@ TomahawkApp::startServent()
     }
 }
 
+
 void
 TomahawkApp::setupSIP()
 {
diff --git a/src/tomahawkwindow.cpp b/src/tomahawkwindow.cpp
index 4d963c24a..7c464c3bc 100644
--- a/src/tomahawkwindow.cpp
+++ b/src/tomahawkwindow.cpp
@@ -186,7 +186,7 @@ TomahawkWindow::TomahawkWindow( QWidget* parent )
     // propagate sip menu
     connect( SipHandler::instance(), SIGNAL( pluginAdded( SipPlugin* ) ), this, SLOT( onSipPluginAdded( SipPlugin* ) ) );
     connect( SipHandler::instance(), SIGNAL( pluginRemoved( SipPlugin* ) ), this, SLOT( onSipPluginRemoved( SipPlugin* ) ) );
-    foreach( SipPlugin *plugin, APP->sipHandler()->allPlugins() )
+    foreach( SipPlugin *plugin, SipHandler::instance()->allPlugins() )
     {
         connect( plugin, SIGNAL( addMenu( QMenu* ) ), this, SLOT( pluginMenuAdded( QMenu* ) ) );
         connect( plugin, SIGNAL( removeMenu( QMenu* ) ), this, SLOT( pluginMenuRemoved( QMenu* ) ) );
@@ -267,7 +267,7 @@ TomahawkWindow::setupSignals()
     // <Menu Items>
     connect( ui->actionPreferences, SIGNAL( triggered() ), SLOT( showSettingsDialog() ) );
     connect( ui->actionDiagnostics, SIGNAL( triggered() ), SLOT( showDiagnosticsDialog() ) );
-    connect( ui->actionToggleConnect, SIGNAL( triggered() ), APP->sipHandler(), SLOT( toggleConnect() ) );
+    connect( ui->actionToggleConnect, SIGNAL( triggered() ), SipHandler::instance(), SLOT( toggleConnect() ) );
 //    connect( ui->actionAddPeerManually, SIGNAL( triggered() ), SLOT( addPeerManually() ) );
     connect( ui->actionRescanCollection, SIGNAL( triggered() ), SLOT( updateCollectionManually() ) );
     connect( ui->actionLoadXSPF, SIGNAL( triggered() ), SLOT( loadSpiff() ));
@@ -285,9 +285,9 @@ TomahawkWindow::setupSignals()
 #endif
 
     // <SipHandler>
-    connect( APP->sipHandler(), SIGNAL( connected() ), SLOT( onSipConnected() ) );
-    connect( APP->sipHandler(), SIGNAL( disconnected() ), SLOT( onSipDisconnected() ) );
-    connect( APP->sipHandler(), SIGNAL( authError() ), SLOT( onSipError() ) );
+    connect( SipHandler::instance(), SIGNAL( connected( SipPlugin* ) ), SLOT( onSipConnected() ) );
+    connect( SipHandler::instance(), SIGNAL( disconnected( SipPlugin* ) ), SLOT( onSipDisconnected() ) );
+    connect( SipHandler::instance(), SIGNAL( authError( SipPlugin* ) ), SLOT( onSipError() ) );
 
     // set initial connection state
     onSipDisconnected();