File indexing completed on 2024-05-05 04:47:28

0001 /****************************************************************************************
0002  * Copyright (c) 2007 Nikolaj Hald Nielsen <nhn@kde.org>                                *
0003  * Copyright (c) 2008 Seb Ruiz <ruiz@kde.org>                                           *
0004  * Copyright (c) 2013 Ralf Engels <ralf-engels@gmx.de>                                  *
0005  *                                                                                      *
0006  * This program is free software; you can redistribute it and/or modify it under        *
0007  * the terms of the GNU General Public License as published by the Free Software        *
0008  * Foundation; either version 2 of the License, or (at your option) any later           *
0009  * version.                                                                             *
0010  *                                                                                      *
0011  * This program is distributed in the hope that it will be useful, but WITHOUT ANY      *
0012  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A      *
0013  * PARTICULAR PURPOSE. See the GNU General Public License for more details.             *
0014  *                                                                                      *
0015  * You should have received a copy of the GNU General Public License along with         *
0016  * this program.  If not, see <http://www.gnu.org/licenses/>.                           *
0017  ****************************************************************************************/
0018 
0019 #include "CollectionSortFilterProxyModel.h"
0020 
0021 #include "amarokconfig.h"
0022 #include "browsers/CollectionTreeItem.h"
0023 #include "core/meta/Meta.h"
0024 #include "core/support/Debug.h"
0025 #include "widgets/PrettyTreeRoles.h"
0026 
0027 #include <QCollator>
0028 #include <QVariant>
0029 #include <QString>
0030 
0031 CollectionSortFilterProxyModel::CollectionSortFilterProxyModel(  QObject * parent )
0032     : QSortFilterProxyModel( parent )
0033     , m_col( new QCollator )
0034 {
0035     setSortLocaleAware( true );
0036 
0037     setSortRole( PrettyTreeRoles::SortRole );
0038     setFilterRole( PrettyTreeRoles::FilterRole );
0039     setSortCaseSensitivity( Qt::CaseInsensitive );
0040     setFilterCaseSensitivity( Qt::CaseInsensitive );
0041 
0042     setDynamicSortFilter( true );
0043 
0044     m_col->setCaseSensitivity( Qt::CaseInsensitive );
0045 }
0046 
0047 
0048 CollectionSortFilterProxyModel::~CollectionSortFilterProxyModel()
0049 {
0050     delete m_col;
0051 }
0052 
0053 bool
0054 CollectionSortFilterProxyModel::hasChildren(const QModelIndex & parent) const
0055 {
0056     QModelIndex sourceParent = mapToSource(parent);
0057     return sourceModel()->hasChildren(sourceParent);
0058 }
0059 
0060 bool
0061 CollectionSortFilterProxyModel::filterAcceptsRow( int source_row, const QModelIndex& source_parent ) const
0062 {
0063     bool stringAccepted = QSortFilterProxyModel::filterAcceptsRow( source_row, source_parent );
0064 
0065     if( AmarokConfig::showYears())
0066     {
0067         QModelIndex index = sourceModel()->index( source_row, 0, source_parent );
0068         if( treeItem( index )->isAlbumItem() )
0069         {
0070             bool yearLoaded = index.data( PrettyTreeRoles::YearRole ).toInt() >= 0;
0071             return yearLoaded && stringAccepted;
0072         }
0073     }
0074 
0075     return stringAccepted;
0076 }
0077 
0078 bool
0079 CollectionSortFilterProxyModel::lessThan( const QModelIndex &left, const QModelIndex &right ) const
0080 {
0081     CollectionTreeItem *leftItem = treeItem( left );
0082     CollectionTreeItem *rightItem = treeItem( right );
0083 
0084     // various artists and no label items are always at the top
0085     if( !leftItem || leftItem->isVariousArtistItem() || leftItem->isNoLabelItem() )
0086         return true;
0087     if( !rightItem || rightItem->isVariousArtistItem() || rightItem->isNoLabelItem() )
0088         return false;
0089 
0090     if( leftItem->isTrackItem() && rightItem->isTrackItem() )
0091         return lessThanTrack( left, right );
0092 
0093     if( leftItem->isAlbumItem() && rightItem->isAlbumItem() )
0094         return lessThanAlbum( left, right );
0095 
0096     if( leftItem->isDataItem() && rightItem->isDataItem() )
0097         return lessThanItem( left, right );
0098 
0099     return QSortFilterProxyModel::lessThan( left, right );
0100 }
0101 
0102 bool
0103 CollectionSortFilterProxyModel::lessThanTrack( const QModelIndex &left, const QModelIndex &right ) const
0104 {
0105     const Meta::TrackPtr leftTrack = Meta::TrackPtr::dynamicCast( treeItem(left)->data() );
0106     const Meta::TrackPtr rightTrack = Meta::TrackPtr::dynamicCast( treeItem(right)->data() );
0107     if( !leftTrack || !rightTrack )
0108     {
0109         DEBUG_BLOCK
0110         error() << "Should never have compared these two indexes"
0111             << left.data(Qt::DisplayRole) << "and" << right.data(Qt::DisplayRole);
0112         return QSortFilterProxyModel::lessThan( left, right );
0113     }
0114 
0115     if( AmarokConfig::showTrackNumbers() )
0116     {
0117         //First compare by disc number
0118         if ( leftTrack->discNumber() < rightTrack->discNumber() )
0119             return true;
0120         if ( leftTrack->discNumber() > rightTrack->discNumber() )
0121             return false;
0122 
0123         //Disc #'s are equal, compare by track number
0124         if( leftTrack->trackNumber() < rightTrack->trackNumber() )
0125             return true;
0126         if( leftTrack->trackNumber() > rightTrack->trackNumber() )
0127             return false;
0128     }
0129 
0130     // compare by name
0131     {
0132         int comp = m_col->compare( leftTrack->sortableName(), rightTrack->sortableName() );
0133         if( comp < 0 )
0134             return true;
0135         if( comp > 0 )
0136             return false;
0137     }
0138 
0139     return leftTrack.data() < rightTrack.data(); // prevent expanded tracks from switching places (if that ever happens)
0140 }
0141 
0142 bool
0143 CollectionSortFilterProxyModel::lessThanAlbum( const QModelIndex &left, const QModelIndex &right ) const
0144 {
0145     Meta::AlbumPtr leftAlbum = Meta::AlbumPtr::dynamicCast( treeItem(left)->data() );
0146     Meta::AlbumPtr rightAlbum = Meta::AlbumPtr::dynamicCast( treeItem(right)->data() );
0147 
0148     if( !leftAlbum || !rightAlbum )
0149     {
0150         DEBUG_BLOCK
0151         error() << "Should never have compared these two indexes"
0152             << left.data(Qt::DisplayRole) << "and" << right.data(Qt::DisplayRole);
0153         return QSortFilterProxyModel::lessThan( left, right );
0154     }
0155 
0156     // compare by year
0157     if( AmarokConfig::showYears() )
0158     {
0159         int leftYear = left.data( PrettyTreeRoles::YearRole ).toInt();
0160         int rightYear = right.data( PrettyTreeRoles::YearRole ).toInt();
0161 
0162         if( leftYear < rightYear )
0163             return false; // left album is newer
0164         if( leftYear > rightYear )
0165             return true;
0166     }
0167 
0168     // compare by name
0169     {
0170         int comp = m_col->compare( leftAlbum->sortableName(), rightAlbum->sortableName() );
0171         if( comp < 0 )
0172             return true;
0173         if( comp > 0 )
0174             return false;
0175     }
0176 
0177     return leftAlbum.data() < rightAlbum.data(); // prevent expanded albums from switching places
0178 }
0179 
0180 bool
0181 CollectionSortFilterProxyModel::lessThanItem( const QModelIndex &left, const QModelIndex &right ) const
0182 {
0183     Meta::DataPtr leftData = treeItem(left)->data();
0184     Meta::DataPtr rightData = treeItem(right)->data();
0185 
0186     if( !leftData || !rightData )
0187     {
0188         DEBUG_BLOCK
0189         error() << "Should never have compared these two indexes"
0190             << left.data(Qt::DisplayRole) << "and" << right.data(Qt::DisplayRole);
0191         return QSortFilterProxyModel::lessThan( left, right );
0192     }
0193 
0194     // compare by name
0195     {
0196         int comp = m_col->compare( leftData->sortableName(), rightData->sortableName() );
0197         if( comp < 0 )
0198             return true;
0199         if( comp > 0 )
0200             return false;
0201     }
0202 
0203     return leftData.data() < rightData.data(); // prevent expanded data from switching places
0204 }
0205 
0206 inline CollectionTreeItem*
0207 CollectionSortFilterProxyModel::treeItem( const QModelIndex &index ) const
0208 {
0209     return static_cast<CollectionTreeItem*>( index.internalPointer() );
0210 }