~ubuntu-branches/ubuntu/trusty/tomahawk/trusty-proposed

« back to all changes in this revision

Viewing changes to src/libtomahawk/playlist/PlayableProxyModelPlaylistInterface.cpp

  • Committer: Package Import Robot
  • Author(s): Harald Sitter
  • Date: 2013-03-07 21:50:13 UTC
  • Revision ID: package-import@ubuntu.com-20130307215013-6gdjkdds7i9uenvs
Tags: upstream-0.6.0+dfsg
ImportĀ upstreamĀ versionĀ 0.6.0+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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-2011, Jeff Mitchell <jeff@tomahawk-player.org>
 
5
 *
 
6
 *   Tomahawk is free software: you can redistribute it and/or modify
 
7
 *   it under the terms of the GNU General Public License as published by
 
8
 *   the Free Software Foundation, either version 3 of the License, or
 
9
 *   (at your option) any later version.
 
10
 *
 
11
 *   Tomahawk is distributed in the hope that it will be useful,
 
12
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 
14
 *   GNU General Public License for more details.
 
15
 *
 
16
 *   You should have received a copy of the GNU General Public License
 
17
 *   along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
 
18
 */
 
19
 
 
20
#include "PlayableProxyModelPlaylistInterface.h"
 
21
 
 
22
#include "PlayableProxyModel.h"
 
23
#include "Artist.h"
 
24
#include "Album.h"
 
25
#include "Query.h"
 
26
#include "PlayableItem.h"
 
27
#include "Source.h"
 
28
#include "utils/Logger.h"
 
29
 
 
30
using namespace Tomahawk;
 
31
 
 
32
 
 
33
PlayableProxyModelPlaylistInterface::PlayableProxyModelPlaylistInterface( PlayableProxyModel* proxyModel )
 
34
    : PlaylistInterface()
 
35
    , m_proxyModel( proxyModel )
 
36
    , m_repeatMode( PlaylistModes::NoRepeat )
 
37
    , m_shuffled( false )
 
38
{
 
39
    connect( proxyModel, SIGNAL( indexPlayable( QModelIndex ) ), SLOT( onItemsChanged() ) );
 
40
    connect( proxyModel, SIGNAL( filterChanged( QString ) ), SLOT( onItemsChanged() ) );
 
41
    connect( proxyModel, SIGNAL( itemCountChanged( unsigned int ) ), SLOT( onItemsChanged() ) );
 
42
    connect( proxyModel, SIGNAL( currentIndexChanged() ), SLOT( onCurrentIndexChanged() ) );
 
43
}
 
44
 
 
45
 
 
46
PlayableProxyModelPlaylistInterface::~PlayableProxyModelPlaylistInterface()
 
47
{
 
48
    tDebug() << Q_FUNC_INFO;
 
49
    m_proxyModel.clear();
 
50
}
 
51
 
 
52
 
 
53
int
 
54
PlayableProxyModelPlaylistInterface::trackCount() const
 
55
{
 
56
    return ( m_proxyModel.isNull() ? 0 : m_proxyModel.data()->rowCount( QModelIndex() ) );
 
57
}
 
58
 
 
59
 
 
60
QString
 
61
PlayableProxyModelPlaylistInterface::filter() const
 
62
{
 
63
    return ( m_proxyModel.isNull() ? QString() : m_proxyModel.data()->filterRegExp().pattern() );
 
64
}
 
65
 
 
66
 
 
67
QList< Tomahawk::query_ptr >
 
68
PlayableProxyModelPlaylistInterface::tracks() const
 
69
{
 
70
    if ( m_proxyModel.isNull() )
 
71
        return QList< query_ptr >();
 
72
 
 
73
    PlayableProxyModel* proxyModel = m_proxyModel.data();
 
74
    QList< query_ptr > queries;
 
75
 
 
76
    for ( int i = 0; i < proxyModel->rowCount( QModelIndex() ); i++ )
 
77
    {
 
78
        PlayableItem* item = proxyModel->itemFromIndex( proxyModel->mapToSource( proxyModel->index( i, 0 ) ) );
 
79
        if ( item )
 
80
            queries << item->query();
 
81
    }
 
82
 
 
83
    return queries;
 
84
}
 
85
 
 
86
 
 
87
void
 
88
PlayableProxyModelPlaylistInterface::onCurrentIndexChanged()
 
89
{
 
90
    if ( m_proxyModel.data()->currentIndex().isValid() )
 
91
        setCurrentIndex( (qint64) m_proxyModel.data()->mapToSource( m_proxyModel.data()->currentIndex() ).internalPointer() );
 
92
    else
 
93
        setCurrentIndex( -1 );
 
94
}
 
95
 
 
96
 
 
97
void
 
98
PlayableProxyModelPlaylistInterface::setCurrentIndex( qint64 index )
 
99
{
 
100
    Q_ASSERT( m_proxyModel );
 
101
    if ( m_proxyModel.isNull() )
 
102
        return;
 
103
 
 
104
    if ( m_currentIndex == index )
 
105
        return;
 
106
    m_currentIndex = index; // we need to manually set m_currentIndex (protected member from PlaylistInterface) here
 
107
                            // because calling m_proxyModel.data()->setCurrentIndex( ... ) will end up emitting a
 
108
                            // signal which leads right back here and would cause an infinite loop.
 
109
 
 
110
    PlayableItem* item = reinterpret_cast<PlayableItem*>( (void*)index );
 
111
    if ( index >= 0 && item )
 
112
    {
 
113
        if ( m_shuffled && m_shuffleHistory.count() > 1 )
 
114
        {
 
115
            if ( m_proxyModel.data()->itemFromQuery( m_shuffleHistory.at( m_shuffleHistory.count() - 2 ) ) &&
 
116
               ( m_proxyModel.data()->mapFromSource( item->index ) == m_proxyModel.data()->mapFromSource( m_proxyModel.data()->itemFromQuery( m_shuffleHistory.at( m_shuffleHistory.count() - 2 ) )->index ) ) )
 
117
            {
 
118
                // Note: the following lines aren't by mistake:
 
119
                // We detected that we're going to the previous track in our shuffle history and hence we want to remove the currently playing and the previous track from the shuffle history.
 
120
                // The upcoming track will be added right back to the history further down below in this method.
 
121
                m_shuffleHistory.removeLast();
 
122
                m_shuffleHistory.removeLast();
 
123
            }
 
124
        }
 
125
 
 
126
        m_proxyModel.data()->setCurrentIndex( m_proxyModel.data()->mapFromSource( item->index ) );
 
127
        m_shuffleHistory << queryAt( index );
 
128
        m_shuffleCache = QPersistentModelIndex();
 
129
    }
 
130
 
 
131
    PlaylistInterface::setCurrentIndex( index );
 
132
}
 
133
 
 
134
 
 
135
qint64
 
136
PlayableProxyModelPlaylistInterface::siblingIndex( int itemsAway, qint64 rootIndex ) const
 
137
{
 
138
    if ( m_proxyModel.isNull() )
 
139
        return -1;
 
140
 
 
141
    PlayableProxyModel* proxyModel = m_proxyModel.data();
 
142
 
 
143
    while ( m_shuffleHistory.count() && m_shuffleHistory.count() >= proxyModel->rowCount() )
 
144
    {
 
145
        m_shuffleHistory.removeFirst();
 
146
    }
 
147
 
 
148
    QModelIndex idx = QModelIndex();
 
149
    if ( proxyModel->rowCount() )
 
150
    {
 
151
        if ( m_shuffled )
 
152
        {
 
153
            if ( itemsAway < 0 )
 
154
            {
 
155
                if ( m_shuffleHistory.count() > 1 )
 
156
                {
 
157
                    if ( proxyModel->itemFromQuery( m_shuffleHistory.at( m_shuffleHistory.count() - 2 ) ) )
 
158
                        idx = proxyModel->mapFromSource( proxyModel->itemFromQuery( m_shuffleHistory.at( m_shuffleHistory.count() - 2 ) )->index );
 
159
                }
 
160
                else
 
161
                    return -1;
 
162
            }
 
163
            else
 
164
            {
 
165
                // random mode is enabled
 
166
                if ( m_shuffleCache.isValid() )
 
167
                {
 
168
                    idx = m_shuffleCache;
 
169
                }
 
170
                else
 
171
                {
 
172
                    int safetyCounter = 0;
 
173
                    PlayableItem* item = 0;
 
174
                    do
 
175
                    {
 
176
                        safetyCounter++;
 
177
                        idx = proxyModel->index( qrand() % proxyModel->rowCount(), 0 );
 
178
                        item = proxyModel->itemFromIndex( proxyModel->mapToSource( idx ) );
 
179
                    }
 
180
                    while ( safetyCounter < proxyModel->rowCount() &&
 
181
                          ( !item || !item->query()->playable() || m_shuffleHistory.contains( item->query() ) ) );
 
182
 
 
183
                    if ( item && item->query()->playable() )
 
184
                    {
 
185
                        m_shuffleCache = idx;
 
186
                        tDebug( LOGVERBOSE ) << "Next shuffled PlaylistItem cached:" << item->query()->toString() << item->query()->results().at( 0 )->url()
 
187
                                             << "- after" << safetyCounter << "tries to find a track";
 
188
                    }
 
189
                    else
 
190
                    {
 
191
                        tDebug() << Q_FUNC_INFO << "Error finding next shuffled playable track";
 
192
                    }
 
193
                }
 
194
            }
 
195
        }
 
196
        else
 
197
        {
 
198
            if ( m_repeatMode == PlaylistModes::RepeatOne )
 
199
            {
 
200
                idx = proxyModel->currentIndex();
 
201
            }
 
202
            else
 
203
            {
 
204
                // random mode is disabled
 
205
                if ( rootIndex == -1 )
 
206
                {
 
207
                    idx = proxyModel->currentIndex();
 
208
                }
 
209
                else
 
210
                {
 
211
                    PlayableItem* pitem = reinterpret_cast<PlayableItem*>( (void*)rootIndex );
 
212
                    if ( !pitem || !pitem->index.isValid() )
 
213
                        return -1;
 
214
 
 
215
                    idx = proxyModel->mapFromSource( pitem->index );
 
216
                }
 
217
 
 
218
                idx = proxyModel->index( idx.row() + itemsAway, 0 );
 
219
            }
 
220
        }
 
221
    }
 
222
 
 
223
    if ( !idx.isValid() && m_repeatMode == PlaylistModes::RepeatAll )
 
224
    {
 
225
        // repeat all tracks
 
226
        if ( itemsAway > 0 )
 
227
        {
 
228
            // reset to first item
 
229
            idx = proxyModel->index( 0, 0 );
 
230
        }
 
231
        else
 
232
        {
 
233
            // reset to last item
 
234
            idx = proxyModel->index( proxyModel->rowCount() - 1, 0 );
 
235
        }
 
236
    }
 
237
 
 
238
    while ( idx.isValid() )
 
239
    {
 
240
        PlayableItem* item = proxyModel->itemFromIndex( proxyModel->mapToSource( idx ) );
 
241
        if ( item )
 
242
        {
 
243
            return (qint64)( item->index.internalPointer() );
 
244
        }
 
245
 
 
246
        idx = proxyModel->index( idx.row() + ( itemsAway > 0 ? 1 : -1 ), 0 );
 
247
    }
 
248
 
 
249
    return -1;
 
250
}
 
251
 
 
252
 
 
253
Tomahawk::result_ptr
 
254
PlayableProxyModelPlaylistInterface::currentItem() const
 
255
{
 
256
    if ( m_proxyModel.isNull() )
 
257
        return result_ptr();
 
258
 
 
259
    PlayableProxyModel* proxyModel = m_proxyModel.data();
 
260
 
 
261
    PlayableItem* item = proxyModel->itemFromIndex( proxyModel->mapToSource( proxyModel->currentIndex() ) );
 
262
    if ( item && !item->query().isNull() && item->query()->playable() )
 
263
        return item->query()->results().at( 0 );
 
264
 
 
265
    return result_ptr();
 
266
}
 
267
 
 
268
 
 
269
Tomahawk::query_ptr
 
270
PlayableProxyModelPlaylistInterface::queryAt( qint64 index ) const
 
271
{
 
272
    if ( m_proxyModel.isNull() )
 
273
        return query_ptr();
 
274
 
 
275
    PlayableItem* item = reinterpret_cast<PlayableItem*>( (void*)index );
 
276
    if ( item && item->query() )
 
277
        return item->query();
 
278
 
 
279
    return query_ptr();
 
280
}
 
281
 
 
282
 
 
283
Tomahawk::result_ptr
 
284
PlayableProxyModelPlaylistInterface::resultAt( qint64 index ) const
 
285
{
 
286
    if ( m_proxyModel.isNull() )
 
287
        return result_ptr();
 
288
 
 
289
    PlayableItem* item = reinterpret_cast<PlayableItem*>( (void*)index );
 
290
    if ( item && item->result() )
 
291
        return item->result();
 
292
 
 
293
    return result_ptr();
 
294
}
 
295
 
 
296
 
 
297
qint64
 
298
PlayableProxyModelPlaylistInterface::indexOfResult( const Tomahawk::result_ptr& result ) const
 
299
{
 
300
    if ( m_proxyModel.isNull() )
 
301
        return -1;
 
302
 
 
303
    PlayableItem* item = m_proxyModel.data()->itemFromResult( result );
 
304
    if ( item )
 
305
        return (qint64)( item->index.internalPointer() );
 
306
 
 
307
    return -1;
 
308
}
 
309
 
 
310
 
 
311
qint64
 
312
PlayableProxyModelPlaylistInterface::indexOfQuery( const Tomahawk::query_ptr& query ) const
 
313
{
 
314
    if ( m_proxyModel.isNull() )
 
315
        return -1;
 
316
 
 
317
    PlayableItem* item = m_proxyModel.data()->itemFromQuery( query );
 
318
    if ( item )
 
319
        return (qint64)( item->index.internalPointer() );
 
320
 
 
321
    return -1;
 
322
}