PageRenderTime 257ms CodeModel.GetById 80ms app.highlight 79ms RepoModel.GetById 80ms app.codeStats 0ms

/src/libtomahawk/PlaylistInterface.cpp

http://github.com/tomahawk-player/tomahawk
C++ | 310 lines | 218 code | 66 blank | 26 comment | 34 complexity | ba73ce64f254cbe56091ec36cfcfd2e2 MD5 | raw file
  1/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
  2 *
  3 *   Copyright 2010-2012, Christian Muehlhaeuser <muesli@tomahawk-player.org>
  4 *   Copyright 2011, Leo Franchi <lfranchi@kde.org>
  5 *   Copyright 2010-2012, Jeff Mitchell <jeff@tomahawk-player.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 "PlaylistInterface.h"
 22#include "Result.h"
 23#include "Pipeline.h"
 24#include "Source.h"
 25#include "utils/Logger.h"
 26
 27using namespace Tomahawk;
 28
 29
 30PlaylistInterface::PlaylistInterface()
 31    : QObject()
 32    , m_latchMode( PlaylistModes::StayOnSong )
 33    , m_prevAvail( false )
 34    , m_nextAvail( false )
 35    , m_currentIndex( -1 )
 36    , m_finished( false )
 37    , m_foundFirstTrack( false )
 38{
 39    m_id = uuid();
 40}
 41
 42
 43PlaylistInterface::~PlaylistInterface()
 44{
 45}
 46
 47
 48result_ptr
 49PlaylistInterface::previousResult() const
 50{
 51     return siblingResult( -1 );
 52}
 53
 54
 55result_ptr
 56PlaylistInterface::nextResult() const
 57{
 58     return siblingResult( 1 );
 59}
 60
 61
 62qint64
 63PlaylistInterface::siblingResultIndex( int itemsAway, qint64 rootIndex ) const
 64{
 65    qint64 idx = siblingIndex( itemsAway, rootIndex );
 66    QList< qint64 > safetyCheck;
 67
 68    // If safetyCheck contains idx, this means the interface keeps returning the same items and we won't discover anything new - abort
 69    // This can happen in repeat / random mode e.g.
 70    while ( idx >= 0 && !safetyCheck.contains( idx ) )
 71    {
 72        safetyCheck << idx;
 73        Tomahawk::query_ptr query = queryAt( idx );
 74
 75        if ( query && query->playable() )
 76        {
 77            return idx;
 78        }
 79
 80        idx = siblingIndex( itemsAway < 0 ? -1 : 1, idx );
 81    }
 82
 83    return -1;
 84}
 85
 86
 87Tomahawk::result_ptr
 88PlaylistInterface::siblingResult( int itemsAway, qint64 rootIndex ) const
 89{
 90    qint64 idx = siblingResultIndex( itemsAway, rootIndex );
 91    if ( idx >= 0 )
 92    {
 93        Tomahawk::query_ptr query = queryAt( idx );
 94
 95        if ( query && query->playable() )
 96        {
 97            return query->results().first();
 98        }
 99    }
100
101    return Tomahawk::result_ptr();
102}
103
104
105Tomahawk::result_ptr
106PlaylistInterface::setSiblingResult( int itemsAway, qint64 rootIndex )
107{
108    qint64 idx = siblingResultIndex( itemsAway, rootIndex );
109    if ( idx >= 0 )
110    {
111        Tomahawk::query_ptr query = queryAt( idx );
112
113        if ( query && query->playable() )
114        {
115            setCurrentIndex( idx );
116            return query->results().first();
117        }
118    }
119
120    return Tomahawk::result_ptr();
121}
122
123
124int
125PlaylistInterface::posOfResult( const Tomahawk::result_ptr& result ) const
126{
127    const QList< Tomahawk::query_ptr > queries = tracks();
128
129    int res = 0;
130    foreach ( const Tomahawk::query_ptr& query, queries )
131    {
132        if ( query && query->numResults() && query->results().contains( result ) )
133            return res;
134
135        res++;
136    }
137
138    return -1;
139}
140
141
142int
143PlaylistInterface::posOfQuery( const Tomahawk::query_ptr& query ) const
144{
145    const QList< Tomahawk::query_ptr > queries = tracks();
146
147    int res = 0;
148    foreach ( const Tomahawk::query_ptr& q, queries )
149    {
150        if ( query == q )
151            return res;
152
153        res++;
154    }
155
156    return -1;
157}
158
159
160QList<Tomahawk::query_ptr>
161PlaylistInterface::filterTracks( const QList<Tomahawk::query_ptr>& queries )
162{
163    QList<Tomahawk::query_ptr> result;
164
165    for ( int i = 0; i < queries.count(); i++ )
166    {
167        bool picked = true;
168        const query_ptr q1 = queries.at( i );
169
170        for ( int j = 0; j < result.count(); j++ )
171        {
172            if ( !picked )
173                break;
174
175            const query_ptr& q2 = result.at( j );
176
177            if ( q1->track() == q2->track() )
178            {
179                picked = false;
180            }
181        }
182
183        if ( picked )
184        {
185            result << q1;
186        }
187    }
188
189    Pipeline::instance()->resolve( result );
190    return result;
191}
192
193
194bool
195PlaylistInterface::hasNextResult() const
196{
197    Tomahawk::result_ptr r = siblingResult( 1 );
198    return ( r && r->isOnline() );
199}
200
201
202bool
203PlaylistInterface::hasPreviousResult() const
204{
205    Tomahawk::result_ptr r = siblingResult( -1 );
206    return ( r && r->isOnline() );
207}
208
209
210void
211PlaylistInterface::onItemsChanged()
212{
213    if ( QThread::currentThread() != thread() )
214    {
215        QMetaObject::invokeMethod( this, "onItemsChanged", Qt::QueuedConnection );
216        return;
217    }
218
219    Tomahawk::result_ptr prevResult = siblingResult( -1, m_currentIndex );
220    Tomahawk::result_ptr nextResult = siblingResult( 1, m_currentIndex );
221
222    {
223        bool avail = prevResult && prevResult->playable();
224        if ( avail != m_prevAvail )
225        {
226            m_prevAvail = avail;
227            emit previousTrackAvailable( avail );
228        }
229    }
230
231    {
232        bool avail = nextResult && nextResult->playable();
233        if ( avail != m_nextAvail )
234        {
235            m_nextAvail = avail;
236            emit nextTrackAvailable( avail );
237        }
238    }
239}
240
241
242void
243PlaylistInterface::setCurrentIndex( qint64 index )
244{
245    m_currentIndex = index;
246
247    emit currentIndexChanged();
248    onItemsChanged();
249}
250
251
252void
253PlaylistInterface::startLoading()
254{
255    foreach ( const Tomahawk::query_ptr& query, tracks() )
256    {
257        disconnect( query.data(), SIGNAL( playableStateChanged( bool ) ), this, SLOT( onItemsChanged() ) );
258        disconnect( query.data(), SIGNAL( resolvingFinished( bool ) ), this, SLOT( onQueryResolved() ) );
259    }
260
261    m_finished = false;
262}
263
264
265void
266PlaylistInterface::finishLoading()
267{
268    foreach ( const Tomahawk::query_ptr& query, tracks() )
269    {
270        connect( query.data(), SIGNAL( playableStateChanged( bool ) ), SLOT( onItemsChanged() ), Qt::UniqueConnection );
271        connect( query.data(), SIGNAL( resolvingFinished( bool ) ), SLOT( onQueryResolved() ), Qt::UniqueConnection );
272    }
273
274    m_finished = true;
275    emit finishedLoading();
276}
277
278
279void
280PlaylistInterface::onQueryResolved()
281{
282    if ( m_foundFirstTrack )
283        return;
284
285    // We're looking for the first playable track, but want to make sure the
286    // second track doesn't start playing before the first really finished resolving
287    foreach ( const Tomahawk::query_ptr& query, tracks() )
288    {
289        if ( !query->resolvingFinished() )
290        {
291            // Wait for this track to be resolved
292            return;
293        }
294
295        if ( query->playable() )
296        {
297            // We have a playable track, all previous tracks are resolved but not playable
298            break;
299        }
300    }
301
302    // We have either found the first playable track or none of the tracks are playable
303    m_foundFirstTrack = true;
304    emit foundFirstPlayableTrack();
305
306    foreach ( const Tomahawk::query_ptr& query, tracks() )
307    {
308        disconnect( query.data(), SIGNAL( resolvingFinished( bool ) ), this, SLOT( onQueryResolved() ) );
309    }
310}