From 1a1106012b1d15256f13eb1f584a157af10c9a19 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Thu, 5 Jul 2012 22:38:04 -0400 Subject: [PATCH 1/9] Add spotify infoplugin for album lookups --- src/libtomahawk/CMakeLists.txt | 1 + .../accounts/spotify/SpotifyAccount.cpp | 28 ++ .../accounts/spotify/SpotifyAccount.h | 11 +- .../accounts/spotify/SpotifyInfoPlugin.cpp | 263 ++++++++++++++++++ .../accounts/spotify/SpotifyInfoPlugin.h | 74 +++++ 5 files changed, 376 insertions(+), 1 deletion(-) create mode 100644 src/libtomahawk/accounts/spotify/SpotifyInfoPlugin.cpp create mode 100644 src/libtomahawk/accounts/spotify/SpotifyInfoPlugin.h diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index 7075505fd..71481e3a7 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -192,6 +192,7 @@ set( libSources accounts/spotify/SpotifyAccount.cpp accounts/spotify/SpotifyAccountConfig.cpp accounts/spotify/SpotifyPlaylistUpdater.cpp + accounts/spotify/SpotifyInfoPlugin.cpp accounts/lastfm/LastFmAccount.cpp accounts/lastfm/LastFmConfig.cpp diff --git a/src/libtomahawk/accounts/spotify/SpotifyAccount.cpp b/src/libtomahawk/accounts/spotify/SpotifyAccount.cpp index 6380ecb67..2aaa30505 100644 --- a/src/libtomahawk/accounts/spotify/SpotifyAccount.cpp +++ b/src/libtomahawk/accounts/spotify/SpotifyAccount.cpp @@ -29,6 +29,8 @@ #include "Pipeline.h" #include "accounts/AccountManager.h" #include "utils/Closure.h" +#include "SpotifyInfoPlugin.h" +#include "infosystem/InfoSystem.h" #ifndef ENABLE_HEADLESS #include "jobview/JobStatusView.h" @@ -106,6 +108,12 @@ SpotifyAccount::init() AtticaManager::instance()->registerCustomAccount( s_resolverId, this ); qRegisterMetaType< Tomahawk::Accounts::SpotifyPlaylistInfo* >( "Tomahawk::Accounts::SpotifyPlaylist*" ); + if ( infoPlugin() && Tomahawk::InfoSystem::InfoSystem::instance()->workerThread() ) + { + infoPlugin().data()->moveToThread( Tomahawk::InfoSystem::InfoSystem::instance()->workerThread().data() ); + Tomahawk::InfoSystem::InfoSystem::instance()->addInfoPlugin( infoPlugin() ); + } + if ( !AtticaManager::instance()->resolversLoaded() ) { // If we're still waiting to load, wait for the attica resolvers to come down the pipe @@ -328,6 +336,18 @@ SpotifyAccount::connectionState() const } +InfoSystem::InfoPluginPtr +SpotifyAccount::infoPlugin() +{ + if ( m_infoPlugin.isNull() ) + { + m_infoPlugin = QWeakPointer< InfoSystem::SpotifyInfoPlugin >( new InfoSystem::SpotifyInfoPlugin( this ) ); + } + + return InfoSystem::InfoPluginPtr( m_infoPlugin.data() ); +} + + void SpotifyAccount::resolverInstalled(const QString& resolverId) { @@ -384,6 +404,14 @@ SpotifyAccount::setManualResolverPath( const QString &resolverPath ) } +bool +SpotifyAccount::loggedIn() const +{ + // TODO pending newconfigui branch + return enabled() && !m_spotifyResolver.isNull() && m_spotifyResolver.data()->running(); +} + + void SpotifyAccount::hookupAfterDeletion( bool autoEnable ) { diff --git a/src/libtomahawk/accounts/spotify/SpotifyAccount.h b/src/libtomahawk/accounts/spotify/SpotifyAccount.h index 51b55ee44..4490be8b5 100644 --- a/src/libtomahawk/accounts/spotify/SpotifyAccount.h +++ b/src/libtomahawk/accounts/spotify/SpotifyAccount.h @@ -35,6 +35,12 @@ class QTimer; class ScriptResolver; namespace Tomahawk { + +namespace InfoSystem +{ + class SpotifyInfoPlugin; +} + namespace Accounts { class SpotifyAccountConfig; @@ -89,7 +95,7 @@ public: virtual void deauthenticate(); virtual QWidget* aclWidget() { return 0; } - virtual Tomahawk::InfoSystem::InfoPluginPtr infoPlugin() { return Tomahawk::InfoSystem::InfoPluginPtr(); } + virtual Tomahawk::InfoSystem::InfoPluginPtr infoPlugin(); virtual SipPlugin* sipPlugin() { return 0; } virtual bool preventEnabling() const { return m_preventEnabling; } @@ -102,6 +108,8 @@ public: void setManualResolverPath( const QString& resolverPath ); + bool loggedIn() const; + public slots: void aboutToShow( QAction* action, const Tomahawk::playlist_ptr& playlist ); void syncActionTriggered( bool ); @@ -143,6 +151,7 @@ private: QWeakPointer m_configWidget; QWeakPointer m_aboutWidget; QWeakPointer m_spotifyResolver; + QWeakPointer< InfoSystem::SpotifyInfoPlugin > m_infoPlugin; QMap > m_qidToSlotMap; diff --git a/src/libtomahawk/accounts/spotify/SpotifyInfoPlugin.cpp b/src/libtomahawk/accounts/spotify/SpotifyInfoPlugin.cpp new file mode 100644 index 000000000..297b93fe2 --- /dev/null +++ b/src/libtomahawk/accounts/spotify/SpotifyInfoPlugin.cpp @@ -0,0 +1,263 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2012 Leo Franchi + * + * 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 "SpotifyInfoPlugin.h" + +#include "SpotifyAccount.h" +#include "utils/Closure.h" + +using namespace Tomahawk; +using namespace Tomahawk::InfoSystem; + + +SpotifyInfoPlugin::SpotifyInfoPlugin( Accounts::SpotifyAccount* account ) + : InfoPlugin() + , m_account( QWeakPointer< Accounts::SpotifyAccount >( account ) ) +{ + if ( !m_account.isNull() ) + m_supportedGetTypes << InfoAlbumSongs; +} + + +SpotifyInfoPlugin::~SpotifyInfoPlugin() +{ + +} + + +void +SpotifyInfoPlugin::getInfo( InfoRequestData requestData ) +{ + switch ( requestData.type ) + { + case InfoAlbumSongs: + { + if ( !requestData.input.canConvert< Tomahawk::InfoSystem::InfoStringHash >() ) + { + dataError( requestData ); + return; + } + + InfoStringHash hash = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >(); + if ( !hash.contains( "album" ) ) + { + dataError( requestData ); + return; + } + + Tomahawk::InfoSystem::InfoStringHash criteria; + criteria[ "album" ] = hash[ "album" ]; + if ( hash.contains( "artist" ) ) + criteria["artist"] = hash["artist"]; + + emit getCachedInfo( criteria, 2419200000, requestData ); + + return; + } + default: + dataError( requestData ); + } +} + + +void +SpotifyInfoPlugin::notInCacheSlot( InfoStringHash criteria, InfoRequestData requestData ) +{ + switch ( requestData.type ) + { + case InfoAlbumSongs: + { + const QString album = criteria[ "album" ]; + const QString artist = criteria[ "artist" ]; + + if ( m_account.isNull() || !m_account.data()->loggedIn() ) + { + // No running spotify account, use our webservice + QUrl lookupUrl( "http://ws.spotify.com/search/1/album.json" ); + lookupUrl.addQueryItem( "q", QString( "%1 %2" ).arg( album ).arg( album ) ); + + QNetworkReply * reply = TomahawkUtils::nam()->get( QNetworkRequest( lookupUrl ) ); + NewClosure( reply, SIGNAL( finished() ), this, SLOT( albumIdLookupFinished( QNetworkReply*, Tomahawk::InfoSystem::InfoRequestData ) ), reply, requestData ); + } + else + { + // Running resolver, so do the lookup through that + qDebug() << Q_FUNC_INFO << "Doing album lookup through spotify:" << album << artist; + QVariantMap message; + message[ "_msgtype" ] = "albumListing"; + message[ "artist" ] = artist; + message[ "album" ] = album; + + const QString qid = m_account.data()->sendMessage( message, this, "albumListingResult" ); + + m_waitingForResults[ qid ] = requestData; + } + break; + } + default: + { + Q_ASSERT( false ); + break; + } + } +} + + +void +SpotifyInfoPlugin::albumListingResult( const QString& msgType, const QVariantMap& msg ) +{ + Q_ASSERT( msg.contains( "qid" ) ); + Q_ASSERT( m_waitingForResults.contains( msg.value( "qid" ).toString() ) ); + + if ( !msg.contains( "qid" ) || !m_waitingForResults.contains( msg.value( "qid" ).toString() ) ) + return; + + const InfoRequestData requestData = m_waitingForResults.take( msg.value( "qid" ).toString() ); + + QVariantList tracks = msg.value( "tracks" ).toList(); + QStringList trackNameList; + + foreach ( const QVariant track, tracks ) + { + const QVariantMap trackData = track.toMap(); + if ( trackData.contains( "track" ) && !trackData[ "track" ].toString().isEmpty() ) + trackNameList << trackData[ "track" ].toString(); + } + + qDebug() << Q_FUNC_INFO << "Successfully got album listing from spotify resolver"; + trackListResult( trackNameList, requestData ); +} + + +void +SpotifyInfoPlugin::albumIdLookupFinished( QNetworkReply* reply, const InfoRequestData& requestData ) +{ + Q_ASSERT( reply ); + + reply->deleteLater(); + + if ( reply->error() == QNetworkReply::NoError ) + { + QJson::Parser p; + const QVariantMap response = p.parse( reply ).toMap(); + if ( !response.contains( "albums" ) ) + { + dataError( requestData ); + return; + } + + const QVariantList albums = response.value( "albums" ).toList(); + if ( albums.isEmpty() ) + { + dataError( requestData ); + return; + } + + const QVariantMap album = albums.first().toMap(); + const QString id = album.value( "href" ).toString(); + if ( id.isEmpty() || !id.contains( "spotify:album" ) ) + { + qDebug() << "Empty or malformed spotify album ID from json:" << id << response; + dataError( requestData ); + return; + } + + qDebug() << "Doing spotify album lookup via webservice with ID:" << id; + + QUrl lookupUrl( QString( "http://spotikea.tomahawk-player.org/browse/%1" ).arg( id ) ); + + + QNetworkReply * reply = TomahawkUtils::nam()->get( QNetworkRequest( lookupUrl ) ); + NewClosure( reply, SIGNAL( finished() ), this, SLOT( albumContentsLookupFinished( QNetworkReply*, Tomahawk::InfoSystem::InfoRequestData ) ), reply, requestData ); + } + else + { + qDebug() << "Network Error retrieving ID from spotify metadata service:" << reply->error() << reply->errorString() << reply->url(); + } +} + + +void +SpotifyInfoPlugin::albumContentsLookupFinished( QNetworkReply* reply, const InfoRequestData& requestData ) +{ + Q_ASSERT( reply ); + + reply->deleteLater(); + + if ( reply->error() == QNetworkReply::NoError ) + { + QJson::Parser p; + const QVariantMap response = p.parse( reply ).toMap(); + + if ( !response.contains( "album" ) ) + { + dataError( requestData ); + return; + } + + const QVariantMap album = response.value( "album" ).toMap(); + if ( !album.contains( "result" ) || album.value( "result" ).toList().isEmpty() ) + { + dataError( requestData ); + return; + } + + const QVariantList albumTracks = album.value( "result" ).toList(); + QStringList trackNameList; + + foreach ( const QVariant& track, albumTracks ) + { + const QVariantMap trackMap = track.toMap(); + if ( trackMap.contains( "title" ) ) + trackNameList << trackMap.value( "title" ).toString(); + } + + qDebug() << Q_FUNC_INFO << "Successfully got album listing from spotikea service!"; + + if ( trackNameList.isEmpty() ) + dataError( requestData ); + else + trackListResult( trackNameList, requestData ); + } + else + { + qDebug() << "Network Error retrieving ID from spotify metadata service:" << reply->error() << reply->errorString() << reply->url(); + } +} + +void +SpotifyInfoPlugin::dataError( InfoRequestData requestData ) +{ + emit info( requestData, QVariant() ); +} + + +void +SpotifyInfoPlugin::trackListResult( const QStringList& trackNameList, const InfoRequestData& requestData ) +{ + QVariantMap returnedData; + returnedData["tracks"] = trackNameList; + + emit info( requestData, returnedData ); + + Tomahawk::InfoSystem::InfoStringHash criteria; + criteria["artist"] = requestData.input.value< InfoStringHash>()["artist"]; + criteria["album"] = requestData.input.value< InfoStringHash>()["album"]; + + emit updateCache( criteria, 0, requestData.type, returnedData ); +} diff --git a/src/libtomahawk/accounts/spotify/SpotifyInfoPlugin.h b/src/libtomahawk/accounts/spotify/SpotifyInfoPlugin.h new file mode 100644 index 000000000..fafc0cead --- /dev/null +++ b/src/libtomahawk/accounts/spotify/SpotifyInfoPlugin.h @@ -0,0 +1,74 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2012 Leo Franchi + * + * 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 SPOTIFYINFOPLUGIN_H +#define SPOTIFYINFOPLUGIN_H + +#include "infosystem/InfoSystem.h" +#include "DllMacro.h" + +#include + +class QNetworkReply; + +namespace Tomahawk +{ + +namespace Accounts +{ + class SpotifyAccount; +} + +namespace InfoSystem +{ + +class DLLEXPORT SpotifyInfoPlugin : public InfoPlugin +{ + Q_OBJECT + +public: + explicit SpotifyInfoPlugin( Accounts::SpotifyAccount* account ); + virtual ~SpotifyInfoPlugin(); + +public slots: + void albumListingResult( const QString& msgType, const QVariantMap& msg ); + +protected slots: + virtual void init() {} + virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ); + virtual void notInCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData ); + virtual void pushInfo( Tomahawk::InfoSystem::InfoPushData ) {} + +private slots: + void albumIdLookupFinished( QNetworkReply* reply, const Tomahawk::InfoSystem::InfoRequestData& requestData ); + void albumContentsLookupFinished( QNetworkReply* reply, const Tomahawk::InfoSystem::InfoRequestData& requestData ); + +private: + void dataError( InfoRequestData ); + void trackListResult( const QStringList& trackNameList, const Tomahawk::InfoSystem::InfoRequestData& requestData ); + + QHash< QString, InfoRequestData > m_waitingForResults; + + QWeakPointer< Tomahawk::Accounts::SpotifyAccount > m_account; +}; + +} + +} + +#endif // SPOTIFYINFOPLUGIN_H From 7030d43e32a18bb686b96bde860c36340744ba4b Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 6 Jul 2012 04:38:40 +0200 Subject: [PATCH 2/9] * Disable a bit of debug. --- src/AclRegistryImpl.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/AclRegistryImpl.cpp b/src/AclRegistryImpl.cpp index f347d4755..e20585930 100644 --- a/src/AclRegistryImpl.cpp +++ b/src/AclRegistryImpl.cpp @@ -83,7 +83,7 @@ ACLRegistryImpl::isAuthorizedUser( const QString& dbid, const QString &username, } } #endif - + bool found = false; QMutableListIterator< ACLRegistry::User > i( m_cache ); while ( i.hasNext() ) @@ -187,8 +187,8 @@ ACLRegistryImpl::queueNextJob() QMetaObject::invokeMethod( this, "queueNextJob", Qt::QueuedConnection ); return; } - tLog() << Q_FUNC_INFO << "jobCount = " << m_jobCount; - tLog() << Q_FUNC_INFO << "jobQueue size = " << m_jobQueue.length(); + tLog() << Q_FUNC_INFO << "jobCount =" << m_jobCount; + tLog() << Q_FUNC_INFO << "jobQueue size =" << m_jobQueue.length(); if ( m_jobCount != 0 ) return; @@ -202,14 +202,14 @@ ACLRegistryImpl::queueNextJob() ACLRegistry::ACL acl = isAuthorizedUser( dbid, job->username(), ACLRegistry::NotFound, true ); if ( acl != ACLRegistry::NotFound ) { - tLog() << Q_FUNC_INFO << "Found existing acl entry for = " << user.knownAccountIds.first(); + tLog() << Q_FUNC_INFO << "Found existing acl entry for =" << user.knownAccountIds.first(); found = true; break; } } if ( found ) { - tLog() << Q_FUNC_INFO << "deleting job, already have ACL for " << user.knownAccountIds.first(); + tLog() << Q_FUNC_INFO << "deleting job, already have ACL for" << user.knownAccountIds.first(); delete job; QTimer::singleShot( 0, this, SLOT( queueNextJob() ) ); return; @@ -225,6 +225,7 @@ ACLRegistryImpl::queueNextJob() } #endif + void ACLRegistryImpl::wipeEntries() { @@ -232,6 +233,7 @@ ACLRegistryImpl::wipeEntries() save(); } + void ACLRegistryImpl::load() { @@ -244,7 +246,6 @@ ACLRegistryImpl::load() tLog() << Q_FUNC_INFO << "entry is invalid"; continue; } - tLog() << Q_FUNC_INFO << "loading entry"; ACLRegistry::User entryUser = entry.value< ACLRegistry::User >(); if ( entryUser.knownAccountIds.empty() || entryUser.knownDbids.empty() ) { @@ -263,7 +264,7 @@ ACLRegistryImpl::save() QVariantList entryList; foreach ( ACLRegistry::User user, m_cache ) { - tLog() << Q_FUNC_INFO << "user is " << user.uuid << " with known name " << user.knownAccountIds.first(); + tLog() << Q_FUNC_INFO << "user is" << user.uuid << "with known name" << user.knownAccountIds.first(); QVariant val = QVariant::fromValue< ACLRegistry::User >( user ); if ( val.isValid() ) entryList.append( val ); From b4fa46c3c7430a6ad91b5896edaa7606c41d5703 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 6 Jul 2012 04:39:10 +0200 Subject: [PATCH 3/9] * Moved properties context entry below the separator. --- src/libtomahawk/ContextMenu.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/libtomahawk/ContextMenu.cpp b/src/libtomahawk/ContextMenu.cpp index ab1107531..f416f701c 100644 --- a/src/libtomahawk/ContextMenu.cpp +++ b/src/libtomahawk/ContextMenu.cpp @@ -111,20 +111,21 @@ ContextMenu::setQueries( const QList& queries ) if ( m_supportedActions & ActionPage && itemCount() == 1 ) m_sigmap->setMapping( addAction( tr( "&Show Track Page" ) ), ActionPage ); - if ( m_supportedActions & ActionEditMetadata && itemCount() == 1 ) { + addSeparator(); + if ( m_supportedActions & ActionEditMetadata && itemCount() == 1 ) + { if ( m_queries.first()->results().isEmpty() ) return; Tomahawk::result_ptr result = m_queries.first()->results().first(); if ( result->collection() && result->collection()->source() && - result->collection()->source()->isLocal() ) { - m_sigmap->setMapping( addAction( tr( "Properties") ), ActionEditMetadata ); + result->collection()->source()->isLocal() ) + { + m_sigmap->setMapping( addAction( tr( "Properties..." ) ), ActionEditMetadata ); } } - addSeparator(); - if ( m_supportedActions & ActionDelete ) m_sigmap->setMapping( addAction( queries.count() > 1 ? tr( "&Delete Items" ) : tr( "&Delete Item" ) ), ActionDelete ); From 427a26e03410eb54b5927b3b638309ab8a7c10b5 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Mon, 2 Jul 2012 12:07:33 -0400 Subject: [PATCH 4/9] New spotify config --- .../accounts/spotify/SpotifyAccount.cpp | 20 +++++- .../accounts/spotify/SpotifyAccount.h | 2 + .../accounts/spotify/SpotifyAccountConfig.cpp | 69 ++++++++++++++++--- .../accounts/spotify/SpotifyAccountConfig.h | 15 ++-- src/libtomahawk/resolvers/ScriptResolver.cpp | 1 + 5 files changed, 92 insertions(+), 15 deletions(-) diff --git a/src/libtomahawk/accounts/spotify/SpotifyAccount.cpp b/src/libtomahawk/accounts/spotify/SpotifyAccount.cpp index 2aaa30505..71e251dcd 100644 --- a/src/libtomahawk/accounts/spotify/SpotifyAccount.cpp +++ b/src/libtomahawk/accounts/spotify/SpotifyAccount.cpp @@ -543,6 +543,13 @@ SpotifyAccount::resolverMessage( const QString &msgType, const QVariantMap &msg creds[ "highQuality" ] = msg.value( "highQuality" ); setCredentials( creds ); + const bool loggedIn = msg.value( "loggedIn", false ).toBool(); + if ( loggedIn ) + { + configurationWidget(); + m_configWidget.data()->loginResponse( true, QString(), creds[ "username" ].toString() ); + } + qDebug() << "Set creds:" << creds.value( "username" ) << creds.value( "password" ) << msg.value( "username" ) << msg.value( "password" ); QVariantHash config = configuration(); @@ -710,7 +717,7 @@ SpotifyAccount::resolverMessage( const QString &msgType, const QVariantMap &msg if ( m_configWidget.data() ) { const QString message = msg.value( "message" ).toString(); - m_configWidget.data()->loginResponse( success, message ); + m_configWidget.data()->loginResponse( success, message, creds[ "username" ].toString() ); } } else if ( msgType == "playlistDeleted" ) @@ -769,6 +776,7 @@ SpotifyAccount::configurationWidget() { m_configWidget = QWeakPointer< SpotifyAccountConfig >( new SpotifyAccountConfig( this ) ); connect( m_configWidget.data(), SIGNAL( login( QString,QString ) ), this, SLOT( login( QString,QString ) ) ); + connect( m_configWidget.data(), SIGNAL( logout() ), this, SLOT( logout() ) ); m_configWidget.data()->setPlaylists( m_allSpotifyPlaylists ); } @@ -851,7 +859,6 @@ SpotifyAccount::saveConfig() void SpotifyAccount::login( const QString& username, const QString& password ) { - // Send the result to the resolver QVariantMap msg; msg[ "_msgtype" ] = "login"; msg[ "username" ] = username; @@ -863,6 +870,15 @@ SpotifyAccount::login( const QString& username, const QString& password ) } +void +SpotifyAccount::logout() +{ + QVariantMap msg; + msg[ "_msgtype" ] = "logout"; + m_spotifyResolver.data()->sendMessage( msg ); +} + + void SpotifyAccount::startPlaylistSync( SpotifyPlaylistInfo* playlist ) { diff --git a/src/libtomahawk/accounts/spotify/SpotifyAccount.h b/src/libtomahawk/accounts/spotify/SpotifyAccount.h index 4490be8b5..b6df82ca1 100644 --- a/src/libtomahawk/accounts/spotify/SpotifyAccount.h +++ b/src/libtomahawk/accounts/spotify/SpotifyAccount.h @@ -122,6 +122,8 @@ private slots: void resolverMessage( const QString& msgType, const QVariantMap& msg ); void login( const QString& username, const QString& password ); + void logout(); + // SpotifyResolver message handlers, all take msgtype, msg as argument // void ( const QString& msgType, const QVariantMap& msg ); void startPlaylistSyncWithPlaylist( const QString& msgType, const QVariantMap& msg ); diff --git a/src/libtomahawk/accounts/spotify/SpotifyAccountConfig.cpp b/src/libtomahawk/accounts/spotify/SpotifyAccountConfig.cpp index 5e5676f24..10b21cf7b 100644 --- a/src/libtomahawk/accounts/spotify/SpotifyAccountConfig.cpp +++ b/src/libtomahawk/accounts/spotify/SpotifyAccountConfig.cpp @@ -25,6 +25,7 @@ #include #include #include +#include using namespace Tomahawk; using namespace Accounts; @@ -32,9 +33,11 @@ using namespace Accounts; SpotifyAccountConfig::SpotifyAccountConfig( SpotifyAccount *account ) : QWidget( 0 ) , m_ui( new Ui::SpotifyConfig ) + , m_loggedInUser( 0 ) , m_account( account ) , m_playlistsLoading( 0 ) , m_loggedInManually( false ) + , m_isLoggedIn( false ) { m_ui->setupUi( this ); @@ -132,28 +135,42 @@ SpotifyAccountConfig::setPlaylists( const QList& playlist void SpotifyAccountConfig::doLogin() { - m_ui->loginButton->setText( tr( "Logging in..." ) ); - m_ui->loginButton->setEnabled( false ); + if ( !m_isLoggedIn ) + { + m_ui->loginButton->setText( tr( "Logging in..." ) ); + m_ui->loginButton->setEnabled( false ); - m_playlistsLoading->fadeIn(); - m_loggedInManually = true; + m_playlistsLoading->fadeIn(); + m_loggedInManually = true; - emit login( username(), password() ); + emit login( username(), password() ); + } + else + { + // Log out + m_isLoggedIn = false; + m_loggedInManually = false; + m_verifiedUsername.clear(); + emit logout(); + showLoggedOut(); + } } void -SpotifyAccountConfig::loginResponse( bool success, const QString& msg ) +SpotifyAccountConfig::loginResponse( bool success, const QString& msg, const QString& username ) { if ( success ) { - m_ui->loginButton->setText( tr( "Logged in!" ) ); - m_ui->loginButton->setEnabled( false ); + m_verifiedUsername = username; + m_isLoggedIn = true; + showLoggedIn(); } else { setPlaylists( QList< SpotifyPlaylistInfo* >() ); m_playlistsLoading->fadeOut(); + m_ui->loginButton->setText( tr( "Failed: %1" ).arg( msg ) ); m_ui->loginButton->setEnabled( true ); } @@ -161,6 +178,42 @@ SpotifyAccountConfig::loginResponse( bool success, const QString& msg ) } +void +SpotifyAccountConfig::showLoggedIn() +{ + m_ui->passwordEdit->hide(); + m_ui->passwordLabel->hide(); + m_ui->usernameEdit->hide(); + m_ui->usernameLabel->hide(); + + if ( !m_loggedInUser ) + { + m_loggedInUser = new QLabel( this ); + m_ui->verticalLayout->insertWidget( 1, m_loggedInUser, 0, Qt::AlignCenter ); + } + + m_loggedInUser->setText( tr( "Logged in as %1" ).arg( m_verifiedUsername ) ); + + m_ui->loginButton->setText( tr( "Log Out" ) ); + m_ui->loginButton->setEnabled( true ); +} + + +void +SpotifyAccountConfig::showLoggedOut() +{ + m_ui->passwordEdit->show(); + m_ui->passwordLabel->show(); + m_ui->usernameEdit->show(); + m_ui->usernameLabel->show(); + + m_loggedInUser->hide(); + + m_ui->loginButton->setText( tr( "Log In" ) ); + m_ui->loginButton->setEnabled( true ); +} + + void SpotifyAccountConfig::resetLoginButton() { diff --git a/src/libtomahawk/accounts/spotify/SpotifyAccountConfig.h b/src/libtomahawk/accounts/spotify/SpotifyAccountConfig.h index 79c398e04..712e139ad 100644 --- a/src/libtomahawk/accounts/spotify/SpotifyAccountConfig.h +++ b/src/libtomahawk/accounts/spotify/SpotifyAccountConfig.h @@ -23,6 +23,7 @@ #include #include +class QLabel; class AnimatedSpinner; class QShowEvent; @@ -55,14 +56,13 @@ public: void loadFromConfig(); void saveSettings(); - void loginResponse( bool success, const QString& msg ); + void loginResponse( bool success, const QString& msg, const QString& username ); bool loggedInManually() const { return m_loggedInManually; } + signals: void login( const QString& username, const QString& pw ); - -public slots: -// void verifyResult( const QString& msgType, const QVariantMap& msg ); + void logout(); protected: void showEvent( QShowEvent* event ); @@ -72,10 +72,15 @@ private slots: void resetLoginButton(); private: + void showLoggedIn(); + void showLoggedOut(); + Ui::SpotifyConfig* m_ui; + QLabel* m_loggedInUser; + QString m_verifiedUsername; SpotifyAccount* m_account; AnimatedSpinner* m_playlistsLoading; - bool m_loggedInManually; + bool m_loggedInManually, m_isLoggedIn; }; } diff --git a/src/libtomahawk/resolvers/ScriptResolver.cpp b/src/libtomahawk/resolvers/ScriptResolver.cpp index 3bf81dbda..9057e7131 100644 --- a/src/libtomahawk/resolvers/ScriptResolver.cpp +++ b/src/libtomahawk/resolvers/ScriptResolver.cpp @@ -387,6 +387,7 @@ ScriptResolver::doSetup( const QVariantMap& m ) m_ready = true; m_configSent = false; + m_num_restarts = 0; if ( !m_stopped ) Tomahawk::Pipeline::instance()->addResolver( this ); From 35a0db7a07e089266efa34bcd8a7e8a254498367 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Tue, 3 Jul 2012 09:53:49 -0400 Subject: [PATCH 5/9] Some more fixes --- src/libtomahawk/Result.cpp | 4 ++++ .../accounts/spotify/SpotifyAccountConfig.cpp | 12 ++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/libtomahawk/Result.cpp b/src/libtomahawk/Result.cpp index 62e204058..d681cca3f 100644 --- a/src/libtomahawk/Result.cpp +++ b/src/libtomahawk/Result.cpp @@ -207,6 +207,10 @@ Result::toQuery() if ( m_query.isNull() ) { m_query = Tomahawk::Query::get( artist()->name(), track(), album()->name() ); + + if ( m_query.isNull() ) + return query_ptr(); + m_query->setAlbumPos( albumpos() ); m_query->setDiscNumber( discnumber() ); m_query->setDuration( duration() ); diff --git a/src/libtomahawk/accounts/spotify/SpotifyAccountConfig.cpp b/src/libtomahawk/accounts/spotify/SpotifyAccountConfig.cpp index 10b21cf7b..a1e9cc3ef 100644 --- a/src/libtomahawk/accounts/spotify/SpotifyAccountConfig.cpp +++ b/src/libtomahawk/accounts/spotify/SpotifyAccountConfig.cpp @@ -43,8 +43,8 @@ SpotifyAccountConfig::SpotifyAccountConfig( SpotifyAccount *account ) connect( m_ui->loginButton, SIGNAL( clicked( bool ) ), this, SLOT( doLogin() ) ); - connect( m_ui->usernameEdit, SIGNAL( textChanged( QString ) ), this, SLOT( resetLoginButton() ) ); - connect( m_ui->passwordEdit, SIGNAL( textChanged( QString ) ), this, SLOT( resetLoginButton() ) ); + connect( m_ui->usernameEdit, SIGNAL( textEdited( QString ) ), this, SLOT( resetLoginButton() ) ); + connect( m_ui->passwordEdit, SIGNAL( textEdited( QString ) ), this, SLOT( resetLoginButton() ) ); loadFromConfig(); m_playlistsLoading = new AnimatedSpinner( m_ui->playlistList ); @@ -151,6 +151,7 @@ SpotifyAccountConfig::doLogin() m_isLoggedIn = false; m_loggedInManually = false; m_verifiedUsername.clear(); + m_ui->playlistList->clear(); emit logout(); showLoggedOut(); } @@ -217,7 +218,10 @@ SpotifyAccountConfig::showLoggedOut() void SpotifyAccountConfig::resetLoginButton() { - m_ui->loginButton->setText( tr( "Log In" ) ); - m_ui->loginButton->setEnabled( true ); + if ( !m_isLoggedIn ) + { + m_ui->loginButton->setText( tr( "Log In" ) ); + m_ui->loginButton->setEnabled( true ); + } } From ad0be3aa3c24ca44c939dae46927e400c6503d75 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Thu, 5 Jul 2012 23:33:28 -0400 Subject: [PATCH 6/9] Keep config UI in sync with resolver --- .../accounts/spotify/SpotifyAccount.cpp | 50 ++++++++++++------- .../accounts/spotify/SpotifyAccount.h | 2 +- .../accounts/spotify/SpotifyAccountConfig.cpp | 21 ++++++-- src/libtomahawk/resolvers/ScriptResolver.cpp | 15 ------ src/libtomahawk/resolvers/ScriptResolver.h | 1 - 5 files changed, 52 insertions(+), 37 deletions(-) diff --git a/src/libtomahawk/accounts/spotify/SpotifyAccount.cpp b/src/libtomahawk/accounts/spotify/SpotifyAccount.cpp index 71e251dcd..a72b828ea 100644 --- a/src/libtomahawk/accounts/spotify/SpotifyAccount.cpp +++ b/src/libtomahawk/accounts/spotify/SpotifyAccount.cpp @@ -82,6 +82,7 @@ SpotifyAccountFactory::icon() const SpotifyAccount::SpotifyAccount( const QString& accountId ) : CustomAtticaAccount( accountId ) , m_preventEnabling( false ) + , m_loggedIn( false ) { init(); } @@ -203,15 +204,10 @@ SpotifyAccount::hookupResolver() connect( m_spotifyResolver.data(), SIGNAL( changed() ), this, SLOT( resolverChanged() ) ); connect( m_spotifyResolver.data(), SIGNAL( customMessage( QString,QVariantMap ) ), this, SLOT( resolverMessage( QString, QVariantMap ) ) ); - const bool hasMigrated = configuration().value( "hasMigrated" ).toBool(); - if ( !hasMigrated ) - { - qDebug() << "Getting credentials from spotify resolver to migrate to in-app config"; - QVariantMap msg; - msg[ "_msgtype" ] = "getCredentials"; - m_spotifyResolver.data()->sendMessage( msg ); - } - + // Always get logged in status + QVariantMap msg; + msg[ "_msgtype" ] = "getCredentials"; + m_spotifyResolver.data()->sendMessage( msg ); } @@ -407,8 +403,7 @@ SpotifyAccount::setManualResolverPath( const QString &resolverPath ) bool SpotifyAccount::loggedIn() const { - // TODO pending newconfigui branch - return enabled() && !m_spotifyResolver.isNull() && m_spotifyResolver.data()->running(); + return m_loggedIn; } @@ -543,11 +538,13 @@ SpotifyAccount::resolverMessage( const QString &msgType, const QVariantMap &msg creds[ "highQuality" ] = msg.value( "highQuality" ); setCredentials( creds ); - const bool loggedIn = msg.value( "loggedIn", false ).toBool(); - if ( loggedIn ) + m_loggedIn = msg.value( "loggedIn", false ).toBool(); + if ( m_loggedIn ) { configurationWidget(); - m_configWidget.data()->loginResponse( true, QString(), creds[ "username" ].toString() ); + + if ( !m_configWidget.isNull() ) + m_configWidget.data()->loginResponse( true, QString(), creds[ "username" ].toString() ); } qDebug() << "Set creds:" << creds.value( "username" ) << creds.value( "password" ) << msg.value( "username" ) << msg.value( "password" ); @@ -710,6 +707,8 @@ SpotifyAccount::resolverMessage( const QString &msgType, const QVariantMap &msg const bool success = msg.value( "success" ).toBool(); + m_loggedIn = success; + if ( success ) createActions(); @@ -730,6 +729,23 @@ SpotifyAccount::resolverMessage( const QString &msgType, const QVariantMap &msg SpotifyPlaylistUpdater* updater = m_updaters.take( plid ); updater->remove( false ); } + else if ( msgType == "status" ) + { + const bool loggedIn = msg.value( "loggedIn" ).toBool(); + const QString username = msg.value( "username" ).toString(); + + qDebug() << "Got status message with login info:" << loggedIn << username; + + if ( !loggedIn || username.isEmpty() || credentials().value( "username").toString() != username ) + m_loggedIn = false; + + QVariantMap msg; + msg[ "_msgtype" ] = "status"; + msg[ "_status" ] = 1; + sendMessage( msg ); + + return; + } } @@ -769,9 +785,6 @@ SpotifyAccount::icon() const QWidget* SpotifyAccount::configurationWidget() { - if ( m_spotifyResolver.isNull() || !m_spotifyResolver.data()->running() ) - return 0; - if ( m_configWidget.isNull() ) { m_configWidget = QWeakPointer< SpotifyAccountConfig >( new SpotifyAccountConfig( this ) ); @@ -780,6 +793,9 @@ SpotifyAccount::configurationWidget() m_configWidget.data()->setPlaylists( m_allSpotifyPlaylists ); } + if ( m_spotifyResolver.isNull() || !m_spotifyResolver.data()->running() ) + return 0; + return static_cast< QWidget* >( m_configWidget.data() ); } diff --git a/src/libtomahawk/accounts/spotify/SpotifyAccount.h b/src/libtomahawk/accounts/spotify/SpotifyAccount.h index b6df82ca1..e524baed4 100644 --- a/src/libtomahawk/accounts/spotify/SpotifyAccount.h +++ b/src/libtomahawk/accounts/spotify/SpotifyAccount.h @@ -163,7 +163,7 @@ private: QHash< QString, playlist_ptr > m_waitingForCreateReply; - bool m_preventEnabling; + bool m_preventEnabling, m_loggedIn; SmartPointerList< QAction > m_customActions; friend class ::SpotifyPlaylistUpdater; diff --git a/src/libtomahawk/accounts/spotify/SpotifyAccountConfig.cpp b/src/libtomahawk/accounts/spotify/SpotifyAccountConfig.cpp index a1e9cc3ef..2c4f96c58 100644 --- a/src/libtomahawk/accounts/spotify/SpotifyAccountConfig.cpp +++ b/src/libtomahawk/accounts/spotify/SpotifyAccountConfig.cpp @@ -64,10 +64,21 @@ SpotifyAccountConfig::showEvent( QShowEvent *event ) void SpotifyAccountConfig::loadFromConfig() { - m_ui->usernameEdit->setText( m_account->credentials().value( "username" ).toString() ); + const QString username = m_account->credentials().value( "username" ).toString(); + m_ui->usernameEdit->setText( username ); m_ui->passwordEdit->setText( m_account->credentials().value( "password" ).toString() ); m_ui->streamingCheckbox->setChecked( m_account->credentials().value( "highQuality" ).toBool() ); m_ui->deleteOnUnsync->setChecked( m_account->deleteOnUnsync() ); + + if ( m_account->loggedIn() ) + { + qDebug() << "Loading spotify config widget with logged in username:" << username; + if ( !username.isEmpty() ) + m_verifiedUsername = username; + showLoggedIn(); + } + else + showLoggedOut(); } void @@ -149,7 +160,7 @@ SpotifyAccountConfig::doLogin() { // Log out m_isLoggedIn = false; - m_loggedInManually = false; + m_loggedInManually = true; m_verifiedUsername.clear(); m_ui->playlistList->clear(); emit logout(); @@ -163,6 +174,7 @@ SpotifyAccountConfig::loginResponse( bool success, const QString& msg, const QSt { if ( success ) { + qDebug() << Q_FUNC_INFO << "Login response with username:" << username; m_verifiedUsername = username; m_isLoggedIn = true; showLoggedIn(); @@ -193,6 +205,8 @@ SpotifyAccountConfig::showLoggedIn() m_ui->verticalLayout->insertWidget( 1, m_loggedInUser, 0, Qt::AlignCenter ); } + qDebug() << "Showing logged in withuserame:" << m_verifiedUsername; + m_loggedInUser->show(); m_loggedInUser->setText( tr( "Logged in as %1" ).arg( m_verifiedUsername ) ); m_ui->loginButton->setText( tr( "Log Out" ) ); @@ -208,7 +222,8 @@ SpotifyAccountConfig::showLoggedOut() m_ui->usernameEdit->show(); m_ui->usernameLabel->show(); - m_loggedInUser->hide(); + if ( m_loggedInUser ) + m_loggedInUser->hide(); m_ui->loginButton->setText( tr( "Log In" ) ); m_ui->loginButton->setEnabled( true ); diff --git a/src/libtomahawk/resolvers/ScriptResolver.cpp b/src/libtomahawk/resolvers/ScriptResolver.cpp index 9057e7131..ebfd79672 100644 --- a/src/libtomahawk/resolvers/ScriptResolver.cpp +++ b/src/libtomahawk/resolvers/ScriptResolver.cpp @@ -255,11 +255,6 @@ ScriptResolver::handleMsg( const QByteArray& msg ) setupConfWidget( m ); return; } - else if ( msgtype == "status" ) - { - sendStatus(); - return; - } else if ( msgtype == "results" ) { const QString qid = m.value( "qid" ).toString(); @@ -365,16 +360,6 @@ ScriptResolver::resolve( const Tomahawk::query_ptr& query ) } -void -ScriptResolver::sendStatus() -{ - QVariantMap msg; - msg[ "_msgtype" ] = "status"; - msg[ "_status" ] = 1; - sendMessage( msg ); -} - - void ScriptResolver::doSetup( const QVariantMap& m ) { diff --git a/src/libtomahawk/resolvers/ScriptResolver.h b/src/libtomahawk/resolvers/ScriptResolver.h index 36495c60b..0ffb3ac33 100644 --- a/src/libtomahawk/resolvers/ScriptResolver.h +++ b/src/libtomahawk/resolvers/ScriptResolver.h @@ -77,7 +77,6 @@ private: void sendMsg( const QByteArray& msg ); void doSetup( const QVariantMap& m ); void setupConfWidget( const QVariantMap& m ); - void sendStatus(); void startProcess(); From 2004977b0917bb9e307a830629175ee75aaa8d75 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 6 Jul 2012 06:07:55 +0200 Subject: [PATCH 7/9] * Emit resultsChanged() after adding / removing results in a Query. --- src/libtomahawk/Query.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libtomahawk/Query.cpp b/src/libtomahawk/Query.cpp index 456137c49..a8c7f7d7e 100644 --- a/src/libtomahawk/Query.cpp +++ b/src/libtomahawk/Query.cpp @@ -228,6 +228,7 @@ Query::addResults( const QList< Tomahawk::result_ptr >& newresults ) checkResults(); emit resultsAdded( newresults ); + emit resultsChanged(); } @@ -292,6 +293,7 @@ Query::removeResult( const Tomahawk::result_ptr& result ) emit resultsRemoved( result ); checkResults(); + emit resultsChanged(); } From 06c5f2e84bcaa435d298495057b4856764d4bea9 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 6 Jul 2012 06:08:35 +0200 Subject: [PATCH 8/9] * Hooking up to resultsChanged() is enough in PlayableItem. --- src/libtomahawk/playlist/PlayableItem.cpp | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/libtomahawk/playlist/PlayableItem.cpp b/src/libtomahawk/playlist/PlayableItem.cpp index 0bf7237b6..05882210a 100644 --- a/src/libtomahawk/playlist/PlayableItem.cpp +++ b/src/libtomahawk/playlist/PlayableItem.cpp @@ -89,12 +89,6 @@ PlayableItem::PlayableItem( const Tomahawk::query_ptr& query, PlayableItem* pare connect( query.data(), SIGNAL( updated() ), SIGNAL( dataChanged() ) ); - connect( query.data(), SIGNAL( resultsAdded( QList ) ), - SLOT( onResultsChanged() ) ); - - connect( query.data(), SIGNAL( resultsRemoved( Tomahawk::result_ptr ) ), - SLOT( onResultsChanged() ) ); - connect( query.data(), SIGNAL( resultsChanged() ), SLOT( onResultsChanged() ) ); } @@ -113,12 +107,6 @@ PlayableItem::PlayableItem( const Tomahawk::plentry_ptr& entry, PlayableItem* pa connect( m_query.data(), SIGNAL( updated() ), SIGNAL( dataChanged() ) ); - connect( m_query.data(), SIGNAL( resultsAdded( QList ) ), - SLOT( onResultsChanged() ) ); - - connect( m_query.data(), SIGNAL( resultsRemoved( Tomahawk::result_ptr ) ), - SLOT( onResultsChanged() ) ); - connect( m_query.data(), SIGNAL( resultsChanged() ), SLOT( onResultsChanged() ) ); } @@ -130,7 +118,7 @@ PlayableItem::init( PlayableItem* parent, int row ) m_fetchingMore = false; m_isPlaying = false; m_parent = parent; - + if ( parent ) { if ( row < 0 ) @@ -145,7 +133,7 @@ PlayableItem::init( PlayableItem* parent, int row ) this->model = parent->model; } - + if ( !m_query.isNull() ) { onResultsChanged(); From d4def82cd1c9dd632575313367002a40964bf766 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 6 Jul 2012 06:09:21 +0200 Subject: [PATCH 9/9] * Refetch cover when underlying metadata changed in PixmapDelegateFader. --- src/libtomahawk/utils/PixmapDelegateFader.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/libtomahawk/utils/PixmapDelegateFader.cpp b/src/libtomahawk/utils/PixmapDelegateFader.cpp index b1f2bfa56..d31793eef 100644 --- a/src/libtomahawk/utils/PixmapDelegateFader.cpp +++ b/src/libtomahawk/utils/PixmapDelegateFader.cpp @@ -51,6 +51,7 @@ PixmapDelegateFader::PixmapDelegateFader( const artist_ptr& artist, const QSize& { connect( m_artist.data(), SIGNAL( updated() ), SLOT( artistChanged() ) ); connect( m_artist.data(), SIGNAL( coverChanged() ), SLOT( artistChanged() ) ); + m_currentReference = m_artist->cover( size, forceLoad ); } @@ -67,6 +68,7 @@ PixmapDelegateFader::PixmapDelegateFader( const album_ptr& album, const QSize& s { connect( m_album.data(), SIGNAL( updated() ), SLOT( albumChanged() ) ); connect( m_album.data(), SIGNAL( coverChanged() ), SLOT( albumChanged() ) ); + m_currentReference = m_album->cover( size, forceLoad ); } @@ -82,8 +84,10 @@ PixmapDelegateFader::PixmapDelegateFader( const query_ptr& track, const QSize& s if ( !m_track.isNull() ) { connect( m_track.data(), SIGNAL( updated() ), SLOT( trackChanged() ) ); - connect( m_track.data(), SIGNAL( coverChanged() ), SLOT( trackChanged() ) ); - m_currentReference = m_track->cover( size, forceLoad ); + connect( m_track.data(), SIGNAL( resultsChanged() ), SLOT( trackChanged() ) ); + connect( m_track->displayQuery().data(), SIGNAL( coverChanged() ), SLOT( trackChanged() ) ); + + m_currentReference = m_track->displayQuery()->cover( size, forceLoad ); } init(); @@ -144,7 +148,7 @@ PixmapDelegateFader::setSize( const QSize& size ) else if ( !m_artist.isNull() ) m_currentReference = m_artist->cover( m_size ); else if ( !m_track.isNull() ) - m_currentReference = m_track->cover( m_size ); + m_currentReference = m_track->displayQuery()->cover( m_size ); } emit repaintRequest(); @@ -177,7 +181,8 @@ PixmapDelegateFader::trackChanged() if ( m_track.isNull() ) return; - QMetaObject::invokeMethod( this, "setPixmap", Qt::QueuedConnection, Q_ARG( QPixmap, m_track->cover( m_size ) ) ); + connect( m_track->displayQuery().data(), SIGNAL( coverChanged() ), SLOT( trackChanged() ) ); + QMetaObject::invokeMethod( this, "setPixmap", Qt::QueuedConnection, Q_ARG( QPixmap, m_track->displayQuery()->cover( m_size ) ) ); }