File indexing completed on 2024-05-19 04:49:51
0001 /**************************************************************************************** 0002 * Copyright (c) 2009 Téo Mrnjavac <teo@kde.org> * 0003 * Copyright (c) 2010 Nanno Langstraat <langstr@gmail.com> * 0004 * * 0005 * This program is free software; you can redistribute it and/or modify it under * 0006 * the terms of the GNU General Public License as published by the Free Software * 0007 * Foundation; either version 2 of the License, or (at your option) any later * 0008 * version. * 0009 * * 0010 * This program is distributed in the hope that it will be useful, but WITHOUT ANY * 0011 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * 0012 * PARTICULAR PURPOSE. See the GNU General Public License for more details. * 0013 * * 0014 * You should have received a copy of the GNU General Public License along with * 0015 * this program. If not, see <http://www.gnu.org/licenses/>. * 0016 ****************************************************************************************/ 0017 0018 #include "ProxyBase.h" 0019 0020 #include "core/meta/Meta.h" 0021 #include "core/meta/Statistics.h" 0022 #include "core-impl/playlists/types/file/PlaylistFileSupport.h" 0023 #include "playlist/PlaylistModel.h" 0024 0025 namespace Playlist 0026 { 0027 0028 ProxyBase::ProxyBase( AbstractModel *belowModel, QObject *parent ) 0029 : QSortFilterProxyModel( parent ) 0030 , m_belowModel( belowModel ) 0031 { 0032 setSourceModel( m_belowModel->qaim() ); 0033 0034 // Proxy the Playlist::AbstractModel signals. 0035 // If you need to do something special in a subclass, disconnect() this signal and 0036 // do your own connect() call. 0037 connect( qobject_cast<Playlist::Model*>( sourceModel() ), &Playlist::Model::activeTrackChanged, 0038 this, &ProxyBase::activeTrackChanged ); 0039 connect( qobject_cast<Playlist::Model*>( sourceModel() ), &Playlist::Model::queueChanged, 0040 this, &ProxyBase::queueChanged ); 0041 } 0042 0043 ProxyBase::~ProxyBase() 0044 {} 0045 0046 // Pass-through virtual public methods, that pretty much just forward stuff through the stack 0047 // of proxies, start here. 0048 // Please keep them sorted alphabetically. -- Téo 0049 0050 quint64 0051 ProxyBase::activeId() const 0052 { 0053 return m_belowModel->activeId(); 0054 } 0055 0056 int 0057 ProxyBase::activeRow() const 0058 { 0059 // We map the active row form the source to this ProxyModel. 0060 return rowFromSource( m_belowModel->activeRow() ); 0061 } 0062 0063 Meta::TrackPtr 0064 ProxyBase::activeTrack() const 0065 { 0066 return m_belowModel->activeTrack(); 0067 } 0068 0069 QSet<int> 0070 ProxyBase::allRowsForTrack( const Meta::TrackPtr& track ) const 0071 { 0072 QSet<int> proxyModelRows; 0073 0074 foreach( int sourceModelRow, m_belowModel->allRowsForTrack( track ) ) 0075 { 0076 int proxyModelRow = rowFromSource( sourceModelRow ); 0077 if ( proxyModelRow != -1 ) 0078 proxyModelRows.insert( proxyModelRow ); 0079 } 0080 0081 return proxyModelRows; 0082 } 0083 0084 void 0085 ProxyBase::clearSearchTerm() 0086 { 0087 m_belowModel->clearSearchTerm(); 0088 } 0089 0090 bool 0091 ProxyBase::containsTrack( const Meta::TrackPtr& track ) const 0092 { 0093 return ( firstRowForTrack( track ) != -1 ); // Let him do the clever work. 0094 } 0095 0096 int 0097 ProxyBase::currentSearchFields() 0098 { 0099 return m_belowModel->currentSearchFields(); 0100 } 0101 0102 QString 0103 ProxyBase::currentSearchTerm() 0104 { 0105 return m_belowModel->currentSearchTerm(); 0106 } 0107 0108 bool 0109 ProxyBase::exportPlaylist( const QString &path, bool relative ) 0110 { 0111 return Playlists::exportPlaylistFile( tracks(), QUrl::fromLocalFile(path), relative ); 0112 } 0113 0114 void 0115 ProxyBase::filterUpdated() 0116 { 0117 m_belowModel->filterUpdated(); 0118 } 0119 0120 int 0121 ProxyBase::find( const QString &searchTerm, int searchFields ) 0122 { 0123 ProxyBase *proxyBase = dynamic_cast< ProxyBase * >( m_belowModel ); 0124 if ( !proxyBase ) 0125 return -1; 0126 0127 return rowFromSource( proxyBase->find( searchTerm, searchFields ) ); 0128 } 0129 0130 int 0131 ProxyBase::findNext( const QString &searchTerm, int selectedRow, int searchFields ) 0132 { 0133 ProxyBase *proxyBase = dynamic_cast< ProxyBase * >( m_belowModel ); 0134 if ( !proxyBase ) 0135 return -1; 0136 0137 return rowFromSource( proxyBase->findNext( searchTerm, rowToSource( selectedRow ), searchFields ) ); 0138 } 0139 0140 int 0141 ProxyBase::findPrevious( const QString &searchTerm, int selectedRow, int searchFields ) 0142 { 0143 ProxyBase *proxyBase = dynamic_cast< ProxyBase * >( m_belowModel ); 0144 if ( !proxyBase ) 0145 return -1; 0146 0147 return rowFromSource( proxyBase->findPrevious( searchTerm, rowToSource( selectedRow ), searchFields ) ); 0148 } 0149 0150 int 0151 ProxyBase::firstRowForTrack( const Meta::TrackPtr& track ) const 0152 { 0153 // First optimistically try 'firstRowForTrack()'. It'll usually work. 0154 int proxyModelRow = rowFromSource( m_belowModel->firstRowForTrack( track ) ); 0155 if ( proxyModelRow != -1 ) 0156 return proxyModelRow; 0157 else 0158 { 0159 // It might be that there are multiple hits in the source model, and we just got 0160 // unlucky with a source row that's filtered out in this model. So, we need to 0161 // check all hits. 0162 foreach( int sourceModelRow, m_belowModel->allRowsForTrack( track ) ) 0163 { 0164 proxyModelRow = rowFromSource( sourceModelRow ); 0165 if ( proxyModelRow != -1 ) 0166 return proxyModelRow; 0167 } 0168 0169 return -1; 0170 } 0171 } 0172 0173 quint64 0174 ProxyBase::idAt( const int row ) const 0175 { 0176 if( rowExists( row ) ) 0177 return m_belowModel->idAt( rowToSource( row ) ); 0178 return 0; 0179 } 0180 0181 bool 0182 ProxyBase::rowExists( int row ) const 0183 { 0184 QModelIndex index = this->index( row, 0 ); 0185 return index.isValid(); 0186 } 0187 0188 int 0189 ProxyBase::rowForId( const quint64 id ) const 0190 { 0191 return rowFromSource( m_belowModel->rowForId( id ) ); 0192 } 0193 0194 int 0195 ProxyBase::rowFromBottomModel( const int row ) 0196 { 0197 return rowFromSource( m_belowModel->rowFromBottomModel( row ) ); 0198 } 0199 0200 int 0201 ProxyBase::rowToBottomModel( const int row ) 0202 { 0203 return m_belowModel->rowToBottomModel( rowToSource( row ) ); 0204 } 0205 0206 void 0207 ProxyBase::setActiveId( const quint64 id ) 0208 { 0209 m_belowModel->setActiveId( id ); 0210 } 0211 0212 void 0213 ProxyBase::setActiveRow( int row ) 0214 { 0215 m_belowModel->setActiveRow( rowToSource( row ) ); 0216 } 0217 0218 void 0219 ProxyBase::setAllUnplayed() 0220 { 0221 m_belowModel->setAllUnplayed(); 0222 } 0223 0224 void 0225 ProxyBase::emitQueueChanged() 0226 { 0227 Q_ASSERT_X(false, "emitQueueChanged", "queueChanged() should be emitted at the bottom of " 0228 "the model stack so it can be received from every model."); 0229 } 0230 0231 int 0232 ProxyBase::queuePositionOfRow( int row ) 0233 { 0234 return m_belowModel->queuePositionOfRow( rowToSource ( row ) ); 0235 } 0236 0237 void 0238 ProxyBase::showOnlyMatches( bool onlyMatches ) 0239 { 0240 ProxyBase *proxyBase = dynamic_cast< ProxyBase * >( m_belowModel ); 0241 if ( !proxyBase ) 0242 return ; 0243 0244 proxyBase->showOnlyMatches( onlyMatches ); 0245 } 0246 0247 Item::State 0248 ProxyBase::stateOfId( quint64 id ) const 0249 { 0250 return m_belowModel->stateOfId( id ); 0251 } 0252 0253 Item::State 0254 ProxyBase::stateOfRow( int row ) const 0255 { 0256 return m_belowModel->stateOfRow( rowToSource( row ) ); 0257 } 0258 0259 qint64 0260 ProxyBase::totalLength() const 0261 { 0262 return m_belowModel->totalLength(); 0263 } 0264 0265 quint64 0266 ProxyBase::totalSize() const 0267 { 0268 return m_belowModel->totalSize(); 0269 } 0270 0271 Meta::TrackPtr 0272 ProxyBase::trackAt(int row) const 0273 { 0274 return m_belowModel->trackAt( rowToSource( row ) ); 0275 } 0276 0277 Meta::TrackPtr 0278 ProxyBase::trackForId( const quint64 id ) const 0279 { 0280 return m_belowModel->trackForId( id ); 0281 } 0282 0283 Meta::TrackList 0284 ProxyBase::tracks() 0285 { 0286 Meta::TrackList tl; 0287 for( int i = 0; i < rowCount(); ++i ) 0288 tl << trackAt( i ); 0289 return tl; 0290 } 0291 0292 //protected: 0293 0294 bool 0295 ProxyBase::rowMatch( int sourceModelRow, const QString &searchTerms, int searchFields ) const 0296 { 0297 if ( !m_belowModel ) 0298 return false; 0299 0300 Meta::TrackPtr track = m_belowModel->trackAt( sourceModelRow ); 0301 0302 QStringList searchList = searchTerms.split(QLatin1Char(' '), Qt::SkipEmptyParts); 0303 0304 foreach( const QString& searchTerm, searchList ) 0305 { 0306 bool match = false; 0307 0308 if ( searchFields & MatchTrack && 0309 track->prettyName().contains( searchTerm, Qt::CaseInsensitive ) 0310 ) 0311 match = true; 0312 0313 if ( searchFields & MatchArtist && 0314 track->artist() && 0315 track->artist()->prettyName().contains( searchTerm, Qt::CaseInsensitive ) 0316 ) 0317 match = true; 0318 0319 if ( searchFields & MatchAlbum && 0320 track->album() && 0321 track->album()->prettyName().contains( searchTerm, Qt::CaseInsensitive ) 0322 ) 0323 match = true; 0324 0325 if ( searchFields & MatchGenre && 0326 track->genre() && 0327 track->genre()->prettyName().contains( searchTerm, Qt::CaseInsensitive ) 0328 ) 0329 match = true; 0330 0331 if ( searchFields & MatchComposer && 0332 track->composer() && 0333 track->composer()->prettyName().contains( searchTerm, Qt::CaseInsensitive ) 0334 ) 0335 match = true; 0336 0337 if ( searchFields & MatchYear && 0338 track->year() && 0339 track->year()->prettyName().contains( searchTerm, Qt::CaseInsensitive ) 0340 ) 0341 match = true; 0342 0343 if( searchFields & MatchRating ) 0344 { 0345 bool ok; 0346 int rating = QString( searchTerm ).remove( QStringLiteral("rating:") ).toInt( &ok ); 0347 if( ok && ( track->statistics()->rating() == rating ) ) 0348 match = true; 0349 } 0350 0351 if( !match ) 0352 return false; 0353 } 0354 0355 return true; 0356 } 0357 0358 int 0359 ProxyBase::rowFromSource( int sourceModelRow ) const 0360 { 0361 QModelIndex sourceModelIndex = sourceModel()->index( sourceModelRow, 0 ); 0362 QModelIndex proxyModelIndex = mapFromSource( sourceModelIndex ); // Call 'map' even for a 1:1 passthrough proxy: QSFPM might need it. 0363 0364 if ( proxyModelIndex.isValid() ) 0365 return proxyModelIndex.row(); 0366 else 0367 return -1; 0368 } 0369 0370 int 0371 ProxyBase::rowToSource( int proxyModelRow ) const 0372 { 0373 QModelIndex proxyModelIndex = this->index( proxyModelRow, 0 ); 0374 QModelIndex sourceModelIndex = mapToSource( proxyModelIndex ); // Call 'map' even for a 1:1 passthrough proxy: QSFPM might need it. 0375 0376 if( sourceModelIndex.isValid() ) 0377 return sourceModelIndex.row(); 0378 else 0379 if( proxyModelRow == rowCount() ) 0380 return sourceModel()->rowCount(); 0381 else 0382 return -1; 0383 } 0384 0385 } //namespace Playlist 0386