diff --git a/src/libtomahawk/Pipeline.cpp b/src/libtomahawk/Pipeline.cpp index 944a00176..d6aa69bf3 100644 --- a/src/libtomahawk/Pipeline.cpp +++ b/src/libtomahawk/Pipeline.cpp @@ -148,7 +148,10 @@ Pipeline::removeResolver( Resolver* r ) tDebug() << "Removed resolver:" << r->name(); d->resolvers.removeAll( r ); - emit resolverRemoved( r ); + if ( d->running ) { + // Only notify if Pipeline is still active. + emit resolverRemoved( r ); + } } diff --git a/src/libtomahawk/Query.cpp b/src/libtomahawk/Query.cpp index e53a9a03a..d1bdef934 100644 --- a/src/libtomahawk/Query.cpp +++ b/src/libtomahawk/Query.cpp @@ -212,7 +212,7 @@ void Query::refreshResults() { Q_D( Query ); - if ( d->resolveFinished ) + if ( d->resolveFinished && d->allowReresolve ) { d->resolveFinished = false; query_ptr q = d->ownRef.toStrongRef(); @@ -420,6 +420,22 @@ Query::setResolveFinished( bool resolved ) } +void +Query::allowReresolve() +{ + Q_D( Query ); + d->allowReresolve = true; +} + + +void +Query::disallowReresolve() +{ + Q_D( Query ); + d->allowReresolve = false; +} + + void Query::clearResults() { @@ -530,9 +546,9 @@ Query::howSimilar( const Tomahawk::result_ptr& r ) { Q_D( Query ); // result values - const QString rArtistname = r->track()->artistSortname(); + const QString& rArtistname = r->track()->artistSortname(); const QString rAlbumname = r->track()->albumSortname(); - const QString rTrackname = r->track()->trackSortname(); + const QString& rTrackname = r->track()->trackSortname(); QString qArtistname; QString qAlbumname; diff --git a/src/libtomahawk/Query.h b/src/libtomahawk/Query.h index 8fd4b64b6..7a65b9116 100644 --- a/src/libtomahawk/Query.h +++ b/src/libtomahawk/Query.h @@ -82,6 +82,18 @@ public: void setResolveFinished( bool resolved ); + /** + * Allow contacting the Pipeline if the state of this Query changes to + * not solved. + */ + void allowReresolve(); + + /** + * Disallow contacting the Pipeline if the state of this Query changes to + * not solved. + */ + void disallowReresolve(); + void setSaveHTTPResultHint( bool saveResultHint ); bool saveHTTPResultHint() const; diff --git a/src/libtomahawk/Query_p.h b/src/libtomahawk/Query_p.h index 82c25dbce..ef00b9efd 100644 --- a/src/libtomahawk/Query_p.h +++ b/src/libtomahawk/Query_p.h @@ -18,6 +18,7 @@ public: QueryPrivate( Query* q, const track_ptr& track, const QID& _qid ) : q_ptr( q ) + , allowReresolve( true ) , qid( _qid ) , queryTrack( track ) { @@ -25,6 +26,7 @@ public: QueryPrivate( Query* q, const QString& query, const QID& _qid ) : q_ptr( q ) + , allowReresolve( true ) , qid( _qid ) , fullTextQuery( query ) { @@ -40,6 +42,7 @@ private: bool solved; bool playable; bool resolveFinished; + bool allowReresolve; mutable QID qid; QString fullTextQuery; diff --git a/src/libtomahawk/Result.cpp b/src/libtomahawk/Result.cpp index d9712d2ed..d67d53ca8 100644 --- a/src/libtomahawk/Result.cpp +++ b/src/libtomahawk/Result.cpp @@ -281,11 +281,14 @@ Result::onOffline() void -Result::setCollection( const Tomahawk::collection_ptr& collection ) +Result::setCollection( const Tomahawk::collection_ptr& collection , bool emitOnlineEvents ) { m_collection = collection; - connect( m_collection->source().data(), SIGNAL( online() ), SLOT( onOnline() ), Qt::QueuedConnection ); - connect( m_collection->source().data(), SIGNAL( offline() ), SLOT( onOffline() ), Qt::QueuedConnection ); + if ( emitOnlineEvents ) + { + connect( m_collection->source().data(), SIGNAL( online() ), SLOT( onOnline() ), Qt::QueuedConnection ); + connect( m_collection->source().data(), SIGNAL( offline() ), SLOT( onOffline() ), Qt::QueuedConnection ); + } } void diff --git a/src/libtomahawk/Result.h b/src/libtomahawk/Result.h index acaedbc14..61efc9c82 100644 --- a/src/libtomahawk/Result.h +++ b/src/libtomahawk/Result.h @@ -92,7 +92,12 @@ public: void setScore( float score ); void setFileId( unsigned int id ); void setRID( RID id ) { m_rid = id; } - void setCollection( const Tomahawk::collection_ptr& collection ); + /** + * Associate the used collection for this result. + * + * @param emitOnlineEvents disableing this will not emit statusChanged anymore thus the query will not update (use with care!, only when this is the sole result) + */ + void setCollection( const Tomahawk::collection_ptr& collection, bool emitOnlineEvents = true ); void setFriendlySource( const QString& s ); void setPurchaseUrl( const QString& u ); void setLinkUrl( const QString& u ); diff --git a/src/libtomahawk/Track.cpp b/src/libtomahawk/Track.cpp index 4408b7dfa..687b7449d 100644 --- a/src/libtomahawk/Track.cpp +++ b/src/libtomahawk/Track.cpp @@ -49,9 +49,24 @@ static QMutex s_nameCacheMutex; inline QString cacheKey( const QString& artist, const QString& track, const QString& album, int duration, const QString& composer, unsigned int albumpos, unsigned int discnumber ) { + const QString durationStr = QString::number( duration ); + const QString albumposStr = QString::number( albumpos ); + const QString discnumberStr = QString::number( discnumber ); QString str; - QTextStream stream( &str ); - stream << artist << track << album << composer << duration << albumpos << discnumber; + // Preallocate space so that we will only call malloc once. + // With Qt5 we can possibly revert back to just "+" these strings. + // The "+" implementation in Qt4 differs slighty depending on compile + // options which could drastically reduce the performance. + str.reserve( artist.size() + track.size() + album.size() + + composer.size() + durationStr.size() + + albumposStr.size() + discnumberStr.size() ); + str += artist; + str += track; + str += album; + str += composer; + str += durationStr; + str += albumposStr; + str += discnumberStr; return str; } @@ -195,11 +210,19 @@ Track::init() Q_D( Track ); updateSortNames(); +#if QT_VERSION >= QT_VERSION_CHECK( 5, 0, 0 ) + QObject::connect( d->trackData.data(), &TrackData::attributesLoaded, this, &Track::attributesLoaded ); + QObject::connect( d->trackData.data(), &TrackData::socialActionsLoaded, this, &Track::socialActionsLoaded ); + QObject::connect( d->trackData.data(), &TrackData::statsLoaded, this, &Track::statsLoaded ); + QObject::connect( d->trackData.data(), &TrackData::similarTracksLoaded, this, &Track::similarTracksLoaded ); + QObject::connect( d->trackData.data(), &TrackData::lyricsLoaded, this, &Track::lyricsLoaded ); +#else connect( d->trackData.data(), SIGNAL( attributesLoaded() ), SIGNAL( attributesLoaded() ) ); connect( d->trackData.data(), SIGNAL( socialActionsLoaded() ), SIGNAL( socialActionsLoaded() ) ); connect( d->trackData.data(), SIGNAL( statsLoaded() ), SIGNAL( statsLoaded() ) ); connect( d->trackData.data(), SIGNAL( similarTracksLoaded() ), SIGNAL( similarTracksLoaded() ) ); connect( d->trackData.data(), SIGNAL( lyricsLoaded() ), SIGNAL( lyricsLoaded() ) ); +#endif } @@ -381,7 +404,7 @@ Track::toQuery() } -QString +const QString& Track::composerSortname() const { Q_D( const Track ); @@ -389,7 +412,7 @@ Track::composerSortname() const } -QString +const QString& Track::albumSortname() const { Q_D( const Track ); @@ -749,7 +772,7 @@ Track::share( const Tomahawk::source_ptr& source ) } -QString +const QString& Track::artistSortname() const { Q_D( const Track ); @@ -757,7 +780,7 @@ Track::artistSortname() const } -QString +const QString& Track::trackSortname() const { Q_D( const Track ); diff --git a/src/libtomahawk/Track.h b/src/libtomahawk/Track.h index 3e3fdf5ff..e838593df 100644 --- a/src/libtomahawk/Track.h +++ b/src/libtomahawk/Track.h @@ -68,10 +68,10 @@ public: QString toString() const; Tomahawk::query_ptr toQuery(); - QString composerSortname() const; - QString albumSortname() const; - QString artistSortname() const; - QString trackSortname() const; + const QString& composerSortname() const; + const QString& albumSortname() const; + const QString& artistSortname() const; + const QString& trackSortname() const; QString artist() const; QString track() const; diff --git a/src/libtomahawk/TrackData.h b/src/libtomahawk/TrackData.h index 69d99510a..712eb8343 100644 --- a/src/libtomahawk/TrackData.h +++ b/src/libtomahawk/TrackData.h @@ -55,8 +55,8 @@ public: QString toString() const; Tomahawk::query_ptr toQuery(); - QString artistSortname() const { return m_artistSortname; } - QString trackSortname() const { return m_trackSortname; } + const QString& artistSortname() const { return m_artistSortname; } + const QString& trackSortname() const { return m_trackSortname; } QWeakPointer< Tomahawk::TrackData > weakRef() { return m_ownRef; } void setWeakRef( QWeakPointer< Tomahawk::TrackData > weakRef ) { m_ownRef = weakRef; } diff --git a/src/libtomahawk/ViewManager.cpp b/src/libtomahawk/ViewManager.cpp index 6452818a4..04af86274 100644 --- a/src/libtomahawk/ViewManager.cpp +++ b/src/libtomahawk/ViewManager.cpp @@ -305,10 +305,13 @@ ViewManager::show( const Tomahawk::collection_ptr& collection ) view->columnView()->proxyModel()->setStyle( PlayableProxyModel::Collection ); TreeModel* model = new TreeModel(); + PlayableModel* flatModel = new PlayableModel(); view->setTreeModel( model ); + view->setFlatModel( flatModel ); model->addCollection( collection ); + flatModel->appendTracks( collection ); setPage( view ); if ( !collection.isNull() ) diff --git a/src/libtomahawk/database/DatabaseCommand_AllTracks.cpp b/src/libtomahawk/database/DatabaseCommand_AllTracks.cpp index f8fdcb374..f3f605add 100644 --- a/src/libtomahawk/database/DatabaseCommand_AllTracks.cpp +++ b/src/libtomahawk/database/DatabaseCommand_AllTracks.cpp @@ -76,8 +76,7 @@ DatabaseCommand_AllTracks::exec( DatabaseImpl* dbi ) QString sql = QString( "SELECT file.id, artist.name, album.name, track.name, composer.name, file.size, " //0 "file.duration, file.bitrate, file.url, file.source, file.mtime, " //6 - "file.mimetype, file_join.discnumber, file_join.albumpos, artist.id, " //11 - "album.id, track.id, composer.id " //15 + "file.mimetype, file_join.discnumber, file_join.albumpos, track.id " //11 "FROM file, artist, track, file_join " "LEFT OUTER JOIN album " "ON file_join.album = album.id " @@ -99,10 +98,38 @@ DatabaseCommand_AllTracks::exec( DatabaseImpl* dbi ) query.prepare( sql ); query.exec(); + // Small cache to keep already created source objects. + // This saves some mutex locking. + std::map sourceCache; + while( query.next() ) { + QString artist = query.value( 1 ).toString(); + QString album = query.value( 2 ).toString(); + QString track = query.value( 3 ).toString(); + QString composer = query.value( 4 ).toString(); + uint size = query.value( 5 ).toUInt(); + uint duration = query.value( 6 ).toUInt(); + uint bitrate = query.value( 7 ).toUInt(); QString url = query.value( 8 ).toString(); - Tomahawk::source_ptr s = SourceList::instance()->get( query.value( 9 ).toUInt() ); + uint sourceId = query.value( 9 ).toUInt(); + uint modificationTime = query.value( 10 ).toUInt(); + QString mimetype = query.value( 11 ).toString(); + uint discnumber = query.value( 12 ).toUInt(); + uint albumpos = query.value( 13 ).toUInt(); + uint trackId = query.value( 14 ).toUInt(); + + std::map::const_iterator _s = sourceCache.find( sourceId ); + Tomahawk::source_ptr s; + if ( _s == sourceCache.end() ) + { + s = SourceList::instance()->get( sourceId ); + sourceCache[sourceId] = s; + } + else + { + s = _s->second; + } if ( !s ) { Q_ASSERT( false ); @@ -111,30 +138,31 @@ DatabaseCommand_AllTracks::exec( DatabaseImpl* dbi ) if ( !s->isLocal() ) url = QString( "servent://%1\t%2" ).arg( s->nodeId() ).arg( url ); - QString artist, track, album, composer; - artist = query.value( 1 ).toString(); - album = query.value( 2 ).toString(); - track = query.value( 3 ).toString(); - composer = query.value( 4 ).toString(); - Tomahawk::result_ptr result = Tomahawk::Result::get( url ); - Tomahawk::query_ptr qry = Tomahawk::Query::get( artist, track, album ); + Tomahawk::track_ptr t = Tomahawk::Track::get( trackId, + artist, track, album, + duration, composer, + albumpos, discnumber ); + Tomahawk::query_ptr qry = Tomahawk::Query::get( t ); - Tomahawk::track_ptr t = Tomahawk::Track::get( query.value( 16 ).toUInt(), artist, track, album, query.value( 6 ).toUInt(), composer, query.value( 13 ).toUInt(), query.value( 12 ).toUInt() ); - t->loadAttributes(); + if ( m_album || m_artist ) { + t->loadAttributes(); + } result->setTrack( t ); - result->setSize( query.value( 5 ).toUInt() ); - result->setBitrate( query.value( 7 ).toUInt() ); - result->setModificationTime( query.value( 10 ).toUInt() ); - result->setMimetype( query.value( 11 ).toString() ); + result->setSize( size ); + result->setBitrate( bitrate ); + result->setModificationTime( modificationTime ); + result->setMimetype( mimetype ); result->setScore( 1.0 ); - result->setCollection( s->dbCollection() ); + result->setCollection( s->dbCollection(), false ); QList results; results << result; qry->addResults( results ); qry->setResolveFinished( true ); + // These tracks are fixed to the Source. Do not re-resolve. + qry->disallowReresolve(); ql << qry; } diff --git a/src/libtomahawk/database/DatabaseImpl.cpp b/src/libtomahawk/database/DatabaseImpl.cpp index 40cc214e6..29ecf1f37 100644 --- a/src/libtomahawk/database/DatabaseImpl.cpp +++ b/src/libtomahawk/database/DatabaseImpl.cpp @@ -538,7 +538,7 @@ Tomahawk::DatabaseImpl::getTrackFids( int tid ) QString Tomahawk::DatabaseImpl::sortname( const QString& str, bool replaceArticle ) { - QString s = str.toLower().trimmed().replace( QRegExp( "[\\s]{2,}" ), " " ); + QString s = str.simplified().toLower(); if ( replaceArticle && s.startsWith( "the " ) ) { diff --git a/src/libtomahawk/playlist/FlexibleTreeView.cpp b/src/libtomahawk/playlist/FlexibleTreeView.cpp index 97856a7b1..dca61a270 100644 --- a/src/libtomahawk/playlist/FlexibleTreeView.cpp +++ b/src/libtomahawk/playlist/FlexibleTreeView.cpp @@ -48,14 +48,14 @@ FlexibleTreeView::FlexibleTreeView( QWidget* parent, QWidget* extraHeader ) , m_modeHeader( new ModeHeader( this ) ) , m_columnView( new ColumnView() ) , m_treeView( new TreeView() ) - , m_trackView( 0 ) + , m_trackView( new TrackView() ) , m_model( 0 ) + , m_flatModel( 0 ) , m_temporary( false ) { qRegisterMetaType< FlexibleTreeViewMode >( "FlexibleTreeViewMode" ); m_treeView->proxyModel()->setStyle( PlayableProxyModel::Collection ); - m_treeView->proxyModel()->setPlaylistInterface( m_columnView->proxyModel()->playlistInterface() ); // m_trackView->setPlaylistInterface( m_playlistInterface ); @@ -93,8 +93,7 @@ FlexibleTreeView::FlexibleTreeView( QWidget* parent, QWidget* extraHeader ) m_stack->addWidget( m_columnView ); m_stack->addWidget( m_treeView ); - /* m_stack->addWidget( m_gridView ); - m_stack->addWidget( m_trackView );*/ + m_stack->addWidget( m_trackView ); connect( m_header, SIGNAL( filterTextChanged( QString ) ), SLOT( setFilter( QString ) ) ); @@ -182,7 +181,6 @@ FlexibleTreeView::setTreeModel( TreeModel* model ) // m_trackView->setPlayableModel( model ); m_columnView->setTreeModel( model ); m_treeView->setTreeModel( model ); - // m_gridView->setPlayableModel( model ); /* m_trackView->setSortingEnabled( false ); m_trackView->sortByColumn( -1 ); @@ -195,6 +193,27 @@ FlexibleTreeView::setTreeModel( TreeModel* model ) } +void +FlexibleTreeView::setFlatModel( PlayableModel* model ) +{ + if ( m_flatModel ) + { +// disconnect( m_flatModel, SIGNAL( changed() ), this, SLOT( onModelChanged() ) ); + delete m_flatModel; + } + + m_flatModel = model; + + m_trackView->setPlayableModel( model ); + + m_trackView->setSortingEnabled( true ); + m_trackView->sortByColumn( 0 ); + +/* connect( model, SIGNAL( changed() ), SLOT( onModelChanged() ), Qt::UniqueConnection ); + onModelChanged();*/ +} + + void FlexibleTreeView::setCurrentMode( FlexibleTreeViewMode mode ) { @@ -224,7 +243,7 @@ FlexibleTreeView::setCurrentMode( FlexibleTreeViewMode mode ) case Albums: { -// m_stack->setCurrentWidget( m_gridView ); + m_stack->setCurrentWidget( m_trackView ); break; } } @@ -270,7 +289,7 @@ FlexibleTreeView::jumpToCurrentTrack() // note: the order of comparison is important here, if we'd write "b || foo" then foo will not be executed if b is already true! b = m_columnView->jumpToCurrentTrack() || b; -// b = m_trackView->jumpToCurrentTrack() || b; + b = m_trackView->jumpToCurrentTrack() || b; b = m_treeView->jumpToCurrentTrack() || b; return b; @@ -284,8 +303,7 @@ FlexibleTreeView::setFilter( const QString& pattern ) m_columnView->setFilter( pattern ); m_treeView->proxyModel()->setFilter( pattern ); - /* m_gridView->setFilter( pattern ); - m_trackView->setFilter( pattern );*/ + m_trackView->setFilter( pattern ); return true; } @@ -318,8 +336,7 @@ FlexibleTreeView::setEmptyTip( const QString& tip ) { m_columnView->setEmptyTip( tip ); m_treeView->setEmptyTip( tip ); - /* m_gridView->setEmptyTip( tip ); - m_trackView->setEmptyTip( tip );*/ + m_trackView->setEmptyTip( tip ); } diff --git a/src/libtomahawk/playlist/FlexibleTreeView.h b/src/libtomahawk/playlist/FlexibleTreeView.h index a9a35d4a4..012b278e4 100644 --- a/src/libtomahawk/playlist/FlexibleTreeView.h +++ b/src/libtomahawk/playlist/FlexibleTreeView.h @@ -31,6 +31,7 @@ class TrackView; class TreeView; class ColumnView; class TreeModel; +class PlayableModel; class ModeHeader; class PlaylistModel; class FilterHeader; @@ -70,6 +71,7 @@ public: void setTrackView( TrackView* view ); void setTreeModel( TreeModel* model ); + void setFlatModel( PlayableModel* model ); void setPixmap( const QPixmap& pixmap ); void setEmptyTip( const QString& tip ); @@ -97,6 +99,7 @@ private: TrackView* m_trackView; TreeModel* m_model; + PlayableModel* m_flatModel; QStackedWidget* m_stack; FlexibleTreeViewMode m_mode; diff --git a/src/libtomahawk/playlist/PlayableModel.cpp b/src/libtomahawk/playlist/PlayableModel.cpp index 15b9f2d26..2b88246cd 100644 --- a/src/libtomahawk/playlist/PlayableModel.cpp +++ b/src/libtomahawk/playlist/PlayableModel.cpp @@ -682,8 +682,18 @@ PlayableModel::insertInternal( const QList< T >& items, int row, const QList< To plitem->index = createIndex( row + i, 0, plitem ); if ( plitem->query() ) { - connect( plitem->query().data(), SIGNAL( playableStateChanged( bool ) ), SLOT( onQueryBecamePlayable( bool ) ), Qt::UniqueConnection ); - connect( plitem->query().data(), SIGNAL( resolvingFinished( bool ) ), SLOT( onQueryResolved( bool ) ), Qt::UniqueConnection ); + if ( !plitem->query()->playable() ) + { + connect( plitem->query().data(), SIGNAL( playableStateChanged( bool ) ), + SLOT( onQueryBecamePlayable( bool ) ), + Qt::UniqueConnection ); + } + if ( !plitem->query()->resolvingFinished() ) + { + connect( plitem->query().data(), SIGNAL( resolvingFinished( bool ) ), + SLOT( onQueryResolved( bool ) ), + Qt::UniqueConnection ); + } } if ( logs.count() > i ) @@ -904,20 +914,26 @@ PlayableModel::onDataChanged() void PlayableModel::startLoading() { - tDebug() << Q_FUNC_INFO; Q_D( PlayableModel ); - d->loading = true; - emit loadingStarted(); + if ( !d->loading ) + { + tDebug() << Q_FUNC_INFO; + d->loading = true; + emit loadingStarted(); + } } void PlayableModel::finishLoading() { - tDebug() << Q_FUNC_INFO; Q_D( PlayableModel ); - d->loading = false; - emit loadingFinished(); + if ( d->loading ) + { + tDebug() << Q_FUNC_INFO; + d->loading = false; + emit loadingFinished(); + } } @@ -1000,6 +1016,13 @@ PlayableModel::appendTracks( const QList< Tomahawk::track_ptr >& tracks, const Q } +void +PlayableModel::appendTracks( const Tomahawk::collection_ptr& collection ) +{ + insertTracks( collection, rowCount( QModelIndex() ) ); +} + + void PlayableModel::insertArtist( const Tomahawk::artist_ptr& artist, int row ) { @@ -1053,6 +1076,25 @@ PlayableModel::insertQueries( const QList< Tomahawk::query_ptr >& queries, int r } +void +PlayableModel::insertTracks( const Tomahawk::collection_ptr& collection, int row ) +{ + Tomahawk::TracksRequest* req = collection->requestTracks( Tomahawk::album_ptr() ); + connect( dynamic_cast< QObject* >( req ), SIGNAL( tracks( QList< Tomahawk::query_ptr > ) ), + this, SLOT( onTracksAdded( QList< Tomahawk::query_ptr > ) ), Qt::UniqueConnection ); + req->enqueue(); + +// connect( collection.data(), SIGNAL( changed() ), SLOT( onCollectionChanged() ), Qt::UniqueConnection ); +} + + +void +PlayableModel::onTracksAdded( const QList< Tomahawk::query_ptr >& queries ) +{ + appendQueries( queries ); +} + + void PlayableModel::setTitle( const QString& title ) { diff --git a/src/libtomahawk/playlist/PlayableModel.h b/src/libtomahawk/playlist/PlayableModel.h index 72e7fbd53..5a0db0a5c 100644 --- a/src/libtomahawk/playlist/PlayableModel.h +++ b/src/libtomahawk/playlist/PlayableModel.h @@ -158,6 +158,7 @@ public slots: virtual void appendQuery( const Tomahawk::query_ptr& query ); virtual void appendArtist( const Tomahawk::artist_ptr& artist ); virtual void appendAlbum( const Tomahawk::album_ptr& album ); + virtual void appendTracks( const Tomahawk::collection_ptr& collection ); virtual void insertQueries( const QList< Tomahawk::query_ptr >& queries, int row = 0, const QList< Tomahawk::PlaybackLog >& logs = QList< Tomahawk::PlaybackLog >() ); virtual void insertArtists( const QList< Tomahawk::artist_ptr >& artists, int row = 0 ); @@ -165,6 +166,7 @@ public slots: virtual void insertQuery( const Tomahawk::query_ptr& query, int row = 0, const Tomahawk::PlaybackLog& log = Tomahawk::PlaybackLog() ); virtual void insertArtist( const Tomahawk::artist_ptr& artist, int row = 0 ); virtual void insertAlbum( const Tomahawk::album_ptr& album, int row = 0 ); + virtual void insertTracks( const Tomahawk::collection_ptr& collection, int row = 0 ); virtual bool removeRows( int row, int count, const QModelIndex& parent = QModelIndex() ); virtual void remove( int row, bool moreToCome = false ); @@ -191,6 +193,8 @@ private slots: void onPlaybackStarted( const Tomahawk::result_ptr result ); void onPlaybackStopped(); + void onTracksAdded( const QList< Tomahawk::query_ptr >& queries ); + private: void init(); template diff --git a/src/libtomahawk/playlist/PlayableProxyModel.cpp b/src/libtomahawk/playlist/PlayableProxyModel.cpp index 0f8f05425..8db77822c 100644 --- a/src/libtomahawk/playlist/PlayableProxyModel.cpp +++ b/src/libtomahawk/playlist/PlayableProxyModel.cpp @@ -295,52 +295,22 @@ PlayableProxyModel::setMaxVisibleItems( int items ) bool PlayableProxyModel::lessThan( int column, const Tomahawk::query_ptr& q1, const Tomahawk::query_ptr& q2 ) const { + // Attention: This function may be called very often! + // So be aware of its performance. const Tomahawk::track_ptr& t1 = q1->track(); const Tomahawk::track_ptr& t2 = q2->track(); - const QString artist1 = t1->artistSortname(); - const QString artist2 = t2->artistSortname(); - const QString album1 = t1->albumSortname(); - const QString album2 = t2->albumSortname(); - const QString track1 = t1->trackSortname(); - const QString track2 = t2->trackSortname(); - const QString composer1 = t1->composerSortname(); - const QString composer2 = t2->composerSortname(); + const QString& artist1 = t1->artistSortname(); + const QString& artist2 = t2->artistSortname(); + const QString& album1 = t1->albumSortname(); + const QString& album2 = t2->albumSortname(); const unsigned int albumpos1 = t1->albumpos(); const unsigned int albumpos2 = t2->albumpos(); const unsigned int discnumber1 = t1->discnumber(); const unsigned int discnumber2 = t2->discnumber(); - unsigned int duration1 = t1->duration(), duration2 = t2->duration(); - unsigned int bitrate1 = 0, bitrate2 = 0; - unsigned int mtime1 = 0, mtime2 = 0; - unsigned int size1 = 0, size2 = 0; - unsigned int year1 = 0, year2 = 0; - float score1 = 0, score2 = 0; - QString origin1; - QString origin2; qint64 id1 = 0, id2 = 0; - if ( !q1->results().isEmpty() ) - { - Tomahawk::result_ptr r = q1->results().first(); - bitrate1 = r->bitrate(); - mtime1 = r->modificationTime(); - size1 = r->size(); - year1 = r->track()->year(); - score1 = r->score(); - origin1 = r->friendlySource().toLower(); - } - if ( !q2->results().isEmpty() ) - { - Tomahawk::result_ptr r = q2->results().first(); - bitrate2 = r->bitrate(); - mtime2 = r->modificationTime(); - size2 = r->size(); - year2 = r->track()->year(); - score2 = r->score(); - origin2 = r->friendlySource().toLower(); - } - // This makes it a stable sorter and prevents items from randomly jumping about. + // FIXME: This always true. if ( id1 == id2 ) { id1 = (qint64)&q1; @@ -369,7 +339,11 @@ PlayableProxyModel::lessThan( int column, const Tomahawk::query_ptr& q1, const T return QString::localeAwareCompare( artist1, artist2 ) < 0; } - else if ( column == PlayableModel::Composer ) // sort by composer + + // Sort by Composer + const QString& composer1 = t1->composerSortname(); + const QString& composer2 = t2->composerSortname(); + if ( column == PlayableModel::Composer ) { if ( composer1 == composer2 ) { @@ -391,7 +365,9 @@ PlayableProxyModel::lessThan( int column, const Tomahawk::query_ptr& q1, const T return QString::localeAwareCompare( composer1, composer2 ) < 0; } - else if ( column == PlayableModel::Album ) // sort by album + + // Sort by Album + if ( column == PlayableModel::Album ) // sort by album { if ( album1 == album2 ) { @@ -408,7 +384,38 @@ PlayableProxyModel::lessThan( int column, const Tomahawk::query_ptr& q1, const T return QString::localeAwareCompare( album1, album2 ) < 0; } - else if ( column == PlayableModel::Bitrate ) // sort by bitrate + + // Lazy load these variables, they are not used before. + unsigned int bitrate1 = 0, bitrate2 = 0; + unsigned int mtime1 = 0, mtime2 = 0; + unsigned int size1 = 0, size2 = 0; + unsigned int year1 = 0, year2 = 0; + float score1 = 0, score2 = 0; + QString origin1; + QString origin2; + if ( !q1->results().isEmpty() ) + { + Tomahawk::result_ptr r = q1->results().first(); + bitrate1 = r->bitrate(); + mtime1 = r->modificationTime(); + size1 = r->size(); + year1 = r->track()->year(); + score1 = r->score(); + origin1 = r->friendlySource().toLower(); + } + if ( !q2->results().isEmpty() ) + { + Tomahawk::result_ptr r = q2->results().first(); + bitrate2 = r->bitrate(); + mtime2 = r->modificationTime(); + size2 = r->size(); + year2 = r->track()->year(); + score2 = r->score(); + origin2 = r->friendlySource().toLower(); + } + + // Sort by bitrate + if ( column == PlayableModel::Bitrate ) { if ( bitrate1 == bitrate2 ) return id1 < id2; @@ -417,6 +424,9 @@ PlayableProxyModel::lessThan( int column, const Tomahawk::query_ptr& q1, const T } else if ( column == PlayableModel::Duration ) // sort by duration { + unsigned int duration1 = t1->duration(); + unsigned int duration2 = t2->duration(); + if ( duration1 == duration2 ) return id1 < id2;