File indexing completed on 2024-05-19 04:48:40
0001 /**************************************************************************************** 0002 * Copyright (c) 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 #include "PlaylistsByProviderProxy.h" 0018 0019 #include "AmarokMimeData.h" 0020 #include "PlaylistBrowserModel.h" 0021 0022 #include "core/playlists/PlaylistProvider.h" 0023 #include "core/support/Debug.h" 0024 #include "playlistmanager/PlaylistManager.h" 0025 #include "widgets/PrettyTreeRoles.h" 0026 0027 #include <QIcon> 0028 0029 #include <QStack> 0030 0031 PlaylistsByProviderProxy::PlaylistsByProviderProxy( int playlistCategory, QObject *parent ) 0032 : QtGroupingProxy( parent ) 0033 , m_playlistCategory( playlistCategory ) 0034 { 0035 // we need this to track providers with no playlists 0036 connect( The::playlistManager(), &PlaylistManager::providerAdded, 0037 this, &PlaylistsByProviderProxy::slotProviderAdded ); 0038 connect( The::playlistManager(), &PlaylistManager::providerRemoved, 0039 this, &PlaylistsByProviderProxy::slotProviderRemoved ); 0040 } 0041 0042 //TODO: remove this constructor 0043 PlaylistsByProviderProxy::PlaylistsByProviderProxy( QAbstractItemModel *model, int column, int playlistCategory ) 0044 : QtGroupingProxy( model, QModelIndex(), column ) 0045 , m_playlistCategory( playlistCategory ) 0046 { 0047 setSourceModel( model ); 0048 0049 // we need this to track providers with no playlists 0050 connect( The::playlistManager(), &PlaylistManager::providerAdded, 0051 this, &PlaylistsByProviderProxy::slotProviderAdded ); 0052 connect( The::playlistManager(), &PlaylistManager::providerRemoved, 0053 this, &PlaylistsByProviderProxy::slotProviderRemoved ); 0054 } 0055 0056 QVariant 0057 PlaylistsByProviderProxy::data( const QModelIndex &idx, int role ) const 0058 { 0059 //TODO: actions for empty providers 0060 0061 //TODO: filter out actions not from the provider, possibly using QAction separators marking 0062 // the source of the actions (makes sense in the UI as well. 0063 0064 //Turn the QVariantList of the source into a comma separated string, but only for the real items 0065 if( !isGroup( idx ) && idx.column() == PlaylistBrowserNS::PlaylistBrowserModel::ProviderColumn 0066 && role == Qt::DisplayRole ) 0067 { 0068 QVariant indexData = QtGroupingProxy::data( idx, role ); 0069 if( indexData.type() != QVariant::List ) 0070 return indexData; 0071 0072 QString providerString = indexData.toStringList().join( QStringLiteral(", ") ); 0073 return QVariant( providerString ); 0074 } 0075 0076 return QtGroupingProxy::data( idx, role ); 0077 } 0078 0079 Qt::ItemFlags 0080 PlaylistsByProviderProxy::flags( const QModelIndex &idx ) const 0081 { 0082 //TODO: check if provider supports addPlaylist for DropEnabled 0083 if( isGroup( idx ) ) 0084 return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDropEnabled; 0085 0086 return QtGroupingProxy::flags( idx ); 0087 } 0088 0089 bool 0090 PlaylistsByProviderProxy::removeRows( int row, int count, const QModelIndex &parent ) 0091 { 0092 DEBUG_BLOCK 0093 bool result; 0094 debug() << "in parent " << parent << "remove " << count << " starting at row " << row; 0095 QModelIndex originalIdx = mapToSource( parent ); 0096 result = sourceModel()->removeRows( row, count, originalIdx ); 0097 if( result ) 0098 { 0099 beginRemoveRows( parent, row, row + count - 1 ); 0100 endRemoveRows(); 0101 } 0102 return result; 0103 } 0104 0105 //TODO: move the next 3 implementation to QtGroupingProxy 0106 QStringList 0107 PlaylistsByProviderProxy::mimeTypes() const 0108 { 0109 //nothing to add 0110 return sourceModel()->mimeTypes(); 0111 } 0112 0113 QMimeData * 0114 PlaylistsByProviderProxy::mimeData( const QModelIndexList &indexes ) const 0115 { 0116 DEBUG_BLOCK 0117 QModelIndexList sourceIndexes; 0118 foreach( const QModelIndex &idx, indexes ) 0119 { 0120 if( isGroup( idx ) ) 0121 continue; // drags not enabled for playlist providers 0122 QModelIndex originalIdx = mapToSource( idx ); 0123 if( originalIdx.isValid() ) 0124 sourceIndexes << originalIdx; 0125 } 0126 0127 if( sourceIndexes.isEmpty() ) 0128 return nullptr; 0129 return sourceModel()->mimeData( sourceIndexes ); 0130 } 0131 0132 bool 0133 PlaylistsByProviderProxy::dropMimeData( const QMimeData *data, Qt::DropAction action, 0134 int row, int column, const QModelIndex &parent ) 0135 { 0136 DEBUG_BLOCK 0137 debug() << "Dropped on" << parent << "row" << row << "column" << column << "action" << action; 0138 if( action == Qt::IgnoreAction ) 0139 return true; 0140 0141 if( !isGroup( parent ) ) // drops on empty space fall here, it is okay 0142 { 0143 QModelIndex sourceIndex = mapToSource( parent ); 0144 return sourceModel()->dropMimeData( data, action, row, column, sourceIndex ); 0145 } 0146 0147 const AmarokMimeData *amarokData = dynamic_cast<const AmarokMimeData *>( data ); 0148 if( !amarokData ) 0149 { 0150 debug() << __PRETTY_FUNCTION__ << "supports only drag & drop originating in Amarok."; 0151 return false; 0152 } 0153 0154 Playlists::PlaylistProvider *provider = 0155 parent.data( PlaylistBrowserNS::PlaylistBrowserModel::ProviderRole ) 0156 .value<Playlists::PlaylistProvider *>(); 0157 if( !provider ) 0158 { 0159 warning() << "Dropped tracks to a group with no (or multiple) providers!"; 0160 return false; 0161 } 0162 0163 if( amarokData->hasFormat( AmarokMimeData::PLAYLIST_MIME ) ) 0164 { 0165 debug() << "Dropped playlists to provider" << provider->prettyName(); 0166 foreach( Playlists::PlaylistPtr pl, amarokData->playlists() ) 0167 { 0168 // few PlaylistProviders implement addPlaylist(), use save() instead: 0169 The::playlistManager()->save( pl->tracks(), pl->name(), provider, false /* editName */ ); 0170 } 0171 return true; 0172 } 0173 if( amarokData->hasFormat( AmarokMimeData::TRACK_MIME ) ) 0174 { 0175 debug() << "Dropped tracks to provider" << provider->prettyName(); 0176 Meta::TrackList tracks = amarokData->tracks(); 0177 QString playlistName = Amarok::generatePlaylistName( tracks ); 0178 return The::playlistManager()->save( tracks, playlistName, provider ); 0179 } 0180 0181 debug() << __PRETTY_FUNCTION__ << "Unsupported drop mime-data:" << data->formats(); 0182 return false; 0183 } 0184 0185 Qt::DropActions 0186 PlaylistsByProviderProxy::supportedDropActions() const 0187 { 0188 //always add CopyAction because playlists can copied to a Provider 0189 return sourceModel()->supportedDropActions() | Qt::CopyAction; 0190 } 0191 0192 Qt::DropActions 0193 PlaylistsByProviderProxy::supportedDragActions() const 0194 { 0195 //always add CopyAction because playlists can be put into a different group 0196 return sourceModel()->supportedDragActions() | Qt::CopyAction; 0197 } 0198 0199 void 0200 PlaylistsByProviderProxy::setSourceModel( QAbstractItemModel *model ) 0201 { 0202 if( sourceModel() ) 0203 sourceModel()->disconnect(); 0204 0205 QtGroupingProxy::setSourceModel( model ); 0206 0207 connect( sourceModel(), SIGNAL(renameIndex(QModelIndex)), 0208 SLOT(slotRenameIndex(QModelIndex)) ); 0209 } 0210 0211 void 0212 PlaylistsByProviderProxy::buildTree() 0213 { 0214 //clear that data anyway since provider can disappear and should no longer be listed. 0215 m_groupMaps.clear(); 0216 0217 //add the empty providers at the top of the list 0218 PlaylistProviderList providerList = 0219 The::playlistManager()->providersForCategory( m_playlistCategory ); 0220 0221 foreach( Playlists::PlaylistProvider *provider, providerList ) 0222 { 0223 slotProviderAdded( provider, provider->category() ); 0224 } 0225 0226 QtGroupingProxy::buildTree(); 0227 } 0228 0229 void 0230 PlaylistsByProviderProxy::slotRenameIndex( const QModelIndex &sourceIdx ) 0231 { 0232 QModelIndex idx = mapFromSource( sourceIdx ); 0233 if( idx.isValid() ) 0234 Q_EMIT renameIndex( idx ); 0235 } 0236 0237 void 0238 PlaylistsByProviderProxy::slotProviderAdded( Playlists::PlaylistProvider *provider, int category ) 0239 { 0240 DEBUG_BLOCK 0241 if( category != m_playlistCategory ) 0242 return; 0243 0244 if( provider->playlistCount() > 0 0245 || ( provider->playlistCount() < 0 /* not counted */ 0246 && !provider->playlists().isEmpty() ) ) 0247 return; // non-empty providers are handled by PlaylistBrowserModel 0248 0249 ItemData itemData; 0250 itemData.insert( Qt::DisplayRole, provider->prettyName() ); 0251 itemData.insert( Qt::DecorationRole, provider->icon() ); 0252 itemData.insert( PrettyTreeRoles::DecoratorRole, QVariant::fromValue( provider->providerActions() ) ); 0253 itemData.insert( PrettyTreeRoles::DecoratorRoleCount, provider->providerActions().count() ); 0254 0255 itemData.insert( PlaylistBrowserNS::PlaylistBrowserModel::ProviderRole, 0256 QVariant::fromValue<Playlists::PlaylistProvider*>( provider ) ); 0257 RowData rowData; 0258 rowData.insert( PlaylistBrowserNS::PlaylistBrowserModel::PlaylistItemColumn, itemData ); 0259 //Provider column is used for filtering. 0260 rowData.insert( PlaylistBrowserNS::PlaylistBrowserModel::ProviderColumn, itemData ); 0261 0262 addEmptyGroup( rowData ); 0263 } 0264 0265 void 0266 PlaylistsByProviderProxy::slotProviderRemoved( Playlists::PlaylistProvider *provider, int category ) 0267 { 0268 DEBUG_BLOCK 0269 if( category != m_playlistCategory ) 0270 return; 0271 0272 for( int i = 0; i < rowCount(); i++ ) 0273 { 0274 QModelIndex idx = index( i, PlaylistBrowserNS::PlaylistBrowserModel::PlaylistItemColumn ); 0275 Playlists::PlaylistProvider *rowProvider = data( idx, PlaylistBrowserNS::PlaylistBrowserModel::ProviderRole ) 0276 .value<Playlists::PlaylistProvider *>(); 0277 if( rowProvider != provider ) 0278 continue; 0279 0280 removeGroup( idx ); 0281 } 0282 }