diff --git a/data/js/tomahawk.js b/data/js/tomahawk.js index 3fa8d7d9b..611ea1876 100644 --- a/data/js/tomahawk.js +++ b/data/js/tomahawk.js @@ -151,6 +151,10 @@ var TomahawkResolver = { return { qid: qid }; + }, + collection: function() + { + return {}; } }; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3c75fd18a..2eaef5604 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -42,6 +42,7 @@ SET( tomahawkSourcesGui ${tomahawkSourcesGui} sourcetree/SourceTreeView.cpp sourcetree/SourceDelegate.cpp sourcetree/AnimationHelper.cpp + sourcetree/items/ScriptCollectionItem.cpp sourcetree/items/SourceTreeItem.cpp sourcetree/items/SourceItem.cpp sourcetree/items/PlaylistItems.cpp diff --git a/src/libtomahawk/resolvers/QtScriptResolver.cpp b/src/libtomahawk/resolvers/QtScriptResolver.cpp index 50a8fc530..1d844eab1 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.cpp +++ b/src/libtomahawk/resolvers/QtScriptResolver.cpp @@ -903,9 +903,20 @@ QtScriptResolver::loadCollections() { if ( m_capabilities.testFlag( Browsable ) ) { + QVariantMap collectionInfo = m_engine->mainFrame()->evaluateJavaScript( "resolver.collection();" ).toMap(); + if ( collectionInfo.isEmpty() || + !collectionInfo.contains( "prettyname" ) || + !collectionInfo.contains( "description" ) ) + return; + + QString desc = collectionInfo.value( "description" ).toString(); + m_collections.clear(); // at this point we assume that all the tracks browsable through a resolver belong to the local source - Tomahawk::collection_ptr collection( new Tomahawk::ScriptCollection( SourceList::instance()->getLocal(), this ) ); + Tomahawk::ScriptCollection* sc = new Tomahawk::ScriptCollection( SourceList::instance()->getLocal(), this ); + sc->setDescription( desc ); + Tomahawk::collection_ptr collection( sc ); + m_collections.insert( collection->name(), collection ); emit collectionAdded( collection ); diff --git a/src/libtomahawk/resolvers/ScriptCollection.cpp b/src/libtomahawk/resolvers/ScriptCollection.cpp index 788fd15f2..5b2418c4a 100644 --- a/src/libtomahawk/resolvers/ScriptCollection.cpp +++ b/src/libtomahawk/resolvers/ScriptCollection.cpp @@ -68,9 +68,7 @@ ScriptCollection::prettyName() const QString ScriptCollection::itemName() const { - return tr( "%1 Collection", - "Name of a collection based on a resolver, e.g. Subsonic Collection" ) - .arg( m_resolver->name() ); + return m_resolver->name(); } @@ -111,6 +109,20 @@ ScriptCollection::bigIcon() const } +void +ScriptCollection::setDescription( const QString& text ) +{ + m_description = text; +} + + +QString +ScriptCollection::description() const +{ + return m_description; +} + + Tomahawk::ArtistsRequest* ScriptCollection::requestArtists() { diff --git a/src/libtomahawk/resolvers/ScriptCollection.h b/src/libtomahawk/resolvers/ScriptCollection.h index 556439db6..9ff3543b8 100644 --- a/src/libtomahawk/resolvers/ScriptCollection.h +++ b/src/libtomahawk/resolvers/ScriptCollection.h @@ -48,6 +48,9 @@ public: virtual QIcon icon() const; virtual QPixmap bigIcon() const; + virtual void setDescription( const QString& text ); + virtual QString description() const; + virtual ExternalResolver* resolver() { return m_resolver; } virtual Tomahawk::ArtistsRequest* requestArtists(); @@ -56,6 +59,7 @@ public: private: ExternalResolver* m_resolver; + QString m_description; }; } //ns diff --git a/src/sourcetree/SourceDelegate.cpp b/src/sourcetree/SourceDelegate.cpp index f4e5bd73c..b6f5dc19e 100644 --- a/src/sourcetree/SourceDelegate.cpp +++ b/src/sourcetree/SourceDelegate.cpp @@ -2,8 +2,9 @@ * * Copyright 2010-2011, Christian Muehlhaeuser * Copyright 2011-2012, Leo Franchi - * Copyright 2011, Michael Zanetti + * Copyright 2011, Michael Zanetti * Copyright 2010-2012, Jeff Mitchell + * Copyright 2013, Teo Mrnjavac * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,6 +27,7 @@ #include "items/PlaylistItems.h" #include "items/CategoryItems.h" #include "items/TemporaryPageItem.h" +#include "items/ScriptCollectionItem.h" #include "audio/AudioEngine.h" #include "AnimationHelper.h" @@ -34,6 +36,7 @@ #include "ActionCollection.h" #include "ViewManager.h" #include "ContextMenu.h" +#include "resolvers/ScriptCollection.h" #include "utils/TomahawkUtilsGui.h" #include "utils/Logger.h" @@ -78,7 +81,7 @@ SourceDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& SourceTreeItem* item = index.data( SourcesModel::SourceTreeItemRole ).value< SourceTreeItem* >(); SourcesModel::RowType type = static_cast< SourcesModel::RowType >( index.data( SourcesModel::SourceTreeItemTypeRole ).toInt() ); - if ( type == SourcesModel::Collection ) + if ( type == SourcesModel::Collection || type == SourcesModel::ScriptCollection ) { return QSize( option.rect.width(), option.fontMetrics.height() * 3.0 ); } @@ -161,23 +164,54 @@ SourceDelegate::paintCollection( QPainter* painter, const QStyleOptionViewItem& figFont.setPointSize( normal.pointSize() - 1 ); 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 = QFontMetrics( figFont ).width( tracks ); - name = colItem->source()->friendlyName(); - } + SourcesModel::RowType type = static_cast< SourcesModel::RowType >( index.data( SourcesModel::SourceTreeItemTypeRole ).toInt() ); QRect iconRect = option.rect.adjusted( 4, 6, -option.rect.width() + option.rect.height() - 12 + 4, -6 ); - QPixmap avatar = colItem->pixmap( iconRect.size() ); + QString name = index.data().toString(); + QPixmap avatar; + int figWidth = 0; + bool isPlaying = false; + QString desc; + QString tracks; + + if ( type == SourcesModel::Collection ) + { + SourceItem* colItem = qobject_cast< SourceItem* >( item ); + Q_ASSERT( colItem ); + bool status = !( !colItem || colItem->source().isNull() || !colItem->source()->isOnline() ); + + if ( status && colItem && !colItem->source().isNull() ) + { + tracks = QString::number( colItem->source()->trackCount() ); + figWidth = QFontMetrics( figFont ).width( tracks ); + name = colItem->source()->friendlyName(); + } + + avatar = colItem->pixmap( iconRect.size() ); + + if ( status || colItem->source().isNull() ) + painter->setFont( bold ); + + isPlaying = !( colItem->source()->currentTrack().isNull() ); + desc = colItem->source()->textStatus(); + if ( colItem->source().isNull() ) + desc = tr( "All available tracks" ); + } + else if ( type == SourcesModel::ScriptCollection ) + { + ScriptCollectionItem* scItem = qobject_cast< ScriptCollectionItem* >( item ); + Q_ASSERT( scItem ); + + if ( !scItem->collection().isNull() ) + { + name = scItem->collection()->itemName(); + } + + avatar = scItem->icon().pixmap( iconRect.size() ); + + desc = qobject_cast< Tomahawk::ScriptCollection* >( scItem->collection().data() )->description(); + } + painter->drawPixmap( iconRect, avatar ); if ( ( option.state & QStyle::State_Selected ) == QStyle::State_Selected ) @@ -186,75 +220,75 @@ SourceDelegate::paintCollection( QPainter* painter, const QStyleOptionViewItem& } QRect textRect = option.rect.adjusted( iconRect.width() + 8, 6, -figWidth - 28, 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 = !( colItem->source()->currentTrack().isNull() ); - QString desc = colItem->source()->textStatus(); QColor descColor = QColor( "#8d8d8d" ); - if ( colItem->source().isNull() ) - desc = tr( "All available tracks" ); painter->setFont( normal ); textRect = option.rect.adjusted( iconRect.width() + 8, option.rect.height() / 2, -figWidth - 24, -6 ); - bool privacyOn = TomahawkSettings::instance()->privateListeningMode() == TomahawkSettings::FullyPrivate; - if ( !colItem->source().isNull() && colItem->source()->isLocal() && privacyOn ) + if ( type == SourcesModel::Collection ) { - QRect pmRect = textRect; - 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 - TomahawkUtils::ImageType listenAlongPixmap = TomahawkUtils::Invalid; - TomahawkUtils::ImageType realtimeListeningAlongPixmap = TomahawkUtils::Invalid; - if ( index.data( SourcesModel::LatchedOnRole ).toBool() ) + SourceItem* colItem = qobject_cast< SourceItem* >( item ); + Q_ASSERT( colItem ); + + bool privacyOn = TomahawkSettings::instance()->privateListeningMode() == TomahawkSettings::FullyPrivate; + if ( !colItem->source().isNull() && colItem->source()->isLocal() && privacyOn ) { - // Currently listening along - listenAlongPixmap = TomahawkUtils::HeadphonesOn; - if ( !colItem->source()->isLocal() ) + QRect pmRect = textRect; + 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 + TomahawkUtils::ImageType listenAlongPixmap = TomahawkUtils::Invalid; + TomahawkUtils::ImageType realtimeListeningAlongPixmap = TomahawkUtils::Invalid; + if ( index.data( SourcesModel::LatchedOnRole ).toBool() ) { - realtimeListeningAlongPixmap = - colItem->source()->playlistInterface()->latchMode() == Tomahawk::PlaylistModes::RealTime ? - TomahawkUtils::PadlockClosed : TomahawkUtils::PadlockOpen; + // Currently listening along + listenAlongPixmap = TomahawkUtils::HeadphonesOn; + if ( !colItem->source()->isLocal() ) + { + realtimeListeningAlongPixmap = + colItem->source()->playlistInterface()->latchMode() == Tomahawk::PlaylistModes::RealTime ? + TomahawkUtils::PadlockClosed : TomahawkUtils::PadlockOpen; + } } + else if ( !colItem->source()->isLocal() ) + { + listenAlongPixmap = TomahawkUtils::HeadphonesOff; + } + + if ( listenAlongPixmap != TomahawkUtils::Invalid ) + { + QRect pmRect = textRect; + pmRect.setRight( pmRect.left() + pmRect.height() ); + painter->drawPixmap( pmRect, TomahawkUtils::defaultPixmap( listenAlongPixmap, TomahawkUtils::Original, pmRect.size() ) ); + textRect.adjust( pmRect.width() + 3, 0, 0, 0 ); + + m_headphoneRects[ index ] = pmRect; + } + else + m_headphoneRects.remove( index ); + + if ( realtimeListeningAlongPixmap != TomahawkUtils::Invalid ) + { + QRect pmRect = textRect; + pmRect.setRight( pmRect.left() + pmRect.height() ); + painter->drawPixmap( pmRect, TomahawkUtils::defaultPixmap( realtimeListeningAlongPixmap, TomahawkUtils::Original, pmRect.size() ) ); + textRect.adjust( pmRect.width() + 3, 0, 0, 0 ); + + m_lockRects[ index ] = pmRect; + } + else + m_lockRects.remove( index ); + + if ( isPlaying ) + descColor = Qt::black; } - else if ( !colItem->source()->isLocal() ) - { - listenAlongPixmap = TomahawkUtils::HeadphonesOff; - } - - if ( listenAlongPixmap != TomahawkUtils::Invalid ) - { - QRect pmRect = textRect; - pmRect.setRight( pmRect.left() + pmRect.height() ); - painter->drawPixmap( pmRect, TomahawkUtils::defaultPixmap( listenAlongPixmap, TomahawkUtils::Original, pmRect.size() ) ); - textRect.adjust( pmRect.width() + 3, 0, 0, 0 ); - - m_headphoneRects[ index ] = pmRect; - } - else - m_headphoneRects.remove( index ); - - if ( realtimeListeningAlongPixmap != TomahawkUtils::Invalid ) - { - QRect pmRect = textRect; - pmRect.setRight( pmRect.left() + pmRect.height() ); - painter->drawPixmap( pmRect, TomahawkUtils::defaultPixmap( realtimeListeningAlongPixmap, TomahawkUtils::Original, pmRect.size() ) ); - textRect.adjust( pmRect.width() + 3, 0, 0, 0 ); - - m_lockRects[ index ] = pmRect; - } - else - m_lockRects.remove( index ); - - if ( isPlaying ) - descColor = Qt::black; } if ( m_trackHovered == index ) @@ -270,26 +304,33 @@ SourceDelegate::paintCollection( QPainter* painter, const QStyleOptionViewItem& painter->setPen( descColor ); painter->drawText( textRect, text, to ); - if ( colItem->source() && colItem->source()->currentTrack() && colItem->source()->state() == DBSyncConnection::SYNCED ) - m_trackRects[ index ] = textRect.adjusted( 0, 0, -textRect.width() + painter->fontMetrics().width( text ), 0 ); - else - m_trackRects.remove( index ); - - if ( status ) + if ( type == SourcesModel::Collection ) { - painter->setRenderHint( QPainter::Antialiasing ); + SourceItem* colItem = qobject_cast< SourceItem* >( item ); + Q_ASSERT( colItem ); + bool status = !( !colItem || colItem->source().isNull() || !colItem->source()->isOnline() ); - QRect figRect = option.rect.adjusted( option.rect.width() - figWidth - 13, 0, -14, -option.rect.height() + option.fontMetrics.height() * 1.1 ); - int hd = ( option.rect.height() - figRect.height() ) / 2; - figRect.adjust( 0, hd, 0, hd ); + if ( colItem->source() && colItem->source()->currentTrack() && colItem->source()->state() == DBSyncConnection::SYNCED ) + m_trackRects[ index ] = textRect.adjusted( 0, 0, -textRect.width() + painter->fontMetrics().width( text ), 0 ); + else + m_trackRects.remove( index ); - painter->setFont( figFont ); + if ( status ) + { + painter->setRenderHint( QPainter::Antialiasing ); - QColor figColor( 167, 183, 211 ); - painter->setPen( figColor ); - painter->setBrush( figColor ); + QRect figRect = option.rect.adjusted( option.rect.width() - figWidth - 13, 0, -14, -option.rect.height() + option.fontMetrics.height() * 1.1 ); + int hd = ( option.rect.height() - figRect.height() ) / 2; + figRect.adjust( 0, hd, 0, hd ); - TomahawkUtils::drawBackgroundAndNumbers( painter, tracks, figRect ); + painter->setFont( figFont ); + + QColor figColor( 167, 183, 211 ); + painter->setPen( figColor ); + painter->setBrush( figColor ); + + TomahawkUtils::drawBackgroundAndNumbers( painter, tracks, figRect ); + } } painter->restore(); @@ -430,7 +471,7 @@ SourceDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, co if ( type != SourcesModel::Group && type != SourcesModel::Category && type != SourcesModel::Divider ) QApplication::style()->drawControl( QStyle::CE_ItemViewItem, &o3, painter ); - if ( type == SourcesModel::Collection ) + if ( type == SourcesModel::Collection || type == SourcesModel::ScriptCollection ) { paintCollection( painter, o, index ); } diff --git a/src/sourcetree/SourcesModel.cpp b/src/sourcetree/SourcesModel.cpp index 84e95a49e..ae3a8c18a 100644 --- a/src/sourcetree/SourcesModel.cpp +++ b/src/sourcetree/SourcesModel.cpp @@ -25,6 +25,7 @@ #include +#include "sourcetree/items/ScriptCollectionItem.h" #include "sourcetree/items/SourceTreeItem.h" #include "sourcetree/items/SourceItem.h" #include "sourcetree/items/GroupItem.h" @@ -515,12 +516,9 @@ SourcesModel::onScriptCollectionAdded( const collection_ptr& collection ) QModelIndex parent = indexFromItem( m_cloudGroup ); beginInsertRows( parent, rowCount( parent ), rowCount( parent ) ); - GenericPageItem* item = new GenericPageItem( this, + ScriptCollectionItem* item = new ScriptCollectionItem( this, m_cloudGroup, - collection->itemName(), - collection->icon(), - boost::bind( &SourcesModel::scriptCollectionClicked, this, collection ), - boost::bind( &SourcesModel::getScriptCollectionPage, this, collection ) ); + collection ); endInsertRows(); m_scriptCollections.insert( collection, item ); diff --git a/src/sourcetree/SourcesModel.h b/src/sourcetree/SourcesModel.h index 80c1f55b7..37e6a43c3 100644 --- a/src/sourcetree/SourcesModel.h +++ b/src/sourcetree/SourcesModel.h @@ -61,7 +61,9 @@ public: GenericPage = 6, TemporaryPage = 7, - LovedTracksPage = 10 + LovedTracksPage = 10, + + ScriptCollection = 11 }; enum CategoryType { diff --git a/src/sourcetree/items/ScriptCollectionItem.cpp b/src/sourcetree/items/ScriptCollectionItem.cpp new file mode 100644 index 000000000..52162bdc6 --- /dev/null +++ b/src/sourcetree/items/ScriptCollectionItem.cpp @@ -0,0 +1,93 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2013, Teo Mrnjavac + * + * 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 . + */ + +#include "ScriptCollectionItem.h" + +#include "audio/AudioEngine.h" +#include "ViewManager.h" + +ScriptCollectionItem::ScriptCollectionItem( SourcesModel* model, + SourceTreeItem* parent, + const Tomahawk::collection_ptr& collection ) + : SourceTreeItem( model, parent, SourcesModel::ScriptCollection ) + , m_collection( collection ) + , m_page( 0 ) +{} + + +ScriptCollectionItem::~ScriptCollectionItem() +{ + model()->removeSourceItemLink( this ); +} + + +void +ScriptCollectionItem::activate() +{ + m_page = ViewManager::instance()->show( m_collection ); + model()->linkSourceItemToPage( this, m_page ); +} + + +QString +ScriptCollectionItem::text() const +{ + return m_collection->prettyName(); +} + + +QString +ScriptCollectionItem::tooltip() const +{ + return m_collection->prettyName(); +} + + +QIcon +ScriptCollectionItem::icon() const +{ + return m_collection->icon(); +} + + +bool +ScriptCollectionItem::isBeingPlayed() const +{ + if ( m_page ) + { + if ( m_page->isBeingPlayed() ) + return true; + + if ( !m_page->playlistInterface().isNull() && + m_page->playlistInterface() == AudioEngine::instance()->currentTrackPlaylist() ) + return true; + + if ( !m_page->playlistInterface().isNull() && + m_page->playlistInterface()->hasChildInterface( AudioEngine::instance()->currentTrackPlaylist() ) ) + return true; + } + return false; +} + + +Tomahawk::collection_ptr +ScriptCollectionItem::collection() const +{ + return m_collection; +} + diff --git a/src/sourcetree/items/ScriptCollectionItem.h b/src/sourcetree/items/ScriptCollectionItem.h new file mode 100644 index 000000000..74a476d39 --- /dev/null +++ b/src/sourcetree/items/ScriptCollectionItem.h @@ -0,0 +1,49 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2013, Teo Mrnjavac + * + * 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 . + */ + +#ifndef SCRIPTCOLLECTIONITEM_H +#define SCRIPTCOLLECTIONITEM_H + +#include "SourceTreeItem.h" + +class ScriptCollectionItem : public SourceTreeItem +{ + Q_OBJECT +public: + explicit ScriptCollectionItem( SourcesModel* model, + SourceTreeItem* parent, + const Tomahawk::collection_ptr& collection ); + + virtual ~ScriptCollectionItem(); + virtual void activate(); + virtual QString text() const; + virtual QString tooltip() const; + virtual QIcon icon() const; + virtual bool isBeingPlayed() const; + + virtual Tomahawk::collection_ptr collection() const; + +private: + QIcon m_icon; + QString m_text; + + Tomahawk::collection_ptr m_collection; + Tomahawk::ViewPage* m_page; +}; + +#endif // SCRIPTCOLLECTIONITEM_H