1
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
3
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
4
* Copyright 2010-2011, Jeff Mitchell <jeff@tomahawk-player.org>
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.
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.
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/>.
20
#include "PlayableProxyModelPlaylistInterface.h"
22
#include "PlayableProxyModel.h"
26
#include "PlayableItem.h"
28
#include "utils/Logger.h"
30
using namespace Tomahawk;
33
PlayableProxyModelPlaylistInterface::PlayableProxyModelPlaylistInterface( PlayableProxyModel* proxyModel )
35
, m_proxyModel( proxyModel )
36
, m_repeatMode( PlaylistModes::NoRepeat )
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() ) );
46
PlayableProxyModelPlaylistInterface::~PlayableProxyModelPlaylistInterface()
48
tDebug() << Q_FUNC_INFO;
54
PlayableProxyModelPlaylistInterface::trackCount() const
56
return ( m_proxyModel.isNull() ? 0 : m_proxyModel.data()->rowCount( QModelIndex() ) );
61
PlayableProxyModelPlaylistInterface::filter() const
63
return ( m_proxyModel.isNull() ? QString() : m_proxyModel.data()->filterRegExp().pattern() );
67
QList< Tomahawk::query_ptr >
68
PlayableProxyModelPlaylistInterface::tracks() const
70
if ( m_proxyModel.isNull() )
71
return QList< query_ptr >();
73
PlayableProxyModel* proxyModel = m_proxyModel.data();
74
QList< query_ptr > queries;
76
for ( int i = 0; i < proxyModel->rowCount( QModelIndex() ); i++ )
78
PlayableItem* item = proxyModel->itemFromIndex( proxyModel->mapToSource( proxyModel->index( i, 0 ) ) );
80
queries << item->query();
88
PlayableProxyModelPlaylistInterface::onCurrentIndexChanged()
90
if ( m_proxyModel.data()->currentIndex().isValid() )
91
setCurrentIndex( (qint64) m_proxyModel.data()->mapToSource( m_proxyModel.data()->currentIndex() ).internalPointer() );
93
setCurrentIndex( -1 );
98
PlayableProxyModelPlaylistInterface::setCurrentIndex( qint64 index )
100
Q_ASSERT( m_proxyModel );
101
if ( m_proxyModel.isNull() )
104
if ( m_currentIndex == index )
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.
110
PlayableItem* item = reinterpret_cast<PlayableItem*>( (void*)index );
111
if ( index >= 0 && item )
113
if ( m_shuffled && m_shuffleHistory.count() > 1 )
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 ) ) )
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();
126
m_proxyModel.data()->setCurrentIndex( m_proxyModel.data()->mapFromSource( item->index ) );
127
m_shuffleHistory << queryAt( index );
128
m_shuffleCache = QPersistentModelIndex();
131
PlaylistInterface::setCurrentIndex( index );
136
PlayableProxyModelPlaylistInterface::siblingIndex( int itemsAway, qint64 rootIndex ) const
138
if ( m_proxyModel.isNull() )
141
PlayableProxyModel* proxyModel = m_proxyModel.data();
143
while ( m_shuffleHistory.count() && m_shuffleHistory.count() >= proxyModel->rowCount() )
145
m_shuffleHistory.removeFirst();
148
QModelIndex idx = QModelIndex();
149
if ( proxyModel->rowCount() )
155
if ( m_shuffleHistory.count() > 1 )
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 );
165
// random mode is enabled
166
if ( m_shuffleCache.isValid() )
168
idx = m_shuffleCache;
172
int safetyCounter = 0;
173
PlayableItem* item = 0;
177
idx = proxyModel->index( qrand() % proxyModel->rowCount(), 0 );
178
item = proxyModel->itemFromIndex( proxyModel->mapToSource( idx ) );
180
while ( safetyCounter < proxyModel->rowCount() &&
181
( !item || !item->query()->playable() || m_shuffleHistory.contains( item->query() ) ) );
183
if ( item && item->query()->playable() )
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";
191
tDebug() << Q_FUNC_INFO << "Error finding next shuffled playable track";
198
if ( m_repeatMode == PlaylistModes::RepeatOne )
200
idx = proxyModel->currentIndex();
204
// random mode is disabled
205
if ( rootIndex == -1 )
207
idx = proxyModel->currentIndex();
211
PlayableItem* pitem = reinterpret_cast<PlayableItem*>( (void*)rootIndex );
212
if ( !pitem || !pitem->index.isValid() )
215
idx = proxyModel->mapFromSource( pitem->index );
218
idx = proxyModel->index( idx.row() + itemsAway, 0 );
223
if ( !idx.isValid() && m_repeatMode == PlaylistModes::RepeatAll )
228
// reset to first item
229
idx = proxyModel->index( 0, 0 );
233
// reset to last item
234
idx = proxyModel->index( proxyModel->rowCount() - 1, 0 );
238
while ( idx.isValid() )
240
PlayableItem* item = proxyModel->itemFromIndex( proxyModel->mapToSource( idx ) );
243
return (qint64)( item->index.internalPointer() );
246
idx = proxyModel->index( idx.row() + ( itemsAway > 0 ? 1 : -1 ), 0 );
254
PlayableProxyModelPlaylistInterface::currentItem() const
256
if ( m_proxyModel.isNull() )
259
PlayableProxyModel* proxyModel = m_proxyModel.data();
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 );
270
PlayableProxyModelPlaylistInterface::queryAt( qint64 index ) const
272
if ( m_proxyModel.isNull() )
275
PlayableItem* item = reinterpret_cast<PlayableItem*>( (void*)index );
276
if ( item && item->query() )
277
return item->query();
284
PlayableProxyModelPlaylistInterface::resultAt( qint64 index ) const
286
if ( m_proxyModel.isNull() )
289
PlayableItem* item = reinterpret_cast<PlayableItem*>( (void*)index );
290
if ( item && item->result() )
291
return item->result();
298
PlayableProxyModelPlaylistInterface::indexOfResult( const Tomahawk::result_ptr& result ) const
300
if ( m_proxyModel.isNull() )
303
PlayableItem* item = m_proxyModel.data()->itemFromResult( result );
305
return (qint64)( item->index.internalPointer() );
312
PlayableProxyModelPlaylistInterface::indexOfQuery( const Tomahawk::query_ptr& query ) const
314
if ( m_proxyModel.isNull() )
317
PlayableItem* item = m_proxyModel.data()->itemFromQuery( query );
319
return (qint64)( item->index.internalPointer() );