PageRenderTime 175ms CodeModel.GetById 80ms app.highlight 73ms RepoModel.GetById 18ms app.codeStats 0ms

/src/libtomahawk/playlist/TreeProxyModel.cpp

http://github.com/tomahawk-player/tomahawk
C++ | 406 lines | 297 code | 73 blank | 36 comment | 67 complexity | eb062b22d1611943d54af03a1d2f006b MD5 | raw file
  1/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
  2 *
  3 *   Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
  4 *   Copyright 2010-2012, Jeff Mitchell <jeff@tomahawk-player.org>
  5 *   Copyright 2013,      Teo Mrnjavac <teo@kde.org>
  6 *
  7 *   Tomahawk is free software: you can redistribute it and/or modify
  8 *   it under the terms of the GNU General Public License as published by
  9 *   the Free Software Foundation, either version 3 of the License, or
 10 *   (at your option) any later version.
 11 *
 12 *   Tomahawk is distributed in the hope that it will be useful,
 13 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 14 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 15 *   GNU General Public License for more details.
 16 *
 17 *   You should have received a copy of the GNU General Public License
 18 *   along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
 19 */
 20
 21#include "TreeProxyModel.h"
 22
 23#include "TreeProxyModelPlaylistInterface.h"
 24#include "Source.h"
 25#include "Query.h"
 26#include "database/Database.h"
 27#include "database/DatabaseImpl.h"
 28#include "collection/AlbumsRequest.h"
 29#include "collection/ArtistsRequest.h"
 30#include "database/DatabaseCommand_AllAlbums.h"
 31#include "PlayableItem.h"
 32#include "utils/Logger.h"
 33
 34#include <QListView>
 35
 36TreeProxyModel::TreeProxyModel( QObject* parent )
 37    : PlayableProxyModel( parent )
 38    , m_artistsFilterCmd( 0 )
 39    , m_model( 0 )
 40{
 41    setPlaylistInterface( Tomahawk::playlistinterface_ptr( new Tomahawk::TreeProxyModelPlaylistInterface( this ) ) );
 42}
 43
 44
 45void
 46TreeProxyModel::setSourcePlayableModel( TreeModel* model )
 47{
 48    if ( m_model )
 49    {
 50        disconnect( m_model, SIGNAL( rowsInserted( QModelIndex, int, int ) ), this, SLOT( onRowsInserted( QModelIndex, int, int ) ) );
 51        disconnect( m_model, SIGNAL( modelReset() ), this, SLOT( onModelReset() ) );
 52    }
 53
 54    PlayableProxyModel::setSourcePlayableModel( model );
 55    m_model = model;
 56
 57    if ( m_model )
 58    {
 59        connect( m_model, SIGNAL( rowsInserted( QModelIndex, int, int ) ), SLOT( onRowsInserted( QModelIndex, int, int ) ) );
 60        connect( m_model, SIGNAL( modelReset() ), SLOT( onModelReset() ) );
 61    }
 62}
 63
 64
 65void
 66TreeProxyModel::onRowsInserted( const QModelIndex& parent, int /* start */, int /* end */ )
 67{
 68    if ( m_filter.isEmpty() )
 69        return;
 70    if ( sender() != m_model )
 71        return;
 72
 73    PlayableItem* pi = m_model->itemFromIndex( m_model->index( parent.row(), 0, parent.parent() ) );
 74    if ( pi->artist().isNull() )
 75        return;
 76
 77    Tomahawk::AlbumsRequest* cmd = 0;
 78    if ( !m_model->collection().isNull() )
 79        cmd = m_model->collection()->requestAlbums( pi->artist() );
 80    else
 81        cmd = new Tomahawk::DatabaseCommand_AllAlbums( Tomahawk::collection_ptr(), pi->artist() );
 82
 83    cmd->setFilter( m_filter );
 84
 85    connect( dynamic_cast< QObject* >( cmd ), SIGNAL( albums( QList<Tomahawk::album_ptr> ) ),
 86             SLOT( onFilterAlbums( QList<Tomahawk::album_ptr> ) ) );
 87
 88    cmd->enqueue();
 89}
 90
 91
 92void
 93TreeProxyModel::onModelReset()
 94{
 95    m_cache.clear();
 96    m_artistsFilter.clear();
 97    m_albumsFilter.clear();
 98}
 99
100
101void
102TreeProxyModel::setFilter( const QString& pattern )
103{
104    emit filteringStarted();
105
106    m_filter = pattern;
107
108    beginResetModel();
109    m_albumsFilter.clear();
110    endResetModel();
111
112    if ( m_artistsFilterCmd )
113    {
114        disconnect( dynamic_cast< QObject* >( m_artistsFilterCmd ), SIGNAL( artists( QList<Tomahawk::artist_ptr> ) ),
115                    this, SLOT( onFilterArtists( QList<Tomahawk::artist_ptr> ) ) );
116
117        delete m_artistsFilterCmd;
118        m_artistsFilterCmd = 0;
119    }
120
121    if ( m_filter.isEmpty() )
122    {
123        filterFinished();
124    }
125    else
126    {
127        Tomahawk::ArtistsRequest* cmd = 0;
128        if ( !m_model->collection().isNull() )
129            cmd = m_model->collection()->requestArtists();
130        else
131            cmd = new Tomahawk::DatabaseCommand_AllArtists(); //for SuperCollection, TODO: replace with a proper proxy-ArtistsRequest
132
133        cmd->setFilter( pattern );
134        m_artistsFilterCmd = cmd;
135
136        connect( dynamic_cast< QObject* >( cmd ), SIGNAL( artists( QList<Tomahawk::artist_ptr> ) ),
137                 SLOT( onFilterArtists( QList<Tomahawk::artist_ptr> ) ) );
138
139        cmd->enqueue();
140    }
141}
142
143
144QString
145TreeProxyModel::filter() const
146{
147    return m_filter;
148}
149
150
151void
152TreeProxyModel::onFilterArtists( const QList<Tomahawk::artist_ptr>& artists )
153{
154    bool finished = true;
155    m_artistsFilter = artists;
156    m_artistsFilterCmd = 0;
157
158    foreach ( const Tomahawk::artist_ptr& artist, artists )
159    {
160        const QModelIndex idx = m_model->indexFromArtist( artist );
161        if ( m_model->rowCount( idx ) )
162        {
163            finished = false;
164
165            Tomahawk::AlbumsRequest* cmd = m_model->collection()->requestAlbums( artist );
166            cmd->setFilter( m_filter );
167
168            connect( dynamic_cast< QObject* >( cmd ), SIGNAL( albums( QList<Tomahawk::album_ptr> ) ),
169                     SLOT( onFilterAlbums( QList<Tomahawk::album_ptr> ) ) );
170
171            cmd->enqueue();
172        }
173    }
174
175    if ( finished )
176        filterFinished();
177}
178
179
180void
181TreeProxyModel::onFilterAlbums( const QList<Tomahawk::album_ptr>& albums )
182{
183    foreach ( const Tomahawk::album_ptr& album, albums )
184    {
185        m_albumsFilter << album;
186    }
187
188    filterFinished();
189}
190
191
192void
193TreeProxyModel::filterFinished()
194{
195    if ( m_artistsFilterCmd )
196    {
197        disconnect( dynamic_cast< QObject* >( m_artistsFilterCmd ), SIGNAL( artists( QList<Tomahawk::artist_ptr> ) ),
198                    this, SLOT( onFilterArtists( QList<Tomahawk::artist_ptr> ) ) );
199
200        delete m_artistsFilterCmd;
201        m_artistsFilterCmd = 0;
202    }
203
204    setFilterRegExp( m_filter );
205    emit filterChanged( m_filter );
206    emit filteringFinished();
207}
208
209
210bool
211TreeProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex& sourceParent ) const
212{
213    PlayableItem* item = sourceModel()->itemFromIndex( sourceModel()->index( sourceRow, 0, sourceParent ) );
214    Q_ASSERT( item );
215
216    //FIXME: m_cache lookup is broken
217    if ( /*m_model->mode() == Tomahawk::DatabaseMode &&*/ !item->query().isNull() )
218    {
219/*        QList< Tomahawk::query_ptr > rl = m_cache.values( sourceParent );
220        foreach ( const Tomahawk::query_ptr& cachedQuery, rl )
221        {
222            if ( cachedQuery.isNull() )
223                continue;
224
225            if ( cachedQuery->track()->track() == item->query()->track()->track() &&
226               ( cachedQuery->track()->albumpos() == item->query()->track()->albumpos() || cachedQuery->track()->albumpos() == 0 ) )
227            {
228                return ( cachedQuery.data() == item->query().data() );
229            }
230        }*/
231
232        for ( int i = 0; i < sourceModel()->rowCount( sourceParent ); i++ )
233        {
234            if ( i == sourceRow )
235                continue;
236
237            PlayableItem* ti = sourceModel()->itemFromIndex( sourceModel()->index( i, 0, sourceParent ) );
238            if ( ti && ti->name() == item->name() && !ti->query().isNull() )
239            {
240                if ( ti->query()->track()->albumpos() == item->query()->track()->albumpos() || ti->query()->track()->albumpos() == 0 || item->query()->track()->albumpos() == 0 )
241                {
242                    if ( item->result().isNull() )
243                        return false;
244
245                    if ( !ti->result().isNull() )
246                    {
247                        if ( !item->result()->isOnline() && ti->result()->isOnline() )
248                            return false;
249
250                        if ( ( !item->result()->isLocal() ) &&
251                             !ti->result()->isLocal() )
252                        {
253                            return false;
254                        }
255                    }
256                }
257            }
258        }
259    }
260
261    bool accepted = false;
262    if ( m_filter.isEmpty() )
263        accepted = true;
264    else if ( !item->artist().isNull() )
265        accepted = m_artistsFilter.contains( item->artist() );
266    else if ( !item->album().isNull() )
267        accepted = m_albumsFilter.contains( item->album() );
268
269    if ( !accepted )
270    {
271        QStringList sl = m_filter.split( " ", QString::SkipEmptyParts );
272        foreach( const QString& s, sl )
273        {
274            if ( !item->name().contains( s, Qt::CaseInsensitive ) &&
275                 !item->albumName().contains( s, Qt::CaseInsensitive ) &&
276                 !item->artistName().contains( s, Qt::CaseInsensitive ) )
277            {
278                return false;
279            }
280        }
281    }
282
283    m_cache.insertMulti( sourceParent, item->query() );
284    return true;
285}
286
287
288bool
289TreeProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right ) const
290{
291    PlayableItem* p1 = sourceModel()->itemFromIndex( left );
292    PlayableItem* p2 = sourceModel()->itemFromIndex( right );
293
294    if ( !p1 )
295        return true;
296    if ( !p2 )
297        return false;
298
299/*    if ( !p1->result().isNull() && p2->result().isNull() )
300        return true;
301    if ( p1->result().isNull() && !p2->result().isNull() )
302        return false;*/
303
304    unsigned int albumpos1 = 0;
305    unsigned int albumpos2 = 0;
306    unsigned int discnumber1 = 0;
307    unsigned int discnumber2 = 0;
308    if ( !p1->query().isNull() )
309    {
310        albumpos1 = p1->query()->track()->albumpos();
311        discnumber1 = p1->query()->track()->discnumber();
312    }
313    if ( !p2->query().isNull() )
314    {
315        albumpos2 = p2->query()->track()->albumpos();
316        discnumber2 = p2->query()->track()->discnumber();
317    }
318    if ( !p1->result().isNull() )
319    {
320        if ( albumpos1 == 0 )
321            albumpos1 = p1->result()->track()->albumpos();
322        if ( discnumber1 == 0 )
323            discnumber1 = p1->result()->track()->discnumber();
324    }
325    if ( !p2->result().isNull() )
326    {
327        if ( albumpos2 == 0 )
328            albumpos2 = p2->result()->track()->albumpos();
329        if ( discnumber2 == 0 )
330            discnumber2 = p2->result()->track()->discnumber();
331    }
332    discnumber1 = qMax( 1, (int)discnumber1 );
333    discnumber2 = qMax( 1, (int)discnumber2 );
334
335    if ( discnumber1 != discnumber2 )
336    {
337        return discnumber1 < discnumber2;
338    }
339    else
340    {
341        if ( albumpos1 != albumpos2 )
342            return albumpos1 < albumpos2;
343    }
344
345    const QString& lefts = textForItem( p1 );
346    const QString& rights = textForItem( p2 );
347    if ( lefts == rights )
348        return (qint64)&p1 < (qint64)&p2;
349
350    return QString::localeAwareCompare( lefts, rights ) < 0;
351}
352
353
354QString
355TreeProxyModel::textForItem( PlayableItem* item ) const
356{
357    if ( !item )
358        return QString();
359
360    if ( !item->artist().isNull() )
361    {
362        return item->artist()->sortname();
363    }
364    else if ( !item->album().isNull() )
365    {
366        return Tomahawk::DatabaseImpl::sortname( item->album()->name() );
367    }
368    else if ( !item->result().isNull() )
369    {
370        return item->result()->track()->trackSortname();
371    }
372    else if ( !item->query().isNull() )
373    {
374        return item->query()->track()->track();
375    }
376
377    return QString();
378}
379
380
381QModelIndex
382TreeProxyModel::indexFromArtist( const Tomahawk::artist_ptr& artist ) const
383{
384    return mapFromSource( m_model->indexFromArtist( artist ) );
385}
386
387
388QModelIndex
389TreeProxyModel::indexFromAlbum( const Tomahawk::album_ptr& album ) const
390{
391    return mapFromSource( m_model->indexFromAlbum( album ) );
392}
393
394
395QModelIndex
396TreeProxyModel::indexFromResult( const Tomahawk::result_ptr& result ) const
397{
398    return mapFromSource( m_model->indexFromResult( result ) );
399}
400
401
402QModelIndex
403TreeProxyModel::indexFromQuery( const Tomahawk::query_ptr& query ) const
404{
405    return mapFromSource( m_model->indexFromQuery( query ) );
406}