Warning, file /multimedia/amarok/src/browsers/CollectionTreeItemModel.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /**************************************************************************************** 0002 * Copyright (c) 2007 Alexandre Pereira de Oliveira <aleprj@gmail.com> * 0003 * Copyright (c) 2007-2009 Maximilian Kossick <maximilian.kossick@googlemail.com> * 0004 * Copyright (c) 2007 Nikolaj Hald Nielsen <nhn@kde.org> * 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 #define DEBUG_PREFIX "CollectionTreeItemModel" 0020 0021 #include "CollectionTreeItemModel.h" 0022 0023 #include <amarokconfig.h> 0024 #include "AmarokMimeData.h" 0025 #include "CollectionTreeItem.h" 0026 #include "core/support/Debug.h" 0027 #include "core/support/Amarok.h" 0028 #include "core/collections/Collection.h" 0029 #include "core/collections/CollectionLocation.h" 0030 #include "core/collections/QueryMaker.h" 0031 #include "core/meta/Meta.h" 0032 #include "core-impl/collections/support/CollectionManager.h" 0033 #include "core-impl/collections/support/FileCollectionLocation.h" 0034 0035 #include <KLocalizedString> 0036 0037 #include <QTimer> 0038 #include <QMap> 0039 0040 CollectionTreeItemModel::CollectionTreeItemModel( const QList<CategoryId::CatMenuId> &levelType ) 0041 : CollectionTreeItemModelBase() 0042 { 0043 m_rootItem = new CollectionTreeItem( this ); 0044 CollectionManager *collMgr = CollectionManager::instance(); 0045 connect( collMgr, &CollectionManager::collectionAdded, this, &CollectionTreeItemModel::collectionAdded, Qt::QueuedConnection ); 0046 connect( collMgr, &CollectionManager::collectionRemoved, this, &CollectionTreeItemModel::collectionRemoved ); 0047 0048 QList<Collections::Collection *> collections = CollectionManager::instance()->viewableCollections(); 0049 foreach( Collections::Collection *coll, collections ) 0050 { 0051 connect( coll, &Collections::Collection::updated, this, &CollectionTreeItemModel::slotFilterWithoutAutoExpand ); 0052 m_collections.insert( coll->collectionId(), CollectionRoot( coll, new CollectionTreeItem( coll, m_rootItem, this ) ) ); 0053 } 0054 0055 setLevels( levelType ); 0056 } 0057 0058 Qt::ItemFlags 0059 CollectionTreeItemModel::flags( const QModelIndex &idx ) const 0060 { 0061 if( !idx.isValid() ) 0062 return {}; 0063 0064 Qt::ItemFlags flags = CollectionTreeItemModelBase::flags( idx ); 0065 if( idx.parent().isValid() ) 0066 return flags; // has parent -> not a collection -> no drops 0067 0068 // we depend on someone (probably CollectionTreeView) to call 0069 // CollectionTreeItemModelBase::setDragSourceCollections() every time a drag is 0070 // initiated or enters collection browser widget 0071 CollectionTreeItem *item = static_cast<CollectionTreeItem*>( idx.internalPointer() ); 0072 Q_ASSERT(item->type() == CollectionTreeItem::Collection); 0073 if( m_dragSourceCollections.contains( item->parentCollection() ) ) 0074 return flags; // attempt to drag tracks from the same collection, don't allow this (bug 291068) 0075 0076 if( !item->parentCollection()->isWritable() ) 0077 return flags; // not writeable, disallow drops 0078 0079 // all paranoid checks passed, tracks can be dropped to this item 0080 return flags | Qt::ItemIsDropEnabled; 0081 } 0082 0083 QVariant 0084 CollectionTreeItemModel::data(const QModelIndex &index, int role) const 0085 { 0086 if (!index.isValid()) 0087 return QVariant(); 0088 0089 CollectionTreeItem *item = static_cast<CollectionTreeItem*>(index.internalPointer()); 0090 // subtract one here because there is a collection level for this model 0091 return dataForItem( item, role, item->level() - 1 ); 0092 } 0093 0094 bool 0095 CollectionTreeItemModel::dropMimeData( const QMimeData *data, Qt::DropAction action, 0096 int row, int column, const QModelIndex &parent ) 0097 { 0098 Q_UNUSED(row) 0099 Q_UNUSED(column) 0100 //no drops on empty areas 0101 if( !parent.isValid() ) 0102 return false; 0103 0104 CollectionTreeItem *item = static_cast<CollectionTreeItem*>( parent.internalPointer() ); 0105 Q_ASSERT(item->type() == CollectionTreeItem::Collection); 0106 0107 Collections::Collection *targetCollection = item->parentCollection(); 0108 Q_ASSERT(targetCollection); 0109 0110 //TODO: accept external drops. 0111 const AmarokMimeData *mimeData = qobject_cast<const AmarokMimeData *>( data ); 0112 Q_ASSERT(mimeData); 0113 0114 //TODO: optimize for copy from same provider. 0115 Meta::TrackList tracks = mimeData->tracks(); 0116 QMultiMap<Collections::Collection *, Meta::TrackPtr> collectionTrackMap; 0117 0118 foreach( Meta::TrackPtr track, tracks ) 0119 { 0120 Collections::Collection *sourceCollection = track->collection(); 0121 collectionTrackMap.insertMulti( sourceCollection, track ); 0122 } 0123 0124 foreach( Collections::Collection *sourceCollection, collectionTrackMap.uniqueKeys() ) 0125 { 0126 if( sourceCollection == targetCollection ) 0127 continue; // should be already caught by ...Model::flags(), but hey 0128 0129 Collections::CollectionLocation *sourceLocation; 0130 if( sourceCollection ) 0131 { 0132 sourceLocation = sourceCollection->location(); 0133 Q_ASSERT(sourceLocation); 0134 } 0135 else 0136 { 0137 sourceLocation = new Collections::FileCollectionLocation(); 0138 } 0139 0140 // we need to create target collection location per each source collection location 0141 // -- prepareSomething() takes ownership of the pointer. 0142 Collections::CollectionLocation *targetLocation = targetCollection->location(); 0143 Q_ASSERT(targetLocation); 0144 0145 if( action == Qt::CopyAction ) 0146 { 0147 sourceLocation->prepareCopy( collectionTrackMap.values( sourceCollection ), 0148 targetLocation ); 0149 } 0150 else if( action == Qt::MoveAction ) 0151 { 0152 sourceLocation->prepareMove( collectionTrackMap.values( sourceCollection ), 0153 targetLocation ); 0154 } 0155 } 0156 return true; 0157 } 0158 0159 0160 bool 0161 CollectionTreeItemModel::canFetchMore( const QModelIndex &parent ) const 0162 { 0163 if ( !parent.isValid() ) 0164 return false; //children of the root item are the collections, and they are always known 0165 0166 CollectionTreeItem *item = static_cast<CollectionTreeItem*>( parent.internalPointer() ); 0167 return item->level() <= m_levelType.count() && item->requiresUpdate(); 0168 } 0169 0170 void 0171 CollectionTreeItemModel::fetchMore( const QModelIndex &parent ) 0172 { 0173 if ( !parent.isValid() ) 0174 return; 0175 0176 CollectionTreeItem *item = static_cast<CollectionTreeItem*>( parent.internalPointer() ); 0177 ensureChildrenLoaded( item ); 0178 } 0179 0180 Qt::DropActions 0181 CollectionTreeItemModel::supportedDropActions() const 0182 { 0183 // this also causes supportedDragActions() to contain move action 0184 return CollectionTreeItemModelBase::supportedDropActions() | Qt::MoveAction; 0185 } 0186 0187 void 0188 CollectionTreeItemModel::collectionAdded( Collections::Collection *newCollection ) 0189 { 0190 if( !newCollection ) 0191 return; 0192 0193 connect( newCollection, &Collections::Collection::updated, this, &CollectionTreeItemModel::slotFilterWithoutAutoExpand ) ; 0194 0195 QString collectionId = newCollection->collectionId(); 0196 if( m_collections.contains( collectionId ) ) 0197 return; 0198 0199 //inserts new collection at the end. 0200 beginInsertRows( QModelIndex(), m_rootItem->childCount(), m_rootItem->childCount() ); 0201 m_collections.insert( collectionId, CollectionRoot( newCollection, new CollectionTreeItem( newCollection, m_rootItem, this ) ) ); 0202 endInsertRows(); 0203 0204 if( m_collections.count() == 1 ) 0205 QTimer::singleShot( 0, this, &CollectionTreeItemModel::requestCollectionsExpansion ); 0206 } 0207 0208 void 0209 CollectionTreeItemModel::collectionRemoved( const QString &collectionId ) 0210 { 0211 int count = m_rootItem->childCount(); 0212 for( int i = 0; i < count; i++ ) 0213 { 0214 CollectionTreeItem *item = m_rootItem->child( i ); 0215 if( item && !item->isDataItem() && item->parentCollection()->collectionId() == collectionId ) 0216 { 0217 beginRemoveRows( QModelIndex(), i, i ); 0218 m_rootItem->removeChild( i ); 0219 m_collections.remove( collectionId ); 0220 m_expandedCollections.remove( item->parentCollection() ); 0221 endRemoveRows(); 0222 } 0223 } 0224 } 0225 0226 void 0227 CollectionTreeItemModel::filterChildren() 0228 { 0229 int count = m_rootItem->childCount(); 0230 for ( int i = 0; i < count; i++ ) 0231 { 0232 markSubTreeAsDirty( m_rootItem->child( i ) ); 0233 ensureChildrenLoaded( m_rootItem->child( i ) ); 0234 } 0235 } 0236 0237 void 0238 CollectionTreeItemModel::requestCollectionsExpansion() 0239 { 0240 for( int i = 0, count = m_rootItem->childCount(); i < count; i++ ) 0241 { 0242 Q_EMIT expandIndex( itemIndex( m_rootItem->child( i ) ) ); 0243 } 0244 } 0245