From 3c3c1414feea849af030799ebd5edfd8fd592f92 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Hugo=20Lindstr=C3=B6m?= <hugolm84@gmail.com>
Date: Fri, 9 Dec 2011 20:37:54 +0100
Subject: [PATCH 01/11] Allow symlinks in dirtree

---
 src/libtomahawk/widgets/checkdirtree.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/libtomahawk/widgets/checkdirtree.cpp b/src/libtomahawk/widgets/checkdirtree.cpp
index 66ab932bf..ee4bdc86f 100644
--- a/src/libtomahawk/widgets/checkdirtree.cpp
+++ b/src/libtomahawk/widgets/checkdirtree.cpp
@@ -144,7 +144,7 @@ CheckDirModel::getCheck( const QModelIndex& index )
 CheckDirTree::CheckDirTree( QWidget* parent )
     : QTreeView( parent )
 {
-    m_dirModel.setFilter( QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks );
+    m_dirModel.setFilter( QDir::Dirs | QDir::NoDotAndDotDot );
     m_dirModel.setRootPath( "/" );
 
     m_dirModel.setNameFilters( QStringList() << "[^\\.]*" );

From d22bccd9fbbbf5b1c430dbdbb37e2123b636dd27 Mon Sep 17 00:00:00 2001
From: Christian Muehlhaeuser <muesli@gmail.com>
Date: Sat, 10 Dec 2011 02:02:44 +0100
Subject: [PATCH 02/11] * A few cleanups.

---
 src/libtomahawk/database/databaseimpl.cpp | 2 +-
 src/libtomahawk/playlistinterface.h       | 6 +-----
 src/libtomahawk/sourceplaylistinterface.h | 2 --
 3 files changed, 2 insertions(+), 8 deletions(-)

diff --git a/src/libtomahawk/database/databaseimpl.cpp b/src/libtomahawk/database/databaseimpl.cpp
index 136649b53..ef25eac50 100644
--- a/src/libtomahawk/database/databaseimpl.cpp
+++ b/src/libtomahawk/database/databaseimpl.cpp
@@ -385,7 +385,7 @@ DatabaseImpl::searchTable( const QString& table, const QString& name, uint limit
         return resultslist;
 
     QList< QPair<int, float> > resultscapped;
-    for ( unsigned int i = 0; i < limit && i < resultsmap.count(); i++ )
+    for ( int i = 0; i < (int)limit && i < resultsmap.count(); i++ )
     {
         resultscapped << resultslist.at( i );
     }
diff --git a/src/libtomahawk/playlistinterface.h b/src/libtomahawk/playlistinterface.h
index c6017f197..4ef652137 100644
--- a/src/libtomahawk/playlistinterface.h
+++ b/src/libtomahawk/playlistinterface.h
@@ -73,15 +73,11 @@ public:
 
     QObject* object() const { return m_object; }
 
-    static void dontDelete( Tomahawk::PlaylistInterface* obj )
-    {
-        tDebug() << Q_FUNC_INFO << obj;
-    }
     virtual Tomahawk::playlistinterface_ptr getSharedPointer()
     {
         if ( m_sharedPtr.isNull() )
         {
-            m_sharedPtr = Tomahawk::playlistinterface_ptr( this, dontDelete );
+            m_sharedPtr = Tomahawk::playlistinterface_ptr( this );
         }
 
         return m_sharedPtr;
diff --git a/src/libtomahawk/sourceplaylistinterface.h b/src/libtomahawk/sourceplaylistinterface.h
index 6ff1822dd..1b23f5af3 100644
--- a/src/libtomahawk/sourceplaylistinterface.h
+++ b/src/libtomahawk/sourceplaylistinterface.h
@@ -77,8 +77,6 @@ private slots:
     void resolvingFinished( bool hasResults );
 
 private:
-    SourcePlaylistInterface();
-
     Tomahawk::source_ptr m_source;
     Tomahawk::result_ptr m_currentItem;
     bool m_gotNextItem;

From 3b8deef8c5e09dd9b2b373449400421c5c83cfd6 Mon Sep 17 00:00:00 2001
From: Jason Herskowitz <jherskowitz@globallistic.com>
Date: Sun, 11 Dec 2011 16:20:52 -0500
Subject: [PATCH 03/11] New spinner animation

---
 data/images/loading-animation.gif | Bin 2608 -> 8534 bytes
 1 file changed, 0 insertions(+), 0 deletions(-)

diff --git a/data/images/loading-animation.gif b/data/images/loading-animation.gif
index 7fc9059880268a3e4eaea926e4e36093eb31bde2..8be8ba338d5b5aec80593295f88bcaf6608bdf18 100644
GIT binary patch
literal 8534
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
G(|-Y9t#!u$

literal 2608
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
U@0!tb_KI6)uefy!|D%`dpR|;|761SM


From 31fb398b378e7666d6631c11566d7b7d54f5f32a Mon Sep 17 00:00:00 2001
From: Dominik Schmidt <dev@dominik-schmidt.de>
Date: Sun, 11 Dec 2011 22:49:26 +0100
Subject: [PATCH 04/11] Update README concerning Jreen

---
 README | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README b/README
index 92fc12534..65df9b01f 100644
--- a/README
+++ b/README
@@ -39,7 +39,7 @@ Dependencies
  The following dependencies are optional, but recommended:
 
   Attica 0.2.0 - ftp://ftp.kde.org/pub/kde/stable/attica/
-  jreen (Git) - https://github.com/euroelessar/jreen
+  Jreen 1.0.1 - https://github.com/euroelessar/jreen
   QTweetLib 0.3.0 - https://github.com/minimoog/QTweetLib
 
  Third party libraries that we ship with our source:

From 6064b2029ec71fafa688694a61ebc945279c9881 Mon Sep 17 00:00:00 2001
From: Christian Muehlhaeuser <muesli@gmail.com>
Date: Wed, 14 Dec 2011 11:16:09 +0100
Subject: [PATCH 05/11] * New sidebar style. Also, first steps towards
 reorganizing it.

---
 src/CMakeLists.txt                            |   8 +-
 src/libtomahawk/playlistinterface.h           |   7 +-
 src/libtomahawk/utils/proxystyle.cpp          |   6 +-
 src/libtomahawk/viewmanager.cpp               |  11 +
 src/libtomahawk/viewmanager.h                 |   3 +
 src/sourcetree/items/categoryitems.cpp        |   7 +-
 src/sourcetree/items/categoryitems.h          |   3 +
 src/sourcetree/items/groupitem.cpp            |  55 +++
 src/sourcetree/items/groupitem.h              |  53 ++
 src/sourcetree/items/historyitem.cpp          |  96 ++++
 src/sourcetree/items/historyitem.h            |  57 +++
 src/sourcetree/items/playlistitems.cpp        |   6 +-
 .../{collectionitem.cpp => sourceitem.cpp}    | 213 ++++----
 .../items/{collectionitem.h => sourceitem.h}  |  17 +-
 src/sourcetree/items/sourcetreeitem.cpp       |  10 +-
 src/sourcetree/items/sourcetreeitem.h         |   3 +
 src/sourcetree/sourcedelegate.cpp             | 459 +++++++++++-------
 src/sourcetree/sourcedelegate.h               |   6 +
 src/sourcetree/sourcesmodel.cpp               | 124 +++--
 src/sourcetree/sourcesmodel.h                 |  45 +-
 src/sourcetree/sourcesproxymodel.cpp          |  33 +-
 src/sourcetree/sourcesproxymodel.h            |   5 +
 src/sourcetree/sourcetreeview.cpp             |  30 +-
 src/sourcetree/sourcetreeview.h               |   3 +-
 24 files changed, 873 insertions(+), 387 deletions(-)
 create mode 100644 src/sourcetree/items/groupitem.cpp
 create mode 100644 src/sourcetree/items/groupitem.h
 create mode 100644 src/sourcetree/items/historyitem.cpp
 create mode 100644 src/sourcetree/items/historyitem.h
 rename src/sourcetree/items/{collectionitem.cpp => sourceitem.cpp} (65%)
 rename src/sourcetree/items/{collectionitem.h => sourceitem.h} (89%)

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 984150128..75cade522 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -58,11 +58,13 @@ SET( tomahawkSourcesGui ${tomahawkSourcesGui}
      sourcetree/sourcedelegate.cpp
      sourcetree/animationhelper.cpp
      sourcetree/items/sourcetreeitem.cpp
-     sourcetree/items/collectionitem.cpp
+     sourcetree/items/sourceitem.cpp
      sourcetree/items/playlistitems.cpp
      sourcetree/items/categoryitems.cpp
      sourcetree/items/genericpageitems.cpp
      sourcetree/items/temporarypageitem.cpp
+     sourcetree/items/groupitem.cpp
+     sourcetree/items/historyitem.cpp
 
      breakpad/BreakPad.cpp
 
@@ -110,11 +112,13 @@ SET( tomahawkHeadersGui ${tomahawkHeadersGui}
      sourcetree/sourcedelegate.h
      sourcetree/animationhelper.h
      sourcetree/items/sourcetreeitem.h
-     sourcetree/items/collectionitem.h
+     sourcetree/items/sourceitem.h
      sourcetree/items/playlistitems.h
      sourcetree/items/categoryitems.h
      sourcetree/items/genericpageitems.h
      sourcetree/items/temporarypageitem.h
+     sourcetree/items/groupitem.h
+     sourcetree/items/historyitem.h
 
      tomahawktrayicon.h
      audiocontrols.h
diff --git a/src/libtomahawk/playlistinterface.h b/src/libtomahawk/playlistinterface.h
index 4ef652137..991a84275 100644
--- a/src/libtomahawk/playlistinterface.h
+++ b/src/libtomahawk/playlistinterface.h
@@ -73,11 +73,16 @@ public:
 
     QObject* object() const { return m_object; }
 
+    static void dontDelete( Tomahawk::PlaylistInterface* obj )
+    {
+        tDebug() << Q_FUNC_INFO << obj;
+    }
+
     virtual Tomahawk::playlistinterface_ptr getSharedPointer()
     {
         if ( m_sharedPtr.isNull() )
         {
-            m_sharedPtr = Tomahawk::playlistinterface_ptr( this );
+            m_sharedPtr = Tomahawk::playlistinterface_ptr( this, dontDelete );
         }
 
         return m_sharedPtr;
diff --git a/src/libtomahawk/utils/proxystyle.cpp b/src/libtomahawk/utils/proxystyle.cpp
index 1e906f0f6..99bd5f69c 100644
--- a/src/libtomahawk/utils/proxystyle.cpp
+++ b/src/libtomahawk/utils/proxystyle.cpp
@@ -34,14 +34,12 @@ ProxyStyle::drawPrimitive( PrimitiveElement pe, const QStyleOption* opt, QPainte
 {
     if ( pe == PE_IndicatorBranch )
     {
-        if ( opt->state & QStyle::State_Children )
+        if ( opt->state & QStyle::State_Children && !w->property( "flattenBranches" ).toBool() )
         {
-            QRect r = opt->rect;
-
             int hd = ( opt->rect.height() - ARROW_HEIGHT ) / 2;
             int wd = ( opt->rect.width() - ARROW_WIDTH ) / 2;
-            r.adjust( wd, hd, 0, 0 );
 
+            QRect r = opt->rect.adjusted( wd, hd, 0, 0 );
             QPointF pointsOpened[3] = { QPointF( r.x(), r.y() ), QPointF( r.x() + ARROW_WIDTH, r.y() ), QPointF( r.x() + ARROW_WIDTH / 2, r.y() + ARROW_HEIGHT ) };
             QPointF pointsClosed[3] = { QPointF( r.x(), r.y() ), QPointF( r.x() + ARROW_WIDTH, r.y() + ARROW_HEIGHT / 2 ), QPointF( r.x(), r.y() + ARROW_HEIGHT ) };
 
diff --git a/src/libtomahawk/viewmanager.cpp b/src/libtomahawk/viewmanager.cpp
index 2841f39a1..b33804d02 100644
--- a/src/libtomahawk/viewmanager.cpp
+++ b/src/libtomahawk/viewmanager.cpp
@@ -40,6 +40,7 @@
 #include "sourcelist.h"
 #include "tomahawksettings.h"
 
+#include "customplaylistview.h"
 #include "dynamic/widgets/DynamicWidget.h"
 
 #include "widgets/welcomewidget.h"
@@ -71,6 +72,7 @@ ViewManager::ViewManager( QObject* parent )
     , m_widget( new QWidget() )
     , m_welcomeWidget( new WelcomeWidget() )
     , m_whatsHotWidget( new WhatsHotWidget() )
+    , m_topLovedWidget( 0 )
     , m_currentMode( PlaylistInterface::Tree )
 {
     s_instance = this;
@@ -418,6 +420,15 @@ ViewManager::showWhatsHotPage()
 }
 
 
+Tomahawk::ViewPage*
+ViewManager::showTopLovedPage()
+{
+    if ( !m_topLovedWidget )
+        m_topLovedWidget = new CustomPlaylistView( CustomPlaylistView::AllLovedTracks, source_ptr(), m_widget );
+
+    return show( m_topLovedWidget );
+}
+
 
 void
 ViewManager::setTableMode()
diff --git a/src/libtomahawk/viewmanager.h b/src/libtomahawk/viewmanager.h
index 3c2bed9a6..1a9b698b8 100644
--- a/src/libtomahawk/viewmanager.h
+++ b/src/libtomahawk/viewmanager.h
@@ -90,6 +90,7 @@ public:
 
     Tomahawk::ViewPage* welcomeWidget() const { return m_welcomeWidget; }
     Tomahawk::ViewPage* whatsHotWidget() const { return m_whatsHotWidget; }
+    Tomahawk::ViewPage* topLovedWidget() const { return m_topLovedWidget; }
     ArtistView* superCollectionView() const { return m_superCollectionView; }
 
     /// Get the view page for the given item. Not pretty...
@@ -133,6 +134,7 @@ public slots:
     Tomahawk::ViewPage* showSuperCollection();
     Tomahawk::ViewPage* showWelcomePage();
     Tomahawk::ViewPage* showWhatsHotPage();
+    Tomahawk::ViewPage* showTopLovedPage();
     void showCurrentTrack();
 
     // Returns the shown viewpage
@@ -194,6 +196,7 @@ private:
     QueueView* m_queue;
     WelcomeWidget* m_welcomeWidget;
     WhatsHotWidget* m_whatsHotWidget;
+    Tomahawk::ViewPage* m_topLovedWidget;
 
     QList< Tomahawk::collection_ptr > m_superCollections;
 
diff --git a/src/sourcetree/items/categoryitems.cpp b/src/sourcetree/items/categoryitems.cpp
index cd0461f25..3cd74f326 100644
--- a/src/sourcetree/items/categoryitems.cpp
+++ b/src/sourcetree/items/categoryitems.cpp
@@ -365,6 +365,8 @@ CategoryItem::CategoryItem( SourcesModel* model, SourceTreeItem* parent, Sources
         m_addItem = new CategoryAddItem( model, this, m_category );
     }
     //     endRowsAdded();
+
+    connect( this, SIGNAL( toggleExpandRequest( SourceTreeItem* ) ), model, SLOT( itemToggleExpandRequest( SourceTreeItem* ) ) );
 }
 
 
@@ -405,8 +407,5 @@ CategoryItem::peerSortValue() const
 void
 CategoryItem::activate()
 {
-    if( m_category == SourcesModel::StationsCategory ) {
-        // TODO activate stations page
-    }
-
+    emit toggleExpandRequest( this );
 }
diff --git a/src/sourcetree/items/categoryitems.h b/src/sourcetree/items/categoryitems.h
index 0b9697955..c1e3dcadd 100644
--- a/src/sourcetree/items/categoryitems.h
+++ b/src/sourcetree/items/categoryitems.h
@@ -75,6 +75,9 @@ public:
 
     SourcesModel::CategoryType categoryType() { return m_category; }
 
+signals:
+    void toggleExpandRequest( SourceTreeItem* );
+
 private:
     SourcesModel::CategoryType m_category;
     CategoryAddItem* m_addItem;
diff --git a/src/sourcetree/items/groupitem.cpp b/src/sourcetree/items/groupitem.cpp
new file mode 100644
index 000000000..57e8b56cd
--- /dev/null
+++ b/src/sourcetree/items/groupitem.cpp
@@ -0,0 +1,55 @@
+/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
+ *
+ *   Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
+ *   Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
+ *
+ *   Tomahawk is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   Tomahawk is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "groupitem.h"
+
+#include "utils/tomahawkutils.h"
+#include "utils/logger.h"
+#include "viewmanager.h"
+#include "audio/audioengine.h"
+
+using namespace Tomahawk;
+
+
+GroupItem::GroupItem( SourcesModel* model, SourceTreeItem* parent, const QString& text, int peerSortValue )
+    : SourceTreeItem( model, parent, SourcesModel::Group )
+    , m_text( text )
+    , m_peerSortValue( peerSortValue )
+{
+    connect( this, SIGNAL( toggleExpandRequest( SourceTreeItem* ) ), model, SLOT( itemToggleExpandRequest( SourceTreeItem* ) ) );
+}
+
+
+GroupItem::~GroupItem()
+{
+}
+
+
+void
+GroupItem::activate()
+{
+    emit toggleExpandRequest( this );
+}
+
+
+QString
+GroupItem::text() const
+{
+    return m_text;
+}
diff --git a/src/sourcetree/items/groupitem.h b/src/sourcetree/items/groupitem.h
new file mode 100644
index 000000000..ae129b773
--- /dev/null
+++ b/src/sourcetree/items/groupitem.h
@@ -0,0 +1,53 @@
+/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
+ *
+ *   Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
+ *   Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
+ *
+ *   Tomahawk is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   Tomahawk is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GROUP_ITEM_H
+#define GROUP_ITEM_H
+
+#include "sourcetreeitem.h"
+
+#include "boost/function.hpp"
+#include "boost/bind.hpp"
+
+// generic item that has some name, some text, and calls a certain slot when activated. badabing!
+class GroupItem : public SourceTreeItem
+{
+    Q_OBJECT
+public:
+    // takes 2 function pointers: show: called when wanting to show the desired view page. get: called to get the view page from ViewManager if it exists
+    GroupItem( SourcesModel* model, SourceTreeItem* parent, const QString& text, int peerSortValue = 0 );
+    virtual ~GroupItem();
+
+    virtual QString text() const;
+    virtual void activate();
+    virtual bool willAcceptDrag( const QMimeData* data ) const { Q_UNUSED( data ); return false; }
+    virtual QIcon icon() const { return QIcon(); }
+    virtual int peerSortValue() const { return m_peerSortValue; }
+    virtual bool isBeingPlayed() const { return false; }
+
+signals:
+    void activated();
+    void toggleExpandRequest( SourceTreeItem* );
+
+private:
+    QString m_text;
+    int m_peerSortValue;
+};
+
+#endif
diff --git a/src/sourcetree/items/historyitem.cpp b/src/sourcetree/items/historyitem.cpp
new file mode 100644
index 000000000..09aaa2b6a
--- /dev/null
+++ b/src/sourcetree/items/historyitem.cpp
@@ -0,0 +1,96 @@
+/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
+ *
+ *   Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
+ *   Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
+ *
+ *   Tomahawk is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   Tomahawk is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "historyitem.h"
+
+#include "viewmanager.h"
+#include "genericpageitems.h"
+#include "utils/tomahawkutilsgui.h"
+#include "utils/logger.h"
+#include "playlist/customplaylistview.h"
+#include "temporarypageitem.h"
+#include "sourcelist.h"
+
+using namespace Tomahawk;
+
+
+HistoryItem::HistoryItem( SourcesModel* model, SourceTreeItem* parent, const QString& text, int peerSortValue )
+    : GroupItem( model, parent, text, peerSortValue )
+{
+    connect( this, SIGNAL( toggleExpandRequest( SourceTreeItem* ) ), model, SLOT( itemToggleExpandRequest( SourceTreeItem* ) ) );
+    connect( ViewManager::instance(), SIGNAL( tempPageActivated( Tomahawk::ViewPage* ) ), SLOT( tempPageActivated( Tomahawk::ViewPage* ) ) );
+}
+
+
+HistoryItem::~HistoryItem()
+{
+}
+
+
+void
+HistoryItem::activate()
+{
+    emit toggleExpandRequest( this );
+}
+
+
+void
+HistoryItem::tempPageActivated( Tomahawk::ViewPage* v )
+{
+    const int idx = children().count();
+    int latest = idx;
+    if ( idx )
+    {
+        latest = children().last()->IDValue();
+
+        foreach ( TemporaryPageItem* page, m_tempItems )
+        {
+            if ( page->page() == v )
+            {
+                emit selectRequest( page );
+                return;
+            }
+        }
+    }
+
+    // Only keep 5 temporary pages at once
+    while ( m_tempItems.size() > 4 )
+    {
+        TemporaryPageItem* item = m_tempItems.takeFirst();
+        QTimer::singleShot( 0, item, SLOT( removeFromList() ) );
+    }
+
+    emit beginRowsAdded( idx, idx );
+
+    TemporaryPageItem* tempPage = new TemporaryPageItem( model(), this, v, latest + 1 );
+    connect( tempPage, SIGNAL( removed() ), this, SLOT( temporaryPageDestroyed() ) );
+    m_tempItems << tempPage;
+    endRowsAdded();
+
+    emit selectRequest( tempPage );
+}
+
+
+void
+HistoryItem::temporaryPageDestroyed()
+{
+    TemporaryPageItem* tempPage = qobject_cast< TemporaryPageItem* >( sender() );
+    Q_ASSERT( tempPage );
+    m_tempItems.removeAll( tempPage );
+}
diff --git a/src/sourcetree/items/historyitem.h b/src/sourcetree/items/historyitem.h
new file mode 100644
index 000000000..d3dd23449
--- /dev/null
+++ b/src/sourcetree/items/historyitem.h
@@ -0,0 +1,57 @@
+/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
+ *
+ *   Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
+ *   Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
+ *
+ *   Tomahawk is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   Tomahawk is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef HISTORY_ITEM_H
+#define HISTORY_ITEM_H
+
+#include "groupitem.h"
+
+class TemporaryPageItem;
+class GenericPageItem;
+class CategoryItem;
+
+namespace Tomahawk
+{
+    class ViewPage;
+}
+
+class HistoryItem : public GroupItem
+{
+    Q_OBJECT
+public:
+    HistoryItem( SourcesModel* model, SourceTreeItem* parent, const QString& text, int peerSortValue = 0 );
+    virtual ~HistoryItem();
+
+    virtual void activate();
+
+signals:
+    void activated();
+    void toggleExpandRequest( SourceTreeItem* );
+
+private slots:
+    void tempPageActivated( Tomahawk::ViewPage* );
+    void temporaryPageDestroyed();
+
+private:
+    QList< TemporaryPageItem* > m_tempItems;
+
+private:
+};
+
+#endif
diff --git a/src/sourcetree/items/playlistitems.cpp b/src/sourcetree/items/playlistitems.cpp
index 7785eceef..1df14c381 100644
--- a/src/sourcetree/items/playlistitems.cpp
+++ b/src/sourcetree/items/playlistitems.cpp
@@ -25,7 +25,7 @@
 #include "viewmanager.h"
 #include "playlist/dynamic/GeneratorInterface.h"
 #include "categoryitems.h"
-#include "collectionitem.h"
+#include "sourceitem.h"
 #include "utils/tomahawkutils.h"
 #include "utils/logger.h"
 #include "dropjob.h"
@@ -337,7 +337,7 @@ DynamicPlaylistItem::checkReparentHackNeeded( const DynamicPlaylistRevision& rev
         CategoryItem* from = cat;
         CategoryItem* to = 0;
         if( cat->categoryType() == SourcesModel::PlaylistsCategory && revision.mode == OnDemand ) { // WRONG
-            CollectionItem* col = qobject_cast< CollectionItem* >( cat->parent() );
+            SourceItem* col = qobject_cast< SourceItem* >( cat->parent() );
             to = col->stationsCategory();
             if( !to ) { // you have got to be fucking kidding me
                 int fme = col->children().count();
@@ -348,7 +348,7 @@ DynamicPlaylistItem::checkReparentHackNeeded( const DynamicPlaylistRevision& rev
                 col->setStationsCategory( to );
             }
         } else if( cat->categoryType() == SourcesModel::StationsCategory && revision.mode == Static ) { // WRONG
-            CollectionItem* col = qobject_cast< CollectionItem* >( cat->parent() );
+            SourceItem* col = qobject_cast< SourceItem* >( cat->parent() );
             to = col->playlistsCategory();
 //            qDebug() << "TRYING TO HACK TO:" << to;
             if( !to ) { // you have got to be fucking kidding me
diff --git a/src/sourcetree/items/collectionitem.cpp b/src/sourcetree/items/sourceitem.cpp
similarity index 65%
rename from src/sourcetree/items/collectionitem.cpp
rename to src/sourcetree/items/sourceitem.cpp
index 4307d5dbb..5a78379ff 100644
--- a/src/sourcetree/items/collectionitem.cpp
+++ b/src/sourcetree/items/sourceitem.cpp
@@ -16,7 +16,7 @@
  *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#include "collectionitem.h"
+#include "sourceitem.h"
 
 #include "categoryitems.h"
 #include "playlistitems.h"
@@ -28,14 +28,13 @@
 #include "widgets/SocialPlaylistWidget.h"
 #include "playlist/customplaylistview.h"
 #include "source.h"
-#include "temporarypageitem.h"
-#include <sourcelist.h>
+#include "sourcelist.h"
 
-/// CollectionItem
+/// SourceItem
 
 using namespace Tomahawk;
 
-CollectionItem::CollectionItem(  SourcesModel* mdl, SourceTreeItem* parent, const Tomahawk::source_ptr& source )
+SourceItem::SourceItem( SourcesModel* mdl, SourceTreeItem* parent, const Tomahawk::source_ptr& source )
     : SourceTreeItem( mdl, parent, SourcesModel::Collection )
     , m_source( source )
     , m_playlists( 0 )
@@ -43,51 +42,31 @@ CollectionItem::CollectionItem(  SourcesModel* mdl, SourceTreeItem* parent, cons
     , m_latchedOn( false )
     , m_sourceInfoItem( 0   )
     , m_coolPlaylistsItem( 0 )
-    , m_lovedTracksItem()
+    , m_collectionPage( 0 )
     , m_sourceInfoPage( 0 )
     , m_coolPlaylistsPage( 0 )
     , m_lovedTracksPage( 0 )
     , m_whatsHotPage( 0 )
 {
-    m_lovedTracksItem = new GenericPageItem( model(), this, ( m_source.isNull() ? tr( "Top Loved Tracks" ) : tr( "Loved Tracks" ) ), QIcon( RESPATH "images/loved_playlist.png" ),
-                                             boost::bind( &CollectionItem::lovedTracksClicked, this ),
-                                             boost::bind( &CollectionItem::getLovedTracksPage, this ) );
-    m_lovedTracksItem->setSortValue( -250 );
-
     if ( m_source.isNull() )
     {
-        // super collection
-        connect( ViewManager::instance(), SIGNAL( tempPageActivated( Tomahawk::ViewPage*) ), this, SLOT( tempPageActivated( Tomahawk::ViewPage* ) ) );
-
-                // add misc children of root node
-        GenericPageItem* recent = new GenericPageItem( model(), this, tr( "Dashboard" ), QIcon( RESPATH "images/dashboard.png" ),
-                             boost::bind( &ViewManager::showWelcomePage, ViewManager::instance() ),
-                             boost::bind( &ViewManager::welcomeWidget, ViewManager::instance() )
-                                                    );
-        recent->setSortValue( -300 );
-
-        GenericPageItem* hot = new GenericPageItem( model(), this, tr( "Charts" ), QIcon( RESPATH "images/charts.png" ),
-                             boost::bind( &ViewManager::showWhatsHotPage, ViewManager::instance() ),
-                             boost::bind( &ViewManager::whatsHotWidget, ViewManager::instance() )
-                                                    );
-        hot->setSortValue( -300 );
-
-
-        // TODO finish implementing and making pretty
-//         m_coolPlaylistsItem = new GenericPageItem( model(), this, tr( "Cool Stuff" ), QIcon( RESPATH "images/new-additions.png" ),
-//                                                    boost::bind( &CollectionItem::coolPlaylistsClicked, this ),
-//                                                    boost::bind( &CollectionItem::getCoolPlaylistsPage, this )
-//                                                  );
-//         m_coolPlaylistsItem->setSortValue( 200 );
-
         m_superCol = TomahawkUtils::createAvatarFrame( QPixmap( RESPATH "images/supercollection.png" ) );
-
         return;
     }
 
+    m_lovedTracksItem = new GenericPageItem( model(), this, tr( "Loved Tracks" ), QIcon( RESPATH "images/loved_playlist.png" ),
+                                             boost::bind( &SourceItem::lovedTracksClicked, this ),
+                                             boost::bind( &SourceItem::getLovedTracksPage, this ) );
+    m_lovedTracksItem->setSortValue( -250 );
+
+    m_collectionItem = new GenericPageItem( model(), this, tr( "Collection" ), QIcon( RESPATH "images/drop-song.png" ), //FIXME different icon
+                                            boost::bind( &SourceItem::collectionClicked, this ),
+                                            boost::bind( &SourceItem::getCollectionPage, this ) );
+    m_collectionItem->setSortValue( -350 );
+
     m_sourceInfoItem = new GenericPageItem( model(), this, tr( "New Additions" ), QIcon( RESPATH "images/new-additions.png" ),
-                                            boost::bind( &CollectionItem::sourceInfoClicked, this ),
-                                            boost::bind( &CollectionItem::getSourceInfoPage, this ) );
+                                            boost::bind( &SourceItem::sourceInfoClicked, this ),
+                                            boost::bind( &SourceItem::getSourceInfoPage, this ) );
     m_sourceInfoItem->setSortValue( -300 );
 
     // create category items if there are playlists to show, or stations to show
@@ -114,14 +93,14 @@ CollectionItem::CollectionItem(  SourcesModel* mdl, SourceTreeItem* parent, cons
 
     // load auto playlists and stations!
 
-    connect( source.data(), SIGNAL( stats( QVariantMap ) ), this, SIGNAL( updated() ) );
-    connect( source.data(), SIGNAL( syncedWithDatabase() ), this, SIGNAL( updated() ) );
-    connect( source.data(), SIGNAL( playbackStarted( Tomahawk::query_ptr ) ), this, SIGNAL( updated() ) );
-    connect( source.data(), SIGNAL( stateChanged() ), this, SIGNAL( updated() ) );
-    connect( source.data(), SIGNAL( offline() ), this, SIGNAL( updated() ) );
-    connect( source.data(), SIGNAL( online() ), this, SIGNAL( updated() ) );
-    connect( SourceList::instance(), SIGNAL( sourceLatchedOn( Tomahawk::source_ptr, Tomahawk::source_ptr ) ), this, SLOT( latchedOn( Tomahawk::source_ptr, Tomahawk::source_ptr ) ) );
-    connect( SourceList::instance(), SIGNAL( sourceLatchedOff( Tomahawk::source_ptr, Tomahawk::source_ptr ) ), this, SLOT( latchedOff( Tomahawk::source_ptr, Tomahawk::source_ptr ) ) );
+    connect( source.data(), SIGNAL( stats( QVariantMap ) ), SIGNAL( updated() ) );
+    connect( source.data(), SIGNAL( syncedWithDatabase() ), SIGNAL( updated() ) );
+    connect( source.data(), SIGNAL( playbackStarted( Tomahawk::query_ptr ) ), SIGNAL( updated() ) );
+    connect( source.data(), SIGNAL( stateChanged() ), SIGNAL( updated() ) );
+    connect( source.data(), SIGNAL( offline() ), SIGNAL( updated() ) );
+    connect( source.data(), SIGNAL( online() ), SIGNAL( updated() ) );
+    connect( SourceList::instance(), SIGNAL( sourceLatchedOn( Tomahawk::source_ptr, Tomahawk::source_ptr ) ), SLOT( latchedOn( Tomahawk::source_ptr, Tomahawk::source_ptr ) ) );
+    connect( SourceList::instance(), SIGNAL( sourceLatchedOff( Tomahawk::source_ptr, Tomahawk::source_ptr ) ), SLOT( latchedOff( Tomahawk::source_ptr, Tomahawk::source_ptr ) ) );
 
     connect( source->collection().data(), SIGNAL( playlistsAdded( QList<Tomahawk::playlist_ptr> ) ),
              SLOT( onPlaylistsAdded( QList<Tomahawk::playlist_ptr> ) ), Qt::QueuedConnection );
@@ -131,30 +110,30 @@ CollectionItem::CollectionItem(  SourcesModel* mdl, SourceTreeItem* parent, cons
              SLOT( onStationsAdded( QList<Tomahawk::dynplaylist_ptr> ) ), Qt::QueuedConnection );
 
     if ( m_source->isLocal() )
-        QTimer::singleShot(0, this, SLOT(requestExpanding()));
+        QTimer::singleShot( 0, this, SLOT( requestExpanding() ) );
 }
 
 
 Tomahawk::source_ptr
-CollectionItem::source() const
+SourceItem::source() const
 {
     return m_source;
 }
 
 
 QString
-CollectionItem::text() const
+SourceItem::text() const
 {
     return m_source.isNull() ? tr( "Super Collection" ) : m_source->friendlyName();
 }
 
 
 int
-CollectionItem::IDValue() const
+SourceItem::IDValue() const
 {
-    if( m_source.isNull() )
+    if ( m_source.isNull() )
         return -1;
-    if( m_source->isLocal() )
+    if ( m_source->isLocal() )
         return 0;
 
     return m_source->id();
@@ -162,46 +141,46 @@ CollectionItem::IDValue() const
 
 
 int
-CollectionItem::peerSortValue() const
+SourceItem::peerSortValue() const
 {
-    if( m_source.isNull() )
+    if ( m_source.isNull() || m_source->isLocal() )
         return -1;
-    if( m_source->isLocal() )
-        return 0;
 
     return 1;
 }
 
 
 void
-CollectionItem::activate()
+SourceItem::activate()
 {
     ViewPage* p = 0;
     if ( source().isNull() )
         p = ViewManager::instance()->showSuperCollection();
     else
-        p = ViewManager::instance()->show( source()->collection() );
+        emit toggleExpandRequest( this );
+//        p = ViewManager::instance()->show( source()->collection() );
 
     model()->linkSourceItemToPage( this, p );
 }
 
 
 QIcon
-CollectionItem::icon() const
+SourceItem::icon() const
 {
     if ( m_source.isNull() )
        return m_superCol;
     else
     {
-        if( m_source->avatar().isNull() )
+        if ( m_source->avatar().isNull() )
             return m_defaultAvatar;
         else
             return m_source->avatar( Source::FancyStyle );
     }
 }
 
+
 bool
-CollectionItem::localLatchedOn() const
+SourceItem::localLatchedOn() const
 {
     // Don't show a listen icon if this is the local collection and we are latched on to someone who went offline
     // we are technically still latched on (if they come back online we'll be still listening along) but it's not visible
@@ -216,7 +195,7 @@ CollectionItem::localLatchedOn() const
 
 
 void
-CollectionItem::latchedOff( const source_ptr& from, const source_ptr& to )
+SourceItem::latchedOff( const source_ptr& from, const source_ptr& to )
 {
     if ( from->isLocal() && ( m_source == to || m_source == from ) )
     {
@@ -226,8 +205,9 @@ CollectionItem::latchedOff( const source_ptr& from, const source_ptr& to )
     }
 }
 
+
 void
-CollectionItem::latchedOn( const source_ptr& from, const source_ptr& to )
+SourceItem::latchedOn( const source_ptr& from, const source_ptr& to )
 {
     if ( from->isLocal() && ( m_source == to || m_source == from ) )
     {
@@ -239,29 +219,32 @@ CollectionItem::latchedOn( const source_ptr& from, const source_ptr& to )
 
 
 void
-CollectionItem::playlistsAddedInternal( SourceTreeItem* parent, const QList< dynplaylist_ptr >& playlists )
+SourceItem::playlistsAddedInternal( SourceTreeItem* parent, const QList< dynplaylist_ptr >& playlists )
 {
     QList< SourceTreeItem* > items;
     int addOffset = playlists.first()->author()->isLocal() ? 1 : 0;
 
     int from = parent->children().count() - addOffset;
     parent->beginRowsAdded( from, from + playlists.count() - 1 );
-    foreach( const dynplaylist_ptr& p, playlists )
+    foreach ( const dynplaylist_ptr& p, playlists )
     {
         DynamicPlaylistItem* plItem = new DynamicPlaylistItem( model(), parent, p, parent->children().count() - addOffset );
 //        qDebug() << "Dynamic Playlist added:" << p->title() << p->creator() << p->info();
         p->loadRevision();
         items << plItem;
 
-        if( p->mode() == Static ) {
-            if( m_source->isLocal() )
+        if ( p->mode() == Static )
+        {
+            if ( m_source->isLocal() )
                 connect( p.data(), SIGNAL( aboutToBeDeleted( Tomahawk::dynplaylist_ptr ) ),
                         SLOT( onAutoPlaylistDeleted( Tomahawk::dynplaylist_ptr ) ), Qt::QueuedConnection );
             else
                 connect( p.data(), SIGNAL( deleted( Tomahawk::dynplaylist_ptr ) ),
                         SLOT( onAutoPlaylistDeleted( Tomahawk::dynplaylist_ptr ) ), Qt::QueuedConnection );
-        } else {
-            if( m_source->isLocal() )
+        }
+        else
+        {
+            if ( m_source->isLocal() )
                 connect( p.data(), SIGNAL( aboutToBeDeleted( Tomahawk::dynplaylist_ptr ) ),
                         SLOT( onStationDeleted( Tomahawk::dynplaylist_ptr ) ), Qt::QueuedConnection );
             else
@@ -275,7 +258,7 @@ CollectionItem::playlistsAddedInternal( SourceTreeItem* parent, const QList< dyn
 
 template< typename T >
 void
-CollectionItem::playlistDeletedInternal( SourceTreeItem* parent, const T& p )
+SourceItem::playlistDeletedInternal( SourceTreeItem* parent, const T& p )
 {
     Q_ASSERT( parent ); // How can we delete playlists if we have none?
     int curCount = parent->children().count();
@@ -314,7 +297,7 @@ CollectionItem::playlistDeletedInternal( SourceTreeItem* parent, const T& p )
 
 
 void
-CollectionItem::onPlaylistsAdded( const QList< playlist_ptr >& playlists )
+SourceItem::onPlaylistsAdded( const QList< playlist_ptr >& playlists )
 {
 //    qDebug() << Q_FUNC_INFO << m_source->friendlyName() << playlists.count();
 
@@ -355,14 +338,14 @@ CollectionItem::onPlaylistsAdded( const QList< playlist_ptr >& playlists )
 
 
 void
-CollectionItem::onPlaylistDeleted( const  playlist_ptr& playlist )
+SourceItem::onPlaylistDeleted( const  playlist_ptr& playlist )
 {
     playlistDeletedInternal( m_playlists, playlist );
 }
 
 
 void
-CollectionItem::onAutoPlaylistsAdded( const QList< dynplaylist_ptr >& playlists )
+SourceItem::onAutoPlaylistsAdded( const QList< dynplaylist_ptr >& playlists )
 {
     if( playlists.isEmpty() )
         return;
@@ -381,7 +364,7 @@ CollectionItem::onAutoPlaylistsAdded( const QList< dynplaylist_ptr >& playlists
 
 
 void
-CollectionItem::onAutoPlaylistDeleted( const dynplaylist_ptr& playlist )
+SourceItem::onAutoPlaylistDeleted( const dynplaylist_ptr& playlist )
 {
     if( !m_playlists )
         qDebug() << "NO playlist category item for a deleting playlist..";
@@ -391,7 +374,7 @@ CollectionItem::onAutoPlaylistDeleted( const dynplaylist_ptr& playlist )
 
 
 void
-CollectionItem::onStationsAdded( const QList< dynplaylist_ptr >& stations )
+SourceItem::onStationsAdded( const QList< dynplaylist_ptr >& stations )
 {
     if( stations.isEmpty() )
         return;
@@ -410,59 +393,21 @@ CollectionItem::onStationsAdded( const QList< dynplaylist_ptr >& stations )
 
 
 void
-CollectionItem::onStationDeleted( const dynplaylist_ptr& station )
+SourceItem::onStationDeleted( const dynplaylist_ptr& station )
 {
     playlistDeletedInternal( m_stations, station );
 }
 
 
 void
-CollectionItem::requestExpanding()
+SourceItem::requestExpanding()
 {
-    emit expandRequest(this);
-}
-
-
-void
-CollectionItem::tempPageActivated( Tomahawk::ViewPage* v )
-{
-    const int idx = children().count();
-    const int latest = children().last()->IDValue();
-
-    foreach ( TemporaryPageItem* page, m_tempItems )
-    {
-        if ( page->page() == v )
-        {
-            emit selectRequest( page );
-            return;
-        }
-    }
-
-    // Only keep 5 temporary pages at once
-    while ( m_tempItems.size() > 4 )
-    {
-        TemporaryPageItem* item = m_tempItems.takeFirst();
-        QTimer::singleShot( 0, item, SLOT( removeFromList() ) );
-    }
-    emit beginRowsAdded( idx, idx );
-    TemporaryPageItem* tempPage = new TemporaryPageItem( model(), this, v, latest + 1 );
-    connect( tempPage, SIGNAL( removed() ), this, SLOT( temporaryPageDestroyed() ) );
-    m_tempItems << tempPage;
-    endRowsAdded();
-    emit selectRequest( tempPage );
-}
-
-void
-CollectionItem::temporaryPageDestroyed()
-{
-    TemporaryPageItem* tempPage = qobject_cast< TemporaryPageItem* >( sender() );
-    Q_ASSERT( tempPage );
-    m_tempItems.removeAll( tempPage );
+    emit expandRequest( this );
 }
 
 
 ViewPage*
-CollectionItem::sourceInfoClicked()
+SourceItem::sourceInfoClicked()
 {
     if( m_source.isNull() )
         return 0;
@@ -473,19 +418,37 @@ CollectionItem::sourceInfoClicked()
 
 
 ViewPage*
-CollectionItem::getSourceInfoPage() const
+SourceItem::getSourceInfoPage() const
 {
     return m_sourceInfoPage;
 }
 
 
 ViewPage*
-CollectionItem::coolPlaylistsClicked()
+SourceItem::collectionClicked()
 {
-    if( !m_source.isNull() )
+    if( m_source.isNull() )
         return 0;
 
-    if( !m_coolPlaylistsPage )
+    m_collectionPage = ViewManager::instance()->show( m_source->collection() );
+    return m_collectionPage;
+}
+
+
+ViewPage*
+SourceItem::getCollectionPage() const
+{
+    return m_collectionPage;;
+}
+
+
+ViewPage*
+SourceItem::coolPlaylistsClicked()
+{
+    if ( !m_source.isNull() )
+        return 0;
+
+    if ( !m_coolPlaylistsPage )
         m_coolPlaylistsPage = new SocialPlaylistWidget( ViewManager::instance()->widget() );
 
     ViewManager::instance()->show( m_coolPlaylistsPage );
@@ -494,16 +457,16 @@ CollectionItem::coolPlaylistsClicked()
 
 
 ViewPage*
-CollectionItem::getCoolPlaylistsPage() const
+SourceItem::getCoolPlaylistsPage() const
 {
     return m_coolPlaylistsPage;
 }
 
 
 ViewPage*
-CollectionItem::lovedTracksClicked()
+SourceItem::lovedTracksClicked()
 {
-    if( !m_lovedTracksPage )
+    if ( !m_lovedTracksPage )
         m_lovedTracksPage = new CustomPlaylistView( m_source.isNull() ? CustomPlaylistView::AllLovedTracks : CustomPlaylistView::SourceLovedTracks, m_source, ViewManager::instance()->widget() );
 
     ViewManager::instance()->show( m_lovedTracksPage );
@@ -512,7 +475,7 @@ CollectionItem::lovedTracksClicked()
 
 
 ViewPage*
-CollectionItem::getLovedTracksPage() const
+SourceItem::getLovedTracksPage() const
 {
     return m_lovedTracksPage;
 }
diff --git a/src/sourcetree/items/collectionitem.h b/src/sourcetree/items/sourceitem.h
similarity index 89%
rename from src/sourcetree/items/collectionitem.h
rename to src/sourcetree/items/sourceitem.h
index 41409032c..7827721e3 100644
--- a/src/sourcetree/items/collectionitem.h
+++ b/src/sourcetree/items/sourceitem.h
@@ -16,8 +16,8 @@
  *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#ifndef COLLECTION_ITEM_H
-#define COLLECTION_ITEM_H
+#ifndef SOURCE_ITEM_H
+#define SOURCE_ITEM_H
 
 #include "sourcetreeitem.h"
 
@@ -30,11 +30,11 @@ namespace Tomahawk
     class ViewPage;
 }
 
-class CollectionItem : public SourceTreeItem
+class SourceItem : public SourceTreeItem
 {
     Q_OBJECT
 public:
-    CollectionItem( SourcesModel* model, SourceTreeItem* parent, const Tomahawk::source_ptr& source );
+    SourceItem( SourcesModel* model, SourceTreeItem* parent, const Tomahawk::source_ptr& source );
 
     virtual QString text() const;
     virtual void activate();
@@ -64,12 +64,12 @@ private slots:
 
     void requestExpanding();
 
-    void tempPageActivated( Tomahawk::ViewPage* );
-    void temporaryPageDestroyed();
-
     Tomahawk::ViewPage* sourceInfoClicked();
     Tomahawk::ViewPage* getSourceInfoPage() const;
 
+    Tomahawk::ViewPage* collectionClicked();
+    Tomahawk::ViewPage* getCollectionPage() const;
+
     Tomahawk::ViewPage* coolPlaylistsClicked();
     Tomahawk::ViewPage* getCoolPlaylistsPage() const;
 
@@ -89,11 +89,12 @@ private:
     bool m_latchedOn;
     Tomahawk::source_ptr m_latchedOnTo;
 
-    QList< TemporaryPageItem* > m_tempItems;
+    GenericPageItem* m_collectionItem;
     GenericPageItem* m_sourceInfoItem;
     GenericPageItem* m_coolPlaylistsItem;
     GenericPageItem* m_lovedTracksItem;
 
+    Tomahawk::ViewPage* m_collectionPage;
     Tomahawk::ViewPage* m_sourceInfoPage;
     Tomahawk::ViewPage* m_coolPlaylistsPage;
     Tomahawk::ViewPage* m_lovedTracksPage;
diff --git a/src/sourcetree/items/sourcetreeitem.cpp b/src/sourcetree/items/sourcetreeitem.cpp
index 5f82833c3..01a0224f8 100644
--- a/src/sourcetree/items/sourcetreeitem.cpp
+++ b/src/sourcetree/items/sourcetreeitem.cpp
@@ -29,18 +29,20 @@ SourceTreeItem::SourceTreeItem( SourcesModel* model, SourceTreeItem* parent, Sou
     , m_parent( parent )
     , m_model( model )
 {
-    connect( this, SIGNAL( beginChildRowsAdded( int,int ) ), m_model, SLOT( onItemRowsAddedBegin( int,int ) ) );
-    connect( this, SIGNAL( beginChildRowsRemoved( int,int ) ), m_model, SLOT( onItemRowsRemovedBegin( int,int ) ) );
+    connect( this, SIGNAL( beginChildRowsAdded( int, int ) ), m_model, SLOT( onItemRowsAddedBegin( int, int ) ) );
+    connect( this, SIGNAL( beginChildRowsRemoved( int, int ) ), m_model, SLOT( onItemRowsRemovedBegin( int, int ) ) );
     connect( this, SIGNAL( childRowsAdded() ), m_model, SLOT( onItemRowsAddedDone() ) );
     connect( this, SIGNAL( childRowsRemoved() ), m_model, SLOT( onItemRowsRemovedDone() ) );
     connect( this, SIGNAL( updated() ), m_model, SLOT( itemUpdated() ) );
     connect( this, SIGNAL( selectRequest( SourceTreeItem* ) ), m_model, SLOT( itemSelectRequest( SourceTreeItem* ) ) );
     connect( this, SIGNAL( expandRequest( SourceTreeItem* ) ), m_model, SLOT( itemExpandRequest( SourceTreeItem* ) ) );
-    if( !m_parent )
+    connect( this, SIGNAL( toggleExpandRequest( SourceTreeItem* ) ), m_model, SLOT( itemToggleExpandRequest( SourceTreeItem* ) ) );
+
+    if ( !m_parent )
         return;
 
     // caller must call begin/endInsertRows
-    if( index < 0 )
+    if ( index < 0 )
         m_parent->appendChild( this );
     else
         m_parent->insertChild( index, this );
diff --git a/src/sourcetree/items/sourcetreeitem.h b/src/sourcetree/items/sourcetreeitem.h
index 814cc0f2d..4e17f7e35 100644
--- a/src/sourcetree/items/sourcetreeitem.h
+++ b/src/sourcetree/items/sourcetreeitem.h
@@ -25,6 +25,7 @@
 #include "sourcesmodel.h"
 
 class QMimeData;
+
 class SourceTreeItem : public QObject
 {
     Q_OBJECT
@@ -80,6 +81,7 @@ signals:
     void updated();
     void selectRequest( SourceTreeItem* );
     void expandRequest( SourceTreeItem* );
+    void toggleExpandRequest( SourceTreeItem* );
 
     void beginChildRowsAdded( int fromRow, int toRow );
     void childRowsAdded();
@@ -90,6 +92,7 @@ signals:
 protected:
     void setRowType( SourcesModel::RowType t ) { m_type = t; }
     void setParentItem( SourceTreeItem* item ) { m_parent = item; }
+
 private:
     SourcesModel::RowType m_type;
 
diff --git a/src/sourcetree/sourcedelegate.cpp b/src/sourcetree/sourcedelegate.cpp
index 13c538c95..331df0243 100644
--- a/src/sourcetree/sourcedelegate.cpp
+++ b/src/sourcetree/sourcedelegate.cpp
@@ -21,7 +21,7 @@
 #include "sourcedelegate.h"
 
 #include "items/sourcetreeitem.h"
-#include "items/collectionitem.h"
+#include "items/sourceitem.h"
 #include "items/playlistitems.h"
 #include "items/categoryitems.h"
 #include "items/temporarypageitem.h"
@@ -37,7 +37,7 @@
 #include <audio/audioengine.h>
 #include <actioncollection.h>
 
-#define TREEVIEW_INDENT_ADD -7
+#define TREEVIEW_INDENT_ADD 12
 
 
 SourceDelegate::SourceDelegate( QAbstractItemView* parent )
@@ -81,17 +81,21 @@ QSize
 SourceDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const
 {
     SourceTreeItem *item = index.data( SourcesModel::SourceTreeItemRole ).value< SourceTreeItem* >();
+    SourcesModel::RowType type = static_cast< SourcesModel::RowType >( index.data( SourcesModel::SourceTreeItemTypeRole ).toInt() );
 
-    if ( index.data( SourcesModel::SourceTreeItemTypeRole ).toInt() == SourcesModel::Collection )
+    if ( type == SourcesModel::Collection )
     {
-        return QSize( option.rect.width(), 44 );
+        return QSize( option.rect.width(), 40 );
+    }
+    else if ( type == SourcesModel::Divider )
+    {
+        return QSize( option.rect.width(), 6 );
     }
     else if ( m_expandedMap.contains( index ) )
     {
         if ( !m_expandedMap.value( index )->initialized() )
         {
             int dropTypes = dropTypeCount( item );
-            qDebug() << "droptypecount is " << dropTypes;
             QSize originalSize = QStyledItemDelegate::sizeHint( option, index );
             QSize targetSize = originalSize + QSize( 0, dropTypes == 0 ? 0 : 56 );
             m_expandedMap.value( index )->initialize( originalSize, targetSize, 300 );
@@ -105,166 +109,286 @@ SourceDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex&
 }
 
 
+void
+SourceDelegate::paintDecorations( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const
+{
+    SourcesModel::RowType type = static_cast< SourcesModel::RowType >( index.data( SourcesModel::SourceTreeItemTypeRole ).toInt() );
+    SourceTreeItem* item = index.data( SourcesModel::SourceTreeItemRole ).value< SourceTreeItem* >();
+
+    // Paint the speaker icon next to the currently-playing playlist
+    const bool playable = ( type == SourcesModel::StaticPlaylist ||
+        type == SourcesModel::AutomaticPlaylist ||
+        type == SourcesModel::Station ||
+        type == SourcesModel::TemporaryPage ||
+        type == SourcesModel::GenericPage );
+    const bool playing = ( AudioEngine::instance()->isPlaying() || AudioEngine::instance()->isPaused() );
+
+    if ( playable && playing && item->isBeingPlayed() )
+    {
+        const int iconW = option.rect.height() - 4;
+        QRect iconRect = QRect( option.rect.x() - iconW - 4, option.rect.y() + 2, iconW, iconW );
+        QPixmap speaker = option.state & QStyle::State_Selected ? m_nowPlayingSpeaker : m_nowPlayingSpeakerDark;
+        speaker = speaker.scaledToHeight( iconW, Qt::SmoothTransformation );
+        painter->drawPixmap( iconRect, speaker );
+    }
+}
+
+
+void
+SourceDelegate::paintCollection( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const
+{
+    QFont normal = painter->font();
+    QFont bold = painter->font();
+    bold.setBold( true );
+
+    SourceTreeItem* item = index.data( SourcesModel::SourceTreeItemRole ).value< SourceTreeItem* >();
+    SourceItem* colItem = qobject_cast< SourceItem* >( item );
+    Q_ASSERT( colItem );
+    bool status = !( !colItem || colItem->source().isNull() || !colItem->source()->isOnline() );
+
+    QString tracks;
+    QString name = index.data().toString();
+    int figWidth = 0;
+
+    if ( status && colItem && !colItem->source().isNull() )
+    {
+        tracks = QString::number( colItem->source()->trackCount() );
+        figWidth = painter->fontMetrics().width( tracks );
+        name = colItem->source()->friendlyName();
+    }
+
+    QRect iconRect = option.rect.adjusted( 4, 6, -option.rect.width() + option.rect.height() - 12 + 4, -6 );
+
+    QPixmap avatar = colItem->icon().pixmap( iconRect.size() );
+    painter->drawPixmap( iconRect, avatar.scaledToHeight( iconRect.height(), Qt::SmoothTransformation ) );
+
+    if ( ( option.state & QStyle::State_Selected ) == QStyle::State_Selected )
+    {
+        painter->setPen( option.palette.color( QPalette::HighlightedText ) );
+    }
+
+    QRect textRect = option.rect.adjusted( iconRect.width() + 8, 6, -figWidth - 24, 0 );
+    if ( status || colItem->source().isNull() )
+        painter->setFont( bold );
+    QString text = painter->fontMetrics().elidedText( name, Qt::ElideRight, textRect.width() );
+    painter->drawText( textRect, text );
+
+    bool isPlaying = false;
+    QString desc = status ? colItem->source()->textStatus() : tr( "Offline" );
+    if ( colItem->source().isNull() )
+        desc = tr( "All available tracks" );
+    if ( status && desc.isEmpty() && !colItem->source()->currentTrack().isNull() )
+    {
+        desc = colItem->source()->currentTrack()->artist() + " - " + colItem->source()->currentTrack()->track();
+        isPlaying = true;
+    }
+    if ( desc.isEmpty() )
+        desc = tr( "Online" );
+
+    textRect = option.rect.adjusted( iconRect.width() + 8, painter->fontMetrics().height() + 9, -figWidth - 24, -6 );
+    painter->setFont( normal );
+    bool privacyOn = TomahawkSettings::instance()->privateListeningMode() == TomahawkSettings::FullyPrivate;
+    if ( !colItem->source().isNull() && colItem->source()->isLocal() && privacyOn )
+    {
+        QRect pmRect = textRect;
+        pmRect.setTop( pmRect.bottom() - painter->fontMetrics().height() + 3 );
+        pmRect.setRight( pmRect.left() + pmRect.height() );
+        ActionCollection::instance()->getAction( "togglePrivacy" )->icon().paint( painter, pmRect );
+        textRect.adjust( pmRect.width() + 3, 0, 0, 0 );
+    }
+    if ( isPlaying || ( !colItem->source().isNull() && colItem->source()->isLocal() ) )
+    {
+        // Show a listen icon
+        QPixmap pm;
+        if ( index.data( SourcesModel::LatchedOnRole ).toBool() )
+        {
+            // Currently listening along
+            pm = m_headphonesOn;
+        }
+        else if ( !colItem->source()->isLocal() )
+        {
+            pm = m_headphonesOff;
+        }
+
+        if ( !pm.isNull() )
+        {
+            QRect pmRect = textRect;
+            pmRect.setTop( pmRect.bottom() - painter->fontMetrics().height() + 3 );
+            pmRect.setRight( pmRect.left() + pmRect.height() );
+            painter->drawPixmap( pmRect, pm.scaledToHeight( pmRect.height(), Qt::SmoothTransformation ) );
+            textRect.adjust( pmRect.width() + 3, 0, 0, 0 );
+        }
+    }
+
+    text = painter->fontMetrics().elidedText( desc, Qt::ElideRight, textRect.width() );
+    QTextOption to( Qt::AlignBottom );
+    painter->drawText( textRect, text, to );
+
+    if ( status )
+    {
+        painter->setRenderHint( QPainter::Antialiasing );
+
+        QRect figRect = option.rect.adjusted( option.rect.width() - figWidth - 8, 0, -13, -option.rect.height() + 16 );
+        int hd = ( option.rect.height() - figRect.height() ) / 2;
+        figRect.adjust( 0, hd, 0, hd );
+#ifdef Q_WS_WIN
+        figRect.adjust( -3, 0, 3, 0 );
+#endif
+        painter->setFont( bold );
+
+        QColor figColor( 167, 183, 211 );
+        painter->setPen( figColor );
+        painter->setBrush( figColor );
+
+        TomahawkUtils::drawBackgroundAndNumbers( painter, tracks, figRect );
+    }
+}
+
+
+void
+SourceDelegate::paintCategory( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const
+{
+    QTextOption to( Qt::AlignVCenter );
+
+    painter->setPen( option.palette.color( QPalette::Base ) );
+    painter->setBrush( option.palette.color( QPalette::Base ) );
+    painter->drawRect( option.rect );
+    painter->setRenderHint( QPainter::Antialiasing );
+
+    painter->setPen( Qt::white );
+    painter->drawText( option.rect.translated( 4, 1 ), index.data().toString().toUpper(), to );
+    painter->setPen( QColor( 99, 113, 128 ) );
+    painter->drawText( option.rect.translated( 4, 0 ), index.data().toString().toUpper(), to );
+
+    if ( option.state & QStyle::State_MouseOver )
+    {
+        QString text = tr( "Show" );
+        if ( option.state & QStyle::State_Open )
+            text = tr( "Hide" );
+
+        QFont font = painter->font();
+        font.setPixelSize( 11 );
+        font.setBold( true );
+        painter->setFont( font );
+        QTextOption to( Qt::AlignVCenter | Qt::AlignRight );
+
+        // draw close icon
+        painter->setPen( Qt::white );
+        painter->drawText( option.rect.translated( -4, 1 ), text, to );
+        painter->setPen( QColor( 99, 113, 128 ) );
+        painter->drawText( option.rect.translated( -4, 0 ), text, to );
+    }
+}
+
+
+void
+SourceDelegate::paintGroup( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const
+{
+    QFont font = painter->font();
+    font.setPixelSize( 12 );
+    font.setBold( true );
+    painter->setFont( font );
+
+    QTextOption to( Qt::AlignVCenter );
+
+    painter->setPen( option.palette.color( QPalette::Base ) );
+    painter->setBrush( option.palette.color( QPalette::Base ) );
+    painter->drawRect( option.rect );
+    painter->setRenderHint( QPainter::Antialiasing );
+
+    painter->setPen( Qt::white );
+    painter->drawText( option.rect.translated( 4, 1 ), index.data().toString().toUpper(), to );
+    painter->setPen( QColor( 99, 113, 128 ) );
+    painter->drawText( option.rect.translated( 4, 0 ), index.data().toString().toUpper(), to );
+
+    if ( option.state & QStyle::State_MouseOver )
+    {
+        QString text = tr( "Show" );
+        if ( option.state & QStyle::State_Open )
+            text = tr( "Hide" );
+
+        font.setPixelSize( font.pixelSize() - 1 );
+        painter->setFont( font );
+        QTextOption to( Qt::AlignVCenter | Qt::AlignRight );
+
+        // draw close icon
+        painter->setPen( Qt::white );
+        painter->drawText( option.rect.translated( -4, 1 ), text, to );
+        painter->setPen( QColor( 99, 113, 128 ) );
+        painter->drawText( option.rect.translated( -4, 0 ), text, to );
+    }
+}
+
+
 void
 SourceDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const
 {
     QStyleOptionViewItem o = option;
     QStyleOptionViewItemV4 o3 = option;
 
-#ifdef Q_WS_MAC
-    QFont savedFont = painter->font();
-    QFont smaller = savedFont;
-    smaller.setPointSize( smaller.pointSize() - 2 );
-    painter->setFont( smaller );
-    o.font = smaller;
-#endif
+    painter->save();
+
+    QFont font = painter->font();
+    font.setPixelSize( 11 );
+    painter->setFont( font );
+    o.font = font;
+    o3.font = font;
+
+    SourcesModel::RowType type = static_cast< SourcesModel::RowType >( index.data( SourcesModel::SourceTreeItemTypeRole ).toInt() );
+    SourceTreeItem* item = index.data( SourcesModel::SourceTreeItemRole ).value< SourceTreeItem* >();
+    Q_ASSERT( item );
 
     if ( ( option.state & QStyle::State_Enabled ) == QStyle::State_Enabled )
     {
         o.state = QStyle::State_Enabled;
 
+        if ( ( option.state & QStyle::State_MouseOver ) == QStyle::State_MouseOver )
+        {
+            o.state |= QStyle::State_MouseOver;
+            o3.state |= QStyle::State_MouseOver;
+        }
+
+        if ( ( option.state & QStyle::State_Open ) == QStyle::State_Open )
+        {
+            o.state |= QStyle::State_Open;
+        }
+
         if ( ( option.state & QStyle::State_Selected ) == QStyle::State_Selected )
         {
-            o3.state |= QStyle::State_Selected;
+            if ( type != SourcesModel::Collection )
+                o3.state |= QStyle::State_Selected;
+            else
+                o3.state &= ~QStyle::State_Selected;
+
             o.palette.setColor( QPalette::Base, QColor( 0, 0, 0, 0 ) );
             o.palette.setColor( QPalette::Text, o.palette.color( QPalette::HighlightedText ) );
             o3.palette.setColor( QPalette::Text, o.palette.color( QPalette::HighlightedText ) );
         }
     }
 
-    SourcesModel::RowType type = static_cast< SourcesModel::RowType >( index.data( SourcesModel::SourceTreeItemTypeRole ).toInt() );
-    SourceTreeItem* item = index.data( SourcesModel::SourceTreeItemRole ).value< SourceTreeItem* >();
-    Q_ASSERT( item );
-
-    if ( type != SourcesModel::Collection && type != SourcesModel::Category )
-        o3.rect.setX( 0 );
-
-    QApplication::style()->drawControl( QStyle::CE_ItemViewItem, &o3, painter );
-
-    // Paint the speaker icon next to the currently-playing playlist
-    const bool playable = ( type == SourcesModel::StaticPlaylist ||
-                            type == SourcesModel::AutomaticPlaylist ||
-                            type == SourcesModel::Station ||
-                            type == SourcesModel::TemporaryPage ||
-                            type == SourcesModel::GenericPage );
-    const bool playing = ( AudioEngine::instance()->isPlaying() || AudioEngine::instance()->isPaused() );
-    if ( playable && playing && item->isBeingPlayed() )
+    // shrink the indentations
     {
-        const int iconW = o3.rect.height() - 4;
-        QRect iconRect = QRect( option.rect.x() - iconW - 4, option.rect.y() + 2, iconW, iconW );
-        QPixmap speaker = o3.state & QStyle::State_Selected ? m_nowPlayingSpeaker : m_nowPlayingSpeakerDark;
-        speaker = speaker.scaledToHeight( iconW, Qt::SmoothTransformation );
-        painter->drawPixmap( iconRect, speaker );
+        int indentMult = 0;
+        QModelIndex counter = index;
+        while ( counter.parent().isValid() )
+        {
+            indentMult++;
+            counter = counter.parent();
+        }
+
+        int indentDelta = o.rect.x() - m_parent->viewport()->x();
+        o.rect.setX( o.rect.x() - indentDelta + indentMult * TREEVIEW_INDENT_ADD );
+        o3.rect.setX( 0 );
     }
 
+    if ( type != SourcesModel::Group && type != SourcesModel::Category && type != SourcesModel::Divider )
+        QApplication::style()->drawControl( QStyle::CE_ItemViewItem, &o3, painter );
+
+    paintDecorations( painter, o3, index );
+
     if ( type == SourcesModel::Collection )
     {
-        painter->save();
-
-        QFont normal = painter->font();
-        QFont bold = painter->font();
-        bold.setBold( true );
-
-        CollectionItem* colItem = qobject_cast< CollectionItem* >( item );
-        Q_ASSERT( colItem );
-        bool status = !( !colItem || colItem->source().isNull() || !colItem->source()->isOnline() );
-
-        QString tracks;
-        QString name = index.data().toString();
-        int figWidth = 0;
-
-        if ( status && colItem && !colItem->source().isNull() )
-        {
-            tracks = QString::number( colItem->source()->trackCount() );
-            figWidth = painter->fontMetrics().width( tracks );
-            name = colItem->source()->friendlyName();
-        }
-
-        QRect iconRect = option.rect.adjusted( 4, 6, -option.rect.width() + option.rect.height() - 12 + 4, -6 );
-
-        QPixmap avatar = colItem->icon().pixmap( iconRect.size() );
-        painter->drawPixmap( iconRect, avatar.scaledToHeight( iconRect.height(), Qt::SmoothTransformation ) );
-
-        if ( ( option.state & QStyle::State_Selected ) == QStyle::State_Selected )
-        {
-            painter->setPen( o.palette.color( QPalette::HighlightedText ) );
-        }
-
-        QRect textRect = option.rect.adjusted( iconRect.width() + 8, 6, -figWidth - 24, 0 );
-        if ( status || colItem->source().isNull() )
-            painter->setFont( bold );
-        QString text = painter->fontMetrics().elidedText( name, Qt::ElideRight, textRect.width() );
-        painter->drawText( textRect, text );
-
-        bool isPlaying = false;
-        QString desc = status ? colItem->source()->textStatus() : tr( "Offline" );
-        if ( colItem->source().isNull() )
-            desc = tr( "All available tracks" );
-        if ( status && desc.isEmpty() && !colItem->source()->currentTrack().isNull() )
-        {
-            desc = colItem->source()->currentTrack()->artist() + " - " + colItem->source()->currentTrack()->track();
-            isPlaying = true;
-        }
-        if ( desc.isEmpty() )
-            desc = tr( "Online" );
-
-        textRect = option.rect.adjusted( iconRect.width() + 8, painter->fontMetrics().height() + 6, -figWidth - 24, -4 );
-        painter->setFont( normal );
-        bool privacyOn = TomahawkSettings::instance()->privateListeningMode() == TomahawkSettings::FullyPrivate;
-        if ( !colItem->source().isNull() && colItem->source()->isLocal() && privacyOn )
-        {
-            QRect pmRect = textRect;
-            pmRect.setTop( pmRect.bottom() - painter->fontMetrics().height() + 3 );
-            pmRect.setRight( pmRect.left() + pmRect.height() );
-            ActionCollection::instance()->getAction( "togglePrivacy" )->icon().paint( painter, pmRect );
-            textRect.adjust( pmRect.width() + 3, 0, 0, 0 );
-        }
-        if ( isPlaying || ( !colItem->source().isNull() && colItem->source()->isLocal() ) )
-        {
-            // Show a listen icon
-            QPixmap pm;
-            if ( index.data( SourcesModel::LatchedOnRole ).toBool() )
-            {
-                // Currently listening along
-                pm = m_headphonesOn;
-            } else if ( !colItem->source()->isLocal() ) {
-                pm = m_headphonesOff;
-            }
-
-            if ( !pm.isNull() )
-            {
-                QRect pmRect = textRect;
-                pmRect.setTop( pmRect.bottom() - painter->fontMetrics().height() + 3 );
-                pmRect.setRight( pmRect.left() + pmRect.height() );
-    //             tDebug() << "DOING HEADPHONES RECT:" << pmRect;
-                painter->drawPixmap( pmRect, pm.scaledToHeight( pmRect.height(), Qt::SmoothTransformation ) );
-                textRect.adjust( pmRect.width() + 3, 0, 0, 0 );
-            }
-        }
-        text = painter->fontMetrics().elidedText( desc, Qt::ElideRight, textRect.width() );
-        QTextOption to( Qt::AlignBottom );
-        painter->drawText( textRect, text, to );
-
-        if ( status )
-        {
-            painter->setRenderHint( QPainter::Antialiasing );
-
-            QRect figRect = o.rect.adjusted( o.rect.width() - figWidth - 8, 0, -13, -o.rect.height() + 16 );
-            int hd = ( option.rect.height() - figRect.height() ) / 2;
-            figRect.adjust( 0, hd, 0, hd );
-#ifdef Q_WS_WIN
-            figRect.adjust( -3, 0, 3, 0 );
-#endif
-            painter->setFont( bold );
-
-            QColor figColor( 167, 183, 211 );
-            painter->setPen( figColor );
-            painter->setBrush( figColor );
-
-            TomahawkUtils::drawBackgroundAndNumbers( painter, tracks, figRect );
-        }
-
-        painter->restore();
+        paintCollection( painter, o, index );
     }
     else if ( ( type == SourcesModel::StaticPlaylist || type == SourcesModel::CategoryAdd ) &&
               m_expandedMap.contains( index ) && m_expandedMap.value( index )->partlyExpanded() && dropTypeCount( item ) > 0 )
@@ -275,8 +399,6 @@ SourceDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, co
         o.rect.adjust( 0, 0, 0, - option.rect.height() + m_expandedMap.value( index )->originalSize().height() );
         QStyledItemDelegate::paint( painter, o, index );
 
-        painter->save();
-
         // Get whole rect for the menu
         QRect itemsRect = option.rect.adjusted( -option.rect.x(), m_expandedMap.value( index )->originalSize().height(), 0, 0 );
         QPoint cursorPos = m_parent->mapFromGlobal( QCursor::pos() );
@@ -287,9 +409,6 @@ SourceDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, co
         {
             m_gradient = QLinearGradient( itemsRect.topLeft(), itemsRect.bottomLeft() );
             m_gradient.setColorAt( 0.0, Qt::white );
-            //        m_gradient.setColorAt( 0.8, QColor( 0xd6, 0xd6, 0xd6 ) ); // light grey
-            //        m_gradient.setColorAt( 1.0, QColor( 0xf4, 0x17, 0x05 ) ); // dark red
-            //        m_gradient.setColorAt( 1.0, QColor( 0xb1, 0xb1, 0xb1 ) ); // not so light but still not dark grey
             m_gradient.setColorAt( 0.9, QColor( 0x88, 0x88, 0x88 ) );
             m_gradient.setColorAt( 1.0, QColor( 0x99, 0x99, 0x99 ) ); // dark grey
         }
@@ -352,11 +471,30 @@ SourceDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, co
 
             count++;
         }
+    }
+    else if ( type == SourcesModel::Group )
+    {
+        paintGroup( painter, o3, index );
+    }
+    else if ( type == SourcesModel::Category )
+    {
+        paintCategory( painter, o3, index );
+    }
+    else if ( type == SourcesModel::Divider )
+    {
+        QRect middle = o.rect.adjusted( 0, 2, 0, -2 );
+        painter->setRenderHint( QPainter::Antialiasing, false );
 
-        painter->restore();
+        QColor bgcolor = o3.palette.color( QPalette::Base );
+
+        painter->setPen( bgcolor.darker( 120 ) );
+        painter->drawLine( middle.topLeft(), middle.topRight() );
+        painter->setPen( bgcolor.lighter( 120 ) );
+        painter->drawLine( middle.bottomLeft(), middle.bottomRight() );
     }
     else
     {
+        o.state &= ~QStyle::State_MouseOver;
         QStyledItemDelegate::paint( painter, o, index );
 
         if ( type == SourcesModel::TemporaryPage )
@@ -376,29 +514,9 @@ SourceDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, co
                 painter->drawPixmap( r, p );
             }
         }
-
-        /*QStyleOptionViewItemV4 opt = o;
-        initStyleOption( &opt, index );
-
-        // shrink the indentations. count how indented this item is and remove it
-        int indentMult = 0;
-        QModelIndex counter = index;
-        while ( counter.parent().isValid() )
-        {
-            indentMult++;
-            counter = counter.parent();
-        }
-        int realX = opt.rect.x() + indentMult * TREEVIEW_INDENT_ADD;
-
-        opt.rect.setX( realX );
-        const QWidget *widget = opt.widget;
-        QStyle *style = widget ? widget->style() : QApplication::style();
-        style->drawControl( QStyle::CE_ItemViewItem, &opt, painter, widget ); */
     }
 
-#ifdef Q_WS_MAC
-    painter->setFont( savedFont );
-#endif
+    painter->restore();
 }
 
 
@@ -415,7 +533,7 @@ SourceDelegate::updateEditorGeometry( QWidget* editor, const QStyleOptionViewIte
 
 
 bool
-SourceDelegate::editorEvent ( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index )
+SourceDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index )
 {
     if ( event->type() == QEvent::MouseButtonRelease || event->type() == QEvent::MouseButtonPress )
     {
@@ -447,7 +565,7 @@ SourceDelegate::editorEvent ( QEvent* event, QAbstractItemModel* model, const QS
         }
         else if ( type == SourcesModel::Collection )
         {
-            CollectionItem* colItem = qobject_cast< CollectionItem* >( index.data( SourcesModel::SourceTreeItemRole ).value< SourceTreeItem* >() );
+            SourceItem* colItem = qobject_cast< SourceItem* >( index.data( SourcesModel::SourceTreeItemRole ).value< SourceTreeItem* >() );
             Q_ASSERT( colItem );
 
             if ( !colItem->source().isNull() && !colItem->source()->currentTrack().isNull() && !colItem->source()->isLocal() )
@@ -460,7 +578,6 @@ SourceDelegate::editorEvent ( QEvent* event, QAbstractItemModel* model, const QS
                 const int height = fm.height() + 3;
 
                 QRect headphonesRect( option.rect.height() + 10, o.rect.bottom() - height, height, height );
-//                 tDebug() << "CHECKING CLICK RECT:" << headphonesRect;
                 if ( headphonesRect.contains( ev->pos() ) )
                 {
                     if ( event->type() == QEvent::MouseButtonRelease )
diff --git a/src/sourcetree/sourcedelegate.h b/src/sourcetree/sourcedelegate.h
index 38389be55..2fc371ba8 100644
--- a/src/sourcetree/sourcedelegate.h
+++ b/src/sourcetree/sourcedelegate.h
@@ -56,6 +56,12 @@ private slots:
     void animationFinished( const QModelIndex& );
 
 private:
+    void paintDecorations( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
+
+    void paintCollection( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
+    void paintCategory( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
+    void paintGroup( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
+
     QAbstractItemView* m_parent;
     mutable int m_iconHeight;
     QModelIndex m_dropHoverIndex;
diff --git a/src/sourcetree/sourcesmodel.cpp b/src/sourcetree/sourcesmodel.cpp
index 3a82f686c..4ddf6fa36 100644
--- a/src/sourcetree/sourcesmodel.cpp
+++ b/src/sourcetree/sourcesmodel.cpp
@@ -25,8 +25,10 @@
 #include <QSize>
 
 #include "sourcetree/items/sourcetreeitem.h"
-#include "sourcetree/items/collectionitem.h"
+#include "sourcetree/items/sourceitem.h"
+#include "sourcetree/items/groupitem.h"
 #include "sourcetree/items/genericpageitems.h"
+#include "sourcetree/items/historyitem.h"
 #include "sourcelist.h"
 #include "playlist.h"
 #include "collection.h"
@@ -50,6 +52,7 @@ SourcesModel::SourcesModel( QObject* parent )
 {
     m_rootItem = new SourceTreeItem( this, 0, Invalid );
 
+    appendGroups();
     appendItem( source_ptr() );
 
     onSourcesAdded( SourceList::instance()->sources() );
@@ -71,6 +74,9 @@ SourcesModel::rowTypeToString( RowType type )
 {
     switch ( type )
     {
+        case Group:
+            return tr( "Group" );
+
         case Collection:
             return tr( "Collection" );
 
@@ -92,35 +98,35 @@ SourcesModel::rowTypeToString( RowType type )
 QVariant
 SourcesModel::data( const QModelIndex& index, int role ) const
 {
-    if( !index.isValid() )
+    if ( !index.isValid() )
         return QVariant();
 
-    switch( role )
+    switch ( role )
     {
-    case Qt::SizeHintRole:
-        return QSize( 0, 18 );
-    case SourceTreeItemRole:
-        return QVariant::fromValue< SourceTreeItem* >( itemFromIndex( index ) );
-    case SourceTreeItemTypeRole:
-        return itemFromIndex( index )->type();
-    case Qt::DisplayRole:
-    case Qt::EditRole:
-        return itemFromIndex( index )->text();
-    case Qt::DecorationRole:
-        return itemFromIndex( index )->icon();
-    case SourcesModel::SortRole:
-        return itemFromIndex( index )->peerSortValue();
-    case SourcesModel::IDRole:
-        return itemFromIndex( index )->IDValue();
-    case SourcesModel::LatchedOnRole:
-    {
-        if ( itemFromIndex( index )->type() == Collection )
+        case Qt::SizeHintRole:
+            return QSize( 0, 18 );
+        case SourceTreeItemRole:
+            return QVariant::fromValue< SourceTreeItem* >( itemFromIndex( index ) );
+        case SourceTreeItemTypeRole:
+            return itemFromIndex( index )->type();
+        case Qt::DisplayRole:
+        case Qt::EditRole:
+            return itemFromIndex( index )->text();
+        case Qt::DecorationRole:
+            return itemFromIndex( index )->icon();
+        case SourcesModel::SortRole:
+            return itemFromIndex( index )->peerSortValue();
+        case SourcesModel::IDRole:
+            return itemFromIndex( index )->IDValue();
+        case SourcesModel::LatchedOnRole:
         {
-            CollectionItem* cItem = qobject_cast< CollectionItem* >( itemFromIndex( index ) );
-            return cItem->localLatchedOn();
+            if ( itemFromIndex( index )->type() == Collection )
+            {
+                SourceItem* cItem = qobject_cast< SourceItem* >( itemFromIndex( index ) );
+                return cItem->localLatchedOn();
+            }
+            return false;
         }
-        return false;
-    }
     }
     return QVariant();
 }
@@ -236,21 +242,63 @@ SourcesModel::supportedDropActions() const
 Qt::ItemFlags
 SourcesModel::flags( const QModelIndex& index ) const
 {
-    if ( index.isValid() ) {
+    if ( index.isValid() )
+    {
         return itemFromIndex( index )->flags();
-    } else {
-        return 0;
     }
+    else
+        return 0;
+}
+
+
+void
+SourcesModel::appendGroups()
+{
+    beginInsertRows( QModelIndex(), rowCount(), rowCount() + 2 );
+
+    SourceTreeItem* divider = new SourceTreeItem( this, m_rootItem, SourcesModel::Divider, 0 );
+    HistoryItem* history = new HistoryItem( this, m_rootItem, tr( "History" ), 5 );
+    GroupItem* browse = new GroupItem( this, m_rootItem, tr( "Browse" ), 10 );
+
+    // super collection
+    GenericPageItem* loved = new GenericPageItem( this, browse, tr( "Top Loved Tracks" ), QIcon( RESPATH "images/loved_playlist.png" ),
+                                                  boost::bind( &ViewManager::showTopLovedPage, ViewManager::instance() ),
+                                                  boost::bind( &ViewManager::topLovedWidget, ViewManager::instance() ) );
+    loved->setSortValue( -250 );
+
+    // add misc children of root node
+    GenericPageItem* recent = new GenericPageItem( this, browse, tr( "Dashboard" ), QIcon( RESPATH "images/dashboard.png" ),
+                                                   boost::bind( &ViewManager::showWelcomePage, ViewManager::instance() ),
+                                                   boost::bind( &ViewManager::welcomeWidget, ViewManager::instance() ) );
+    recent->setSortValue( -300 );
+
+    GenericPageItem* hot = new GenericPageItem( this, browse, tr( "Charts" ), QIcon( RESPATH "images/charts.png" ),
+                                                boost::bind( &ViewManager::showWhatsHotPage, ViewManager::instance() ),
+                                                boost::bind( &ViewManager::whatsHotWidget, ViewManager::instance() ) );
+    hot->setSortValue( -300 );
+
+    m_collectionsGroup = new GroupItem( this, m_rootItem, tr( "Friends" ), 15 );
+
+    endInsertRows();
 }
 
 
 void
 SourcesModel::appendItem( const Tomahawk::source_ptr& source )
 {
-    beginInsertRows( QModelIndex(), rowCount(), rowCount() );
-    // append to end
-    new CollectionItem( this, m_rootItem, source );
+    SourceTreeItem* parent;
+    if ( !source.isNull() && source->isLocal() )
+    {
+        parent = m_rootItem;
+    }
+    else
+    {
+        parent = m_collectionsGroup;
+    }
 
+    QModelIndex idx = indexFromItem( parent );
+    beginInsertRows( idx, rowCount( idx ), rowCount( idx ) );
+    new SourceItem( this, parent, source );
     endInsertRows();
 }
 
@@ -265,7 +313,7 @@ SourcesModel::removeItem( const Tomahawk::source_ptr& source )
     for ( int row = 0; row < rows; row++ )
     {
         QModelIndex idx = index( row, 0, QModelIndex() );
-        CollectionItem* item = static_cast< CollectionItem* >( idx.internalPointer() );
+        SourceItem* item = static_cast< SourceItem* >( idx.internalPointer() );
         if ( item && item->source() == source )
         {
 //            qDebug() << "Found removed source item:" << item->source()->userName();
@@ -348,12 +396,12 @@ SourcesModel::viewPageActivated( Tomahawk::ViewPage* page )
                 m_sourcesWithViewPageItems[ s ] = collectionOfPlaylist;
                 tDebug() << "Emitting dataChanged for offline source:" << idx << idx.isValid() << collectionOfPlaylist << collectionOfPlaylist->text();
                 emit dataChanged( idx, idx );
-
             }
         }
     }
 }
 
+
 SourceTreeItem*
 SourcesModel::activatePlaylistPage( ViewPage* p, SourceTreeItem* i )
 {
@@ -425,7 +473,6 @@ SourcesModel::itemUpdated()
 void
 SourcesModel::onItemRowsAddedBegin( int first, int last )
 {
-
     Q_ASSERT( qobject_cast< SourceTreeItem* >( sender() ) );
     SourceTreeItem* item = qobject_cast< SourceTreeItem* >( sender() );
 
@@ -486,6 +533,7 @@ SourcesModel::linkSourceItemToPage( SourceTreeItem* item, ViewPage* p )
     m_viewPageDelayedCacheItem = 0;
 }
 
+
 void
 SourcesModel::onWidgetDestroyed( QWidget* w )
 {
@@ -576,9 +624,17 @@ SourcesModel::itemSelectRequest( SourceTreeItem* item )
     emit selectRequest( QPersistentModelIndex( indexFromItem( item ) ) );
 }
 
+
 void
 SourcesModel::itemExpandRequest( SourceTreeItem *item )
 {
     qDebug() << "expanding source" << indexFromItem( item ) << item;
     emit expandRequest( QPersistentModelIndex( indexFromItem( item ) ) );
 }
+
+
+void
+SourcesModel::itemToggleExpandRequest( SourceTreeItem *item )
+{
+    emit toggleExpandRequest( QPersistentModelIndex( indexFromItem( item ) ) );
+}
diff --git a/src/sourcetree/sourcesmodel.h b/src/sourcetree/sourcesmodel.h
index 7e9dc08f2..6f2e69605 100644
--- a/src/sourcetree/sourcesmodel.h
+++ b/src/sourcetree/sourcesmodel.h
@@ -1,19 +1,21 @@
-
-/*
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License along
-    with this program; if not, write to the Free Software Foundation, Inc.,
-    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-*/
+/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
+ *
+ *   Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
+ *   Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
+ *
+ *   Tomahawk is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   Tomahawk is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
+ */
 
 
 #ifndef SOURCESMODEL_H
@@ -28,6 +30,7 @@
 class QMimeData;
 
 class SourceTreeItem;
+class GroupItem;
 
 namespace Tomahawk {
     class Source;
@@ -41,8 +44,10 @@ class SourcesModel : public QAbstractItemModel
 public:
     enum RowType {
         Invalid = -1,
+        Divider = 9,
 
         Collection = 0,
+        Group = 8,
 
         Category = 1,
         CategoryAdd = 2,
@@ -65,7 +70,7 @@ public:
         SourceTreeItemTypeRole  = Qt::UserRole + 11,
         SortRole                = Qt::UserRole + 12,
         IDRole                  = Qt::UserRole + 13,
-        LatchedOnRole                  = Qt::UserRole + 14
+        LatchedOnRole           = Qt::UserRole + 14
     };
 
     SourcesModel( QObject* parent = 0 );
@@ -87,6 +92,8 @@ public:
     virtual Qt::DropActions supportedDropActions() const;
     virtual Qt::ItemFlags flags(const QModelIndex& index) const;
 
+    void appendGroups();
+
     void appendItem( const Tomahawk::source_ptr& source );
     bool removeItem( const Tomahawk::source_ptr& source );
 
@@ -110,10 +117,12 @@ public slots:
 
     void itemSelectRequest( SourceTreeItem* item );
     void itemExpandRequest( SourceTreeItem* item );
+    void itemToggleExpandRequest( SourceTreeItem* item );
 
 signals:
     void selectRequest( const QPersistentModelIndex& idx );
     void expandRequest( const QPersistentModelIndex& idx );
+    void toggleExpandRequest( const QPersistentModelIndex& idx );
 
 private slots:
     void onSourcesAdded( const QList<Tomahawk::source_ptr>& sources );
@@ -121,12 +130,14 @@ private slots:
     void onSourceRemoved( const Tomahawk::source_ptr& source );
 
     void onWidgetDestroyed( QWidget* w );
+
 private:
     SourceTreeItem* itemFromIndex( const QModelIndex& idx ) const;
     int rowForItem( SourceTreeItem* item ) const;
     SourceTreeItem* activatePlaylistPage( Tomahawk::ViewPage* p, SourceTreeItem* i );
 
     SourceTreeItem* m_rootItem;
+    GroupItem* m_collectionsGroup;
 
     QList< Tomahawk::source_ptr > m_sourcesWithViewPage;
     QHash< Tomahawk::source_ptr, SourceTreeItem* > m_sourcesWithViewPageItems;
diff --git a/src/sourcetree/sourcesproxymodel.cpp b/src/sourcetree/sourcesproxymodel.cpp
index b5d484c5e..2b5eeec94 100644
--- a/src/sourcetree/sourcesproxymodel.cpp
+++ b/src/sourcetree/sourcesproxymodel.cpp
@@ -1,6 +1,7 @@
 /* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
  *
  *   Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
+ *   Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
  *
  *   Tomahawk is free software: you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License as published by
@@ -22,7 +23,7 @@
 
 #include "sourcelist.h"
 #include "sourcesmodel.h"
-#include "sourcetree/items/collectionitem.h"
+#include "sourcetree/items/sourceitem.h"
 
 #include "utils/logger.h"
 
@@ -37,6 +38,11 @@ SourcesProxyModel::SourcesProxyModel( SourcesModel* model, QObject* parent )
 
     setSourceModel( model );
 
+    connect( model, SIGNAL( rowsInserted( QModelIndex, int, int ) ), SLOT( onModelChanged() ) );
+    connect( model, SIGNAL( rowsRemoved( QModelIndex, int, int ) ), SLOT( onModelChanged() ) );
+
+    if ( model && model->metaObject()->indexOfSignal( "toggleExpandRequest(QPersistentModelIndex)" ) > -1 )
+        connect( model, SIGNAL( toggleExpandRequest( QPersistentModelIndex ) ), this, SLOT( toggleExpandRequested( QPersistentModelIndex ) ), Qt::QueuedConnection );
     if ( model && model->metaObject()->indexOfSignal( "expandRequest(QPersistentModelIndex)" ) > -1 )
         connect( model, SIGNAL( expandRequest( QPersistentModelIndex ) ), this, SLOT( expandRequested( QPersistentModelIndex ) ), Qt::QueuedConnection );
     if ( model && model->metaObject()->indexOfSignal( "selectRequest(QPersistentModelIndex)" ) > -1 )
@@ -55,10 +61,16 @@ SourcesProxyModel::showOfflineSources( bool offlineSourcesShown )
 bool
 SourcesProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex& sourceParent ) const
 {
+    // always filter empty top-level groups
+    SourceTreeItem* item = m_model->data( sourceModel()->index( sourceRow, 0, sourceParent ), SourcesModel::SourceTreeItemRole ).value< SourceTreeItem* >();
+
+    if ( item && item->type() != SourcesModel::Divider && item->parent()->parent() == 0 && !item->children().count() )
+        return false;
+
     if ( !m_filtered )
         return true;
 
-    CollectionItem* sti = qobject_cast< CollectionItem* >( m_model->data( sourceModel()->index( sourceRow, 0, sourceParent ), SourcesModel::SourceTreeItemRole ).value< SourceTreeItem* >() );
+    SourceItem* sti = qobject_cast< SourceItem* >( item );
     if ( sti )
     {
         if ( sti->source().isNull() || sti->source()->isOnline() )
@@ -68,6 +80,7 @@ SourcesProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex& sourcePar
         else
             return false;
     }
+
     // accept rows that aren't sources
     return true;
 }
@@ -76,7 +89,6 @@ SourcesProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex& sourcePar
 void
 SourcesProxyModel::selectRequested( const QPersistentModelIndex& idx )
 {
-    qDebug() << "selectRequested for idx" << idx << idx.data(Qt::DisplayRole).toString() << mapFromSource( idx ) << mapFromSource( idx ).data(Qt::DisplayRole).toString();
     emit selectRequest( QPersistentModelIndex( mapFromSource( idx ) ) );
 }
 
@@ -84,11 +96,17 @@ SourcesProxyModel::selectRequested( const QPersistentModelIndex& idx )
 void
 SourcesProxyModel::expandRequested( const QPersistentModelIndex& idx )
 {
-    qDebug() << "emitting expand for idx" << idx << idx.data(Qt::DisplayRole).toString() << mapFromSource( idx ) << mapFromSource( idx ).data(Qt::DisplayRole).toString();
     emit expandRequest( QPersistentModelIndex( mapFromSource( idx ) ) );
 }
 
 
+void
+SourcesProxyModel::toggleExpandRequested( const QPersistentModelIndex& idx )
+{
+    emit toggleExpandRequest( QPersistentModelIndex( mapFromSource( idx ) ) );
+}
+
+
 bool
 SourcesProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right ) const
 {
@@ -103,3 +121,10 @@ SourcesProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right )
     else
         return QString::localeAwareCompare( lefts, rights ) < 0;
 }
+
+
+void
+SourcesProxyModel::onModelChanged()
+{
+    invalidateFilter();
+}
diff --git a/src/sourcetree/sourcesproxymodel.h b/src/sourcetree/sourcesproxymodel.h
index a1908b73c..1d66277f9 100644
--- a/src/sourcetree/sourcesproxymodel.h
+++ b/src/sourcetree/sourcesproxymodel.h
@@ -35,15 +35,20 @@ public slots:
 
     void selectRequested( const QPersistentModelIndex& );
     void expandRequested( const QPersistentModelIndex& );
+    void toggleExpandRequested( const QPersistentModelIndex& );
 
 signals:
     void selectRequest( const QPersistentModelIndex& idx );
     void expandRequest( const QPersistentModelIndex& idx );
+    void toggleExpandRequest( const QPersistentModelIndex& idx );
 
 protected:
     bool filterAcceptsRow( int sourceRow, const QModelIndex& sourceParent ) const;
     bool lessThan( const QModelIndex& left, const QModelIndex& right ) const;
 
+private slots:
+    void onModelChanged();
+
 private:
     SourcesModel* m_model;
 
diff --git a/src/sourcetree/sourcetreeview.cpp b/src/sourcetree/sourcetreeview.cpp
index 32341dfec..01ecd8995 100644
--- a/src/sourcetree/sourcetreeview.cpp
+++ b/src/sourcetree/sourcetreeview.cpp
@@ -35,7 +35,7 @@
 #include "sourcelist.h"
 #include "sourcedelegate.h"
 #include "sourcetree/items/playlistitems.h"
-#include "sourcetree/items/collectionitem.h"
+#include "sourcetree/items/sourceitem.h"
 #include "audio/audioengine.h"
 #include "sourceplaylistinterface.h"
 #include "tomahawksettings.h"
@@ -56,6 +56,8 @@ SourceTreeView::SourceTreeView( QWidget* parent )
     , m_latchManager( new LatchManager( this ) )
     , m_dragging( false )
 {
+    setProperty( "flattenBranches", QVariant( true ) );
+
     setFrameShape( QFrame::NoFrame );
     setAttribute( Qt::WA_MacShowFocusRect, 0 );
     setContentsMargins( 0, 0, 0, 0 );
@@ -71,11 +73,12 @@ SourceTreeView::SourceTreeView( QWidget* parent )
     setDropIndicatorShown( false );
     setAllColumnsShowFocus( true );
     setUniformRowHeights( false );
-    setIndentation( 14 );
+    setIndentation( 0 );
     setSortingEnabled( true );
     sortByColumn( 0, Qt::AscendingOrder );
     setVerticalScrollMode( QTreeView::ScrollPerPixel );
     setMouseTracking( true );
+
     // TODO animation conflicts with the expanding-playlists-when-collection-is-null
     // so investigate
 //     setAnimated( true );
@@ -93,6 +96,7 @@ SourceTreeView::SourceTreeView( QWidget* parent )
     m_proxyModel = new SourcesProxyModel( m_model, this );
     connect( m_proxyModel, SIGNAL( selectRequest( QPersistentModelIndex ) ), this, SLOT( selectRequest( QPersistentModelIndex ) ) );
     connect( m_proxyModel, SIGNAL( expandRequest( QPersistentModelIndex ) ), this, SLOT( expandRequest( QPersistentModelIndex ) ) );
+    connect( m_proxyModel, SIGNAL( toggleExpandRequest( QPersistentModelIndex ) ), this, SLOT( toggleExpandRequest( QPersistentModelIndex ) ) );
 
     setModel( m_proxyModel );
 
@@ -152,7 +156,7 @@ SourceTreeView::setupMenus()
 
     if ( type == SourcesModel::Collection )
     {
-        CollectionItem* item = itemFromIndex< CollectionItem >( m_contextMenuIndex );
+        SourceItem* item = itemFromIndex< SourceItem >( m_contextMenuIndex );
         source_ptr source = item->source();
         if ( !source.isNull() )
         {
@@ -198,7 +202,7 @@ SourceTreeView::setupMenus()
     connect( deletePlaylistAction, SIGNAL( triggered() ), SLOT( deletePlaylist() ) );
     connect( copyPlaylistAction,   SIGNAL( triggered() ), SLOT( copyPlaylistLink() ) );
     connect( addToLocalAction,     SIGNAL( triggered() ), SLOT( addToLocal() ) );
-    connect( latchOnAction,          SIGNAL( triggered() ), SLOT( latchOnOrCatchUp() ), Qt::QueuedConnection );
+    connect( latchOnAction,        SIGNAL( triggered() ), SLOT( latchOnOrCatchUp() ), Qt::QueuedConnection );
 }
 
 
@@ -235,7 +239,6 @@ SourceTreeView::onItemExpanded( const QModelIndex& idx )
 void
 SourceTreeView::selectRequest( const QPersistentModelIndex& idx )
 {
-    qDebug() << "Select request for:" << idx << idx.data().toString() << selectionModel()->selectedIndexes().contains( idx );
     if ( !selectionModel()->selectedIndexes().contains( idx ) )
     {
         scrollTo( idx, QTreeView::EnsureVisible );
@@ -247,11 +250,20 @@ SourceTreeView::selectRequest( const QPersistentModelIndex& idx )
 void
 SourceTreeView::expandRequest( const QPersistentModelIndex &idx )
 {
-    qDebug() << "Expanding idx" << idx << idx.data( Qt::DisplayRole ).toString();
     expand( idx );
 }
 
 
+void
+SourceTreeView::toggleExpandRequest( const QPersistentModelIndex &idx )
+{
+    if ( isExpanded( idx ) )
+        collapse( idx );
+    else
+        expand( idx );
+}
+
+
 void
 SourceTreeView::loadPlaylist()
 {
@@ -359,7 +371,7 @@ SourceTreeView::latchOnOrCatchUp()
     if( type != SourcesModel::Collection )
         return;
 
-    CollectionItem* item = itemFromIndex< CollectionItem >( m_contextMenuIndex );
+    SourceItem* item = itemFromIndex< SourceItem >( m_contextMenuIndex );
     source_ptr source = item->source();
 
     latchOnOrCatchUp( source );
@@ -378,7 +390,7 @@ SourceTreeView::latchOff()
     if( type != SourcesModel::Collection )
         return;
 
-    const CollectionItem* item = itemFromIndex< CollectionItem >( m_contextMenuIndex );
+    const SourceItem* item = itemFromIndex< SourceItem >( m_contextMenuIndex );
     const source_ptr source = item->source();
 
     latchOff( source );
@@ -436,7 +448,7 @@ SourceTreeView::onCustomContextMenu( const QPoint& pos )
     }
     else if ( model()->data( m_contextMenuIndex, SourcesModel::SourceTreeItemTypeRole ) == SourcesModel::Collection )
     {
-        CollectionItem* item = itemFromIndex< CollectionItem >( m_contextMenuIndex );
+        SourceItem* item = itemFromIndex< SourceItem >( m_contextMenuIndex );
         if ( !item->source().isNull() && !item->source()->isLocal() )
             m_latchMenu.exec( mapToGlobal( pos ) );
         else if ( !item->source().isNull() )
diff --git a/src/sourcetree/sourcetreeview.h b/src/sourcetree/sourcetreeview.h
index 141e4c427..4a518cac7 100644
--- a/src/sourcetree/sourcetreeview.h
+++ b/src/sourcetree/sourcetreeview.h
@@ -64,6 +64,7 @@ private slots:
     void onItemActivated( const QModelIndex& index );
     void selectRequest( const QPersistentModelIndex& idx );
     void expandRequest( const QPersistentModelIndex& idx );
+    void toggleExpandRequest( const QPersistentModelIndex& idx );
 
     void loadPlaylist();
     void deletePlaylist( const QModelIndex& = QModelIndex() );
@@ -74,7 +75,7 @@ private slots:
     void latchOff();
     void latchOnOrCatchUp( const Tomahawk::source_ptr& source );
     void latchOff( const Tomahawk::source_ptr& source );
-    
+
     void onCustomContextMenu( const QPoint& pos );
 
 protected:

From 4f4406ffb1aa92ca5e3f664f8cc87112745f26d8 Mon Sep 17 00:00:00 2001
From: Christian Muehlhaeuser <muesli@gmail.com>
Date: Wed, 14 Dec 2011 11:24:30 +0100
Subject: [PATCH 06/11] * Indent playlists / stations correctly. This is
 possibly causing issues with the OS X background color. Needs checking.

---
 src/sourcetree/sourcedelegate.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/sourcetree/sourcedelegate.cpp b/src/sourcetree/sourcedelegate.cpp
index 331df0243..ea69300b4 100644
--- a/src/sourcetree/sourcedelegate.cpp
+++ b/src/sourcetree/sourcedelegate.cpp
@@ -478,7 +478,7 @@ SourceDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, co
     }
     else if ( type == SourcesModel::Category )
     {
-        paintCategory( painter, o3, index );
+        paintCategory( painter, o, index );
     }
     else if ( type == SourcesModel::Divider )
     {

From f32de6beced535d36655c48e966f4ef855c5412f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Hugo=20Lindstr=C3=B6m?= <hugolm84@gmail.com>
Date: Wed, 14 Dec 2011 13:01:05 +0100
Subject: [PATCH 07/11] Use pong instead to check if spotifyApi is online

---
 src/tomahawkapp.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/tomahawkapp.cpp b/src/tomahawkapp.cpp
index 57b643019..d10832c5f 100644
--- a/src/tomahawkapp.cpp
+++ b/src/tomahawkapp.cpp
@@ -282,7 +282,7 @@ TomahawkApp::init()
     GlobalActionManager::instance();
 
     // check if our spotify playlist api server is up and running, and enable spotify playlist drops if so
-    QNetworkReply* r = TomahawkUtils::nam()->get( QNetworkRequest( QUrl( SPOTIFY_PLAYLIST_API_URL "/playlist/test" ) ) );
+    QNetworkReply* r = TomahawkUtils::nam()->get( QNetworkRequest( QUrl( SPOTIFY_PLAYLIST_API_URL "/pong" ) ) );
     connect( r, SIGNAL( finished() ), this, SLOT( spotifyApiCheckFinished() ) );
 #endif
 

From d59ffc55b157d7a8166f8b3250bf9ffb83c1c843 Mon Sep 17 00:00:00 2001
From: Jason Herskowitz <jherskowitz@globallistic.com>
Date: Wed, 14 Dec 2011 09:33:32 -0500
Subject: [PATCH 08/11] Transparent spinner

---
 data/images/loading-animation.gif | Bin 8534 -> 10387 bytes
 1 file changed, 0 insertions(+), 0 deletions(-)

diff --git a/data/images/loading-animation.gif b/data/images/loading-animation.gif
index 8be8ba338d5b5aec80593295f88bcaf6608bdf18..c7cfddcb19f94cf3246d0976f7576599ba07ee08 100644
GIT binary patch
literal 10387
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
E2jWq!9RL6T

literal 8534
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
G(|-Y9t#!u$


From c3e8420b57197775d585214040fa2e0dc7eb4a6a Mon Sep 17 00:00:00 2001
From: Christian Muehlhaeuser <muesli@gmail.com>
Date: Wed, 14 Dec 2011 17:05:20 +0100
Subject: [PATCH 09/11] * Removed PhantomJS warning from tomahawk.js.

---
 data/js/tomahawk.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/data/js/tomahawk.js b/data/js/tomahawk.js
index 17cc645bc..3d9bcc57c 100644
--- a/data/js/tomahawk.js
+++ b/data/js/tomahawk.js
@@ -2,7 +2,7 @@
 // if run in phantomjs add fake Tomahawk environment
 if(window.Tomahawk === undefined)
 {
-    alert("PHANTOMJS ENVIRONMENT");
+//    alert("PHANTOMJS ENVIRONMENT");
     var Tomahawk = {
         fakeEnv: function()
         {

From 54c203982f1d376e29a8dc014ecbeb678c8b52b5 Mon Sep 17 00:00:00 2001
From: Christian Muehlhaeuser <muesli@gmail.com>
Date: Thu, 15 Dec 2011 20:58:24 +0100
Subject: [PATCH 10/11] * Fixed resolving regression, which caused omitting
 some results.

---
 src/libtomahawk/database/databasecommand_resolve.cpp | 6 +++---
 src/libtomahawk/network/servent.cpp                  | 2 +-
 src/libtomahawk/resolvers/qtscriptresolver.h         | 2 +-
 src/tomahawkapp.cpp                                  | 1 -
 4 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/src/libtomahawk/database/databasecommand_resolve.cpp b/src/libtomahawk/database/databasecommand_resolve.cpp
index d050d2eda..a140417d0 100644
--- a/src/libtomahawk/database/databasecommand_resolve.cpp
+++ b/src/libtomahawk/database/databasecommand_resolve.cpp
@@ -76,9 +76,9 @@ DatabaseCommand_Resolve::resolve( DatabaseImpl* lib )
     typedef QPair<int, float> scorepair_t;
 
     // STEP 1
-    QList< QPair<int, float> > artists = lib->searchTable( "artist", m_query->artist(), 10 );
-    QList< QPair<int, float> > tracks = lib->searchTable( "track", m_query->track(), 10 );
-    QList< QPair<int, float> > albums = lib->searchTable( "album", m_query->album(), 10 );
+    QList< QPair<int, float> > artists = lib->searchTable( "artist", m_query->artist() );
+    QList< QPair<int, float> > tracks = lib->searchTable( "track", m_query->track() );
+    QList< QPair<int, float> > albums = lib->searchTable( "album", m_query->album() );
 
     if ( artists.length() == 0 || tracks.length() == 0 )
     {
diff --git a/src/libtomahawk/network/servent.cpp b/src/libtomahawk/network/servent.cpp
index 941515fda..7cc7c021a 100644
--- a/src/libtomahawk/network/servent.cpp
+++ b/src/libtomahawk/network/servent.cpp
@@ -378,7 +378,7 @@ Servent::readyRead()
     }
 
     // they connected to us and want something we are offering
-    if( conntype == "accept-offer" || "push-offer" )
+    if ( conntype == "accept-offer" || conntype == "push-offer" )
     {
         sock->_msg.clear();
         tDebug( LOGVERBOSE ) << Q_FUNC_INFO << key << nodeid << "socket peer address = " << sock->peerAddress() << "socket peer name = " << sock->peerName();
diff --git a/src/libtomahawk/resolvers/qtscriptresolver.h b/src/libtomahawk/resolvers/qtscriptresolver.h
index 00c453c94..4006f3221 100644
--- a/src/libtomahawk/resolvers/qtscriptresolver.h
+++ b/src/libtomahawk/resolvers/qtscriptresolver.h
@@ -53,6 +53,7 @@ public:
     Q_INVOKABLE void addCustomUrlHandler( const QString& protocol, const QString& callbackFuncName );
 
     QSharedPointer<QIODevice> customIODeviceFactory( const Tomahawk::result_ptr& result );
+
 public slots:
     QByteArray readRaw( const QString& fileName );
     QString readBase64( const QString& fileName );
@@ -66,7 +67,6 @@ public slots:
 
     void addTrackResults( const QVariantMap& results );
 
-
 private:
     QString m_scriptPath, m_urlCallback;
     QVariantMap m_resolverConfig;
diff --git a/src/tomahawkapp.cpp b/src/tomahawkapp.cpp
index d10832c5f..f341ef379 100644
--- a/src/tomahawkapp.cpp
+++ b/src/tomahawkapp.cpp
@@ -226,7 +226,6 @@ TomahawkApp::init()
 #ifndef ENABLE_HEADLESS
     EchonestGenerator::setupCatalogs();
 
-
     if ( !m_headless )
     {
         tDebug() << "Init MainWindow.";

From 52cb7cebd90f0ea9f9fb70f4b9b78fc964952e7b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Hugo=20Lindstr=C3=B6m?= <hugolm84@gmail.com>
Date: Sat, 17 Dec 2011 18:06:44 +0100
Subject: [PATCH 11/11] Forgot about spotifyApiReply.

---
 src/tomahawkapp.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/tomahawkapp.cpp b/src/tomahawkapp.cpp
index f341ef379..fad32b2a2 100644
--- a/src/tomahawkapp.cpp
+++ b/src/tomahawkapp.cpp
@@ -539,10 +539,10 @@ TomahawkApp::spotifyApiCheckFinished()
     QNetworkReply* reply = qobject_cast< QNetworkReply* >( sender() );
     Q_ASSERT( reply );
 
-    if ( reply->error() == QNetworkReply::ContentNotFoundError )
-        DropJob::setCanParseSpotifyPlaylists( true );
-    else
+    if ( reply->error() )
         DropJob::setCanParseSpotifyPlaylists( false );
+    else
+        DropJob::setCanParseSpotifyPlaylists( true );
 #endif
 }