File indexing completed on 2024-05-19 04:48:40
0001 /**************************************************************************************** 0002 * Copyright (c) 2009-2010 Bart Cerneels <bart.cerneels@kde.org> * 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 "PlaylistBrowserModel" 0018 0019 #include "PlaylistBrowserModel.h" 0020 0021 #include "AmarokMimeData.h" 0022 #include "playlistmanager/PlaylistManager.h" 0023 #include "playlist/PlaylistController.h" 0024 #include "playlist/PlaylistModel.h" 0025 #include "core/support/Debug.h" 0026 #include "widgets/PrettyTreeRoles.h" 0027 0028 #include <QIcon> 0029 0030 #include <QAction> 0031 0032 #include <algorithm> 0033 0034 using namespace PlaylistBrowserNS; 0035 0036 // to be used with qSort. 0037 static bool 0038 lessThanPlaylistTitles( const Playlists::PlaylistPtr &lhs, const Playlists::PlaylistPtr &rhs ) 0039 { 0040 return lhs->prettyName().toLower() < rhs->prettyName().toLower(); 0041 } 0042 0043 PlaylistBrowserModel::PlaylistBrowserModel( int playlistCategory ) 0044 : m_playlistCategory( playlistCategory ) 0045 { 0046 connect( The::playlistManager(), &PlaylistManager::updated, this, &PlaylistBrowserModel::slotUpdate ); 0047 0048 connect( The::playlistManager(), &PlaylistManager::playlistAdded, 0049 this, &PlaylistBrowserModel::slotPlaylistAdded ); 0050 connect( The::playlistManager(), &PlaylistManager::playlistRemoved, 0051 this, &PlaylistBrowserModel::slotPlaylistRemoved ); 0052 connect( The::playlistManager(), &PlaylistManager::playlistUpdated, 0053 this, &PlaylistBrowserModel::slotPlaylistUpdated ); 0054 0055 connect( The::playlistManager(), &PlaylistManager::renamePlaylist, 0056 this, &PlaylistBrowserModel::slotRenamePlaylist ); 0057 0058 m_playlists = loadPlaylists(); 0059 } 0060 0061 QVariant 0062 PlaylistBrowserModel::data( const QModelIndex &index, int role ) const 0063 { 0064 int row = REMOVE_TRACK_MASK(index.internalId()); 0065 Playlists::PlaylistPtr playlist = m_playlists.value( row ); 0066 0067 QString name; 0068 QIcon icon; 0069 int playlistCount = 0; 0070 QList<QAction *> providerActions; 0071 QList<Playlists::PlaylistProvider *> providers = 0072 The::playlistManager()->getProvidersForPlaylist( playlist ); 0073 Playlists::PlaylistProvider *provider = providers.count() == 1 ? providers.first() : nullptr; 0074 Meta::TrackPtr track; 0075 0076 switch( index.column() ) 0077 { 0078 case PlaylistBrowserModel::PlaylistItemColumn: //playlist or track data 0079 { 0080 if( IS_TRACK(index) ) 0081 { 0082 track = playlist->tracks()[index.row()]; 0083 name = track->prettyName(); 0084 icon = QIcon::fromTheme( QStringLiteral("amarok_track") ); 0085 } 0086 else 0087 { 0088 name = playlist->prettyName(); 0089 icon = QIcon::fromTheme( QStringLiteral("amarok_playlist") ); 0090 } 0091 break; 0092 } 0093 case PlaylistBrowserModel::LabelColumn: //group 0094 { 0095 if( !playlist->groups().isEmpty() ) 0096 { 0097 name = playlist->groups().first(); 0098 icon = QIcon::fromTheme( QStringLiteral("folder") ); 0099 } 0100 break; 0101 } 0102 0103 case PlaylistBrowserModel::ProviderColumn: //source 0104 { 0105 if( providers.count() > 1 ) 0106 { 0107 QVariantList nameData; 0108 QVariantList iconData; 0109 QVariantList playlistCountData; 0110 QVariantList providerActionsData; 0111 foreach( Playlists::PlaylistProvider *provider, providers ) 0112 { 0113 name = provider->prettyName(); 0114 nameData << name; 0115 icon = provider->icon(); 0116 iconData << QVariant( icon ); 0117 playlistCount = provider->playlists().count(); 0118 if( playlistCount >= 0 ) 0119 playlistCountData << i18ncp( 0120 "number of playlists from one source", 0121 "One Playlist", "%1 playlists", 0122 playlistCount ); 0123 else 0124 playlistCountData << i18nc( 0125 "normally number of playlists, but they are still loading", 0126 "Loading..." ); 0127 providerActions << provider->providerActions(); 0128 providerActionsData << QVariant::fromValue( providerActions ); 0129 } 0130 switch( role ) 0131 { 0132 case Qt::DisplayRole: 0133 case Qt::EditRole: 0134 case Qt::ToolTipRole: 0135 return nameData; 0136 case Qt::DecorationRole: 0137 return iconData; 0138 case PrettyTreeRoles::ByLineRole: 0139 return playlistCountData; 0140 case PrettyTreeRoles::DecoratorRoleCount: 0141 return providerActions.count(); 0142 case PrettyTreeRoles::DecoratorRole: 0143 return providerActionsData; 0144 } 0145 } 0146 else if( provider ) 0147 { 0148 name = provider->prettyName(); 0149 icon = provider->icon(); 0150 playlistCount = provider->playlistCount(); 0151 providerActions << provider->providerActions(); 0152 } 0153 0154 break; 0155 } 0156 0157 default: break; 0158 } 0159 0160 0161 switch( role ) 0162 { 0163 case Qt::DisplayRole: 0164 case Qt::EditRole: 0165 case Qt::ToolTipRole: 0166 return name; 0167 case Qt::DecorationRole: 0168 return QVariant( icon ); 0169 case PrettyTreeRoles::ByLineRole: 0170 if( IS_TRACK(index) ) 0171 return QVariant(); 0172 else 0173 return i18ncp( "number of playlists from one source", "One playlist", 0174 "%1 playlists", playlistCount ); 0175 case PlaylistBrowserModel::ProviderRole: 0176 return provider ? QVariant::fromValue( provider ) : QVariant(); 0177 case PlaylistBrowserModel::PlaylistRole: 0178 return playlist ? QVariant::fromValue( playlist ) : QVariant(); 0179 case PlaylistBrowserModel::TrackRole: 0180 return track ? QVariant::fromValue( track ) : QVariant(); 0181 0182 default: 0183 return QVariant(); 0184 } 0185 } 0186 0187 bool 0188 PlaylistBrowserModel::setData( const QModelIndex &idx, const QVariant &value, int role ) 0189 { 0190 0191 if( !idx.isValid() ) 0192 return false; 0193 0194 switch( idx.column() ) 0195 { 0196 case ProviderColumn: 0197 { 0198 if( role == Qt::DisplayRole || role == Qt::EditRole ) 0199 { 0200 Playlists::PlaylistProvider *provider = getProviderByName( value.toString() ); 0201 if( !provider ) 0202 return false; 0203 0204 if( IS_TRACK( idx ) ) 0205 { 0206 Meta::TrackPtr track = trackFromIndex( idx ); 0207 if( !track ) 0208 return false; 0209 debug() << QStringLiteral( "Copy track \"%1\" to \"%2\"." ) 0210 .arg( track->prettyName(), provider->prettyName() ); 0211 // return !provider->addTrack( track ).isNull(); 0212 provider->addTrack( track ); //ignore result since UmsPodcastProvider returns NULL 0213 return true; 0214 } 0215 else 0216 { 0217 Playlists::PlaylistPtr playlist = playlistFromIndex( idx ); 0218 if( !playlist || ( playlist->provider() == provider ) ) 0219 return false; 0220 0221 foreach( Playlists::PlaylistPtr tempPlaylist , provider->playlists() ) 0222 { 0223 if ( tempPlaylist->name() == playlist->name() ) 0224 return false; 0225 } 0226 0227 debug() << QStringLiteral( "Copy playlist \"%1\" to \"%2\"." ) 0228 .arg( playlist->prettyName(), provider->prettyName() ); 0229 0230 return !provider->addPlaylist( playlist ).isNull(); 0231 } 0232 } 0233 0234 //return true even for the data we didn't handle to get QAbstractItemModel::setItemData to work 0235 //TODO: implement setItemData() 0236 return true; 0237 } 0238 case LabelColumn: 0239 { 0240 debug() << "changing group of item " << idx.internalId() << " to " << value.toString(); 0241 Playlists::PlaylistPtr item = m_playlists.value( idx.internalId() ); 0242 item->setGroups( value.toStringList() ); 0243 0244 return true; 0245 } 0246 } 0247 0248 return false; 0249 } 0250 0251 QModelIndex 0252 PlaylistBrowserModel::index( int row, int column, const QModelIndex &parent) const 0253 { 0254 if( !parent.isValid() ) 0255 { 0256 if( row >= 0 && row < m_playlists.count() ) 0257 return createIndex( row, column, row ); 0258 } 0259 else //if it has a parent it is a track 0260 { 0261 //but check if the playlist indeed has that track 0262 Playlists::PlaylistPtr playlist = m_playlists.value( parent.row() ); 0263 if( row < playlist->tracks().count() ) 0264 return createIndex( row, column, SET_TRACK_MASK(parent.row()) ); 0265 } 0266 0267 return QModelIndex(); 0268 } 0269 0270 QModelIndex 0271 PlaylistBrowserModel::parent( const QModelIndex &index ) const 0272 { 0273 if( IS_TRACK(index) ) 0274 { 0275 int row = REMOVE_TRACK_MASK(index.internalId()); 0276 return this->index( row, index.column(), QModelIndex() ); 0277 } 0278 0279 return QModelIndex(); 0280 } 0281 0282 bool 0283 PlaylistBrowserModel::hasChildren( const QModelIndex &parent ) const 0284 { 0285 if( parent.column() > 0 ) 0286 return false; 0287 if( !parent.isValid() ) 0288 { 0289 return !m_playlists.isEmpty(); 0290 } 0291 else if( !IS_TRACK(parent) ) 0292 { 0293 Playlists::PlaylistPtr playlist = m_playlists.value( parent.internalId() ); 0294 return playlist->trackCount() != 0; //-1 might mean there are tracks, but not yet loaded. 0295 } 0296 0297 return false; 0298 } 0299 0300 int 0301 PlaylistBrowserModel::rowCount( const QModelIndex &parent ) const 0302 { 0303 if( parent.column() > 0 ) 0304 return 0; 0305 0306 if( !parent.isValid() ) 0307 { 0308 return m_playlists.count(); 0309 } 0310 else if( !IS_TRACK(parent) ) 0311 { 0312 Playlists::PlaylistPtr playlist = m_playlists.value( parent.internalId() ); 0313 return playlist->trackCount(); 0314 } 0315 0316 return 0; 0317 } 0318 0319 int 0320 PlaylistBrowserModel::columnCount( const QModelIndex &parent ) const 0321 { 0322 if( !parent.isValid() ) //for playlists (children of root) 0323 return 3; //name, group and provider 0324 0325 //for tracks 0326 return 1; //only name 0327 } 0328 0329 bool 0330 PlaylistBrowserModel::canFetchMore( const QModelIndex &parent ) const 0331 { 0332 if( parent.column() > 0 ) 0333 return false; 0334 0335 if( !parent.isValid() ) 0336 { 0337 return false; 0338 } 0339 else if( !IS_TRACK(parent) ) 0340 { 0341 Playlists::PlaylistPtr playlist = m_playlists.value( parent.internalId() ); 0342 //TODO: implement incremental loading of tracks by checking for == 0343 if( playlist->trackCount() != playlist->tracks().count() ) 0344 return true; //tracks still need to be loaded. 0345 } 0346 0347 return false; 0348 } 0349 0350 void 0351 PlaylistBrowserModel::fetchMore ( const QModelIndex &parent ) 0352 { 0353 if( parent.column() > 0 ) 0354 return; 0355 0356 //TODO: load playlists dynamically from provider 0357 if( !parent.isValid() ) 0358 return; 0359 0360 if( !IS_TRACK(parent) ) 0361 { 0362 Playlists::PlaylistPtr playlist = m_playlists.value( parent.internalId() ); 0363 // TODO: following doesn't seem to be needed, PlaylistBrowserModel seems to be able to cope with async track loading fine 0364 playlist->makeLoadingSync(); 0365 playlist->triggerTrackLoad(); 0366 } 0367 } 0368 0369 Qt::ItemFlags 0370 PlaylistBrowserModel::flags( const QModelIndex &idx ) const 0371 { 0372 //Both providers and groups can be empty. QtGroupingProxy makes empty groups from the data in 0373 //the rootnode (here an invalid QModelIndex). 0374 //TODO: editable only if provider is writable. 0375 if( idx.column() == PlaylistBrowserModel::ProviderColumn ) 0376 return Qt::ItemIsEnabled | Qt::ItemIsEditable; 0377 0378 if( idx.column() == PlaylistBrowserModel::LabelColumn ) 0379 return Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsDropEnabled; 0380 0381 if( !idx.isValid() ) 0382 return Qt::ItemIsDropEnabled; 0383 0384 if( IS_TRACK(idx) ) 0385 return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled; 0386 0387 //item is a playlist 0388 return Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | 0389 Qt::ItemIsDropEnabled; 0390 } 0391 0392 QVariant 0393 PlaylistBrowserModel::headerData( int section, Qt::Orientation orientation, int role ) const 0394 { 0395 if( orientation == Qt::Horizontal && role == Qt::DisplayRole ) 0396 { 0397 switch( section ) 0398 { 0399 case PlaylistBrowserModel::PlaylistItemColumn: return i18n("Name"); 0400 case PlaylistBrowserModel::LabelColumn: return i18n("Group"); 0401 case PlaylistBrowserModel::ProviderColumn: return i18n("Source"); 0402 default: return QVariant(); 0403 } 0404 } 0405 0406 return QVariant(); 0407 } 0408 0409 QStringList 0410 PlaylistBrowserModel::mimeTypes() const 0411 { 0412 QStringList ret; 0413 ret << AmarokMimeData::PLAYLIST_MIME; 0414 ret << AmarokMimeData::TRACK_MIME; 0415 return ret; 0416 } 0417 0418 QMimeData* 0419 PlaylistBrowserModel::mimeData( const QModelIndexList &indices ) const 0420 { 0421 AmarokMimeData* mime = new AmarokMimeData(); 0422 0423 Playlists::PlaylistList playlists; 0424 Meta::TrackList tracks; 0425 0426 foreach( const QModelIndex &index, indices ) 0427 { 0428 if( IS_TRACK(index) ) 0429 tracks << trackFromIndex( index ); 0430 else 0431 playlists << m_playlists.value( index.internalId() ); 0432 } 0433 0434 mime->setPlaylists( playlists ); 0435 mime->setTracks( tracks ); 0436 0437 return mime; 0438 } 0439 0440 bool 0441 PlaylistBrowserModel::dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, 0442 const QModelIndex &parent ) 0443 { 0444 DEBUG_BLOCK 0445 debug() << "Dropped on" << parent << "row" << row << "column" << column << "action" << action; 0446 if( action == Qt::IgnoreAction ) 0447 return true; 0448 0449 //drop on track is not possible 0450 if( IS_TRACK(parent) ) 0451 return false; 0452 0453 const AmarokMimeData* amarokMime = dynamic_cast<const AmarokMimeData*>( data ); 0454 if( !amarokMime ) 0455 return false; 0456 0457 if( data->hasFormat( AmarokMimeData::PLAYLIST_MIME ) ) 0458 { 0459 // TODO: is this ever called???? 0460 Playlists::PlaylistList playlists = amarokMime->playlists(); 0461 0462 foreach( Playlists::PlaylistPtr playlist, playlists ) 0463 { 0464 if( !m_playlists.contains( playlist ) ) 0465 debug() << "Unknown playlist dragged in: " << playlist->prettyName(); 0466 } 0467 0468 return true; 0469 } 0470 else if( data->hasFormat( AmarokMimeData::TRACK_MIME ) ) 0471 { 0472 Meta::TrackList tracks = amarokMime->tracks(); 0473 if( !parent.isValid() && row == -1 && column == -1 ) 0474 { 0475 debug() << "Dropped tracks on empty area: create new playlist in a default provider"; 0476 The::playlistManager()->save( tracks, Amarok::generatePlaylistName( tracks ) ); 0477 return true; 0478 } 0479 else if( !parent.isValid() ) 0480 { 0481 warning() << "Dropped tracks between root items, this is not supported!"; 0482 return false; 0483 } 0484 else 0485 { 0486 debug() << "Dropped tracks on " << parent << " at row: " << row; 0487 0488 Playlists::PlaylistPtr playlist = playlistFromIndex( parent ); 0489 if( !playlist ) 0490 return false; 0491 0492 foreach( Meta::TrackPtr track, tracks ) 0493 playlist->addTrack( track, ( row >= 0 ) ? row++ : -1 ); // increment only if positive 0494 0495 return true; 0496 } 0497 } 0498 0499 return false; 0500 } 0501 0502 void 0503 PlaylistBrowserModel::metadataChanged( const Playlists::PlaylistPtr &playlist ) 0504 { 0505 int indexNumber = m_playlists.indexOf( playlist ); 0506 if( indexNumber == -1 ) 0507 { 0508 error() << "This playlist is not in the list of this model."; 0509 return; 0510 } 0511 QModelIndex playlistIdx = index( indexNumber, 0 ); 0512 Q_EMIT dataChanged( playlistIdx, playlistIdx ); 0513 } 0514 0515 void 0516 PlaylistBrowserModel::trackAdded(const Playlists::PlaylistPtr &playlist, const Meta::TrackPtr &track, 0517 int position ) 0518 { 0519 Q_UNUSED( track ); 0520 int indexNumber = m_playlists.indexOf( playlist ); 0521 if( indexNumber == -1 ) 0522 { 0523 error() << "This playlist is not in the list of this model."; 0524 return; 0525 } 0526 QModelIndex playlistIdx = index( indexNumber, 0, QModelIndex() ); 0527 beginInsertRows( playlistIdx, position, position ); 0528 endInsertRows(); 0529 } 0530 0531 void 0532 PlaylistBrowserModel::trackRemoved(const Playlists::PlaylistPtr &playlist, int position ) 0533 { 0534 int indexNumber = m_playlists.indexOf( playlist ); 0535 if( indexNumber == -1 ) 0536 { 0537 error() << "This playlist is not in the list of this model."; 0538 return; 0539 } 0540 QModelIndex playlistIdx = index( indexNumber, 0, QModelIndex() ); 0541 beginRemoveRows( playlistIdx, position, position ); 0542 endRemoveRows(); 0543 } 0544 0545 void 0546 PlaylistBrowserModel::slotRenamePlaylist( Playlists::PlaylistPtr playlist ) 0547 { 0548 if( !playlist->provider() || playlist->provider()->category() != m_playlistCategory ) 0549 return; 0550 0551 int row = 0; 0552 foreach( Playlists::PlaylistPtr p, m_playlists ) 0553 { 0554 if( p == playlist ) 0555 { 0556 Q_EMIT renameIndex( index( row, 0 ) ); 0557 break; 0558 } 0559 row++; 0560 } 0561 } 0562 0563 void 0564 PlaylistBrowserModel::slotUpdate( int category ) 0565 { 0566 if( category != m_playlistCategory ) 0567 return; 0568 0569 beginResetModel(); 0570 0571 foreach( Playlists::PlaylistPtr playlist, m_playlists ) 0572 unsubscribeFrom( playlist ); 0573 0574 m_playlists.clear(); 0575 m_playlists = loadPlaylists(); 0576 0577 endResetModel(); 0578 } 0579 0580 Playlists::PlaylistList 0581 PlaylistBrowserModel::loadPlaylists() 0582 { 0583 Playlists::PlaylistList playlists = 0584 The::playlistManager()->playlistsOfCategory( m_playlistCategory ); 0585 QListIterator<Playlists::PlaylistPtr> i( playlists ); 0586 0587 debug() << playlists.count() << " playlists for category " << m_playlistCategory; 0588 0589 while( i.hasNext() ) 0590 { 0591 Playlists::PlaylistPtr playlist = i.next(); 0592 subscribeTo( playlist ); 0593 } 0594 0595 std::sort( playlists.begin(), playlists.end(), lessThanPlaylistTitles ); 0596 0597 return playlists; 0598 } 0599 0600 void 0601 PlaylistBrowserModel::slotPlaylistAdded( Playlists::PlaylistPtr playlist, int category ) 0602 { 0603 //ignore playlists of a different category 0604 if( category != m_playlistCategory ) 0605 return; 0606 0607 subscribeTo( playlist ); 0608 int i; 0609 for( i = 0; i < m_playlists.count(); i++ ) 0610 { 0611 if( lessThanPlaylistTitles( playlist, m_playlists[i] ) ) 0612 break; 0613 } 0614 0615 beginInsertRows( QModelIndex(), i, i ); 0616 m_playlists.insert( i, playlist ); 0617 endInsertRows(); 0618 } 0619 0620 void 0621 PlaylistBrowserModel::slotPlaylistRemoved( Playlists::PlaylistPtr playlist, int category ) 0622 { 0623 if( category != m_playlistCategory ) 0624 return; 0625 0626 int position = m_playlists.indexOf( playlist ); 0627 if( position == -1 ) 0628 { 0629 error() << "signal received for removed playlist not in m_playlists"; 0630 return; 0631 } 0632 0633 beginRemoveRows( QModelIndex(), position, position ); 0634 m_playlists.removeAt( position ); 0635 endRemoveRows(); 0636 } 0637 0638 void 0639 PlaylistBrowserModel::slotPlaylistUpdated( Playlists::PlaylistPtr playlist, int category ) 0640 { 0641 if( category != m_playlistCategory ) 0642 return; 0643 0644 int position = m_playlists.indexOf( playlist ); 0645 if( position == -1 ) 0646 { 0647 error() << "signal received for updated playlist not in m_playlists"; 0648 return; 0649 } 0650 0651 //TODO: this should work by signaling a change in the model data, but QtGroupingProxy doesn't 0652 //work like that ATM 0653 // const QModelIndex &idx = index( position, 0 ); 0654 // Q_EMIT dataChanged( idx, idx ); 0655 0656 //HACK: remove and readd so QtGroupingProxy can put it in the correct groups. 0657 beginRemoveRows( QModelIndex(), position, position ); 0658 endRemoveRows(); 0659 0660 beginInsertRows( QModelIndex(), position, position ); 0661 endInsertRows(); 0662 } 0663 0664 Meta::TrackList 0665 PlaylistBrowserModel::tracksFromIndexes( const QModelIndexList &list ) const 0666 { 0667 Meta::TrackList tracks; 0668 foreach( const QModelIndex &index, list ) 0669 { 0670 if( IS_TRACK(index) ) 0671 tracks << trackFromIndex( index ); 0672 else if( Playlists::PlaylistPtr playlist = playlistFromIndex( index ) ) 0673 { 0674 playlist->makeLoadingSync(); 0675 //first trigger a load of the tracks or we'll end up with an empty list 0676 playlist->triggerTrackLoad(); 0677 tracks << playlist->tracks(); 0678 } 0679 } 0680 return tracks; 0681 } 0682 0683 Meta::TrackPtr 0684 PlaylistBrowserModel::trackFromIndex( const QModelIndex &idx ) const 0685 { 0686 if( !idx.isValid() || !IS_TRACK(idx) ) 0687 return Meta::TrackPtr(); 0688 0689 int playlistRow = REMOVE_TRACK_MASK(idx.internalId()); 0690 if( playlistRow >= m_playlists.count() ) 0691 return Meta::TrackPtr(); 0692 0693 Playlists::PlaylistPtr playlist = m_playlists.value( playlistRow ); 0694 if( playlist.isNull() || playlist->tracks().count() <= idx.row() ) 0695 return Meta::TrackPtr(); 0696 0697 return playlist->tracks()[idx.row()]; 0698 } 0699 0700 Playlists::PlaylistPtr 0701 PlaylistBrowserModel::playlistFromIndex( const QModelIndex &index ) const 0702 { 0703 if( !index.isValid() ) 0704 return Playlists::PlaylistPtr(); 0705 0706 return m_playlists.value( index.internalId() ); 0707 } 0708 0709 Playlists::PlaylistProvider * 0710 PlaylistBrowserModel::providerForIndex( const QModelIndex &idx ) const 0711 { 0712 if( !idx.isValid() ) 0713 return nullptr; 0714 0715 int playlistRow; 0716 if( IS_TRACK( idx ) ) 0717 playlistRow = REMOVE_TRACK_MASK( idx.internalId() ); 0718 else 0719 playlistRow = idx.row(); 0720 0721 if( playlistRow >= m_playlists.count() ) 0722 return nullptr; 0723 0724 return m_playlists.at( playlistRow )->provider(); 0725 } 0726 0727 Playlists::PlaylistProvider * 0728 PlaylistBrowserModel::getProviderByName( const QString &name ) 0729 { 0730 QList<Playlists::PlaylistProvider *> providers = 0731 The::playlistManager()->providersForCategory( m_playlistCategory ); 0732 foreach( Playlists::PlaylistProvider *provider, providers ) 0733 { 0734 if( provider->prettyName() == name ) 0735 return provider; 0736 } 0737 return nullptr; 0738 }