PageRenderTime 166ms CodeModel.GetById 40ms app.highlight 68ms RepoModel.GetById 53ms app.codeStats 0ms

/src/libtomahawk/playlist/TreeModel.cpp

http://github.com/tomahawk-player/tomahawk
C++ | 418 lines | 285 code | 92 blank | 41 comment | 42 complexity | fa9a9104d3b31b9f5c55bbe0cb23c667 MD5 | raw file
  1/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
  2 *
  3 *   Copyright 2010-2015, Christian Muehlhaeuser <muesli@tomahawk-player.org>
  4 *   Copyright 2010-2011, Jeff Mitchell <jeff@tomahawk-player.org>
  5 *   Copyright 2012,      Leo Franchi <lfranchi@kde.org>
  6 *   Copyright 2013,      Teo Mrnjavac <teo@kde.org>
  7 *
  8 *   Tomahawk is free software: you can redistribute it and/or modify
  9 *   it under the terms of the GNU General Public License as published by
 10 *   the Free Software Foundation, either version 3 of the License, or
 11 *   (at your option) any later version.
 12 *
 13 *   Tomahawk is distributed in the hope that it will be useful,
 14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 16 *   GNU General Public License for more details.
 17 *
 18 *   You should have received a copy of the GNU General Public License
 19 *   along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
 20 */
 21
 22#include "TreeModel.h"
 23
 24#include <QMimeData>
 25
 26#include "Pipeline.h"
 27#include "Source.h"
 28#include "SourceList.h"
 29#include "audio/AudioEngine.h"
 30#include "database/DatabaseCommand_AllAlbums.h"
 31#include "database/DatabaseCommand_AllTracks.h"
 32#include "database/Database.h"
 33#include "AlbumPlaylistInterface.h"
 34#include "PlayableItem.h"
 35#include "utils/TomahawkUtilsGui.h"
 36#include "utils/Closure.h"
 37#include "utils/Logger.h"
 38
 39using namespace Tomahawk;
 40
 41
 42TreeModel::TreeModel( QObject* parent )
 43    : PlayableModel( parent )
 44    , m_mode( DatabaseMode )
 45{
 46    PlayableModel::setIcon( TomahawkUtils::tinted( TomahawkUtils::defaultPixmap(
 47                                                       TomahawkUtils::DefaultCollection,
 48                                                       TomahawkUtils::Original,
 49                                                       // big enough for the ViewPage header on retina
 50                                                       QSize( 256, 256 ) ), Qt::white ) );
 51
 52    connect( AudioEngine::instance(), SIGNAL( started( Tomahawk::result_ptr ) ), SLOT( onPlaybackStarted( Tomahawk::result_ptr ) ), Qt::DirectConnection );
 53    connect( AudioEngine::instance(), SIGNAL( stopped() ), SLOT( onPlaybackStopped() ), Qt::DirectConnection );
 54}
 55
 56
 57TreeModel::~TreeModel()
 58{
 59    tDebug() << Q_FUNC_INFO;
 60}
 61
 62
 63void
 64TreeModel::setMode( ModelMode mode )
 65{
 66    clear();
 67    m_mode = mode;
 68    emit modeChanged( mode );
 69}
 70
 71
 72Tomahawk::collection_ptr
 73TreeModel::collection() const
 74{
 75    return m_collection;
 76}
 77
 78
 79void
 80TreeModel::getCover( const QModelIndex& index )
 81{
 82    PlayableItem* item = itemFromIndex( index );
 83
 84    if ( !item->artist().isNull() && !item->artist()->coverLoaded() )
 85        item->artist()->cover( QSize( 0, 0 ) );
 86    else if ( !item->album().isNull() && !item->album()->coverLoaded() )
 87        item->album()->cover( QSize( 0, 0 ) );
 88}
 89
 90
 91bool
 92TreeModel::canFetchMore( const QModelIndex& parent ) const
 93{
 94    PlayableItem* parentItem = itemFromIndex( parent );
 95
 96    if ( parentItem->fetchingMore() )
 97        return false;
 98
 99    if ( !parentItem->artist().isNull() )
100    {
101        return true;
102    }
103    else if ( !parentItem->album().isNull() )
104    {
105        return true;
106    }
107
108    return false;
109}
110
111
112void
113TreeModel::fetchMore( const QModelIndex& parent )
114{
115    PlayableItem* parentItem = itemFromIndex( parent );
116    if ( !parentItem || parentItem->fetchingMore() )
117        return;
118
119    parentItem->setFetchingMore( true );
120    if ( !parentItem->artist().isNull() )
121    {
122        tDebug() << Q_FUNC_INFO << "Loading Artist:" << parentItem->artist()->name();
123        fetchAlbums( parentItem->artist() );
124    }
125    else if ( !parentItem->album().isNull() )
126    {
127        tDebug() << Q_FUNC_INFO << "Loading Album:" << parentItem->album()->artist()->name() << parentItem->album()->name() << parentItem->album()->id();
128        addTracks( parentItem->album(), parent );
129    }
130    else
131        Q_ASSERT( false );
132}
133
134
135void
136TreeModel::addArtists( const artist_ptr& artist )
137{
138    if ( artist.isNull() )
139        return;
140
141    startLoading();
142
143    QList<Tomahawk::artist_ptr> artists;
144    artists << artist;
145    onArtistsAdded( artists );
146}
147
148
149void
150TreeModel::fetchAlbums( const artist_ptr& artist )
151{
152    startLoading();
153
154    connect( artist.data(), SIGNAL( albumsAdded( QList<Tomahawk::album_ptr>, Tomahawk::ModelMode ) ),
155                              SLOT( onAlbumsFound( QList<Tomahawk::album_ptr>, Tomahawk::ModelMode ) ), Qt::UniqueConnection );
156
157    const QModelIndex parent = indexFromArtist( artist );
158    addAlbums( parent, artist->albums( m_mode, m_collection ) );
159}
160
161
162void
163TreeModel::onAlbumsFound( const QList<Tomahawk::album_ptr>& albums, ModelMode mode )
164{
165    if ( m_mode != mode )
166        return;
167
168    Tomahawk::Artist* artist = qobject_cast< Tomahawk::Artist* >( sender() );
169    if ( !artist )
170        return;
171
172    const artist_ptr artistp = artist->weakRef().toStrongRef();
173    disconnect( artist, SIGNAL( albumsAdded( QList<Tomahawk::album_ptr>, Tomahawk::ModelMode ) ),
174                this,     SLOT( onAlbumsFound( QList<Tomahawk::album_ptr>, Tomahawk::ModelMode ) ) );
175
176    const QModelIndex parent = indexFromArtist( artistp );
177    addAlbums( parent, albums );
178}
179
180
181void
182TreeModel::addAlbums( const QModelIndex& parent, const QList<Tomahawk::album_ptr>& albums )
183{
184    finishLoading();
185    if ( albums.isEmpty() )
186        return;
187
188    PlayableItem* parentItem = itemFromIndex( parent );
189
190    QPair< int, int > crows;
191    const int c = rowCount( parent );
192    crows.first = c;
193    crows.second = c + albums.count() - 1;
194
195    emit beginInsertRows( parent, crows.first, crows.second );
196
197    foreach( const album_ptr& album, albums )
198    {
199        PlayableItem* albumitem = new PlayableItem( album, parentItem );
200        albumitem->index = createIndex( parentItem->children.count() - 1, 0, albumitem );
201        connect( albumitem, SIGNAL( dataChanged() ), SLOT( onDataChanged() ) );
202
203        getCover( albumitem->index );
204    }
205
206    emit endInsertRows();
207}
208
209
210void
211TreeModel::addTracks( const album_ptr& album, const QModelIndex& parent )
212{
213    startLoading();
214
215    QList<query_ptr> tracks = album->tracks( m_mode, m_collection );
216    onTracksAdded( tracks, parent );
217
218    if ( tracks.isEmpty() )
219        startLoading();
220
221    NewClosure( album.data(), SIGNAL( tracksAdded( QList<Tomahawk::query_ptr>, Tomahawk::ModelMode, Tomahawk::collection_ptr ) ),
222                const_cast<TreeModel*>(this), SLOT( addTracks( Tomahawk::album_ptr, QModelIndex ) ), album, parent );
223}
224
225
226void
227TreeModel::addCollection( const collection_ptr& collection )
228{
229    startLoading();
230
231    m_collection = collection;
232
233    Tomahawk::ArtistsRequest* req = m_collection->requestArtists();
234    connect( dynamic_cast< QObject* >( req ), SIGNAL( artists( QList< Tomahawk::artist_ptr > ) ),
235             this, SLOT( onArtistsAdded( QList< Tomahawk::artist_ptr > ) ), Qt::UniqueConnection );
236    req->enqueue();
237
238    setIcon( collection->bigIcon() );
239    setTitle( collection->prettyName() );
240    setDescription( collection->description() );
241}
242
243
244//void
245//TreeModel::addFilteredCollection( const collection_ptr& collection, unsigned int amount, DatabaseCommand_AllArtists::SortOrder order )
246//{
247//    qDebug() << Q_FUNC_INFO << collection->name()
248//                            << collection->source()->id()
249//                            << collection->source()->nodeId()
250//                            << amount << order;
251//    DatabaseCommand_AllArtists* cmd = new DatabaseCommand_AllArtists( collection );
252//    cmd->setLimit( amount );
253//    cmd->setSortOrder( order );
254//    cmd->setSortDescending( true );
255
256//    connect( cmd, SIGNAL( artists( QList<Tomahawk::artist_ptr>, Tomahawk::collection_ptr ) ),
257//                    SLOT( onArtistsAdded( QList<Tomahawk::artist_ptr>, Tomahawk::collection_ptr ) ) );
258
259//    Database::instance()->enqueue( Tomahawk::dbcmd_ptr( cmd ) );
260
261//    if ( collection->source()->isLocal() )
262//        setTitle( tr( "My Collection" ) );
263//    else
264//        setTitle( tr( "Collection of %1" ).arg( collection->source()->friendlyName() ) );
265//}
266
267
268void
269TreeModel::onArtistsAdded( const QList<Tomahawk::artist_ptr>& artists )
270{
271    finishLoading();
272
273    if ( artists.isEmpty() )
274        return;
275
276    int c = rowCount( QModelIndex() );
277    QPair< int, int > crows;
278    crows.first = c;
279    crows.second = c + artists.count() - 1;
280
281    emit beginInsertRows( QModelIndex(), crows.first, crows.second );
282
283    foreach( const artist_ptr& artist, artists )
284    {
285        PlayableItem* artistitem = new PlayableItem( artist, rootItem() );
286        artistitem->index = createIndex( rootItem()->children.count() - 1, 0, artistitem );
287        connect( artistitem, SIGNAL( dataChanged() ), SLOT( onDataChanged() ) );
288    }
289
290    emit endInsertRows();
291}
292
293
294void
295TreeModel::onTracksAdded( const QList<Tomahawk::query_ptr>& tracks, const QModelIndex& parent )
296{
297    finishLoading();
298
299    if ( tracks.isEmpty() )
300        return;
301
302    PlayableItem* parentItem = itemFromIndex( parent );
303
304    QPair< int, int > crows;
305    int c = rowCount( parent );
306    removeRows( 0, c, parent );
307
308    crows.first = c;
309    crows.second = c + tracks.count() - 1;
310
311    emit beginInsertRows( parent, crows.first, crows.second );
312
313    foreach( const query_ptr& query, tracks )
314    {
315        PlayableItem* item = new PlayableItem( query, parentItem );
316        item->index = createIndex( parentItem->children.count() - 1, 0, item );
317
318        connect( item, SIGNAL( dataChanged() ), SLOT( onDataChanged() ) );
319    }
320
321    emit endInsertRows();
322    emit selectRequest( index( 0, 0, parent ) );
323}
324
325
326QModelIndex
327TreeModel::indexFromArtist( const Tomahawk::artist_ptr& artist ) const
328{
329    for ( int i = 0; i < rowCount( QModelIndex() ); i++ )
330    {
331        QModelIndex idx = index( i, 0, QModelIndex() );
332        PlayableItem* item = itemFromIndex( idx );
333        if ( item && item->artist() == artist )
334        {
335            return idx;
336        }
337    }
338
339    tDebug() << Q_FUNC_INFO << "Could not find item for artist:" << artist->name();
340    return QModelIndex();
341}
342
343
344QModelIndex
345TreeModel::indexFromAlbum( const Tomahawk::album_ptr& album ) const
346{
347    QModelIndex artistIdx = indexFromArtist( album->artist() );
348    for ( int i = 0; i < rowCount( artistIdx ); i++ )
349    {
350        QModelIndex idx = index( i, 0, artistIdx );
351        PlayableItem* item = itemFromIndex( idx );
352        if ( item && item->album() == album )
353        {
354            return idx;
355        }
356    }
357
358    tDebug() << Q_FUNC_INFO << "Could not find item for album:" << album->name() << album->artist()->name();
359    return QModelIndex();
360}
361
362
363QModelIndex
364TreeModel::indexFromResult( const Tomahawk::result_ptr& result ) const
365{
366    QModelIndex albumIdx = indexFromAlbum( result->track()->albumPtr() );
367    for ( int i = 0; i < rowCount( albumIdx ); i++ )
368    {
369        QModelIndex idx = index( i, 0, albumIdx );
370        PlayableItem* item = itemFromIndex( idx );
371        // tDebug() << Q_FUNC_INFO << item->result()->toString();
372        if ( item && item->result() == result )
373        {
374            return idx;
375        }
376    }
377
378    tDebug() << Q_FUNC_INFO << "Could not find item for result:" << result->toString();
379    return QModelIndex();
380}
381
382
383QModelIndex
384TreeModel::indexFromQuery( const Tomahawk::query_ptr& query ) const
385{
386    QModelIndex albumIdx = indexFromAlbum( query->queryTrack()->albumPtr() );
387    for ( int i = 0; i < rowCount( albumIdx ); i++ )
388    {
389        QModelIndex idx = index( i, 0, albumIdx );
390        PlayableItem* item = itemFromIndex( idx );
391        if ( item && item->result() && item->result()->track()->equals( query->track() ) )
392        {
393            return idx;
394        }
395    }
396
397    tDebug() << Q_FUNC_INFO << "Could not find item for query:" << query->toString();
398    return QModelIndex();
399}
400
401
402PlayableItem*
403TreeModel::itemFromResult( const Tomahawk::result_ptr& result ) const
404{
405    QModelIndex albumIdx = indexFromAlbum( result->track()->albumPtr() );
406    for ( int i = 0; i < rowCount( albumIdx ); i++ )
407    {
408        QModelIndex idx = index( i, 0, albumIdx );
409        PlayableItem* item = itemFromIndex( idx );
410        if ( item && item->result() == result )
411        {
412            return item;
413        }
414    }
415
416    tDebug() << Q_FUNC_INFO << "Could not find item for result:" << result->toString();
417    return 0;
418}