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