File indexing completed on 2024-05-05 04:51:44
0001 /* 0002 SPDX-FileCopyrightText: 2008 Sebastian Trueg <trueg@k3b.org> 0003 SPDX-FileCopyrightText: 2009 Gustavo Pichorim Boiko <gustavo.boiko@kdemail.net> 0004 SPDX-FileCopyrightText: 2009-2011 Michal Malek <michalm@jabster.pl> 0005 SPDX-FileCopyrightText: 1998-2009 Sebastian Trueg <trueg@k3b.org> 0006 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 0010 #include "k3bdataprojectmodel.h" 0011 0012 #include "k3bdatadoc.h" 0013 #include "k3bdiritem.h" 0014 #include "k3bfileitem.h" 0015 #include "k3bisooptions.h" 0016 #include "k3bspecialdataitem.h" 0017 0018 #include <KUrlMimeData> 0019 #include <KLocalizedString> 0020 #include <KIconEngine> 0021 0022 #include <QDataStream> 0023 #include <QMimeData> 0024 #include <QFont> 0025 0026 0027 class K3b::DataProjectModel::Private 0028 { 0029 public: 0030 Private( DataProjectModel* parent ) 0031 : project( 0 ), 0032 q( parent ) { 0033 } 0034 0035 K3b::DataDoc* project; 0036 0037 K3b::DataItem* getChild( K3b::DirItem* dir, int offset ); 0038 int findChildIndex( K3b::DataItem* item ); 0039 void _k_itemsAboutToBeInserted( K3b::DirItem* parent, int start, int end ); 0040 void _k_itemsAboutToBeRemoved( K3b::DirItem* parent, int start, int end ); 0041 void _k_itemsInserted( K3b::DirItem* parent, int start, int end ); 0042 void _k_itemsRemoved( K3b::DirItem* parent, int start, int end ); 0043 void _k_volumeIdChanged(); 0044 0045 private: 0046 DataProjectModel* q; 0047 0048 bool m_removingItem; 0049 }; 0050 0051 0052 0053 K3b::DataItem* K3b::DataProjectModel::Private::getChild( K3b::DirItem* dir, int offset ) 0054 { 0055 QList<K3b::DataItem*> const& children = dir->children(); 0056 if ( offset >= 0 && offset < children.count() ) { 0057 return children[offset]; 0058 } 0059 0060 return 0; 0061 } 0062 0063 0064 int K3b::DataProjectModel::Private::findChildIndex( K3b::DataItem* item ) 0065 { 0066 if ( !item ) 0067 return 0; 0068 else if ( DirItem* dir = item->parent() ) 0069 return dir->children().indexOf( item ); 0070 else 0071 return 0; 0072 } 0073 0074 0075 void K3b::DataProjectModel::Private::_k_itemsAboutToBeInserted( K3b::DirItem* parent, int start, int end ) 0076 { 0077 qDebug() << q->indexForItem( parent ) << start << end; 0078 q->beginInsertRows( q->indexForItem( parent ), start, end ); 0079 } 0080 0081 0082 void K3b::DataProjectModel::Private::_k_itemsAboutToBeRemoved( K3b::DirItem* parent, int start, int end ) 0083 { 0084 m_removingItem = true; 0085 qDebug() << q->indexForItem( parent ) << start << end; 0086 q->beginRemoveRows( q->indexForItem( parent ), start, end ); 0087 } 0088 0089 0090 void K3b::DataProjectModel::Private::_k_itemsInserted( K3b::DirItem* /*parent*/, int /*start*/, int /*end*/ ) 0091 { 0092 q->endInsertRows(); 0093 } 0094 0095 0096 void K3b::DataProjectModel::Private::_k_itemsRemoved( K3b::DirItem* /*parent*/, int /*start*/, int /*end*/ ) 0097 { 0098 if ( m_removingItem ) { 0099 q->endRemoveRows(); 0100 } 0101 } 0102 0103 0104 void K3b::DataProjectModel::Private::_k_volumeIdChanged() 0105 { 0106 QModelIndex index = q->index( 0, 0 ); 0107 emit q->dataChanged( index, index ); 0108 } 0109 0110 0111 K3b::DataProjectModel::DataProjectModel( K3b::DataDoc* doc, QObject* parent ) 0112 : QAbstractItemModel( parent ), 0113 d( new Private(this) ) 0114 { 0115 d->project = doc; 0116 0117 connect( doc, SIGNAL(itemsAboutToBeInserted(K3b::DirItem*,int,int)), 0118 this, SLOT(_k_itemsAboutToBeInserted(K3b::DirItem*,int,int)), Qt::DirectConnection ); 0119 connect( doc, SIGNAL(itemsAboutToBeRemoved(K3b::DirItem*,int,int)), 0120 this, SLOT(_k_itemsAboutToBeRemoved(K3b::DirItem*,int,int)), Qt::DirectConnection ); 0121 connect( doc, SIGNAL(itemsInserted(K3b::DirItem*,int,int)), 0122 this, SLOT(_k_itemsInserted(K3b::DirItem*,int,int)), Qt::DirectConnection ); 0123 connect( doc, SIGNAL(itemsRemoved(K3b::DirItem*,int,int)), 0124 this, SLOT(_k_itemsRemoved(K3b::DirItem*,int,int)), Qt::DirectConnection ); 0125 connect( doc, SIGNAL(volumeIdChanged()), 0126 this, SLOT(_k_volumeIdChanged()), Qt::DirectConnection ); 0127 } 0128 0129 0130 K3b::DataProjectModel::~DataProjectModel() 0131 { 0132 delete d; 0133 } 0134 0135 0136 K3b::DataDoc* K3b::DataProjectModel::project() const 0137 { 0138 return d->project; 0139 } 0140 0141 K3b::DataItem* K3b::DataProjectModel::itemForIndex( const QModelIndex& index ) const 0142 { 0143 if ( index.isValid() ) { 0144 Q_ASSERT( index.internalPointer() ); 0145 return static_cast<K3b::DataItem*>( index.internalPointer() ); 0146 } 0147 else { 0148 return 0; 0149 } 0150 } 0151 0152 QModelIndex K3b::DataProjectModel::indexForItem( K3b::DataItem* item ) const 0153 { 0154 return createIndex( d->findChildIndex( item ), 0, item ); 0155 } 0156 0157 0158 int K3b::DataProjectModel::columnCount( const QModelIndex& /*index*/ ) const 0159 { 0160 return NumColumns; 0161 } 0162 0163 0164 QVariant K3b::DataProjectModel::data( const QModelIndex& index, int role ) const 0165 { 0166 if ( DataItem* item = itemForIndex( index ) ) { 0167 0168 if ( role == ItemTypeRole ) { 0169 if (item->isDir()) 0170 return DirItemType; 0171 else 0172 return FileItemType; 0173 } 0174 else if ( role == CustomFlagsRole ) { 0175 if (item->isRemoveable()) 0176 return ItemIsRemovable; 0177 else 0178 return 0; 0179 } 0180 else if ( role == Qt::StatusTipRole ) { 0181 if (item->isSymLink()) 0182 return i18nc( "Symlink target shown in status bar", "Link to %1", static_cast<FileItem*>( item )->linkDest() ); 0183 else 0184 return QVariant(); 0185 } 0186 0187 switch( index.column() ) { 0188 case FilenameColumn: 0189 if( role == Qt::DisplayRole || 0190 role == Qt::EditRole || 0191 role == SortRole ) { 0192 return item->k3bName(); 0193 } 0194 else if ( role == Qt::DecorationRole ) { 0195 QString iconName; 0196 if ( item->isDir() && item->parent() ) { 0197 iconName = ( static_cast<K3b::DirItem*>( item )->depth() > 7 ? "folder-root" : "folder" ); 0198 } 0199 else if ( item->isDir() ) { 0200 iconName = "media-optical-data"; 0201 } 0202 else { 0203 iconName = item->mimeType().iconName(); 0204 } 0205 0206 if( item->isSymLink() ) 0207 return QIcon( new KIconEngine( iconName, nullptr, QStringList() << "emblem-symbolic-link" ) ); 0208 else 0209 return QIcon::fromTheme( iconName ); 0210 } 0211 else if( role == Qt::FontRole && item->isSymLink() ) { 0212 QFont font; 0213 font.setItalic( true ); 0214 return font; 0215 } 0216 break; 0217 0218 case TypeColumn: 0219 if( role == Qt::DisplayRole || 0220 role == SortRole ) { 0221 if ( item->isSpecialFile() ) { 0222 return static_cast<K3b::SpecialDataItem*>( item )->specialType(); 0223 } 0224 else { 0225 return item->mimeType().comment(); 0226 } 0227 } 0228 break; 0229 0230 case SizeColumn: 0231 if( role == Qt::DisplayRole ) { 0232 return KIO::convertSize( item->size() ); 0233 } 0234 else if ( role == SortRole ) { 0235 return item->size(); 0236 } 0237 break; 0238 } 0239 } 0240 0241 return QVariant(); 0242 } 0243 0244 0245 QVariant K3b::DataProjectModel::headerData( int section, Qt::Orientation orientation, int role ) const 0246 { 0247 Q_UNUSED( orientation ); 0248 0249 if ( role == Qt::DisplayRole ) { 0250 switch( section ) { 0251 case FilenameColumn: 0252 return i18nc( "file name", "Name" ); 0253 case TypeColumn: 0254 return i18nc( "file type", "Type" ); 0255 case SizeColumn: 0256 return i18nc( "file size", "Size" ); 0257 } 0258 } 0259 0260 return QVariant(); 0261 } 0262 0263 0264 Qt::ItemFlags K3b::DataProjectModel::flags( const QModelIndex& index ) const 0265 { 0266 if ( index.isValid() ) { 0267 Qt::ItemFlags f = Qt::ItemIsSelectable|Qt::ItemIsEnabled|Qt::ItemIsDropEnabled; 0268 if ( index.column() == FilenameColumn ) { 0269 f |= Qt::ItemIsEditable; 0270 } 0271 if ( itemForIndex( index ) != d->project->root() ) { 0272 f |= Qt::ItemIsDragEnabled; 0273 } 0274 0275 return f; 0276 } 0277 else { 0278 return QAbstractItemModel::flags( index )|Qt::ItemIsDropEnabled; 0279 } 0280 } 0281 0282 0283 QModelIndex K3b::DataProjectModel::index( int row, int column, const QModelIndex& parent ) const 0284 { 0285 if ( !hasIndex( row, column, parent ) ) { 0286 return QModelIndex(); 0287 } 0288 else if ( parent.isValid() ) { 0289 K3b::DirItem* dir = itemForIndex( parent )->getDirItem(); 0290 K3b::DataItem* child = d->getChild( dir, row ); 0291 if ( child && parent.column() == 0 ) { 0292 return createIndex( row, column, child ); 0293 } 0294 else { 0295 return QModelIndex(); 0296 } 0297 } 0298 else { 0299 // doc root item 0300 return createIndex( row, column, d->project->root() ); 0301 } 0302 } 0303 0304 0305 QModelIndex K3b::DataProjectModel::parent( const QModelIndex& index ) const 0306 { 0307 //qDebug() << index; 0308 if( K3b::DataItem* item = itemForIndex( index ) ) { 0309 if( K3b::DirItem* dir = item->parent() ) { 0310 return createIndex( d->findChildIndex( dir ), 0, dir ); 0311 } 0312 } 0313 return QModelIndex(); 0314 } 0315 0316 0317 int K3b::DataProjectModel::rowCount( const QModelIndex& parent ) const 0318 { 0319 if ( parent.isValid() ) { 0320 K3b::DataItem* item = itemForIndex( parent ); 0321 K3b::DirItem* dir = dynamic_cast<K3b::DirItem*>( item ); 0322 if ( dir != 0 && parent.column() == 0 ) { 0323 return( dir->children().count() ); 0324 } 0325 else { 0326 return 0; 0327 } 0328 } 0329 else { 0330 return 1; 0331 } 0332 } 0333 0334 0335 bool K3b::DataProjectModel::setData( const QModelIndex& index, const QVariant& value, int role ) 0336 { 0337 if ( index.isValid() ) { 0338 K3b::DataItem* item = itemForIndex( index ); 0339 if ( role == Qt::EditRole ) { 0340 if ( index.column() == 0 ) { 0341 item->setK3bName( value.toString() ); 0342 emit dataChanged( index, index ); 0343 return true; 0344 } 0345 } 0346 } 0347 0348 return false; 0349 } 0350 0351 0352 QMimeData* K3b::DataProjectModel::mimeData( const QModelIndexList& indexes ) const 0353 { 0354 QMimeData* mime = new QMimeData(); 0355 0356 QSet<K3b::DataItem*> items; 0357 QList<QUrl> urls; 0358 foreach( const QModelIndex& index, indexes ) { 0359 K3b::DataItem* item = itemForIndex( index ); 0360 items << item; 0361 0362 QUrl url = QUrl::fromLocalFile( item->localPath() ); 0363 if ( item->isFile() && !urls.contains(url) ) { 0364 urls << url; 0365 } 0366 } 0367 mime->setUrls(urls); 0368 0369 // the easy road: encode the pointers 0370 QByteArray itemData; 0371 QDataStream itemDataStream( &itemData, QIODevice::WriteOnly ); 0372 foreach( K3b::DataItem* item, items ) { 0373 itemDataStream << ( qint64 )item; 0374 } 0375 mime->setData( "application/x-k3bdataitem", itemData ); 0376 0377 return mime; 0378 } 0379 0380 0381 Qt::DropActions K3b::DataProjectModel::supportedDropActions() const 0382 { 0383 return Qt::CopyAction | Qt::MoveAction; 0384 } 0385 0386 0387 QStringList K3b::DataProjectModel::mimeTypes() const 0388 { 0389 QStringList s = KUrlMimeData::mimeDataTypes(); 0390 s += QString::fromLatin1( "application/x-k3bdataitem" ); 0391 return s; 0392 } 0393 0394 0395 bool K3b::DataProjectModel::dropMimeData( const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent ) 0396 { 0397 qDebug(); 0398 0399 // no need to handle the row as item order is not important (the model just forces us to use them above) 0400 Q_UNUSED( row ); 0401 Q_UNUSED( column ); 0402 0403 if (action == Qt::IgnoreAction) 0404 return true; 0405 0406 // determine the target dir: 0407 // - drop ontp an item -> get the item's dir (i.e. itself or its parent) 0408 // - drop onto the viewport -> the project's root 0409 // -------------------------------------------------------------- 0410 K3b::DirItem* dir = d->project->root(); 0411 if ( parent.isValid() ) { 0412 dir = itemForIndex( parent )->getDirItem(); 0413 } 0414 0415 if ( data->hasFormat( "application/x-k3bdataitem" ) ) { 0416 if( action == Qt::MoveAction ) 0417 return false; 0418 0419 qDebug() << "data item drop"; 0420 0421 QByteArray itemData = data->data( "application/x-k3bdataitem" ); 0422 QDataStream itemDataStream( itemData ); 0423 QList<K3b::DataItem*> items; 0424 while ( !itemDataStream.atEnd() ) { 0425 qint64 p; 0426 itemDataStream >> p; 0427 items << ( K3b::DataItem* )p; 0428 } 0429 // always move the items, no copy from within the views 0430 emit moveItemsRequested( items, dir ); 0431 return true; 0432 } 0433 else if ( data->hasUrls() ) { 0434 qDebug() << "url list drop"; 0435 QList<QUrl> urls = KUrlMimeData::urlsFromMimeData( data ); 0436 emit addUrlsRequested( urls, dir ); 0437 return true; 0438 } 0439 else { 0440 return false; 0441 } 0442 } 0443 0444 0445 bool K3b::DataProjectModel::removeRows( int row, int count, const QModelIndex& parent) 0446 { 0447 DirItem* dirItem = dynamic_cast<DirItem*>( itemForIndex( parent ) ); 0448 if( dirItem && row >= 0 && count > 0 ) { 0449 // remove the indexes from the project 0450 d->project->removeItems( dirItem, row, count ); 0451 return true; 0452 } 0453 else { 0454 return false; 0455 } 0456 } 0457 0458 0459 QModelIndex K3b::DataProjectModel::buddy( const QModelIndex& index ) const 0460 { 0461 if( index.isValid() && index.column() != FilenameColumn) 0462 return DataProjectModel::index( index.row(), FilenameColumn, index.parent() ); 0463 else 0464 return index; 0465 } 0466 0467 #include "moc_k3bdataprojectmodel.cpp"