diff -r 4cc1412daed0 -r 560ce2306a17 mpviewplugins/mpdetailsviewplugin/src/mpquerymanager.cpp --- a/mpviewplugins/mpdetailsviewplugin/src/mpquerymanager.cpp Fri Aug 06 16:51:36 2010 -0500 +++ b/mpviewplugins/mpdetailsviewplugin/src/mpquerymanager.cpp Tue Aug 24 03:36:14 2010 -0500 @@ -16,7 +16,6 @@ */ #include "mpquerymanager.h" -#include #include #include #include @@ -25,58 +24,31 @@ #include #include #include -#include #include #include -#include -#include #include - -#include -#include -#include +#include +#include #include "mptrace.h" -const int KUndefined = -1; const int KRecommendationCount = 2; MpQueryManager::MpQueryManager() : mManager(0), mAlbumArtDownloader(0), - mThumbnailManager(0), mDefaultRecommendationAlbumArt("qtg_large_album_art"), mRequestType(NoRequest), - mRecommendationCount(0) - + mRecommendationCount(0) { TX_ENTRY - - QString privatePathQt( QCoreApplication::applicationDirPath() ); - TX_LOG_ARGS( "Private path: " << privatePathQt ); - QDir dir( privatePathQt ); - QString newDir = "detailsview"; - bool res = dir.mkdir( newDir ); - TX_LOG_ARGS( "New dir creation result: " << res); + mManager = new QNetworkAccessManager( this ); + // A second intance is necessary to reduce complexity. + // Otherwise, we would have to shoot async events when we want to receive inspire me items' album art + // and that may not always work. + mAlbumArtDownloader = new QNetworkAccessManager( this ); - // TODO: Instead of writing the album art to a file, - // then using Thumbnail Manager to convert it, etc. - // have you considered just loading it directly into QPixmap? - // QPixmap provides a loadFromData() that can load from QByteArray. - // This would not only make the availability of the album art immediate, - // but also save a lot of cleanup in file system, thumbnail manager, etc. - privatePathQt = privatePathQt + "/detailsview"; - QString albumArt1( privatePathQt + "/albumOne.png" ); - QString albumArt2( privatePathQt + "/albumTwo.png" ); - mRecommendationAlbumArtsName << albumArt1 << albumArt2; - TX_LOG_ARGS( "recommendation album art names: " << mRecommendationAlbumArtsName ); - - mManager = new QNetworkAccessManager( this ); - mAlbumArtDownloader = new QNetworkAccessManager( this ); // TODO: check if we can only use mManager - mThumbnailManager = new ThumbnailManager( this ); - mThumbnailManager->setQualityPreference( ThumbnailManager::OptimizeForQuality ); - mThumbnailManager->setThumbnailSize( ThumbnailManager::ThumbnailSmall ); - + mDownloadSignalMapper = new QSignalMapper(this); TX_EXIT } @@ -90,9 +62,7 @@ if ( mAlbumArtDownloader ) { mAlbumArtDownloader->deleteLater(); } - if( mThumbnailManager ) { - mThumbnailManager->deleteLater(); - } + delete mDownloadSignalMapper; TX_EXIT } @@ -115,21 +85,6 @@ TX_EXIT } - -void MpQueryManager::queryLocalMusicStore(QString artist,QString album,QString title) -{ - TX_ENTRY - mArtist=artist; - mAlbum=album; - mTitle=title; - // TODO: country information handling, MCC - QString queryURI("http://api.music.ovi.com/1.0/ru/?"); - constructRequest( queryURI ); - TX_LOG_ARGS( "queryURI : " << queryURI ); - retrieveInformation( queryURI ); - mRequestType = LocalStoreRequest; - TX_EXIT -} void MpQueryManager::queryInspireMeItems(QString artist,QString album,QString title) { @@ -140,7 +95,6 @@ // start querying inspire me items QString queryRecommendation("http://api.music.ovi.com/1.0/" + mMusicStore + "/releases/recommend/?"); constructRequest( queryRecommendation ); - // TODO: Store the token to a cenrep key // TODO: Tokens change per new ovi api release. // Need to figure out a way to get them updated on the fly queryRecommendation.append("&Token=03574704-e3d1-4466-9691-e0b34c7abfff"); @@ -161,13 +115,6 @@ mRecommendationArtists.clear(); mRecommendationAlbumArtsLink.clear(); mRecommendationAlbumArtsMap.clear(); - for ( int i = 0; i < mRecommendationAlbumArtsName.count(); ++i ) { - QFile file( mRecommendationAlbumArtsName.at( i ) ); - TX_LOG_ARGS( "File " << file.fileName() << " exists: " << file.exists() ); - if ( file.exists() && file.remove() ) { - TX_LOG_ARGS( "File " << file.fileName() << " removed"); - } - } TX_EXIT } @@ -284,7 +231,6 @@ void MpQueryManager::retrieveInformationNetworkError( QNetworkReply::NetworkError error ) { TX_ENTRY_ARGS( "Network error for retrieving Information" << error); - // TODO: agree on error handling Q_UNUSED(error) @@ -298,7 +244,6 @@ */ void MpQueryManager::retrieveInformationSslErrors( const QList &/*error*/ ) { - // TODO: agree on error handling TX_ENTRY_ARGS( "SSL error for retrieving Information" ); disconnect( mManager, SIGNAL( finished( QNetworkReply * ) ), this, SLOT( retrieveInformationFinished( QNetworkReply * ) ) ); signalError(); @@ -308,91 +253,47 @@ /*! Slot to call when downloading finished */ -void MpQueryManager::albumArtDownloaded( QNetworkReply* reply ) +void MpQueryManager::albumArtDownloaded( int index ) { - TX_ENTRY_ARGS( "mDownloadedAlbumArts = " << mDownloadedAlbumArts ); - TX_ENTRY_ARGS( "QNetworkReply obj " << reply); + TX_ENTRY_ARGS( "mDownloadedAlbumArts = " << mDownloadedAlbumArts << "index = " << index); + QNetworkReply* reply = qobject_cast ( qobject_cast( sender() )->mapping( index ) ); // It seems we get several finished signals for the same reply obj // do nothing if we get a second signal if( mReplys.indexOf(reply) == -1 ) { TX_LOG_ARGS("Warning: QNetworkReply AA request may have been processed in previous call: " << reply ); return; } - + if ( reply->error() == QNetworkReply::NoError ) { - - QString fileName = mRecommendationAlbumArtsName.at( mDownloadedAlbumArts ); - QByteArray imageData = reply->readAll(); - bool ret = writeImageToFile( imageData, fileName ); + QPixmap albumart; + bool result = albumart.loadFromData( reply->readAll() ); + if ( result ) { + mRecommendationAlbumArtsMap.insert( mRecommendationAlbumArtsLink.at( index ), HbIcon( QIcon( albumart ) ) ); - // If file writing went OK, emit a signal with the real filename - // If it failed, use empty filename (since file was removed in any case) - if ( ret ) { - // TODO: If album album arts come in different order than they have been asked, - // then inspire me items will use swapped album arts. Correct - setAlbumArtUri( mRecommendationAlbumArtsLink.at( mDownloadedAlbumArts), - mRecommendationAlbumArtsName.at( mDownloadedAlbumArts ) ); + } else { + mRecommendationAlbumArtsMap.insert( mRecommendationAlbumArtsLink.at( index ), mDefaultRecommendationAlbumArt ); } - else { - setAlbumArtUri(mRecommendationAlbumArtsLink.at( mDownloadedAlbumArts), ""); - } + ++mDownloadedAlbumArts; mReplys.removeAll(reply); // remove it so that we wont process it again reply->deleteLater(); // make sure reply is deleted, as we longer care about it } else { TX_LOG_ARGS( "Error: Downloading album art failed! Will keep using the default AA" ); + mRecommendationAlbumArtsMap.insert( mRecommendationAlbumArtsLink.at( index ), mDefaultRecommendationAlbumArt ); } + mDownloadSignalMapper->removeMappings( reply ); if( mDownloadedAlbumArts == mRecommendationCount) { // no need to be informed anymore - mAlbumArtDownloader->disconnect(this); + mDownloadSignalMapper->disconnect(this); + emit inspireMeItemAlbumArtReady(); } TX_EXIT } -/*! - Write the image data to a file with the given filename. - If writing operation fails for any reason (e.g. OOD), - returns false, otherwise true. - */ -bool MpQueryManager::writeImageToFile(const QByteArray &aImageData, const QString &aImageFileName ) -{ - bool ret( false ); - TX_ENTRY_ARGS( "imagefile: " << aImageFileName ); - if ( aImageFileName.isEmpty() ) { - TX_LOG_ARGS( "Only store two album arts" ); - } - else { - QFile file( aImageFileName ); - if ( !file.open( QIODevice::ReadWrite ) ) { - TX_LOG_ARGS( "Unable to open file" ); - } - else { - qint64 writtenBytes = file.write( aImageData ); - // Verify file write status - if ( writtenBytes < aImageData.size() ) { - // If write succeeded only partially, or completely failed, - // remove the file from filesystem to remove risk of corruption - TX_LOG_ARGS( "Wrote only " << writtenBytes << " bytes, aborting operation!" ); - file.close(); - QFile::remove( mRecommendationAlbumArtsName.at( mDownloadedAlbumArts ) ); - } - else { - // If write fully succeeded, flush contents - TX_LOG_ARGS( "Wrote all the bytes (" << writtenBytes << "), flushing and closing!"); - file.flush(); - file.close(); - ret = true; - } - } - } - TX_LOG_ARGS( "Returning with value: " << ret ); - TX_EXIT - return ret; -} /*! Get Atom response from Ovi server based on query @@ -428,7 +329,6 @@ while ( !link.isNull() ) { if ( link.attribute( "title" ) == "albumart100" ) { mRecommendationAlbumArtsLink.append( link.attribute( "href" ) ); - // TODO: This may get called twice for one inspire me item. Investigate why mRecommendationAlbumArtsMap.insert( link.attribute( "href" ), mDefaultRecommendationAlbumArt ); break; } @@ -457,12 +357,15 @@ if ( mRecommendationAlbumArtsLink.at( i ).contains( "http", Qt::CaseInsensitive ) ) { reply = mAlbumArtDownloader->get( QNetworkRequest( QUrl( mRecommendationAlbumArtsLink.at(i) ) ) ); mReplys.append( reply ); + connect( reply, SIGNAL( finished() ), mDownloadSignalMapper, SLOT( map() ) ); + mDownloadSignalMapper->setMapping( reply, i ); + connect( reply, SIGNAL( error( QNetworkReply::NetworkError ) ), this, SLOT( retrieveInformationNetworkError( QNetworkReply::NetworkError ) ) ); connect( reply, SIGNAL( sslErrors( QList ) ), this, SLOT( retrieveInformationSslErrors( QList ) ) ); } } // we have queried for album arts for inspire me items. Now, time to wait for a response - connect( mAlbumArtDownloader, SIGNAL( finished( QNetworkReply * ) ), this, SLOT( albumArtDownloaded( QNetworkReply * ) ) ); + connect( mDownloadSignalMapper, SIGNAL( mapped( int ) ), this, SLOT( albumArtDownloaded( int ) ) ); } else if ( rootElement.attribute( "type" ) == "storeList" ) { @@ -470,10 +373,15 @@ QDomElement entry = rootElement.firstChildElement( "workspace" ); QString previousMusicStore = mMusicStore; mMusicStore = entry.attribute( "countryCode" ); - if(!mMusicStore.isEmpty()) { - bool musicStoreUpdated = (previousMusicStore != mMusicStore); - TX_LOG_ARGS("Music Store" << mMusicStore ); - emit localMusicStoreRetrieved(musicStoreUpdated); + if( !mMusicStore.isEmpty() ) { + bool musicStoreUpdated = ( previousMusicStore != mMusicStore ); + TX_LOG_ARGS("Music Store" << mMusicStore ); + emit localMusicStoreRetrieved( musicStoreUpdated ); + if( musicStoreUpdated ) { + QSettings settings; + TX_LOG_ARGS( "Storing music store value: " << mMusicStore ); + settings.setValue( "LocalMusicStore", QVariant( mMusicStore ) ); + } } else { emit localMusicStoreRetrievalError(); @@ -485,28 +393,14 @@ TX_EXIT } -void MpQueryManager::clearThumbnails() -{ - TX_ENTRY - for(int i = 0; i < mThumbnailRequests.count(); ++i ) { - mThumbnailManager->cancelRequest(mThumbnailRequests.at(i)); - } - mThumbnailRequests.clear(); - for(int i = 0; i < mRecommendationAlbumArtsName.count(); ++i) { - mThumbnailManager->deleteThumbnails(mRecommendationAlbumArtsName.at(i)); // async, returns immidiately - } - TX_EXIT -} void MpQueryManager::reset() { TX_ENTRY mManager->disconnect(this); mAlbumArtDownloader->disconnect(this); - mThumbnailManager->disconnect(this); clearNetworkReplies(); clearRecommendations(); - clearThumbnails(); mRecommendationAlbumArtsMap.clear(); TX_EXIT } @@ -521,8 +415,8 @@ QStringList keys; keys << "artist" << "albumtitle" << "tracktitle" << "orderby"; - // TODO: need to clarify which crition to use for sort, currently hard code to "relevancy" - // order can be relevancy, alltimedownloads, streetreleasedate, sortname, recentdownloads + // "relevancy" is the selected sort order + // sort order types can be relevancy, alltimedownloads, streetreleasedate, sortname, recentdownloads QStringList values; values << mArtist << mAlbum << mTitle << QString("relevancy"); TX_LOG_ARGS( "Artist: " << mArtist ); @@ -558,71 +452,14 @@ return str.left( str.length() - 1 ); } -/*! - Sets recommendation album art -*/ -void MpQueryManager::setAlbumArtUri( const QString &albumArtUri, const QString &albumArtName ) +bool MpQueryManager::isLocalMusicStore() { - // TODO: rename this function. Doing too many things - TX_ENTRY_ARGS( "albumArtUri = " << albumArtUri ) - TX_LOG_ARGS( "albumArtName = " << albumArtName ) - if ( !albumArtUri.isEmpty() && !albumArtName.isEmpty() ) { - // TODO: this is no good to pass the address of the albumArtUri. It is an item in the list, which can cleaned - int id = mThumbnailManager->getThumbnail( albumArtName, reinterpret_cast( const_cast( &albumArtUri ) ) ); - if ( id == KUndefined ) { - // Request failed. Set default album art - mRecommendationAlbumArtsMap.insert( albumArtUri, mDefaultRecommendationAlbumArt ); - } - else { - // Async request went throu - TX_LOG_ARGS("Request to thumbnail manager made. Id: " << id) - mThumbnailRequests.append(id); - mThumbnailManager->disconnect( this ); // to prevent multiple same connections with thumbnailmanager - QObject::connect( mThumbnailManager, SIGNAL( thumbnailReady( QPixmap , void * , int , int ) ), - this, SLOT( thumbnailReady( QPixmap , void * , int , int ) ) ); - } - } - else { - // No album art uri. Set default album art. - mRecommendationAlbumArtsMap.insert( albumArtUri, mDefaultRecommendationAlbumArt ); + if( mMusicStore.isEmpty() ) { + QSettings settings; + QVariant settingsvariant = settings.value( "LocalMusicStore", "" ); + mMusicStore = settingsvariant.toString(); + TX_LOG_ARGS( "Got local music store from settings:" << mMusicStore ); } - TX_EXIT -} - -/*! - Slot to handle the recommendation album art -*/ -void MpQueryManager::thumbnailReady( - const QPixmap pixmap, - void *data, - int id, - int error ) -{ - TX_ENTRY - - if( mThumbnailRequests.indexOf(id) == -1 ) { - TX_LOG_ARGS("Warning: some old thumbnail request from previous song. Ignoring") - return; - } - - // TODO: Using data from array, which can be reset. There must be a safer way - QString uri = *( reinterpret_cast( data ) ); - TX_LOG_ARGS( "Uri: " << uri ); - - if ( error == 0 ) { - TX_LOG_ARGS( "album art link: " << uri ); - mRecommendationAlbumArtsMap.insert( uri, HbIcon(QIcon(pixmap)) ); - } - else { - mRecommendationAlbumArtsMap.insert( uri, mDefaultRecommendationAlbumArt ); - } - - emit inspireMeItemAlbumArtReady(); - TX_EXIT -} - -bool MpQueryManager::isLocalMusicStore() const -{ TX_LOG_ARGS( "isLocalMusicStore = " << !mMusicStore.isEmpty() ) return !mMusicStore.isEmpty(); }