File indexing completed on 2025-01-05 04:25:40

0001 /****************************************************************************************
0002  * Copyright (c) 2008 Andreas Muetzel <andreas.muetzel@gmx.net>                         *
0003  *                                                                                      *
0004  * This program is free software; you can redistribute it and/or modify it under        *
0005  * the terms of the GNU General Public License as published by the Free Software        *
0006  * Foundation; either version 2 of the License, or (at your option) any later           *
0007  * version.                                                                             *
0008  *                                                                                      *
0009  * This program is distributed in the hope that it will be useful, but WITHOUT ANY      *
0010  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A      *
0011  * PARTICULAR PURPOSE. See the GNU General Public License for more details.             *
0012  *                                                                                      *
0013  * You should have received a copy of the GNU General Public License along with         *
0014  * this program.  If not, see <http://www.gnu.org/licenses/>.                           *
0015  ****************************************************************************************/
0016 
0017 #define DEBUG_PREFIX "AlbumsModel"
0018 
0019 #include "AlbumsModel.h"
0020 #include "AlbumsDefs.h"
0021 #include "AlbumItem.h"
0022 #include "AmarokMimeData.h"
0023 #include "core/support/Debug.h"
0024 #include <support/MetaUtility.h>
0025 #include "TrackItem.h"
0026 
0027 #include <QCollator>
0028 #include <QFontMetrics>
0029 #include <QGuiApplication>
0030 
0031 AlbumsModel::AlbumsModel( QObject *parent )
0032     : QStandardItemModel( parent )
0033     , m_rowHeight( 0 )
0034 {
0035     connect( qApp, &QGuiApplication::fontDatabaseChanged, this, &AlbumsModel::updateRowHeight );
0036     updateRowHeight();
0037 }
0038 
0039 int
0040 AlbumsModel::rowHeight() const
0041 {
0042     return m_rowHeight;
0043 }
0044 
0045 void
0046 AlbumsModel::updateRowHeight()
0047 {
0048     QFont font;
0049     m_rowHeight = QFontMetrics( font ).height();
0050 }
0051 
0052 QVariant
0053 AlbumsModel::data( const QModelIndex &index, int role ) const
0054 {
0055     if( !index.isValid() )
0056         return QVariant();
0057 
0058     if( role == Qt::DisplayRole )
0059     {
0060         const QStandardItem *item = itemFromIndex( index );
0061 
0062         if( const auto album = dynamic_cast<const AlbumItem *>( item ) )
0063         {
0064             QString name = album->data( NameRole ).toString();
0065             int year     = album->data( AlbumYearRole ).toInt();
0066 
0067             QStringList texts;
0068             texts << ((year > 0) ? QString( "%1 (%2)" ).arg( name, QString::number(year) ) : name);
0069             texts << album->data( AlbumLengthRole ).toString();
0070 
0071             return texts.join('\n');
0072         }
0073 
0074         if( const auto track = dynamic_cast<const TrackItem *>( item ) )
0075         {
0076             bool isCompilation = track->data( AlbumCompilationRole ).toBool();
0077             const QString &name = track->data( NameRole ).toString();
0078             const QString &artist = track->data( TrackArtistRole ).toString();
0079             QString length = " (" + Meta::msToPrettyTime( track->data( TrackLengthRole ).toInt() ) + ')';
0080             QString number = track->data( TrackNumberRole ).toString() + ". ";
0081             QString middle = isCompilation ? QString( "%1 - %2" ).arg( artist, name ) : name;
0082 
0083             return QStringList( { number, middle, length } ).join( ' ' );
0084         }
0085     }
0086 
0087     if( role == Qt::SizeHintRole )
0088     {
0089         const QStandardItem *item = itemFromIndex( index );
0090         int h = 4;
0091         h += (item->type() != AlbumType) ? m_rowHeight : static_cast<const AlbumItem *>( item )->iconSize();
0092         return QSize( -1, h );
0093     }
0094     return itemFromIndex( index )->data( role );
0095 }
0096 
0097 QMimeData*
0098 AlbumsModel::mimeData( const QModelIndexList &indices ) const
0099 {
0100     DEBUG_BLOCK
0101     if( indices.isEmpty() )
0102         return nullptr;
0103 
0104     Meta::TrackList tracks;
0105     foreach( const QModelIndex &index, indices )
0106         tracks << tracksForIndex( index );
0107     QSet< AmarokSharedPointer<Meta::Track> > tracksSet(tracks.begin(), tracks.end());
0108     tracks = tracksSet.values();
0109 
0110     // http://doc.trolltech.com/4.4/qabstractitemmodel.html#mimeData
0111     // If the list of indexes is empty, or there are no supported MIME types,
0112     // 0 is returned rather than a serialized empty list.
0113     if( tracks.isEmpty() )
0114         return nullptr;
0115 
0116     AmarokMimeData *mimeData = new AmarokMimeData();
0117     mimeData->setTracks( tracks );
0118     return mimeData;
0119 }
0120 
0121 Meta::TrackList
0122 AlbumsModel::tracksForIndex( const QModelIndex &index ) const
0123 {
0124     Meta::TrackList tracks;
0125     if( !index.isValid() )
0126         return tracks;
0127 
0128     if( hasChildren( index ) )
0129     {
0130         for( int i = 0, rows = rowCount( index ); i < rows; ++i )
0131             tracks << tracksForIndex( index.model()->index( i, 0, index ) );
0132     }
0133     else if( QStandardItem *item = itemFromIndex( index ) )
0134     {
0135         if( item->type() == TrackType )
0136         {
0137             TrackItem* trackItem = static_cast<TrackItem*>( item );
0138             if( trackItem )
0139                 tracks << trackItem->track();
0140         }
0141     }
0142     return tracks;
0143 }
0144 
0145 QStringList
0146 AlbumsModel::mimeTypes() const
0147 {
0148     QStringList types;
0149     types << AmarokMimeData::TRACK_MIME;
0150     return types;
0151 }
0152 
0153 AlbumsProxyModel::AlbumsProxyModel( QObject *parent )
0154     : QSortFilterProxyModel( parent )
0155     , m_mode( SortByCreateDate )
0156     , m_collator( new QCollator )
0157 {
0158     m_collator->setNumericMode( true );
0159 }
0160 
0161 AlbumsProxyModel::~AlbumsProxyModel()
0162 {
0163     delete m_collator;
0164 }
0165 
0166 bool
0167 AlbumsProxyModel::lessThan( const QModelIndex &left, const QModelIndex &right ) const
0168 {
0169     const QStandardItemModel *model = static_cast<QStandardItemModel*>( sourceModel() );
0170     const QStandardItem *leftItem = model->itemFromIndex( left );
0171     int type = leftItem->type();
0172     if( type == AlbumType && m_mode == SortByCreateDate )
0173     {
0174         const AlbumItem *leftAlbum = static_cast<const AlbumItem *>( leftItem );
0175         const AlbumItem *rightAlbum = static_cast<const AlbumItem *>( model->itemFromIndex( right ) );
0176         QDateTime leftMaxCreateDate, rightMaxCreateDate;
0177         foreach( Meta::TrackPtr track, leftAlbum->album()->tracks() )
0178             if( track->createDate() > leftMaxCreateDate )
0179                 leftMaxCreateDate = track->createDate();
0180         foreach( Meta::TrackPtr track, rightAlbum->album()->tracks() )
0181             if( track->createDate() > rightMaxCreateDate )
0182                 rightMaxCreateDate = track->createDate();
0183         return leftMaxCreateDate > rightMaxCreateDate;
0184     }
0185     else if( type == AlbumType || type == TrackType )
0186         return leftItem->operator<( *model->itemFromIndex( right ) );
0187     else
0188     {
0189         return m_collator->compare( leftItem->text(), model->itemFromIndex(right)->text() ) < 0;
0190     }
0191 }
0192 
0193 bool
0194 AlbumsProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex &sourceParent ) const
0195 {
0196     const QStandardItemModel *model = static_cast<QStandardItemModel*>( sourceModel() );
0197     const QModelIndex &srcIndex     = sourceModel()->index( sourceRow, 0, sourceParent );
0198     const QStandardItem *item       = model->itemFromIndex( srcIndex );
0199 
0200     if( item->data( NameRole ).toString().contains( filterRegExp() ) )
0201         return true;
0202 
0203     if( item->type() == AlbumType )
0204     {
0205         for( int i = 0, count = model->rowCount( srcIndex ); i < count; ++i )
0206         {
0207             const QModelIndex &kid = model->index( i, 0, srcIndex );
0208             if( kid.data( NameRole ).toString().contains( filterRegExp() ) )
0209                 return true;
0210         }
0211     }
0212     return false;
0213 }
0214 
0215 AlbumsProxyModel::Mode
0216 AlbumsProxyModel::mode() const
0217 {
0218     return m_mode;
0219 }
0220 
0221 void
0222 AlbumsProxyModel::setMode( Mode mode )
0223 {
0224     m_mode = mode;
0225 }
0226 
0227 QHash<int, QByteArray>
0228 AlbumsProxyModel::roleNames() const
0229 {
0230     QHash<int, QByteArray> roleNames;
0231 
0232     roleNames.insert( Qt::DisplayRole, "display" );
0233     roleNames.insert( Qt::SizeHintRole, "size" );
0234     roleNames.insert( NameRole, "name" );
0235     roleNames.insert( AlbumCompilationRole, "albumIsCompilation" );
0236     roleNames.insert( AlbumMaxTrackNumberRole, "albumMaxTrackNumber" );
0237     roleNames.insert( AlbumLengthRole, "albumLength" );
0238     roleNames.insert( AlbumYearRole, "albumYear" );
0239     roleNames.insert( AlbumCoverRole, "albumCover" );
0240     roleNames.insert( TrackArtistRole, "trackArtist" );
0241     roleNames.insert( TrackNumberRole, "trackNumber" );
0242     roleNames.insert( TrackLengthRole, "trackLength" );
0243 
0244     return roleNames;
0245 }
0246