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 }