File indexing completed on 2024-04-28 04:50:21

0001 /*
0002     SPDX-FileCopyrightText: 2011 Michal Malek <michalm@jabster.pl>
0003     SPDX-FileCopyrightText: 1998-2008 Sebastian Trueg <trueg@k3b.org>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #include "k3baudiotrackmodel.h"
0009 #include "k3baudiocdtrackdrag.h"
0010 
0011 #include "k3bmedium.h"
0012 #include "k3bcdtext.h"
0013 
0014 #include <KLocalizedString>
0015 
0016 #include <KCDDB/CDInfo>
0017 
0018 #include <QMimeData>
0019 #include <QFont>
0020 
0021 Q_DECLARE_METATYPE( K3b::Medium )
0022 Q_DECLARE_METATYPE( K3b::Msf )
0023 
0024 
0025 class K3b::AudioTrackModel::Private
0026 {
0027 public:
0028     K3b::Medium medium;
0029     KCDDB::CDInfo cddbCache;
0030 
0031     QVector<bool> itemCheckedList;
0032 
0033     QString getField( KCDDB::Type field ) const;
0034     QString getField( KCDDB::Type field, int trackIndex ) const;
0035 };
0036 
0037 
0038 QString K3b::AudioTrackModel::Private::getField( KCDDB::Type field ) const
0039 {
0040     QString s = cddbCache.get( field ).toString();
0041     if ( s.isEmpty() ) {
0042         s = medium.cddbInfo().get( field ).toString();
0043     }
0044     if ( s.isEmpty() ) {
0045         switch( field ) {
0046         case KCDDB::Title:
0047             s = medium.cdText().title();
0048             break;
0049         case KCDDB::Artist:
0050             s = medium.cdText().performer();
0051             break;
0052         case KCDDB::Comment:
0053             s = medium.cdText().message();
0054             break;
0055         default:
0056             break;
0057         }
0058     }
0059 
0060     return s;
0061 }
0062 
0063 
0064 QString K3b::AudioTrackModel::Private::getField( KCDDB::Type field, int trackIndex ) const
0065 {
0066     QString s = cddbCache.track( trackIndex ).get( field ).toString();
0067     if ( s.isEmpty() ) {
0068         s = medium.cddbInfo().track( trackIndex ).get( field ).toString();
0069     }
0070     if ( s.isEmpty() ) {
0071         switch( field ) {
0072         case KCDDB::Title:
0073             s = medium.cdText().track( trackIndex ).title();
0074             break;
0075         case KCDDB::Artist:
0076             s = medium.cdText().track( trackIndex ).performer();
0077             break;
0078         case KCDDB::Comment:
0079             s = medium.cdText().track( trackIndex ).message();
0080             break;
0081         default:
0082             break;
0083         }
0084     }
0085 
0086     return s;
0087 }
0088 
0089 
0090 
0091 K3b::AudioTrackModel::AudioTrackModel( QObject* parent )
0092     : QAbstractItemModel( parent ),
0093       d( new Private() )
0094 {
0095 }
0096 
0097 
0098 K3b::AudioTrackModel::~AudioTrackModel()
0099 {
0100     delete d;
0101 }
0102 
0103 
0104 void K3b::AudioTrackModel::setMedium( const K3b::Medium& medium )
0105 {
0106     beginResetModel();
0107     d->medium = medium;
0108     d->itemCheckedList.resize( d->medium.toc().count() );
0109     for ( int i = 0; i < d->medium.toc().count(); ++i ) {
0110         if( d->medium.toc()[i].type() == K3b::Device::Track::TYPE_AUDIO )
0111             d->itemCheckedList[i] = true;
0112         else
0113             d->itemCheckedList[i] = false;
0114     }
0115     endResetModel();
0116 }
0117 
0118 
0119 void K3b::AudioTrackModel::setCddbInfo( const KCDDB::CDInfo& data )
0120 {
0121     beginResetModel();
0122     d->cddbCache = data;
0123     endResetModel();
0124 }
0125 
0126 
0127 KCDDB::CDInfo K3b::AudioTrackModel::cddbInfo() const
0128 {
0129     return d->cddbCache;
0130 }
0131 
0132 
0133 K3b::Medium K3b::AudioTrackModel::medium() const
0134 {
0135     return d->medium;
0136 }
0137 
0138 
0139 int K3b::AudioTrackModel::columnCount( const QModelIndex& parent ) const
0140 {
0141     Q_UNUSED( parent );
0142     return NumColumns;
0143 }
0144 
0145 
0146 QVariant K3b::AudioTrackModel::headerData( int section, Qt::Orientation orientation, int role ) const
0147 {
0148     Q_UNUSED( orientation );
0149 
0150     if ( role == Qt::DisplayRole ) {
0151         switch( section ) {
0152         case TrackNumberColumn:
0153             return i18nc( "audio track number", "No." );
0154         case ArtistColumn:
0155             return i18n( "Artist" );
0156         case TitleColumn:
0157             return i18nc( "audio track title", "Title" );
0158         case LengthColumn:
0159             return i18n( "Length" );
0160         }
0161     }
0162 
0163     return QVariant();
0164 }
0165 
0166 
0167 QVariant K3b::AudioTrackModel::data( const QModelIndex& index, int role ) const
0168 {
0169 //    qDebug() << index << role;
0170 
0171     // FIXME: add a cache for all the values that can be changed (maybe a local KCDDB::CDInfo)
0172     // which will then be the first choice for all values
0173 
0174     int trackIndex = index.row();
0175 
0176     switch( role ) {
0177     case MediumRole:
0178         return QVariant::fromValue( d->medium );
0179 
0180     case TrackNumberRole:
0181         return trackIndex+1;
0182 
0183     case ArtistRole:
0184         return d->getField( KCDDB::Artist, trackIndex );
0185 
0186     case TitleRole:
0187         return d->getField( KCDDB::Title, trackIndex );
0188 
0189     case CommentRole:
0190         return d->getField( KCDDB::Comment, trackIndex );
0191 
0192     case LengthRole:
0193         return QVariant::fromValue( d->medium.toc()[trackIndex].length() );
0194 
0195     case Qt::DisplayRole:
0196     case Qt::EditRole:
0197         switch( index.column() ) {
0198         case TrackNumberColumn:
0199             return trackIndex+1;
0200         case ArtistColumn:
0201             return d->getField( KCDDB::Artist, trackIndex );
0202         case TitleColumn:
0203         {
0204             if( d->medium.toc()[trackIndex].type() == Device::Track::TYPE_DATA )
0205                 return i18n( "Data Track" );
0206             else
0207                 return d->getField( KCDDB::Title, trackIndex );
0208         }
0209         case LengthColumn:
0210             return d->medium.toc()[trackIndex].length().toString();
0211         }
0212         break;
0213 
0214     case Qt::CheckStateRole:
0215         if ( index.column() == TrackNumberColumn ) {
0216             return trackChecked( trackIndex ) ? Qt::Checked : Qt::Unchecked;
0217         }
0218         break;
0219 
0220     case Qt::TextAlignmentRole:
0221         if ( index.column() == LengthColumn ) {
0222             return Qt::AlignHCenter;
0223         }
0224         break;
0225         
0226     case Qt::FontRole:
0227         if( d->medium.toc()[trackIndex].type() == Device::Track::TYPE_DATA )
0228         {
0229             QFont font;
0230             font.setItalic( true );
0231             return font;
0232         }
0233     }
0234 
0235     return QVariant();
0236 }
0237 
0238 
0239 Qt::ItemFlags K3b::AudioTrackModel::flags( const QModelIndex& index ) const
0240 {
0241     Qt::ItemFlags f = Qt::ItemFlags();
0242 
0243     if ( index.isValid() && index.row() >= 0 && index.row() < d->medium.toc().count() &&
0244          d->medium.toc()[index.row()].type() == K3b::Device::Track::TYPE_AUDIO ) {
0245 
0246         f |= Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable;
0247 
0248         switch( index.column() ) {
0249         case ArtistColumn:
0250         case TitleColumn:
0251             f |= Qt::ItemIsEditable;
0252             break;
0253         }
0254     }
0255 
0256     return f;
0257 }
0258 
0259 
0260 QModelIndex K3b::AudioTrackModel::index( int row, int column, const QModelIndex& parent ) const
0261 {
0262     if ( !parent.isValid() &&
0263          row < d->medium.toc().count() &&
0264          column < NumColumns ) {
0265         return createIndex( row, column );
0266     }
0267     else {
0268         return QModelIndex();
0269     }
0270 }
0271 
0272 
0273 QModelIndex K3b::AudioTrackModel::parent( const QModelIndex& ) const
0274 {
0275     return QModelIndex();
0276 }
0277 
0278 
0279 int K3b::AudioTrackModel::rowCount( const QModelIndex& parent ) const
0280 {
0281     if ( !parent.isValid() ) {
0282         // FIXME: only use audio tracks
0283         return d->medium.toc().count();
0284     }
0285     else {
0286         return 0;
0287     }
0288 }
0289 
0290 
0291 void K3b::AudioTrackModel::setTrackChecked( int track, bool checked )
0292 {
0293     if ( track >= 0 && track < d->itemCheckedList.count() ) {
0294         d->itemCheckedList[track] = checked;
0295         emit dataChanged( index( track, TrackNumberColumn ), index( track, TrackNumberColumn ) );
0296     }
0297 }
0298 
0299 
0300 bool K3b::AudioTrackModel::trackChecked( int trackIndex ) const
0301 {
0302     if ( trackIndex >= 0 &&
0303          trackIndex < d->medium.toc().count() ) {
0304         return d->itemCheckedList[trackIndex];
0305     }
0306     else {
0307         return false;
0308     }
0309 }
0310 
0311 
0312 QList<int> K3b::AudioTrackModel::checkedTrackIndices() const
0313 {
0314     QList<int> l;
0315     for ( int i = 0; i < d->itemCheckedList.count(); ++i ) {
0316         if ( d->itemCheckedList[i] ) {
0317             l.append( i );
0318         }
0319     }
0320     return l;
0321 }
0322 
0323 
0324 bool K3b::AudioTrackModel::setData( const QModelIndex& index, const QVariant& value, int role )
0325 {
0326     if ( index.isValid() ) {
0327         switch ( role ) {
0328         case Qt::EditRole:
0329             switch( index.column() ) {
0330             case ArtistColumn:
0331                 d->cddbCache.track( index.row() ).set( KCDDB::Artist, value );
0332                 emit dataChanged( index, index );
0333                 return true;
0334 
0335             case TitleColumn:
0336                 d->cddbCache.track( index.row() ).set( KCDDB::Title, value );
0337                 emit dataChanged( index, index );
0338                 return true;
0339             }
0340             break;
0341 
0342         case Qt::CheckStateRole:
0343             setTrackChecked( index.row(), value.toInt() == Qt::Checked );
0344             return true;
0345 
0346         case ArtistRole:
0347             d->cddbCache.track( index.row() ).set( KCDDB::Artist, value );
0348             emit dataChanged( index, index );
0349             return true;
0350 
0351         case TitleRole:
0352             d->cddbCache.track( index.row() ).set( KCDDB::Title, value );
0353             emit dataChanged( index, index );
0354             return true;
0355 
0356         case CommentRole:
0357             d->cddbCache.track( index.row() ).set( KCDDB::Comment, value );
0358             emit dataChanged( index, index );
0359             return true;
0360         }
0361     }
0362 
0363     return false;
0364 }
0365 
0366 
0367 QStringList K3b::AudioTrackModel::mimeTypes() const
0368 {
0369     return AudioCdTrackDrag::mimeDataTypes();
0370 }
0371 
0372 
0373 QMimeData* K3b::AudioTrackModel::mimeData( const QModelIndexList& indexes ) const
0374 {
0375     // FIXME: Add QDataStream operators to K3b::Medium and encode a complete K3b::Medium in
0376     // the mimedata including the modified cddb. This way, ejecting the medium during the
0377     // d'n'd is not a problem
0378     QList<int> trackNumbers;
0379     foreach( const QModelIndex& index, indexes ) {
0380         if ( index.column() == TrackNumberColumn )
0381             trackNumbers << index.data( TrackNumberColumn ).toInt();
0382     }
0383     AudioCdTrackDrag drag( d->medium.toc(), trackNumbers, d->cddbCache, d->medium.device() );
0384     QMimeData* mime = new QMimeData();
0385     drag.populateMimeData( mime );
0386     return mime;
0387 }
0388 
0389 
0390 void K3b::AudioTrackModel::checkAll()
0391 {
0392     for ( int i = 0; i < d->medium.toc().count(); ++i ) {
0393         d->itemCheckedList[i] = true;
0394     }
0395     emit dataChanged( index( 0, TrackNumberColumn ), index( d->itemCheckedList.count(), TrackNumberColumn ) );
0396 }
0397 
0398 
0399 void K3b::AudioTrackModel::uncheckAll()
0400 {
0401     for ( int i = 0; i < d->medium.toc().count(); ++i ) {
0402         d->itemCheckedList[i] = false;
0403     }
0404     emit dataChanged( index( 0, TrackNumberColumn ), index( d->itemCheckedList.count(), TrackNumberColumn ) );
0405 }
0406 
0407 #include "moc_k3baudiotrackmodel.cpp"