diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index 121cfdfc9..46ae46ab2 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -119,6 +119,7 @@ set( libGuiSources widgets/playlisttypeselectordlg.cpp widgets/welcomewidget.cpp widgets/whatshotwidget.cpp + widgets/ChartDataLoader.cpp widgets/RecentlyPlayedPlaylistsModel.cpp widgets/RecentPlaylistsModel.cpp widgets/OverlayButton.cpp @@ -237,6 +238,7 @@ set( libGuiHeaders widgets/welcomewidget.h widgets/whatshotwidget.h widgets/whatshotwidget_p.h + widgets/ChartDataLoader.h widgets/RecentlyPlayedPlaylistsModel.h widgets/RecentPlaylistsModel.h widgets/OverlayButton.h diff --git a/src/libtomahawk/infosystem/infoplugins/generic/chartsplugin.cpp b/src/libtomahawk/infosystem/infoplugins/generic/chartsplugin.cpp index 02eff8d12..8c719f021 100644 --- a/src/libtomahawk/infosystem/infoplugins/generic/chartsplugin.cpp +++ b/src/libtomahawk/infosystem/infoplugins/generic/chartsplugin.cpp @@ -453,7 +453,7 @@ ChartsPlugin::chartReturned() QVariantList chartResponse = res.value( "list" ).toList(); QList< Tomahawk::InfoSystem::InfoStringHash > top_tracks; QList< Tomahawk::InfoSystem::InfoStringHash > top_albums; - QStringList top_artists; + QList< Tomahawk::InfoSystem::InfoStringHash > top_artists; /// Deside what type, we need to handle it differently /// @todo: We allready know the type, append it to breadcrumb hash @@ -528,7 +528,9 @@ ChartsPlugin::chartReturned() } else { - top_artists.append( artist ); + Tomahawk::InfoSystem::InfoStringHash artistHash; + artistHash["artist"] = artist; + top_artists.append( artistHash ); } } @@ -538,7 +540,7 @@ ChartsPlugin::chartReturned() if( chartType() == Artist ) { tDebug() << "ChartsPlugin:" << "\tgot " << top_artists.size() << " artists"; - returnedData[ "artists" ] = QVariant::fromValue< QStringList >( top_artists ); + returnedData[ "artists" ] = QVariant::fromValue< QList< Tomahawk::InfoSystem::InfoStringHash > >( top_artists ); returnedData[ "type" ] = "artists"; } diff --git a/src/libtomahawk/widgets/ChartDataLoader.cpp b/src/libtomahawk/widgets/ChartDataLoader.cpp new file mode 100644 index 000000000..363270fb6 --- /dev/null +++ b/src/libtomahawk/widgets/ChartDataLoader.cpp @@ -0,0 +1,72 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2011, 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 "ChartDataLoader.h" + +using namespace Tomahawk; + + +ChartDataLoader::ChartDataLoader() + : QObject( 0 ) +{ +} + +void +ChartDataLoader::go() +{ + qDebug() << "CHART LOADING DATA!" << QThread::currentThreadId(); + switch ( m_type ) + { + case Track: + { + QList< query_ptr > track_ptrs; + foreach ( const Tomahawk::InfoSystem::InfoStringHash& track, m_data ) + { + track_ptrs << Query::get( track[ "artist" ], track[ "track" ], QString(), uuid(), false ); + } + + emit tracks( this, track_ptrs ); + break; + } + case Artist: + { + QList< artist_ptr > artist_ptrs; + + foreach ( const Tomahawk::InfoSystem::InfoStringHash& artistname, m_data ) { + artist_ptrs << Artist::get( artistname[ "artist" ], false ); + } + + emit artists( this, artist_ptrs ); + break; + } + case Album: + { + QList< album_ptr > album_ptrs; + + foreach ( const Tomahawk::InfoSystem::InfoStringHash& album, m_data ) + { + tDebug( LOGVERBOSE) << Q_FUNC_INFO << "Getting album" << album[ "album" ] << "By" << album[ "artist" ]; + artist_ptr artistPtr = Artist::get( album[ "artist" ], false ); + album_ptr albumPtr = Album::get( artistPtr, album[ "album" ], false ); + album_ptrs << albumPtr; + } + + emit albums( this, album_ptrs ); + break; + } + } +} diff --git a/src/libtomahawk/widgets/ChartDataLoader.h b/src/libtomahawk/widgets/ChartDataLoader.h new file mode 100644 index 000000000..001cacc52 --- /dev/null +++ b/src/libtomahawk/widgets/ChartDataLoader.h @@ -0,0 +1,67 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2011, 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 CHARTDATALOADER_H +#define CHARTDATALOADER_H + +#include "infosystem/infosystem.h" +#include "query.h" +#include "artist.h" +#include "album.h" + +#include + +namespace Tomahawk +{ + +/** + Synchronous loading of track, artist, album objects from the db + into their respective tomahawk types. Move this object to a thread + and listen to the result signals. +*/ +class ChartDataLoader : public QObject +{ + Q_OBJECT +public: + enum DataType { + Track, + Artist, + Album + }; + + ChartDataLoader(); + + void setType( DataType type ) { m_type = type; } + void setData( const QList< InfoSystem::InfoStringHash >& data ) { m_data = data; } + +public slots: + void go(); + +signals: + void tracks( Tomahawk::ChartDataLoader*, const QList< Tomahawk::query_ptr >& tracks ); + void artists( Tomahawk::ChartDataLoader*, const QList< Tomahawk::artist_ptr >& artists ); + void albums( Tomahawk::ChartDataLoader*, const QList< Tomahawk::album_ptr >& albums ); + + +private: + DataType m_type; + QList m_data; +}; + +} + +#endif // CHARTDATALOADER_H diff --git a/src/libtomahawk/widgets/whatshotwidget.cpp b/src/libtomahawk/widgets/whatshotwidget.cpp index cd4e5cec8..69cdab9ec 100644 --- a/src/libtomahawk/widgets/whatshotwidget.cpp +++ b/src/libtomahawk/widgets/whatshotwidget.cpp @@ -29,6 +29,7 @@ #include "sourcelist.h" #include "tomahawksettings.h" #include "RecentPlaylistsModel.h" +#include "ChartDataLoader.h" #include "audio/audioengine.h" #include "dynamic/GeneratorInterface.h" @@ -53,6 +54,7 @@ WhatsHotWidget::WhatsHotWidget( QWidget* parent ) , ui( new Ui::WhatsHotWidget ) , m_playlistInterface( 0 ) , m_sortedProxy( 0 ) + , m_workerThread( 0 ) { ui->setupUi( this ); @@ -94,6 +96,9 @@ WhatsHotWidget::WhatsHotWidget( QWidget* parent ) m_playlistInterface = new ChartsPlaylistInterface( this ); + m_workerThread = new QThread( this ); + m_workerThread->start(); + connect( Tomahawk::InfoSystem::InfoSystem::instance(), SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ) ); @@ -106,6 +111,7 @@ WhatsHotWidget::WhatsHotWidget( QWidget* parent ) WhatsHotWidget::~WhatsHotWidget() { + m_workerThread->exit(0); delete m_playlistInterface; delete ui; } @@ -239,68 +245,61 @@ WhatsHotWidget::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestDat const QString chartId = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >().value( "chart_id" ); m_queuedFetches.remove( chartId ); - if( type == "artists" ) + + ChartDataLoader* loader = new ChartDataLoader(); + loader->setProperty( "chartid", chartId ); + loader->moveToThread( m_workerThread ); + + qDebug() << "SCHEDULING LOADING FROM THREAD:" << QThread::currentThreadId(); + if ( type == "artists" ) { - const QStringList artists = returnedData["artists"].toStringList(); + loader->setType( ChartDataLoader::Artist ); + loader->setData( returnedData[ "artists" ].value< QList< Tomahawk::InfoSystem::InfoStringHash > >() ); + + connect( loader, SIGNAL( artists( Tomahawk::ChartDataLoader*, QList< Tomahawk::artist_ptr > ) ), this, SLOT( chartArtistsLoaded( Tomahawk::ChartDataLoader*, QList< Tomahawk::artist_ptr > ) ) ); TreeModel* artistsModel = new TreeModel( ui->artistsViewLeft ); artistsModel->setColumnStyle( TreeModel::TrackOnly ); - foreach ( const QString& artist, artists ) - { - artist_ptr artistPtr = Artist::get( artist, false ); - artistsModel->addArtists( artistPtr ); - } m_artistModels[ chartId ] = artistsModel; if ( m_queueItemToShow == chartId ) setLeftViewArtists( artistsModel ); } - else if( type == "albums" ) + else if ( type == "albums" ) { - QList al; - const QList< Tomahawk::InfoSystem::InfoStringHash > albums = returnedData[ "albums" ].value< QList< Tomahawk::InfoSystem::InfoStringHash > >(); + + loader->setType( ChartDataLoader::Album ); + loader->setData( returnedData[ "albums" ].value< QList< Tomahawk::InfoSystem::InfoStringHash > >() ); + + connect( loader, SIGNAL( albums( Tomahawk::ChartDataLoader*, QList< Tomahawk::album_ptr > ) ), this, SLOT( chartAlbumsLoaded( Tomahawk::ChartDataLoader*, QList< Tomahawk::album_ptr > ) ) ); AlbumModel* albumModel = new AlbumModel( ui->additionsView ); - foreach ( const Tomahawk::InfoSystem::InfoStringHash& album, albums ) - { - tDebug( LOGVERBOSE) << Q_FUNC_INFO << "Getting album" << album[ "album" ] << "By" << album[ "artist" ]; - artist_ptr artistPtr = Artist::get( album[ "artist" ], false ); - album_ptr albumPtr = Album::get( artistPtr, album[ "album" ], false ); - al << albumPtr; - - } - albumModel->addAlbums( al ); m_albumModels[ chartId ] = albumModel; if ( m_queueItemToShow == chartId ) setLeftViewAlbums( albumModel ); } - else if( type == "tracks" ) + else if ( type == "tracks" ) { - const QList< Tomahawk::InfoSystem::InfoStringHash > tracks = returnedData[ "tracks" ].value< QList< Tomahawk::InfoSystem::InfoStringHash > >(); + + loader->setType( ChartDataLoader::Track ); + loader->setData( returnedData[ "tracks" ].value< QList< Tomahawk::InfoSystem::InfoStringHash > >() ); + + connect( loader, SIGNAL( tracks( Tomahawk::ChartDataLoader*, QList< Tomahawk::query_ptr > ) ), this, SLOT( chartTracksLoaded( Tomahawk::ChartDataLoader*, QList< Tomahawk::query_ptr > ) ) ); PlaylistModel* trackModel = new PlaylistModel( ui->tracksViewLeft ); trackModel->setStyle( TrackModel::Short ); - QList tracklist; - foreach ( const Tomahawk::InfoSystem::InfoStringHash& track, tracks ) - { - query_ptr query = Query::get( track[ "artist" ], track[ "track" ], QString(), uuid(), false ); - tracklist << query; - } - Pipeline::instance()->resolve( tracklist ); - trackModel->append( tracklist ); m_trackModels[ chartId ] = trackModel; if ( m_queueItemToShow == chartId ) setLeftViewTracks( trackModel ); } - else - { - tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "WhatsHot: got unknown chart type" << type; - } + + QMetaObject::invokeMethod( loader, "go", Qt::QueuedConnection ); + break; } @@ -473,3 +472,52 @@ WhatsHotWidget::setLeftViewTracks( PlaylistModel* model ) ui->tracksViewLeft->proxyModel()->sort( -1 ); ui->stackLeft->setCurrentIndex( 0 ); } + + +void +WhatsHotWidget::chartArtistsLoaded( ChartDataLoader* loader, const QList< artist_ptr >& artists ) +{ + qDebug() << "DOING CHART ARTIST DATA LOAD!"; + QString chartId = loader->property( "chartid" ).toString(); + Q_ASSERT( m_artistModels.contains( chartId ) ); + + if ( !m_artistModels.contains( chartId ) ) + { + foreach( const artist_ptr& artist, artists ) + m_artistModels[ chartId ]->addArtists( artist ); + } + + loader->deleteLater(); +} + + +void +WhatsHotWidget::chartTracksLoaded( ChartDataLoader* loader, const QList< query_ptr >& tracks ) +{ + + qDebug() << "DOING CHART TRACK DATA LOAD!"; + QString chartId = loader->property( "chartid" ).toString(); + Q_ASSERT( m_trackModels.contains( chartId ) ); + + if ( m_trackModels.contains( chartId ) ) + { + Pipeline::instance()->resolve( tracks ); + m_trackModels[ chartId ]->append( tracks ); + } + + loader->deleteLater(); +} + + +void +WhatsHotWidget::chartAlbumsLoaded( ChartDataLoader* loader, const QList< album_ptr >& albums ) +{ + qDebug() << "DOING CHART ALBUMS DATA LOAD!"; + QString chartId = loader->property( "chartid" ).toString(); + Q_ASSERT( m_albumModels.contains( chartId ) ); + + if ( m_albumModels.contains( chartId ) ) + m_albumModels[ chartId ]->addAlbums( albums ); + + loader->deleteLater(); +} diff --git a/src/libtomahawk/widgets/whatshotwidget.h b/src/libtomahawk/widgets/whatshotwidget.h index 392c39a32..5df378752 100644 --- a/src/libtomahawk/widgets/whatshotwidget.h +++ b/src/libtomahawk/widgets/whatshotwidget.h @@ -46,6 +46,11 @@ namespace Ui class WhatsHotWidget; } +namespace Tomahawk +{ + class ChartDataLoader; +} + /** * \class * \brief The tomahawk page that shows music charts. @@ -83,6 +88,11 @@ private slots: void infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output ); void infoSystemFinished( QString target ); void leftCrumbIndexChanged( QModelIndex ); + + void chartArtistsLoaded( Tomahawk::ChartDataLoader*, const QList< Tomahawk::artist_ptr >& ); + void chartAlbumsLoaded( Tomahawk::ChartDataLoader*, const QList< Tomahawk::album_ptr >& ); + void chartTracksLoaded( Tomahawk::ChartDataLoader*, const QList< Tomahawk::query_ptr >& ); + private: void setLeftViewArtists( TreeModel* artistModel ); void setLeftViewAlbums( AlbumModel* albumModel ); @@ -96,6 +106,11 @@ private: QStandardItemModel* m_crumbModelLeft; QSortFilterProxyModel* m_sortedProxy; + // Load artist, album, and track objects in a thread + // {Artist,Album,Track}::get() calls are all synchronous db calls + // and we don't want to lock up out UI in case the db is busy (e.g. on startup) + QThread* m_workerThread; + // Cache our model data QHash< QString, AlbumModel* > m_albumModels; QHash< QString, TreeModel* > m_artistModels; diff --git a/src/mac/tomahawkapp_mac.mm b/src/mac/tomahawkapp_mac.mm index fae3e1d51..d5a0ca295 100644 --- a/src/mac/tomahawkapp_mac.mm +++ b/src/mac/tomahawkapp_mac.mm @@ -175,6 +175,7 @@ NSString *bundleID = [[NSBundle mainBundle] bundleIdentifier]; OSStatus httpResult = LSSetDefaultHandlerForURLScheme((CFStringRef)@"tomahawk", (CFStringRef)bundleID); + Q_UNUSED(httpResult); //TODO: Check httpResult and httpsResult for errors } return self;