diff --git a/data/images/no-album-art-placeholder.png b/data/images/no-album-art-placeholder.png index a117306e2..d7f2bb28c 100644 Binary files a/data/images/no-album-art-placeholder.png and b/data/images/no-album-art-placeholder.png differ diff --git a/data/images/no-album-no-case.png b/data/images/no-album-no-case.png index 1fbbbb8bf..963cdaa3d 100644 Binary files a/data/images/no-album-no-case.png and b/data/images/no-album-no-case.png differ diff --git a/data/images/no-artist-image-placeholder.png b/data/images/no-artist-image-placeholder.png index 4b0eba323..559a858d4 100644 Binary files a/data/images/no-artist-image-placeholder.png and b/data/images/no-artist-image-placeholder.png differ diff --git a/src/audiocontrols.cpp b/src/audiocontrols.cpp index f536be7c6..f6211ca06 100644 --- a/src/audiocontrols.cpp +++ b/src/audiocontrols.cpp @@ -100,8 +100,6 @@ AudioControls::AudioControls( QWidget* parent ) m_sliderTimeLine.setCurveShape( QTimeLine::LinearCurve ); ui->seekSlider->setTimeLine( &m_sliderTimeLine ); - m_defaultCover = QPixmap( RESPATH "images/no-album-no-case.png" ).scaled( ui->coverImage->size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation ); - connect( &m_phononTickCheckTimer, SIGNAL( timeout() ), SLOT( phononTickCheckTimeout() ) ); connect( &m_sliderTimeLine, SIGNAL( frameChanged( int ) ), ui->seekSlider, SLOT( setValue( int ) ) ); @@ -264,14 +262,14 @@ AudioControls::onAlbumCoverUpdated() void AudioControls::setAlbumCover() { - if ( !m_currentTrack->album()->cover().isNull() ) + if ( !m_currentTrack->album()->cover( ui->coverImage->size() ).isNull() ) { QPixmap cover; - cover.loadFromData( m_currentTrack->album()->cover() ); - ui->coverImage->setPixmap( cover.scaled( ui->coverImage->size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation ) ); + cover = m_currentTrack->album()->cover( ui->coverImage->size() ); + ui->coverImage->setPixmap( cover ); } else - ui->coverImage->setPixmap( m_defaultCover ); + ui->coverImage->setPixmap( TomahawkUtils::defaultPixmap( TomahawkUtils::DefaultAlbumCover, TomahawkUtils::ScaledCover, ui->coverImage->size() ) ); } @@ -279,10 +277,16 @@ void AudioControls::onSocialActionsLoaded() { Query* query = qobject_cast< Query* >( sender() ); - if ( !query || query != m_currentTrack->toQuery().data() ) + if ( !query ) return; - setSocialActions(); + query_ptr currentQuery = m_currentTrack->toQuery(); + if ( query->artist() == currentQuery->artist() && + query->track() == currentQuery->track() && + query->album() == currentQuery->album() ) + { + setSocialActions(); + } } diff --git a/src/audiocontrols.h b/src/audiocontrols.h index 7d7de87c6..651f1dbf8 100644 --- a/src/audiocontrols.h +++ b/src/audiocontrols.h @@ -91,8 +91,6 @@ private: Ui::AudioControls *ui; - QPixmap m_defaultCover; - Tomahawk::result_ptr m_currentTrack; Tomahawk::PlaylistInterface::RepeatMode m_repeatMode; bool m_shuffled; diff --git a/src/libtomahawk/album.cpp b/src/libtomahawk/album.cpp index fd56e8409..c877b80a5 100644 --- a/src/libtomahawk/album.cpp +++ b/src/libtomahawk/album.cpp @@ -32,6 +32,7 @@ using namespace Tomahawk; Album::~Album() { + delete m_cover; } @@ -71,6 +72,7 @@ Album::Album( unsigned int id, const QString& name, const Tomahawk::artist_ptr& , m_id( id ) , m_name( name ) , m_artist( artist ) + , m_cover( 0 ) , m_infoLoaded( false ) { connect( Tomahawk::InfoSystem::InfoSystem::instance(), @@ -97,11 +99,14 @@ Album::artist() const } -QByteArray -Album::cover() const +#ifndef ENABLE_HEADLESS +QPixmap +Album::cover( const QSize& size, bool forceLoad ) const { if ( !m_infoLoaded ) { + if ( !forceLoad ) + return QPixmap(); m_uuid = uuid(); Tomahawk::InfoSystem::InfoStringHash trackInfo; @@ -117,8 +122,31 @@ Album::cover() const Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData ); } - return m_cover; + if ( !m_cover && !m_coverBuffer.isEmpty() ) + { + m_cover = new QPixmap(); + m_cover->loadFromData( m_coverBuffer ); + } + + if ( m_cover && !m_cover->isNull() && !size.isEmpty() ) + { + if ( m_coverCache.contains( size.width() ) ) + { + return m_coverCache.value( size.width() ); + } + + QPixmap scaledCover; + scaledCover = m_cover->scaled( size, Qt::KeepAspectRatio, Qt::SmoothTransformation ); + m_coverCache.insert( size.width(), scaledCover ); + return scaledCover; + } + + if ( m_cover ) + return *m_cover; + else + return QPixmap(); } +#endif void @@ -137,7 +165,7 @@ Album::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVaria const QByteArray ba = returnedData["imgbytes"].toByteArray(); if ( ba.length() ) { - m_cover = ba; + m_coverBuffer = ba; } } diff --git a/src/libtomahawk/album.h b/src/libtomahawk/album.h index b929e9b49..741c7d65a 100644 --- a/src/libtomahawk/album.h +++ b/src/libtomahawk/album.h @@ -19,8 +19,13 @@ #ifndef TOMAHAWKALBUM_H #define TOMAHAWKALBUM_H +#include "config.h" + #include #include +#ifndef ENABLE_HEADLESS + #include +#endif #include "typedefs.h" #include "playlistinterface.h" @@ -44,7 +49,9 @@ public: unsigned int id() const { return m_id; } QString name() const { return m_name; } artist_ptr artist() const; - QByteArray cover() const; +#ifndef ENABLE_HEADLESS + QPixmap cover( const QSize& size, bool forceLoad = true ) const; +#endif bool infoLoaded() const { return m_infoLoaded; } Tomahawk::playlistinterface_ptr playlistInterface(); @@ -64,10 +71,13 @@ private: unsigned int m_id; QString m_name; artist_ptr m_artist; - QByteArray m_cover; + QByteArray m_coverBuffer; + mutable QPixmap* m_cover; bool m_infoLoaded; mutable QString m_uuid; + mutable QHash< int, QPixmap > m_coverCache; + Tomahawk::playlistinterface_ptr m_playlistInterface; }; diff --git a/src/libtomahawk/artist.cpp b/src/libtomahawk/artist.cpp index 0c0ba332c..18937c4a8 100644 --- a/src/libtomahawk/artist.cpp +++ b/src/libtomahawk/artist.cpp @@ -31,6 +31,7 @@ using namespace Tomahawk; Artist::~Artist() { + delete m_cover; } @@ -69,6 +70,7 @@ Artist::Artist( unsigned int id, const QString& name ) : QObject() , m_id( id ) , m_name( name ) + , m_cover( 0 ) , m_infoLoaded( false ) { m_sortname = DatabaseImpl::sortname( name, true ); @@ -89,11 +91,14 @@ Artist::onTracksAdded( const QList& tracks ) } -QByteArray -Artist::cover() const +#ifndef ENABLE_HEADLESS +QPixmap +Artist::cover( const QSize& size, bool forceLoad ) const { if ( !m_infoLoaded ) { + if ( !forceLoad ) + return QPixmap(); m_uuid = uuid(); Tomahawk::InfoSystem::InfoStringHash trackInfo; @@ -108,8 +113,31 @@ Artist::cover() const Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData ); } - return m_cover; + if ( !m_cover && !m_coverBuffer.isEmpty() ) + { + m_cover = new QPixmap(); + m_cover->loadFromData( m_coverBuffer ); + } + + if ( m_cover && !m_cover->isNull() && !size.isEmpty() ) + { + if ( m_coverCache.contains( size.width() ) ) + { + return m_coverCache.value( size.width() ); + } + + QPixmap scaledCover; + scaledCover = m_cover->scaled( size, Qt::KeepAspectRatio, Qt::SmoothTransformation ); + m_coverCache.insert( size.width(), scaledCover ); + return scaledCover; + } + + if ( m_cover ) + return *m_cover; + else + return QPixmap(); } +#endif void @@ -128,7 +156,7 @@ Artist::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVari const QByteArray ba = returnedData["imgbytes"].toByteArray(); if ( ba.length() ) { - m_cover = ba; + m_coverBuffer = ba; } } diff --git a/src/libtomahawk/artist.h b/src/libtomahawk/artist.h index 3e1442023..05efe48eb 100644 --- a/src/libtomahawk/artist.h +++ b/src/libtomahawk/artist.h @@ -19,8 +19,13 @@ #ifndef TOMAHAWKARTIST_H #define TOMAHAWKARTIST_H +#include "config.h" + #include #include +#ifndef ENABLE_HEADLESS + #include +#endif #include "typedefs.h" #include "dllmacro.h" @@ -43,7 +48,9 @@ public: unsigned int id() const { return m_id; } QString name() const { return m_name; } QString sortname() const { return m_sortname; } - QByteArray cover() const; +#ifndef ENABLE_HEADLESS + QPixmap cover( const QSize& size, bool forceLoad = true ) const; +#endif bool infoLoaded() const { return m_infoLoaded; } Tomahawk::playlistinterface_ptr playlistInterface(); @@ -63,10 +70,13 @@ private: unsigned int m_id; QString m_name; QString m_sortname; - QByteArray m_cover; + QByteArray m_coverBuffer; + mutable QPixmap* m_cover; bool m_infoLoaded; mutable QString m_uuid; + mutable QHash< int, QPixmap > m_coverCache; + Tomahawk::playlistinterface_ptr m_playlistInterface; }; diff --git a/src/libtomahawk/audio/audioengine.cpp b/src/libtomahawk/audio/audioengine.cpp index 226d99a3f..5d4be8afc 100644 --- a/src/libtomahawk/audio/audioengine.cpp +++ b/src/libtomahawk/audio/audioengine.cpp @@ -18,6 +18,8 @@ #include "audioengine.h" +#include "config.h" + #include #include @@ -328,13 +330,15 @@ AudioEngine::sendWaitingNotificationSlot() const void AudioEngine::sendNowPlayingNotification() { +#ifndef ENABLE_HEADLESS if ( m_currentTrack->album().isNull() || m_currentTrack->album()->infoLoaded() ) onNowPlayingInfoReady(); else { connect( m_currentTrack->album().data(), SIGNAL( updated() ), SLOT( onNowPlayingInfoReady() ), Qt::UniqueConnection ); - m_currentTrack->album()->cover(); + m_currentTrack->album()->cover( QSize( 0, 0 ) ); } +#endif } @@ -357,9 +361,11 @@ AudioEngine::onNowPlayingInfoReady() if ( !m_currentTrack->album().isNull() ) { +#ifndef ENABLE_HEADLESS QImage cover; - cover.loadFromData( m_currentTrack->album()->cover() ); + cover = m_currentTrack->album()->cover( QSize( 0, 0 ) ).toImage(); playInfo["image"] = QVariant( cover ); +#endif } Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo( diff --git a/src/libtomahawk/contextmenu.cpp b/src/libtomahawk/contextmenu.cpp index 558b9cb29..de5122a05 100644 --- a/src/libtomahawk/contextmenu.cpp +++ b/src/libtomahawk/contextmenu.cpp @@ -88,6 +88,7 @@ ContextMenu::setQueries( const QList& queries ) m_sigmap->setMapping( m_loveAction, ActionLove ); connect( queries.first().data(), SIGNAL( socialActionsLoaded() ), SLOT( onSocialActionsLoaded() ) ); + m_queries.first()->loadSocialActions(); onSocialActionsLoaded(); } diff --git a/src/libtomahawk/database/databasecommand_allalbums.cpp b/src/libtomahawk/database/databasecommand_allalbums.cpp index f0b731291..5de1f6be0 100644 --- a/src/libtomahawk/database/databasecommand_allalbums.cpp +++ b/src/libtomahawk/database/databasecommand_allalbums.cpp @@ -169,7 +169,6 @@ DatabaseCommand_AllAlbums::execForCollection( DatabaseImpl* dbi ) void DatabaseCommand_AllAlbums::exec( DatabaseImpl* dbi ) { - return; if ( !m_artist.isNull() ) { execForArtist( dbi ); diff --git a/src/libtomahawk/database/databasecommand_resolve.cpp b/src/libtomahawk/database/databasecommand_resolve.cpp index 1384f828e..ae6e92910 100644 --- a/src/libtomahawk/database/databasecommand_resolve.cpp +++ b/src/libtomahawk/database/databasecommand_resolve.cpp @@ -20,6 +20,7 @@ #include "artist.h" #include "album.h" +#include "pipeline.h" #include "sourcelist.h" #include "utils/logger.h" @@ -30,10 +31,14 @@ DatabaseCommand_Resolve::DatabaseCommand_Resolve( const query_ptr& query ) : DatabaseCommand() , m_query( query ) { + Q_ASSERT( Pipeline::instance()->isRunning() ); } + DatabaseCommand_Resolve::~DatabaseCommand_Resolve() -{} +{ +} + void DatabaseCommand_Resolve::exec( DatabaseImpl* lib ) diff --git a/src/libtomahawk/infosystem/infoplugins/generic/spotifyPlugin.cpp b/src/libtomahawk/infosystem/infoplugins/generic/spotifyPlugin.cpp index f91476752..bcff0d24b 100644 --- a/src/libtomahawk/infosystem/infoplugins/generic/spotifyPlugin.cpp +++ b/src/libtomahawk/infosystem/infoplugins/generic/spotifyPlugin.cpp @@ -43,7 +43,6 @@ SpotifyPlugin::SpotifyPlugin() : InfoPlugin() , m_chartsFetchJobs( 0 ) { - m_supportedGetTypes << InfoChart << InfoChartCapabilities; } @@ -71,7 +70,6 @@ SpotifyPlugin::getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ) InfoStringHash hash = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >(); - switch ( requestData.type ) { case InfoChart: @@ -87,6 +85,7 @@ SpotifyPlugin::getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ) case InfoChartCapabilities: fetchChartCapabilities( requestData ); break; + default: dataError( requestData ); } @@ -110,7 +109,6 @@ SpotifyPlugin::fetchChart( Tomahawk::InfoSystem::InfoRequestData requestData ) tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Hash did not contain required params!"; dataError( requestData ); return; - } /// Set the criterias for current chart criteria["chart_id"] = hash["chart_id"]; @@ -118,6 +116,8 @@ SpotifyPlugin::fetchChart( Tomahawk::InfoSystem::InfoRequestData requestData ) emit getCachedInfo( criteria, 86400000 /* Expire chart cache in 1 day */, requestData ); } + + void SpotifyPlugin::fetchChartCapabilities( Tomahawk::InfoSystem::InfoRequestData requestData ) { @@ -132,12 +132,12 @@ SpotifyPlugin::fetchChartCapabilities( Tomahawk::InfoSystem::InfoRequestData req emit getCachedInfo( criteria, 604800000, requestData ); } + void SpotifyPlugin::notInCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData ) { switch ( requestData.type ) { - case InfoChart: { /// Fetch the chart, we need source and id @@ -149,8 +149,6 @@ SpotifyPlugin::notInCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, To reply->setProperty( "requestData", QVariant::fromValue< Tomahawk::InfoSystem::InfoRequestData >( requestData ) ); connect( reply, SIGNAL( finished() ), SLOT( chartReturned() ) ); return; - - } case InfoChartCapabilities: { @@ -212,9 +210,8 @@ SpotifyPlugin::chartTypes() } QVariantMap charts; - foreach(QVariant geos, chartObj.value("Charts").toList().takeLast().toMap().value("geo").toList() ) + foreach( QVariant geos, chartObj.value( "Charts" ).toList().takeLast().toMap().value( "geo" ).toList() ) { - const QString geo = geos.toMap().value( "name" ).toString(); const QString geoId = geos.toMap().value( "id" ).toString(); QString country; @@ -225,7 +222,6 @@ SpotifyPlugin::chartTypes() country = geo; else { - QLocale l( QString( "en_%1" ).arg( geo ) ); country = Tomahawk::CountryUtils::fullCountryFromCode( geo ); @@ -240,7 +236,7 @@ SpotifyPlugin::chartTypes() } QList< InfoStringHash > chart_types; - foreach(QVariant types, chartObj.value("Charts").toList().takeFirst().toMap().value("types").toList() ) + foreach( QVariant types, chartObj.value( "Charts" ).toList().takeFirst().toMap().value( "types" ).toList() ) { QString type = types.toMap().value( "id" ).toString(); QString label = types.toMap().value( "name" ).toString(); @@ -251,18 +247,15 @@ SpotifyPlugin::chartTypes() c[ "type" ] = type; chart_types.append( c ); - } charts.insert( country.toUtf8(), QVariant::fromValue >( chart_types ) ); - } QVariantMap defaultMap; defaultMap[ "spotify" ] = QStringList() << "United States" << "Top Albums"; m_allChartsMap[ "defaults" ] = defaultMap; m_allChartsMap.insert( "Spotify", QVariant::fromValue( charts ) ); - } else { @@ -281,13 +274,12 @@ SpotifyPlugin::chartTypes() } m_cachedRequests.clear(); } - } + void SpotifyPlugin::chartReturned() { - /// Chart request returned something! Woho QNetworkReply* reply = qobject_cast( sender() ); QString url = reply->url().toString(); @@ -318,14 +310,13 @@ SpotifyPlugin::chartReturned() else setChartType( None ); - foreach(QVariant result, res.value("toplist").toMap().value("result").toList() ) + foreach( QVariant result, res.value( "toplist" ).toMap().value( "result" ).toList() ) { QString title, artist; QVariantMap chartMap = result.toMap(); if ( !chartMap.isEmpty() ) { - title = chartMap.value( "title" ).toString(); artist = chartMap.value( "artist" ).toString(); @@ -341,7 +332,6 @@ SpotifyPlugin::chartReturned() if( chartType() == Album ) { - InfoStringHash pair; pair["artist"] = artist; pair["album"] = title; @@ -351,10 +341,8 @@ SpotifyPlugin::chartReturned() if( chartType() == Artist ) { - top_artists << chartMap.value( "name" ).toString(); qDebug() << "SpotifyChart type is artist"; - } } } @@ -393,5 +381,4 @@ SpotifyPlugin::chartReturned() } else qDebug() << "Network error in fetching chart:" << reply->url().toString(); - } diff --git a/src/libtomahawk/pipeline.cpp b/src/libtomahawk/pipeline.cpp index 2b25caa14..6184875b1 100644 --- a/src/libtomahawk/pipeline.cpp +++ b/src/libtomahawk/pipeline.cpp @@ -61,6 +61,7 @@ Pipeline::Pipeline( QObject* parent ) Pipeline::~Pipeline() { + tDebug() << Q_FUNC_INFO; m_running = false; // stop script resolvers @@ -418,10 +419,11 @@ Pipeline::shunt( const query_ptr& q ) r->resolve( q ); emit resolving( q ); - m_qidsTimeout.insert( q->id(), true ); - if ( r->timeout() > 0 ) + { + m_qidsTimeout.insert( q->id(), true ); new FuncTimeout( r->timeout(), boost::bind( &Pipeline::timeoutShunt, this, q ), this ); + } } else { diff --git a/src/libtomahawk/pipeline.h b/src/libtomahawk/pipeline.h index 5fa88a2d7..50e33ab57 100644 --- a/src/libtomahawk/pipeline.h +++ b/src/libtomahawk/pipeline.h @@ -48,6 +48,8 @@ public: explicit Pipeline( QObject* parent = 0 ); virtual ~Pipeline(); + bool isRunning() const { return m_running; } + unsigned int pendingQueryCount() const { return m_queries_pending.count(); } unsigned int activeQueryCount() const { return m_qidsState.count(); } diff --git a/src/libtomahawk/playlist/albumitemdelegate.cpp b/src/libtomahawk/playlist/albumitemdelegate.cpp index e28208248..b8c9072d2 100644 --- a/src/libtomahawk/playlist/albumitemdelegate.cpp +++ b/src/libtomahawk/playlist/albumitemdelegate.cpp @@ -40,7 +40,6 @@ AlbumItemDelegate::AlbumItemDelegate( QAbstractItemView* parent, AlbumProxyModel , m_view( parent ) , m_model( proxy ) { - m_defaultCover = QPixmap( RESPATH "images/no-album-art-placeholder.png" ); } @@ -89,21 +88,19 @@ AlbumItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, painter->drawLine( shadowRect.bottomLeft() + QPoint( 0, 4 ), shadowRect.bottomRight() + QPoint( 0, 4 ) ); } + QRect r = option.rect.adjusted( 6, 5, -6, -41 ); QPixmap cover; if ( !item->album().isNull() ) { - cover.loadFromData( item->album()->cover() ); + cover = item->album()->cover( r.size() ); + if ( cover.isNull() ) + cover = TomahawkUtils::defaultPixmap( TomahawkUtils::DefaultAlbumCover, TomahawkUtils::CoverInCase, r.size() ); } else if ( !item->artist().isNull() ) { - cover.loadFromData( item->artist()->cover() ); + cover = item->artist()->cover( r.size() ); } - if ( cover.isNull() ) - cover = m_defaultCover; - - QRect r = option.rect.adjusted( 6, 5, -6, -41 ); - if ( option.state & QStyle::State_Selected ) { #if defined(Q_WS_MAC) || defined(Q_WS_WIN) @@ -123,17 +120,7 @@ AlbumItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, #endif } - QPixmap scover; - if ( m_cache.contains( cover.cacheKey() ) ) - { - scover = m_cache.value( cover.cacheKey() ); - } - else - { - scover = cover.scaled( r.size(), Qt::KeepAspectRatio, Qt::SmoothTransformation ); - m_cache.insert( cover.cacheKey(), scover ); - } - painter->drawPixmap( r, scover ); + painter->drawPixmap( r, cover ); painter->setPen( opt.palette.color( QPalette::Text ) ); QTextOption to; diff --git a/src/libtomahawk/playlist/albumitemdelegate.h b/src/libtomahawk/playlist/albumitemdelegate.h index 86b31bdf5..7d29f6c81 100644 --- a/src/libtomahawk/playlist/albumitemdelegate.h +++ b/src/libtomahawk/playlist/albumitemdelegate.h @@ -49,12 +49,10 @@ private: QAbstractItemView* m_view; AlbumProxyModel* m_model; - mutable QHash< qint64, QPixmap > m_cache; mutable QHash< QPersistentModelIndex, QRect > m_artistNameRects; QPersistentModelIndex m_hoveringOver; QPixmap m_shadowPixmap; - QPixmap m_defaultCover; }; #endif // ALBUMITEMDELEGATE_H diff --git a/src/libtomahawk/playlist/artistview.cpp b/src/libtomahawk/playlist/artistview.cpp index 808b6c8c5..ff83b2eeb 100644 --- a/src/libtomahawk/playlist/artistview.cpp +++ b/src/libtomahawk/playlist/artistview.cpp @@ -80,6 +80,11 @@ ArtistView::ArtistView( QWidget* parent ) setFont( f ); #endif + m_timer.setInterval( SCROLL_TIMEOUT ); + connect( verticalScrollBar(), SIGNAL( rangeChanged( int, int ) ), SLOT( onViewChanged() ) ); + connect( verticalScrollBar(), SIGNAL( valueChanged( int ) ), SLOT( onViewChanged() ) ); + connect( &m_timer, SIGNAL( timeout() ), SLOT( onScrollTimeout() ) ); + connect( this, SIGNAL( doubleClicked( QModelIndex ) ), SLOT( onItemActivated( QModelIndex ) ) ); connect( this, SIGNAL( customContextMenuRequested( const QPoint& ) ), SLOT( onCustomContextMenu( const QPoint& ) ) ); connect( m_contextMenu, SIGNAL( triggered( int ) ), SLOT( onMenuTriggered( int ) ) ); @@ -129,6 +134,7 @@ ArtistView::setTreeModel( TreeModel* model ) connect( m_model, SIGNAL( itemCountChanged( unsigned int ) ), SLOT( onItemCountChanged( unsigned int ) ) ); connect( m_proxyModel, SIGNAL( filterChanged( QString ) ), SLOT( onFilterChanged( QString ) ) ); + connect( m_proxyModel, SIGNAL( rowsInserted( QModelIndex, int, int ) ), SLOT( onViewChanged() ) ); guid(); // this will set the guid on the header @@ -145,6 +151,43 @@ ArtistView::setTreeModel( TreeModel* model ) } +void +ArtistView::onViewChanged() +{ + if ( m_timer.isActive() ) + m_timer.stop(); + + m_timer.start(); +} + + +void +ArtistView::onScrollTimeout() +{ + if ( m_timer.isActive() ) + m_timer.stop(); + + QModelIndex left = indexAt( viewport()->rect().topLeft() ); + while ( left.isValid() && left.parent().isValid() ) + left = left.parent(); + + QModelIndex right = indexAt( viewport()->rect().bottomLeft() ); + while ( right.isValid() && right.parent().isValid() ) + right = right.parent(); + + int max = m_proxyModel->playlistInterface()->trackCount(); + if ( right.isValid() ) + max = right.row() + 1; + + if ( !max ) + return; + + for ( int i = left.row(); i < max; i++ ) + { + m_model->getCover( m_proxyModel->mapToSource( m_proxyModel->index( i, 0 ) ) ); + } +} + void ArtistView::currentChanged( const QModelIndex& current, const QModelIndex& previous ) { diff --git a/src/libtomahawk/playlist/artistview.h b/src/libtomahawk/playlist/artistview.h index 8167f9b73..061bca781 100644 --- a/src/libtomahawk/playlist/artistview.h +++ b/src/libtomahawk/playlist/artistview.h @@ -95,6 +95,8 @@ private slots: void onItemCountChanged( unsigned int items ); void onFilterChanged( const QString& filter ); void onFilteringStarted(); + void onViewChanged(); + void onScrollTimeout(); void onCustomContextMenu( const QPoint& pos ); void onMenuTriggered( int action ); @@ -113,6 +115,7 @@ private: Tomahawk::ContextMenu* m_contextMenu; bool m_showModes; + QTimer m_timer; mutable QString m_guid; }; diff --git a/src/libtomahawk/playlist/customplaylistview.cpp b/src/libtomahawk/playlist/customplaylistview.cpp index 1cb9517cd..5e81cd6ca 100644 --- a/src/libtomahawk/playlist/customplaylistview.cpp +++ b/src/libtomahawk/playlist/customplaylistview.cpp @@ -42,7 +42,7 @@ CustomPlaylistView::CustomPlaylistView( CustomPlaylistView::PlaylistType type, c if ( m_type == SourceLovedTracks ) connect( m_source.data(), SIGNAL( socialAttributesChanged( QString ) ), this, SLOT( socialAttributesChanged( QString ) ) ); - else if ( m_type == AllLovedTracks ) + else if ( m_type == TopLovedTracks ) { connect( SourceList::instance()->getLocal().data(), SIGNAL( socialAttributesChanged( QString ) ), this, SLOT( socialAttributesChanged( QString ) ) ); foreach ( const source_ptr& s, SourceList::instance()->sources( true ) ) @@ -86,12 +86,12 @@ CustomPlaylistView::generateTracks() "GROUP BY track.id " "ORDER BY counter DESC, social_attributes.timestamp DESC " ).arg( m_source->isLocal() ? "IS NULL" : QString( "= %1" ).arg( m_source->id() ) ); break; - case AllLovedTracks: + case TopLovedTracks: sql = QString( "SELECT track.name, artist.name, source, COUNT(*) as counter " "FROM social_attributes, track, artist " - "WHERE social_attributes.id = track.id AND artist.id = track.artist AND social_attributes.k = 'Love' AND social_attributes.v = 'true'" + "WHERE social_attributes.id = track.id AND artist.id = track.artist AND social_attributes.k = 'Love' AND social_attributes.v = 'true' " "GROUP BY track.id " - "ORDER BY counter DESC, social_attributes.timestamp DESC " ); + "ORDER BY counter DESC, social_attributes.timestamp DESC LIMIT 0, 50" ); break; } diff --git a/src/libtomahawk/playlist/customplaylistview.h b/src/libtomahawk/playlist/customplaylistview.h index f03ede49b..692980e40 100644 --- a/src/libtomahawk/playlist/customplaylistview.h +++ b/src/libtomahawk/playlist/customplaylistview.h @@ -33,7 +33,7 @@ class DLLEXPORT CustomPlaylistView : public PlaylistView public: enum PlaylistType { SourceLovedTracks, - AllLovedTracks + TopLovedTracks }; explicit CustomPlaylistView( PlaylistType type, const source_ptr& s, QWidget* parent = 0 ); diff --git a/src/libtomahawk/playlist/treeitemdelegate.cpp b/src/libtomahawk/playlist/treeitemdelegate.cpp index 90fbe4aa7..685a6389e 100644 --- a/src/libtomahawk/playlist/treeitemdelegate.cpp +++ b/src/libtomahawk/playlist/treeitemdelegate.cpp @@ -155,32 +155,18 @@ TreeItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, QPixmap cover; if ( !item->album().isNull() ) { - cover.loadFromData( item->album()->cover() ); + cover = item->album()->cover( r.size(), false ); + if ( cover.isNull() ) + cover = TomahawkUtils::defaultPixmap( TomahawkUtils::DefaultAlbumCover, TomahawkUtils::ScaledCover, r.size() ); } else if ( !item->artist().isNull() ) { - cover.loadFromData( item->artist()->cover() ); + cover = item->artist()->cover( r.size(), false ); + if ( cover.isNull() ) + cover = TomahawkUtils::defaultPixmap( TomahawkUtils::DefaultArtistImage, TomahawkUtils::ScaledCover, r.size() ); } - QPixmap scover; - if ( cover.isNull() ) - { - if ( !item->artist().isNull() ) - cover = m_defaultArtistImage; - else - cover = m_defaultAlbumCover; - } - - if ( m_cache.contains( cover.cacheKey() ) ) - { - scover = m_cache.value( cover.cacheKey() ); - } - else - { - scover = cover.scaled( r.size(), Qt::KeepAspectRatio, Qt::SmoothTransformation ); - m_cache.insert( cover.cacheKey(), scover ); - } - painter->drawPixmap( r, scover ); + painter->drawPixmap( r, cover ); QTextOption to; to.setAlignment( Qt::AlignVCenter ); diff --git a/src/libtomahawk/playlist/treeitemdelegate.h b/src/libtomahawk/playlist/treeitemdelegate.h index 07fff9423..da84fcec9 100644 --- a/src/libtomahawk/playlist/treeitemdelegate.h +++ b/src/libtomahawk/playlist/treeitemdelegate.h @@ -43,8 +43,6 @@ private: ArtistView* m_view; TreeProxyModel* m_model; - mutable QHash< qint64, QPixmap > m_cache; - QPixmap m_nowPlayingIcon; QPixmap m_defaultAlbumCover; QPixmap m_defaultArtistImage; diff --git a/src/libtomahawk/playlist/treemodel.cpp b/src/libtomahawk/playlist/treemodel.cpp index 24e3073e0..bb2026041 100644 --- a/src/libtomahawk/playlist/treemodel.cpp +++ b/src/libtomahawk/playlist/treemodel.cpp @@ -87,6 +87,18 @@ TreeModel::collection() const } +void +TreeModel::getCover( const QModelIndex& index ) +{ + TreeModelItem* item = itemFromIndex( index ); + + if ( !item->artist().isNull() && !item->artist()->infoLoaded() ) + item->artist()->cover( QSize( 0, 0 ) ); + else if ( !item->album().isNull() && !item->album()->infoLoaded() ) + item->album()->cover( QSize( 0, 0 ) ); +} + + void TreeModel::setCurrentItem( const QModelIndex& index ) { @@ -783,6 +795,8 @@ TreeModel::onAlbumsAdded( const QList& albums, const QModel albumitem = new TreeModelItem( album, parentItem ); albumitem->index = createIndex( parentItem->children.count() - 1, 0, albumitem ); connect( albumitem, SIGNAL( dataChanged() ), SLOT( onDataChanged() ) ); + + getCover( albumitem->index ); } emit endInsertRows(); diff --git a/src/libtomahawk/playlist/treemodel.h b/src/libtomahawk/playlist/treemodel.h index 53578bc8b..fb645cf28 100644 --- a/src/libtomahawk/playlist/treemodel.h +++ b/src/libtomahawk/playlist/treemodel.h @@ -98,6 +98,8 @@ public: void addAlbums( const Tomahawk::artist_ptr& artist, const QModelIndex& parent, bool autoRefetch = false ); void addTracks( const Tomahawk::album_ptr& album, const QModelIndex& parent, bool autoRefetch = false ); + void getCover( const QModelIndex& index ); + ColumnStyle columnStyle() const { return m_columnStyle; } void setColumnStyle( ColumnStyle style ); diff --git a/src/libtomahawk/query.cpp b/src/libtomahawk/query.cpp index 8df9cd6f7..40eb1d515 100644 --- a/src/libtomahawk/query.cpp +++ b/src/libtomahawk/query.cpp @@ -489,7 +489,7 @@ Query::loadSocialActions() query_ptr q = m_ownRef.toStrongRef(); DatabaseCommand_LoadSocialActions* cmd = new DatabaseCommand_LoadSocialActions( q ); - connect( cmd, SIGNAL( finished() ), SLOT( onSocialActionsLoaded() )); + connect( cmd, SIGNAL( finished() ), SLOT( onSocialActionsLoaded() ) ); Database::instance()->enqueue( QSharedPointer(cmd) ); } diff --git a/src/libtomahawk/tomahawksettings.cpp b/src/libtomahawk/tomahawksettings.cpp index 11f45aa03..40dc12a58 100644 --- a/src/libtomahawk/tomahawksettings.cpp +++ b/src/libtomahawk/tomahawksettings.cpp @@ -46,19 +46,24 @@ TomahawkSettings::TomahawkSettings( QObject* parent ) { s_instance = this; - if( !contains( "configversion") ) + #ifdef Q_OS_LINUX + QFile file( fileName() ); + file.setPermissions( file.permissions() & ~(QFile::ReadGroup | QFile::WriteGroup | QFile::ExeGroup | QFile::ReadOther | QFile::WriteOther | QFile::ExeOther ) ); + #endif + + if ( !contains( "configversion" ) ) { setValue( "configversion", TOMAHAWK_SETTINGS_VERSION ); doInitialSetup(); } - else if( value( "configversion" ).toUInt() != TOMAHAWK_SETTINGS_VERSION ) + else if ( value( "configversion" ).toUInt() != TOMAHAWK_SETTINGS_VERSION ) { qDebug() << "Config version outdated, old:" << value( "configversion" ).toUInt() << "new:" << TOMAHAWK_SETTINGS_VERSION << "Doing upgrade, if any..."; int current = value( "configversion" ).toUInt(); - while( current < TOMAHAWK_SETTINGS_VERSION ) + while ( current < TOMAHAWK_SETTINGS_VERSION ) { doUpgrade( current, current + 1 ); @@ -67,7 +72,6 @@ TomahawkSettings::TomahawkSettings( QObject* parent ) // insert upgrade code here as required setValue( "configversion", TOMAHAWK_SETTINGS_VERSION ); } - } @@ -100,22 +104,23 @@ TomahawkSettings::doUpgrade( int oldVersion, int newVersion ) { Q_UNUSED( newVersion ); - if( oldVersion == 1 ) + if ( oldVersion == 1 ) { qDebug() << "Migrating config from verson 1 to 2: script resolver config name"; if( contains( "script/resolvers" ) ) { setValue( "script/loadedresolvers", value( "script/resolvers" ) ); remove( "script/resolvers" ); } - } else if( oldVersion == 2 ) + } + else if ( oldVersion == 2 ) { qDebug() << "Migrating config from version 2 to 3: Converting jabber and twitter accounts to new SIP Factory approach"; // migrate old accounts to new system. only jabber and twitter, and max one each. create a new plugin for each if needed // not pretty as we hardcode a plugin id and assume that we know how the config layout is, but hey, this is migration after all - if( contains( "jabber/username" ) && contains( "jabber/password" ) ) + if ( contains( "jabber/username" ) && contains( "jabber/password" ) ) { QString sipName = "sipjabber"; - if( value( "jabber/username" ).toString().contains( "@gmail" ) ) + if ( value( "jabber/username" ).toString().contains( "@gmail" ) ) sipName = "sipgoogle"; setValue( QString( "%1_legacy/username" ).arg( sipName ), value( "jabber/username" ) ); @@ -132,7 +137,7 @@ TomahawkSettings::doUpgrade( int oldVersion, int newVersion ) remove( "jabber/server" ); remove( "jabber/port" ); } - if( contains( "twitter/ScreenName" ) && contains( "twitter/OAuthToken" ) ) + if ( contains( "twitter/ScreenName" ) && contains( "twitter/OAuthToken" ) ) { setValue( "siptwitter_legacy/ScreenName", value( "twitter/ScreenName" ) ); setValue( "siptwitter_legacy/OAuthToken", value( "twitter/OAuthToken" ) ); @@ -153,7 +158,8 @@ TomahawkSettings::doUpgrade( int oldVersion, int newVersion ) } // create a zeroconf plugin too addSipPlugin( "sipzeroconf_legacy" ); - } else if ( oldVersion == 3 ) + } + else if ( oldVersion == 3 ) { if ( contains( "script/atticaresolverstates" ) ) { @@ -192,7 +198,8 @@ TomahawkSettings::doUpgrade( int oldVersion, int newVersion ) tDebug() << "UPGRADING AND DELETING:" << resolverDir.absolutePath(); TomahawkUtils::removeDirectory( resolverDir.absolutePath() ); } - } else if ( oldVersion == 4 ) + } + else if ( oldVersion == 4 ) { // 0.3.0 contained a bug which prevent indexing local files. Force a reindex. QTimer::singleShot( 0, this, SLOT( updateIndex() ) ); @@ -1021,6 +1028,7 @@ TomahawkSettings::setNowPlayingEnabled( bool enable ) setValue( "adium/enablenowplaying", enable ); } + TomahawkSettings::PrivateListeningMode TomahawkSettings::privateListeningMode() const { diff --git a/src/libtomahawk/utils/tomahawkutils.h b/src/libtomahawk/utils/tomahawkutils.h index fc2dcf4a1..6c4b32dfa 100644 --- a/src/libtomahawk/utils/tomahawkutils.h +++ b/src/libtomahawk/utils/tomahawkutils.h @@ -42,6 +42,18 @@ namespace TomahawkUtils MediaTypeTrack }; + enum ImageType + { + DefaultAlbumCover, + DefaultArtistImage + }; + enum ImageMode + { + NoDefaultCover, + CoverInCase, + ScaledCover + }; + class DLLEXPORT NetworkProxyFactory : public QNetworkProxyFactory { public: diff --git a/src/libtomahawk/utils/tomahawkutilsgui.cpp b/src/libtomahawk/utils/tomahawkutilsgui.cpp index 4d1d419d5..637f73cc4 100644 --- a/src/libtomahawk/utils/tomahawkutilsgui.cpp +++ b/src/libtomahawk/utils/tomahawkutilsgui.cpp @@ -36,6 +36,8 @@ #include #endif +#include "logger.h" + namespace TomahawkUtils { static int s_headerHeight = 0; @@ -83,15 +85,15 @@ createDragPixmap( MediaType type, int itemCount ) QPixmap pixmap; switch ( type ) { - case MediaTypeArtist: - pixmap = QPixmap( ":/data/images/artist-icon.png" ).scaledToWidth( size, Qt::SmoothTransformation ); - break; - case MediaTypeAlbum: - pixmap = QPixmap( ":/data/images/album-icon.png" ).scaledToWidth( size, Qt::SmoothTransformation ); - break; - case MediaTypeTrack: - pixmap = QPixmap( QString( ":/data/images/track-icon-%2x%2.png" ).arg( size ) ); - break; + case MediaTypeArtist: + pixmap = QPixmap( ":/data/images/artist-icon.png" ).scaledToWidth( size, Qt::SmoothTransformation ); + break; + case MediaTypeAlbum: + pixmap = QPixmap( ":/data/images/album-icon.png" ).scaledToWidth( size, Qt::SmoothTransformation ); + break; + case MediaTypeTrack: + pixmap = QPixmap( QString( ":/data/images/track-icon-%2x%2.png" ).arg( size ) ); + break; } int x = 0; @@ -303,4 +305,59 @@ alphaBlend( const QColor& colorFrom, const QColor& colorTo, float opacity ) return QColor( r, g, b ); } + +QPixmap +defaultPixmap( ImageType type, ImageMode mode, const QSize& size ) +{ + QPixmap pixmap; + QHash< int, QPixmap > subsubcache; + QHash< int, QHash< int, QPixmap > > subcache; + static QHash< int, QHash< int, QHash< int, QPixmap > > > cache; + + if ( cache.contains( type ) ) + { + subcache = cache.value( type ); + + if ( subcache.contains( mode ) ) + { + subsubcache = subcache.value( mode ); + + if ( subsubcache.contains( size.width() ) ) + return subsubcache.value( size.width() ); + } + } + + switch ( type ) + { + case DefaultAlbumCover: + if ( mode == CoverInCase ) + pixmap = QPixmap( RESPATH "images/no-album-art-placeholder.png" ); + else + pixmap = QPixmap( RESPATH "images/no-album-no-case.png" ); + break; + + case DefaultArtistImage: + pixmap = QPixmap( RESPATH "images/no-artist-image-placeholder.png" ); + break; + + default: + break; + } + + if ( pixmap.isNull() ) + { + Q_ASSERT( false ); + return QPixmap(); + } + + if ( !size.isNull() ) + pixmap = pixmap.scaled( size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation ); + + subsubcache.insert( size.width(), pixmap ); + subcache.insert( mode, subsubcache ); + cache.insert( type, subcache ); + + return pixmap; +} + } // ns diff --git a/src/libtomahawk/utils/tomahawkutilsgui.h b/src/libtomahawk/utils/tomahawkutilsgui.h index 6f8f08674..f353608de 100644 --- a/src/libtomahawk/utils/tomahawkutilsgui.h +++ b/src/libtomahawk/utils/tomahawkutilsgui.h @@ -19,6 +19,8 @@ #ifndef TOMAHAWKUTILSGUI_H #define TOMAHAWKUTILSGUI_H +#include + #include "tomahawkutils.h" #include "dllmacro.h" @@ -46,6 +48,8 @@ namespace TomahawkUtils DLLEXPORT int headerHeight(); DLLEXPORT void setHeaderHeight( int height ); + + DLLEXPORT QPixmap defaultPixmap( ImageType type, ImageMode mode, const QSize& size = QSize( 0, 0 ) ); } #endif // TOMAHAWKUTILSGUI_H diff --git a/src/libtomahawk/viewmanager.cpp b/src/libtomahawk/viewmanager.cpp index 0816d8203..d87f9038a 100644 --- a/src/libtomahawk/viewmanager.cpp +++ b/src/libtomahawk/viewmanager.cpp @@ -432,7 +432,7 @@ Tomahawk::ViewPage* ViewManager::showTopLovedPage() { if ( !m_topLovedWidget ) - m_topLovedWidget = new CustomPlaylistView( CustomPlaylistView::AllLovedTracks, source_ptr(), m_widget ); + m_topLovedWidget = new CustomPlaylistView( CustomPlaylistView::TopLovedTracks, source_ptr(), m_widget ); return show( m_topLovedWidget ); } diff --git a/src/libtomahawk/viewmanager.h b/src/libtomahawk/viewmanager.h index adce43cc6..4dc2148b8 100644 --- a/src/libtomahawk/viewmanager.h +++ b/src/libtomahawk/viewmanager.h @@ -133,6 +133,7 @@ signals: void hideQueueRequested(); void tomahawkLoaded(); + public slots: Tomahawk::ViewPage* showSuperCollection(); Tomahawk::ViewPage* showWelcomePage(); diff --git a/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp index 62b048704..40ba83ec5 100644 --- a/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp @@ -61,7 +61,7 @@ AlbumInfoWidget::AlbumInfoWidget( const Tomahawk::album_ptr& album, ModelMode st ui->tracksView->setTreeModel( m_tracksModel ); ui->tracksView->setRootIsDecorated( false ); - m_pixmap = QPixmap( RESPATH "images/no-album-art-placeholder.png" ).scaledToWidth( 48, Qt::SmoothTransformation ); + m_pixmap = TomahawkUtils::defaultPixmap( TomahawkUtils::DefaultAlbumCover, TomahawkUtils::ScaledCover, QSize( 48, 48 ) ); m_button = new OverlayButton( ui->tracksView ); m_button->setCheckable( true ); @@ -243,10 +243,10 @@ AlbumInfoWidget::loadAlbums( bool autoRefetch ) void AlbumInfoWidget::onAlbumCoverUpdated() { - if ( m_album->cover().isNull() ) + if ( m_album->cover( QSize( 0, 0 ) ).isNull() ) return; - m_pixmap.loadFromData( m_album->cover() ); + m_pixmap = m_album->cover( QSize( 0, 0 ) ); emit pixmapChanged( m_pixmap ); } diff --git a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp index 178713c04..b663b8a72 100644 --- a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp @@ -77,7 +77,7 @@ ArtistInfoWidget::ArtistInfoWidget( const Tomahawk::artist_ptr& artist, QWidget* ui->topHits->setTrackModel( m_topHitsModel ); ui->topHits->setSortingEnabled( false ); - m_pixmap = QPixmap( RESPATH "images/no-album-no-case.png" ).scaledToWidth( 48, Qt::SmoothTransformation ); + m_pixmap = TomahawkUtils::defaultPixmap( TomahawkUtils::DefaultArtistImage, TomahawkUtils::ScaledCover, QSize( 48, 48 ) ); m_button = new OverlayButton( ui->albums ); m_button->setText( tr( "Click to show Super Collection Albums" ) ); @@ -289,10 +289,10 @@ ArtistInfoWidget::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestD void ArtistInfoWidget::onArtistImageUpdated() { - if ( m_artist->cover().isNull() ) + if ( m_artist->cover( QSize( 0, 0 ) ).isNull() ) return; - m_pixmap.loadFromData( m_artist->cover() ); + m_pixmap = m_artist->cover( QSize( 0, 0 ) ); emit pixmapChanged( m_pixmap ); } diff --git a/src/sourcetree/items/groupitem.cpp b/src/sourcetree/items/groupitem.cpp index 01804c0ba..f45f76b09 100644 --- a/src/sourcetree/items/groupitem.cpp +++ b/src/sourcetree/items/groupitem.cpp @@ -28,9 +28,8 @@ using namespace Tomahawk; GroupItem::GroupItem( SourcesModel* model, SourceTreeItem* parent, const QString& text, int peerSortValue ) - : SourceTreeItem( model, parent, SourcesModel::Group ) + : SourceTreeItem( model, parent, SourcesModel::Group, peerSortValue ) , m_text( text ) - , m_peerSortValue( peerSortValue ) { // expand by default QTimer::singleShot( 0, this, SLOT( requestExpanding() ) ); diff --git a/src/sourcetree/items/groupitem.h b/src/sourcetree/items/groupitem.h index 5f173ac0b..3be4e16ee 100644 --- a/src/sourcetree/items/groupitem.h +++ b/src/sourcetree/items/groupitem.h @@ -36,7 +36,6 @@ public: virtual QString text() const; 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; } public slots: @@ -50,7 +49,6 @@ private slots: private: QString m_text; - int m_peerSortValue; }; #endif diff --git a/src/sourcetree/items/sourceitem.cpp b/src/sourcetree/items/sourceitem.cpp index f4084b38e..ede45229e 100644 --- a/src/sourcetree/items/sourceitem.cpp +++ b/src/sourcetree/items/sourceitem.cpp @@ -486,7 +486,7 @@ ViewPage* SourceItem::lovedTracksClicked() { if ( !m_lovedTracksPage ) - m_lovedTracksPage = new CustomPlaylistView( m_source.isNull() ? CustomPlaylistView::AllLovedTracks : CustomPlaylistView::SourceLovedTracks, m_source, ViewManager::instance()->widget() ); + m_lovedTracksPage = new CustomPlaylistView( m_source.isNull() ? CustomPlaylistView::TopLovedTracks : CustomPlaylistView::SourceLovedTracks, m_source, ViewManager::instance()->widget() ); ViewManager::instance()->show( m_lovedTracksPage ); return m_lovedTracksPage; diff --git a/src/sourcetree/items/sourcetreeitem.cpp b/src/sourcetree/items/sourcetreeitem.cpp index 01a0224f8..644331472 100644 --- a/src/sourcetree/items/sourcetreeitem.cpp +++ b/src/sourcetree/items/sourcetreeitem.cpp @@ -23,11 +23,12 @@ using namespace Tomahawk; -SourceTreeItem::SourceTreeItem( SourcesModel* model, SourceTreeItem* parent, SourcesModel::RowType thisType, int index ) +SourceTreeItem::SourceTreeItem( SourcesModel* model, SourceTreeItem* parent, SourcesModel::RowType thisType, int peerSortValue, int index ) : QObject() , m_type( thisType ) , m_parent( parent ) , m_model( model ) + , m_peerSortValue( peerSortValue ) { connect( this, SIGNAL( beginChildRowsAdded( int, int ) ), m_model, SLOT( onItemRowsAddedBegin( int, int ) ) ); connect( this, SIGNAL( beginChildRowsRemoved( int, int ) ), m_model, SLOT( onItemRowsRemovedBegin( int, int ) ) ); diff --git a/src/sourcetree/items/sourcetreeitem.h b/src/sourcetree/items/sourcetreeitem.h index 7e174b789..adde55609 100644 --- a/src/sourcetree/items/sourcetreeitem.h +++ b/src/sourcetree/items/sourcetreeitem.h @@ -43,7 +43,7 @@ public: Q_DECLARE_FLAGS( DropTypes, DropType ) SourceTreeItem() : m_type( SourcesModel::Invalid ), m_parent( 0 ), m_model( 0 ) {} - SourceTreeItem( SourcesModel* model, SourceTreeItem* parent, SourcesModel::RowType thisType, int index = -1 ); // if index is -1, append at end of parent's child list + SourceTreeItem( SourcesModel* model, SourceTreeItem* parent, SourcesModel::RowType thisType, int peerSortValue = 0, int index = -1 ); // if index is -1, append at end of parent's child list virtual ~SourceTreeItem(); // generic info used by the tree model @@ -63,7 +63,7 @@ public: virtual bool willAcceptDrag( const QMimeData* ) const { return false; } virtual bool dropMimeData( const QMimeData*, Qt::DropAction ) { return false; } virtual bool setData( const QVariant&, bool ) { return false; } - virtual int peerSortValue() const { return 0; } // How to sort relative to peers in the tree. + virtual int peerSortValue() const { return m_peerSortValue; } // How to sort relative to peers in the tree. virtual int IDValue() const { return 0; } virtual DropTypes supportedDropTypes( const QMimeData* mimeData ) const { Q_UNUSED( mimeData ); return DropTypesNone; } virtual void setDropType( DropType type ) { m_dropType = type; } @@ -101,6 +101,7 @@ private: SourceTreeItem* m_parent; QList< SourceTreeItem* > m_children; SourcesModel* m_model; + int m_peerSortValue; DropType m_dropType; }; diff --git a/src/sourcetree/sourcedelegate.cpp b/src/sourcetree/sourcedelegate.cpp index 61362ae6f..1a391536b 100644 --- a/src/sourcetree/sourcedelegate.cpp +++ b/src/sourcetree/sourcedelegate.cpp @@ -82,7 +82,7 @@ SourceDelegate::~SourceDelegate() QSize SourceDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const { - SourceTreeItem *item = index.data( SourcesModel::SourceTreeItemRole ).value< SourceTreeItem* >(); + SourceTreeItem* item = index.data( SourcesModel::SourceTreeItemRole ).value< SourceTreeItem* >(); SourcesModel::RowType type = static_cast< SourcesModel::RowType >( index.data( SourcesModel::SourceTreeItemTypeRole ).toInt() ); if ( type == SourcesModel::Collection ) @@ -93,6 +93,10 @@ SourceDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& { return QSize( option.rect.width(), 6 ); } + else if ( type == SourcesModel::Group && index.row() > 0 ) + { + return QSize( option.rect.width(), 24 ); + } else if ( m_expandedMap.contains( index ) ) { if ( !m_expandedMap.value( index )->initialized() ) @@ -128,7 +132,7 @@ SourceDelegate::paintDecorations( QPainter* painter, const QStyleOptionViewItem& 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 ); + QRect iconRect = QRect( 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 ); @@ -238,9 +242,11 @@ SourceDelegate::paintCollection( QPainter* painter, const QStyleOptionViewItem& } } - text = painter->fontMetrics().elidedText( desc, Qt::ElideRight, textRect.width() ); + textRect.adjust( 0, 0, 0, 2 ); + text = painter->fontMetrics().elidedText( desc, Qt::ElideRight, textRect.width() - 4 ); QTextOption to( Qt::AlignVCenter ); - painter->drawText( textRect.adjusted( 0, 0, 0, 2 ), text, to ); + to.setWrapMode( QTextOption::NoWrap ); + painter->drawText( textRect, text, to ); if ( status ) { @@ -305,7 +311,7 @@ SourceDelegate::paintGroup( QPainter* painter, const QStyleOptionViewItem& optio font.setBold( true ); painter->setFont( font ); - QTextOption to( Qt::AlignVCenter ); + QTextOption to( Qt::AlignBottom ); painter->setPen( option.palette.color( QPalette::Base ) ); painter->setBrush( option.palette.color( QPalette::Base ) ); @@ -325,7 +331,7 @@ SourceDelegate::paintGroup( QPainter* painter, const QStyleOptionViewItem& optio font.setPixelSize( font.pixelSize() - 1 ); painter->setFont( font ); - QTextOption to( Qt::AlignVCenter | Qt::AlignRight ); + QTextOption to( Qt::AlignBottom | Qt::AlignRight ); // draw close icon painter->setPen( Qt::white ); @@ -400,8 +406,6 @@ 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 ); - paintDecorations( painter, o3, index ); - if ( type == SourcesModel::Collection ) { paintCollection( painter, o, index ); @@ -532,6 +536,8 @@ SourceDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, co } } + paintDecorations( painter, o3, index ); + painter->restore(); } diff --git a/src/sourcetree/sourcesmodel.cpp b/src/sourcetree/sourcesmodel.cpp index dfe877d96..188b2b5c5 100644 --- a/src/sourcetree/sourcesmodel.cpp +++ b/src/sourcetree/sourcesmodel.cpp @@ -39,6 +39,7 @@ #include "globalactionmanager.h" #include "dropjob.h" #include "items/playlistitems.h" +#include "playlist/artistview.h" #include "playlist/playlistview.h" #include "playlist/dynamic/widgets/DynamicWidget.h" @@ -53,8 +54,6 @@ SourcesModel::SourcesModel( QObject* parent ) m_rootItem = new SourceTreeItem( this, 0, Invalid ); appendGroups(); - appendItem( source_ptr() ); - onSourcesAdded( SourceList::instance()->sources() ); connect( SourceList::instance(), SIGNAL( sourceAdded( Tomahawk::source_ptr ) ), SLOT( onSourceAdded( Tomahawk::source_ptr ) ) ); @@ -265,28 +264,34 @@ SourcesModel::appendGroups() { beginInsertRows( QModelIndex(), rowCount(), rowCount() + 2 ); - new SourceTreeItem( this, m_rootItem, SourcesModel::Divider, 0 ); - new HistoryItem( this, m_rootItem, tr( "History" ), 5 ); - GroupItem* browse = new GroupItem( this, m_rootItem, tr( "Browse" ), 10 ); + GroupItem* browse = new GroupItem( this, m_rootItem, tr( "Browse" ), 0 ); + new HistoryItem( this, m_rootItem, tr( "Search History" ), 1 ); +// new SourceTreeItem( this, m_rootItem, SourcesModel::Divider, 2 ); + m_myMusicGroup = new GroupItem( this, m_rootItem, tr( "My Music" ), 3 ); // super collection + GenericPageItem* sc = new GenericPageItem( this, browse, tr( "SuperCollection" ), QIcon( RESPATH "images/supercollection.png" ), + boost::bind( &ViewManager::showSuperCollection, ViewManager::instance() ), + boost::bind( &ViewManager::superCollectionView, ViewManager::instance() ) ); + sc->setSortValue( 1 ); + + // browse section 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 ); + loved->setSortValue( 2 ); - // 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 ); + recent->setSortValue( 0 ); 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 ); + hot->setSortValue( 3 ); - m_collectionsGroup = new GroupItem( this, m_rootItem, tr( "Friends" ), 15 ); + m_collectionsGroup = new GroupItem( this, m_rootItem, tr( "Friends" ), 4 ); endInsertRows(); } @@ -298,7 +303,7 @@ SourcesModel::appendItem( const Tomahawk::source_ptr& source ) SourceTreeItem* parent; if ( !source.isNull() && source->isLocal() ) { - parent = m_rootItem; + parent = m_myMusicGroup; } else { diff --git a/src/sourcetree/sourcesmodel.h b/src/sourcetree/sourcesmodel.h index 969067396..694e4f8b6 100644 --- a/src/sourcetree/sourcesmodel.h +++ b/src/sourcetree/sourcesmodel.h @@ -139,6 +139,7 @@ private: SourceTreeItem* m_rootItem; GroupItem* m_collectionsGroup; + GroupItem* m_myMusicGroup; 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 a0db5e2ea..de36f87e5 100644 --- a/src/sourcetree/sourcesproxymodel.cpp +++ b/src/sourcetree/sourcesproxymodel.cpp @@ -66,7 +66,7 @@ SourcesProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex& sourcePar if ( item && item->type() != SourcesModel::Divider && item->parent()->parent() == 0 && !item->children().count() ) return false; - + if ( !m_filtered ) return true; diff --git a/src/sourcetree/sourcetreeview.cpp b/src/sourcetree/sourcetreeview.cpp index 330e8aeee..a00deaec2 100644 --- a/src/sourcetree/sourcetreeview.cpp +++ b/src/sourcetree/sourcetreeview.cpp @@ -256,14 +256,14 @@ SourceTreeView::selectRequest( const QPersistentModelIndex& idx ) void -SourceTreeView::expandRequest( const QPersistentModelIndex &idx ) +SourceTreeView::expandRequest( const QPersistentModelIndex& idx ) { expand( idx ); } void -SourceTreeView::toggleExpandRequest( const QPersistentModelIndex &idx ) +SourceTreeView::toggleExpandRequest( const QPersistentModelIndex& idx ) { if ( isExpanded( idx ) ) collapse( idx ); diff --git a/src/tomahawkapp.cpp b/src/tomahawkapp.cpp index 900d56182..7363978ae 100644 --- a/src/tomahawkapp.cpp +++ b/src/tomahawkapp.cpp @@ -61,7 +61,6 @@ #include "utils/logger.h" #include "utils/tomahawkutilsgui.h" -#include #include "config.h" #ifndef ENABLE_HEADLESS @@ -170,7 +169,7 @@ TomahawkApp::init() m_scanManager = QWeakPointer( new ScanManager( this ) ); // init pipeline and resolver factories - new Pipeline( this ); + new Pipeline(); #ifndef ENABLE_HEADLESS Pipeline::instance()->addExternalResolverFactory( boost::bind( &QtScriptResolver::factory, _1 ) ); @@ -300,6 +299,8 @@ TomahawkApp::~TomahawkApp() { tLog() << "Shutting down Tomahawk..."; + Pipeline::instance()->stop(); + if ( !m_servent.isNull() ) delete m_servent.data(); if ( !m_scanManager.isNull() ) @@ -311,22 +312,18 @@ TomahawkApp::~TomahawkApp() if ( !m_infoSystem.isNull() ) delete m_infoSystem.data(); - //FIXME: delete GeneratorFactory::registerFactory( "echonest", new EchonestFactory ); ? - delete Tomahawk::Accounts::AccountManager::instance(); - Pipeline::instance()->stop(); - #ifndef ENABLE_HEADLESS delete m_mainwindow; delete AtticaManager::instance(); #endif + delete Pipeline::instance(); + if ( !m_database.isNull() ) delete m_database.data(); - delete Pipeline::instance(); - tLog() << "Finished shutdown."; } @@ -352,6 +349,13 @@ TomahawkApp::printHelp() echo( " --testdb Use a test database instead of real collection\n" ); echo( " --noupnp Disable UPnP\n" ); echo( " --nosip Disable SIP\n" ); + echo( "\nPlayback Controls:\n" ); + echo( " --playpause Toggle playing/paused state\n" ); + echo( " --play Start/resume playback\n" ); + echo( " --pause Pause playback\n" ); + echo( " --stop Stop playback\n" ); + echo( " --next Advances to the next track (if available)\n" ); + echo( " --prev Returns to the previous track (if available)\n" ); echo( "\nurl is a tomahawk:// command or alternatively a url that Tomahawk can recognize.\n" ); echo( "For more documentation, see http://wiki.tomahawk-player.org/mediawiki/index.php/Tomahawk://_Links\n" ); } @@ -465,7 +469,6 @@ TomahawkApp::initHTTP() tLog() << "Starting HTTPd on" << m_session.listenInterface().toString() << m_session.port(); m_session.start(); - } @@ -512,6 +515,7 @@ TomahawkApp::initServent() } } + // Called after Servent emits ready() void TomahawkApp::initSIP() @@ -540,10 +544,7 @@ TomahawkApp::spotifyApiCheckFinished() QNetworkReply* reply = qobject_cast< QNetworkReply* >( sender() ); Q_ASSERT( reply ); - if ( reply->error() ) - DropJob::setCanParseSpotifyPlaylists( false ); - else - DropJob::setCanParseSpotifyPlaylists( true ); + DropJob::setCanParseSpotifyPlaylists( !reply->error() ); #endif } @@ -603,5 +604,19 @@ TomahawkApp::instanceStarted( KDSingleApplicationGuard::Instance instance ) return; QString arg1 = instance.arguments[ 1 ]; - loadUrl( arg1 ); + if ( loadUrl( arg1 ) ) + return; + + if ( instance.arguments.contains( "--next" ) ) + AudioEngine::instance()->next(); + else if ( instance.arguments.contains( "--prev" ) ) + AudioEngine::instance()->previous(); + else if ( instance.arguments.contains( "--playpause" ) ) + AudioEngine::instance()->playPause(); + else if ( instance.arguments.contains( "--play" ) ) + AudioEngine::instance()->play(); + else if ( instance.arguments.contains( "--pause" ) ) + AudioEngine::instance()->pause(); + else if ( instance.arguments.contains( "--stop" ) ) + AudioEngine::instance()->stop(); }