File indexing completed on 2024-10-06 04:26:01
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 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 "k3bmetaitemmodel.h" 0011 // this header is required to return the ItemTypeRole correctly for the 0012 // places items 0013 #include "k3bdataprojectmodel.h" 0014 0015 #include "k3bcore.h" 0016 0017 #include <list> 0018 0019 #include <QDebug> 0020 #include <QMimeData> 0021 #include <QVector> 0022 #include <QIcon> 0023 0024 // IDEA: K3b::MetaItemModel::placeData( int row, int column ); 0025 0026 #ifdef __clang__ 0027 #define CLANG_ANALYZER_NORETURN __attribute__((analyzer_noreturn)) 0028 #else 0029 #define CLANG_ANALYZER_NORETURN 0030 #endif 0031 0032 namespace { 0033 class Place; 0034 0035 class Node { 0036 public: 0037 Node() 0038 : parent( 0 ), 0039 m_place( 0 ) { 0040 0041 } 0042 0043 virtual ~Node() { 0044 qDeleteAll(children); 0045 } 0046 0047 virtual bool isPlace() const { return false; } 0048 virtual Place* place() const; 0049 void setPlace( Place* place ); 0050 virtual QAbstractItemModel* model() const; 0051 Node* findNodeForOriginalIndex( const QModelIndex& index ); 0052 Node* createNodeForOriginalIndex( const QModelIndex& index ); 0053 Node* getChildNode( const QModelIndex& originalIndex ); 0054 void updateChildren(); 0055 void reset(); 0056 bool supportsMimeData( const QMimeData* data ) const; 0057 0058 // the parent node, 0 for Place instances 0059 Node* parent; 0060 0061 // the model index as returned by the original model, not 0062 // to be used in the public API (exception: mapToSubModel()) 0063 QPersistentModelIndex originalModelIndex; 0064 0065 // the child nodes 0066 QVector<Node*> children; 0067 0068 private: 0069 // the root element of this node 0070 Place* m_place; 0071 }; 0072 0073 0074 class Place : public Node { 0075 public: 0076 Place( QAbstractItemModel* model ) 0077 : m_model( model ) { 0078 } 0079 0080 Place* place() const override; 0081 bool isPlace() const override { return true; } 0082 QAbstractItemModel* model() const override; 0083 0084 // a name and icon for the place (used for display) 0085 // FIXME: better use something like placeData(...) 0086 QString name; 0087 QIcon icon; 0088 0089 // the row index of this node 0090 int row; 0091 0092 bool flat; 0093 0094 private: 0095 QAbstractItemModel* m_model; 0096 }; 0097 0098 0099 QAbstractItemModel* Node::model() const 0100 { 0101 return place()->model(); 0102 } 0103 0104 0105 QAbstractItemModel* Place::model() const 0106 { 0107 return m_model; 0108 } 0109 0110 0111 Place* Node::place() const 0112 { 0113 return m_place; 0114 } 0115 0116 0117 void Node::setPlace( Place* place ) 0118 { 0119 m_place = place; 0120 } 0121 0122 0123 Place* Place::place() const 0124 { 0125 return const_cast<Place*>( this ); 0126 } 0127 0128 0129 void Node::updateChildren() 0130 { 0131 // only update children when there is no items in the list 0132 if ( children.isEmpty() ) { 0133 // TODO: this is kind of evil since indexes store pointers to the nodes 0134 //qDebug() << "resizing children from" << children.size() << "to" << rows; 0135 0136 int rows = model()->rowCount( originalModelIndex ); 0137 for ( int i = 0; i < rows; ++i ) { 0138 Node *node = new Node(); 0139 node->setPlace( place() ); 0140 node->parent = this; 0141 node->originalModelIndex = model()->index( i, 0, originalModelIndex ); 0142 children.append(node); 0143 } 0144 } 0145 } 0146 0147 0148 Node* Node::getChildNode( const QModelIndex& originalIndex ) 0149 { 0150 updateChildren(); 0151 0152 Q_ASSERT(children.size() > originalIndex.row()); 0153 0154 Node* node = children[originalIndex.row()]; 0155 return node; 0156 } 0157 0158 0159 Node* Node::findNodeForOriginalIndex( const QModelIndex& index ) 0160 { 0161 if ( originalModelIndex == index ) { 0162 return this; 0163 } 0164 0165 for ( int i = 0; i < children.count(); ++i ) { 0166 if ( Node* node = children[i]->findNodeForOriginalIndex( index ) ) 0167 return node; 0168 } 0169 0170 return 0; 0171 } 0172 0173 static void K3b_ASSERT(bool test) CLANG_ANALYZER_NORETURN { Q_ASSERT(test); } 0174 0175 Node* Node::createNodeForOriginalIndex( const QModelIndex& index ) 0176 { 0177 if ( !index.isValid() && isPlace() ) { 0178 return this; 0179 } 0180 0181 K3b_ASSERT(index.isValid()); 0182 0183 // all the node mapping is done on the first col, so make sure we use 0184 // an index on the first col 0185 // 0186 // A valid index belongs to a model, and has non-negative row and column numbers 0187 // so index.model() is NOT nullptr if index.isValid() 0188 QModelIndex firstColIndex = index.model()->index(index.row(), 0, index.parent()); 0189 Node* node = findNodeForOriginalIndex( firstColIndex ); 0190 if ( !node ) { 0191 Node* parentNode = createNodeForOriginalIndex( firstColIndex.parent() ); 0192 node = parentNode->getChildNode( firstColIndex ); 0193 } 0194 0195 return node; 0196 } 0197 0198 0199 void Node::reset() 0200 { 0201 qDeleteAll(children); 0202 children.clear(); 0203 } 0204 0205 bool Node::supportsMimeData( const QMimeData* data ) const 0206 { 0207 QStringList supportedFormats = model()->mimeTypes(); 0208 QStringList formats = data->formats(); 0209 Q_FOREACH( const QString& format, formats ) 0210 { 0211 if( supportedFormats.indexOf( format ) >= 0 ) 0212 return true; 0213 } 0214 return false; 0215 } 0216 } // namespace 0217 0218 0219 0220 class K3b::MetaItemModel::Private 0221 { 0222 public: 0223 Private( MetaItemModel* model ) : q( model ) {} 0224 0225 Place* placeForModel( const QAbstractItemModel* model ) { 0226 for (auto &place : places) { 0227 if ( place.model() == model ) { 0228 return &place; 0229 } 0230 } 0231 return 0; 0232 } 0233 0234 void updatePlaceRows() { 0235 int row = 0; 0236 auto end = places.end(); 0237 for ( auto it = places.begin(); 0238 it != end; ++it ) { 0239 it->row = row; 0240 if ( it->flat ) { 0241 row += it->model()->rowCount( QModelIndex() ); 0242 } 0243 else { 0244 ++row; 0245 } 0246 } 0247 } 0248 0249 /** 0250 * root nodes are all non-flat places + 0251 * all root items from flat places. 0252 */ 0253 Node* getRootNode( int row ) { 0254 int i = 0; 0255 auto end = places.end(); 0256 for ( auto it = places.begin(); 0257 it != end; ++it ) { 0258 if ( it->flat ) { 0259 it->updateChildren(); 0260 if ( i + it->children.count() > row ) { 0261 return it->children[row-i]; 0262 } 0263 else { 0264 i += it->children.count(); 0265 } 0266 } 0267 else if ( row == i ) { 0268 return &( *it ); 0269 } 0270 else { 0271 ++i; 0272 } 0273 } 0274 0275 return 0; 0276 } 0277 0278 int getRootNodeRow(Node *node) 0279 { 0280 int row = 0; 0281 auto end = places.end(); 0282 for ( auto it = places.begin(); 0283 it != end; ++it ) { 0284 if (node->isPlace() && node->model() == it->model()) 0285 return row; 0286 0287 if ( it->flat ) { 0288 it->updateChildren(); 0289 for (int i = 0; i < it->children.count(); ++i) 0290 { 0291 if (!node->isPlace() && it->children[i]->originalModelIndex == node->originalModelIndex) 0292 return row; 0293 0294 ++row; 0295 } 0296 } 0297 else 0298 ++row; 0299 } 0300 0301 return -1; 0302 } 0303 /** 0304 * returns the node pointer for the given index. 0305 * This makes it easier to handle multiple column 0306 */ 0307 Node* nodeForIndex( const QModelIndex &index ) 0308 { 0309 // all indexes store the node in their internal pointers 0310 if( index.isValid() && index.model() == q ) 0311 return static_cast<Node*>(index.internalPointer()); 0312 else 0313 return 0; 0314 } 0315 0316 /** 0317 * returns an index from the source model for the given index 0318 */ 0319 QModelIndex sourceIndex( const QModelIndex &index ) 0320 { 0321 Node *node = nodeForIndex(index); 0322 if (!node || node->isPlace()) 0323 return QModelIndex(); 0324 0325 return node->model()->index( node->originalModelIndex.row(), index.column(), node->originalModelIndex.parent() ); 0326 } 0327 0328 std::list<Place> places; 0329 MetaItemModel* q; 0330 }; 0331 0332 0333 0334 K3b::MetaItemModel::MetaItemModel( QObject* parent ) 0335 : QAbstractItemModel( parent ), 0336 d( new Private( this ) ) 0337 { 0338 } 0339 0340 0341 K3b::MetaItemModel::~MetaItemModel() 0342 { 0343 delete d; 0344 } 0345 0346 0347 QModelIndex K3b::MetaItemModel::indexForSubModel( QAbstractItemModel* model ) const 0348 { 0349 if( !d->places.empty() ) { 0350 if( Place* place = d->placeForModel( model ) ) 0351 return createIndex( place->row, 0, place ); 0352 } 0353 return QModelIndex(); 0354 } 0355 0356 0357 QAbstractItemModel* K3b::MetaItemModel::subModelForIndex( const QModelIndex& index ) const 0358 { 0359 if( Node* node = d->nodeForIndex( index ) ) 0360 return node->model(); 0361 else 0362 return 0; 0363 } 0364 0365 0366 QModelIndex K3b::MetaItemModel::mapToSubModel( const QModelIndex& index ) const 0367 { 0368 if ( index.isValid() ) { 0369 Q_ASSERT( index.model() == this ); 0370 return d->sourceIndex( index ); 0371 } 0372 else { 0373 return QModelIndex(); 0374 } 0375 } 0376 0377 0378 QModelIndex K3b::MetaItemModel::mapFromSubModel( const QModelIndex& index ) const 0379 { 0380 if ( index.isValid() ) { 0381 Place *place = d->placeForModel( index.model() ); 0382 Node* node = place->createNodeForOriginalIndex( index ); 0383 Q_ASSERT( node ); 0384 0385 // if the place is not flat, or the parent index is valid 0386 // we just have to return the index for the row and column 0387 if ( !place->flat || index.parent().isValid() ) 0388 return createIndex( index.row(), index.column(), node ); 0389 else { 0390 // now if the place is flat and the parent is not valid, 0391 // we have to adjust the row according to its position in the 0392 // tree 0393 int row = d->getRootNodeRow( node ); 0394 if ( row < 0 ) 0395 return QModelIndex(); 0396 else 0397 return createIndex( row, index.column(), node ); 0398 } 0399 } 0400 else { 0401 return QModelIndex(); 0402 } 0403 } 0404 0405 0406 int K3b::MetaItemModel::columnCount( const QModelIndex& parent ) const 0407 { 0408 QAbstractItemModel *model = subModelForIndex( parent ); 0409 if (!model) 0410 return 1; 0411 0412 return model->columnCount( mapToSubModel( parent ) ); 0413 } 0414 0415 0416 QVariant K3b::MetaItemModel::data( const QModelIndex& index, int role ) const 0417 { 0418 if( Node* node = d->nodeForIndex( index ) ) { 0419 Q_ASSERT( node->model() ); 0420 Q_ASSERT( node->isPlace() || node->originalModelIndex.isValid() ); 0421 0422 if ( node->isPlace() ) { 0423 // provide the root elements of the places 0424 switch( role ) { 0425 case Qt::DisplayRole: 0426 return node->place()->name; 0427 0428 case Qt::DecorationRole: 0429 return node->place()->icon; 0430 0431 case DataProjectModel::ItemTypeRole: 0432 return (int) DataProjectModel::DirItemType; 0433 0434 default: 0435 return QVariant(); 0436 } 0437 } 0438 else { 0439 return node->model()->data( mapToSubModel( index ), role ); 0440 } 0441 } 0442 else { 0443 return QVariant(); 0444 } 0445 } 0446 0447 0448 QModelIndex K3b::MetaItemModel::index( int row, int column, const QModelIndex& parent ) const 0449 { 0450 //qDebug() << row << column << parent; 0451 0452 if ( row < 0 || column < 0 ) { 0453 return QModelIndex(); 0454 } 0455 0456 if ( parent.isValid() ) { 0457 Node* parentNode = d->nodeForIndex( parent ); 0458 0459 Q_ASSERT( parentNode->parent || parentNode->isPlace() ); 0460 Q_ASSERT( parentNode->place() ); 0461 Q_ASSERT( parentNode->model() ); 0462 0463 // for places the originalModelIndex is invalid 0464 QModelIndex originalIndex = parentNode->model()->index( row, 0, parentNode->originalModelIndex ); 0465 Node* node = parentNode->place()->createNodeForOriginalIndex( originalIndex ); 0466 return createIndex( row, column, node ); 0467 } 0468 else { 0469 if ( Node* node = d->getRootNode( row ) ) { 0470 return createIndex( row, column, node ); 0471 } 0472 else { 0473 return QModelIndex(); 0474 } 0475 } 0476 } 0477 0478 0479 QModelIndex K3b::MetaItemModel::parent( const QModelIndex& index ) const 0480 { 0481 //qDebug() << "Parent of" << index; 0482 Node* node = d->nodeForIndex( index ); 0483 0484 if ( !index.isValid() || !node || node->isPlace() ) 0485 return QModelIndex(); 0486 0487 Q_ASSERT( node->parent ); 0488 Q_ASSERT( node->place() ); 0489 Q_ASSERT( node->model() ); 0490 0491 0492 QModelIndex origIndex = mapToSubModel( index ).parent(); 0493 0494 if ( origIndex.isValid() ) { 0495 return mapFromSubModel( origIndex ); 0496 } 0497 else if ( !node->place()->flat ) { 0498 return createIndex( node->place()->row, 0, node->place() ); 0499 } 0500 else { 0501 return QModelIndex(); 0502 } 0503 } 0504 0505 0506 Qt::ItemFlags K3b::MetaItemModel::flags( const QModelIndex& index ) const 0507 { 0508 if ( index.isValid() ) { 0509 Node* node = d->nodeForIndex( index ); 0510 if ( node->isPlace() ) { 0511 // flags from invalid index can be helpful when model is drop-enabled 0512 return node->model()->flags( QModelIndex() )|Qt::ItemIsSelectable|Qt::ItemIsEnabled; 0513 } 0514 else { 0515 return mapToSubModel( index ).flags(); 0516 } 0517 } 0518 0519 return QAbstractItemModel::flags( index ); 0520 } 0521 0522 0523 bool K3b::MetaItemModel::hasChildren( const QModelIndex& parent ) const 0524 { 0525 // qDebug() << parent; 0526 0527 if ( parent.isValid() ) { 0528 Node* parentNode = d->nodeForIndex( parent ); 0529 0530 Q_ASSERT( parentNode->place() ); 0531 Q_ASSERT( parentNode->place()->model() ); 0532 Q_ASSERT( parentNode->model() ); 0533 0534 // the originalModelIndex is invalid for place nodes 0535 return parentNode->model()->hasChildren( mapToSubModel( parent ) ); 0536 } 0537 else { 0538 return !d->places.empty(); 0539 } 0540 } 0541 0542 0543 bool K3b::MetaItemModel::canFetchMore( const QModelIndex& parent ) const 0544 { 0545 // qDebug() << parent; 0546 0547 if ( parent.isValid() ) { 0548 Node* parentNode = d->nodeForIndex( parent ); 0549 return parentNode->model()->canFetchMore( mapToSubModel( parent ) ); 0550 } 0551 else { 0552 return false; 0553 } 0554 } 0555 0556 0557 void K3b::MetaItemModel::fetchMore( const QModelIndex& parent ) 0558 { 0559 // qDebug() << parent; 0560 0561 if ( parent.isValid() ) { 0562 Node* parentNode = d->nodeForIndex( parent ); 0563 parentNode->model()->fetchMore( mapToSubModel( parent ) ); 0564 } 0565 } 0566 0567 0568 int K3b::MetaItemModel::rowCount( const QModelIndex& parent ) const 0569 { 0570 // qDebug() << parent; 0571 if ( parent.column() > 0 ) 0572 return 0; 0573 0574 if ( parent.isValid() ) { 0575 Node* parentNode = d->nodeForIndex( parent ); 0576 return parentNode->model()->rowCount( mapToSubModel( parent ) ); 0577 } 0578 else { 0579 int cnt = 0; 0580 auto end = d->places.end(); 0581 for ( auto it = d->places.begin(); 0582 it != end; ++it ) { 0583 if( it->flat ) { 0584 cnt += it->model()->rowCount( QModelIndex() ); 0585 } 0586 else { 0587 ++cnt; 0588 } 0589 } 0590 return cnt; 0591 } 0592 } 0593 0594 0595 bool K3b::MetaItemModel::setData( const QModelIndex& index, const QVariant& value, int role ) 0596 { 0597 // qDebug() << index; 0598 0599 if ( index.isValid() ) { 0600 Node* node = d->nodeForIndex( index ); 0601 if ( node->isPlace() ) { 0602 // cannot edit the place, should not happen anyway, see flags() 0603 return false; 0604 } 0605 else { 0606 return node->model()->setData( mapToSubModel( index ), value, role ); 0607 } 0608 } 0609 else { 0610 return false; 0611 } 0612 } 0613 0614 0615 QStringList K3b::MetaItemModel::mimeTypes() const 0616 { 0617 QSet<QString> types; 0618 for( auto it = d->places.cbegin(); 0619 it != d->places.cend(); ++it ) 0620 { 0621 const QStringList &mimeTypes = it->model()->mimeTypes(); 0622 types += QSet<QString>(mimeTypes.begin(), mimeTypes.end()); 0623 } 0624 return types.values(); 0625 } 0626 0627 0628 bool K3b::MetaItemModel::dropMimeData( const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent ) 0629 { 0630 // qDebug(); 0631 0632 if ( parent.isValid() ) { 0633 Node* parentNode = d->nodeForIndex( parent ); 0634 0635 if( !parentNode->supportsMimeData( data ) ) { 0636 return false; 0637 } 0638 else { 0639 // for places the originalModelIndex will be invalid 0640 return parentNode->model()->dropMimeData( data, action, row, column, mapToSubModel( parent ) ); 0641 } 0642 } 0643 else if ( row >= 0 ) { 0644 Node *node = d->getRootNode(row); 0645 0646 if( !node->supportsMimeData( data ) ) { 0647 return false; 0648 } 0649 else if (node->isPlace()) { 0650 // if the node is place, threat it like if it was being dropped on an empty space of the 0651 // original model 0652 return node->model()->dropMimeData(data, action, -1, column, QModelIndex()); 0653 } 0654 else { 0655 // if it is not a place (which means the original model is a flat model) 0656 // drop like if it was being dropped in the row/col of the original index 0657 return node->model()->dropMimeData(data, action, node->originalModelIndex.row(), column, QModelIndex()); 0658 } 0659 } 0660 else { 0661 return false; 0662 } 0663 } 0664 0665 0666 bool K3b::MetaItemModel::removeRows( int row, int count, const QModelIndex& parent ) 0667 { 0668 if( parent.isValid() ) { 0669 Node* parentNode = d->nodeForIndex( parent ); 0670 return parentNode->model()->removeRows( row, count, mapToSubModel( parent ) ); 0671 } 0672 else if( row >= 0 ) { 0673 auto it = d->places.cbegin(); 0674 std::advance(it, row); 0675 while (count-- > 0 && it != d->places.cend()) { 0676 it = d->places.erase(it); 0677 } 0678 return true; 0679 } 0680 else { 0681 return false; 0682 } 0683 } 0684 0685 0686 QMimeData* K3b::MetaItemModel::mimeData( const QModelIndexList& indexes ) const 0687 { 0688 if ( !indexes.isEmpty() ) { 0689 QModelIndexList origIndexes; 0690 for ( QModelIndexList::const_iterator it = indexes.constBegin(); 0691 it != indexes.constEnd(); ++it ) { 0692 QModelIndex sourceIndex = mapToSubModel( *it ); 0693 if ( !origIndexes.isEmpty() && sourceIndex.model() != origIndexes.first().model() ) { 0694 qDebug() << "cannot handle indexes from different submodels yet."; 0695 return 0; 0696 } 0697 origIndexes.append( sourceIndex ); 0698 } 0699 return origIndexes.first().model()->mimeData( origIndexes ); 0700 } 0701 0702 return 0; 0703 } 0704 0705 0706 Qt::DropActions K3b::MetaItemModel::supportedDragActions() const 0707 { 0708 Qt::DropActions a = Qt::IgnoreAction; 0709 0710 for (const auto &place : d->places) { 0711 a |= place.model()->supportedDragActions(); 0712 } 0713 return a; 0714 } 0715 0716 0717 Qt::DropActions K3b::MetaItemModel::supportedDropActions() const 0718 { 0719 Qt::DropActions a = Qt::IgnoreAction; 0720 0721 for (const auto &place : d->places) { 0722 a |= place.model()->supportedDropActions(); 0723 } 0724 return a; 0725 } 0726 0727 0728 void K3b::MetaItemModel::addSubModel( const QString& name, const QIcon& icon, QAbstractItemModel* model, bool flat ) 0729 { 0730 const int first = rowCount(QModelIndex()); 0731 const int last = first + (flat ? model->rowCount() - 1 : 0); 0732 0733 if ( first <= last ) 0734 beginInsertRows( QModelIndex(), first, last ); 0735 0736 model->setParent( this ); 0737 0738 d->places.emplace_back(model); 0739 0740 Place& place = d->places.back(); 0741 place.name = name; 0742 place.icon = icon; 0743 place.flat = flat; 0744 place.updateChildren(); 0745 0746 d->updatePlaceRows(); 0747 0748 connect( place.model(), SIGNAL(modelAboutToBeReset()), 0749 this, SLOT(slotAboutToBeReset()) ); 0750 0751 connect( place.model(), SIGNAL(modelReset()), 0752 this, SLOT(slotReset()) ); 0753 0754 connect( place.model(), SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)), 0755 this, SLOT(slotRowsAboutToBeInserted(QModelIndex,int,int)) ); 0756 0757 connect( place.model(), SIGNAL(rowsInserted(QModelIndex,int,int)), 0758 this, SLOT(slotRowsInserted(QModelIndex,int,int)) ); 0759 0760 connect( place.model(), SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), 0761 this, SLOT(slotRowsAboutToBeRemoved(QModelIndex,int,int)) ); 0762 0763 connect( place.model(), SIGNAL(rowsRemoved(QModelIndex,int,int)), 0764 this, SLOT(slotRowsRemoved(QModelIndex,int,int)) ); 0765 0766 connect( place.model(), SIGNAL(dataChanged(QModelIndex,QModelIndex)), 0767 this, SLOT(slotDataChanged(QModelIndex,QModelIndex)) ); 0768 0769 if ( first <= last ) 0770 endInsertRows(); 0771 } 0772 0773 0774 void K3b::MetaItemModel::removeSubModel( QAbstractItemModel* model ) 0775 { 0776 // find the place index 0777 int row = 0; 0778 auto it = d->places.begin(); 0779 while ( it != d->places.end() && ( *it ).model() != model ) { 0780 ++it; 0781 ++row; 0782 } 0783 0784 Q_ASSERT( it != d->places.end() ); 0785 0786 // and simply remove the place from the list 0787 int end = row; 0788 0789 if ( it->flat ) { 0790 end += it->children.count() - 1; 0791 } 0792 0793 0794 // if the model is flat and has no root rows, there is nothing not notify 0795 if ( row <= end ) 0796 beginRemoveRows( QModelIndex(), row, end ); 0797 0798 d->places.erase( it ); 0799 d->updatePlaceRows(); 0800 0801 if ( row <= end ) 0802 endRemoveRows(); 0803 0804 // finally delete the model 0805 delete model; 0806 } 0807 0808 0809 void K3b::MetaItemModel::slotRowsAboutToBeInserted( const QModelIndex& parent, int start, int end ) 0810 { 0811 Place* place = d->placeForModel( qobject_cast<QAbstractItemModel*>( sender() ) ); 0812 Q_ASSERT( place != 0 ); 0813 0814 QModelIndex newParent; 0815 int targetStart = start, targetEnd = end; 0816 0817 // ---------- Preparing to insert ---------- 0818 if( parent.isValid() ) { 0819 // search node corresponding to 'index' 0820 newParent = mapFromSubModel( parent ); 0821 } 0822 else { 0823 if ( place->flat ) { 0824 targetStart += place->row; 0825 targetEnd += place->row; 0826 } 0827 else { 0828 newParent = createIndex( place->row, 0, place ); 0829 } 0830 } 0831 0832 beginInsertRows( newParent, targetStart, targetEnd ); 0833 0834 // ---------- Inserting ---------- 0835 Node* parentNode; 0836 if( parent.isValid() ) 0837 parentNode = place->createNodeForOriginalIndex( parent ); 0838 else 0839 parentNode = place; 0840 0841 // if the node doesn't have children yet (maybe not yet accessed) 0842 // or if it has less items than the start point of this insertion 0843 // simply load the child nodes 0844 if (start > parentNode->children.count()) { 0845 parentNode->updateChildren(); 0846 } 0847 else { 0848 // insert the newly created items in the children list 0849 for( int i = start; i <= end; ++i) { 0850 Node *newChild = new Node(); 0851 newChild->parent = parentNode; 0852 newChild->setPlace( parentNode->place() ); 0853 newChild->originalModelIndex = QModelIndex(); 0854 parentNode->children.insert(i, 1, newChild); 0855 } 0856 } 0857 if( place->flat ) { 0858 d->updatePlaceRows(); 0859 } 0860 } 0861 0862 0863 void K3b::MetaItemModel::slotRowsInserted( const QModelIndex& parent, int start, int end ) 0864 { 0865 Place* place = d->placeForModel( qobject_cast<QAbstractItemModel*>( sender() ) ); 0866 Q_ASSERT( place != 0 ); 0867 0868 Node* parentNode; 0869 if( parent.isValid() ) 0870 parentNode = place->createNodeForOriginalIndex( parent ); 0871 else 0872 parentNode = place; 0873 0874 // updating original indexes in newly created nodes 0875 for( int i = start; i <= end; ++i) { 0876 Node* child = parentNode->children.at( i ); 0877 Q_ASSERT( child != 0 ); 0878 child->originalModelIndex = parentNode->model()->index( i, 0, parent ); 0879 } 0880 0881 endInsertRows(); 0882 } 0883 0884 0885 void K3b::MetaItemModel::slotRowsAboutToBeRemoved( const QModelIndex& parent, int start, int end ) 0886 { 0887 //qDebug(); 0888 0889 Place* place = d->placeForModel( qobject_cast<QAbstractItemModel*>( sender() ) ); 0890 Q_ASSERT( place != 0 ); 0891 0892 QModelIndex newParent; 0893 int targetStart = start, targetEnd = end; 0894 0895 // --------------- Preparing for removing ---------------- 0896 if ( parent.isValid() ) { 0897 // search node corresponding to 'index' 0898 newParent = mapFromSubModel( parent ); 0899 } 0900 else { 0901 if ( place->flat ) { 0902 targetStart += place->row; 0903 targetEnd += place->row; 0904 } 0905 else 0906 newParent = createIndex( place->row, 0, place ); 0907 } 0908 0909 // --------------- Removing ------------------------------- 0910 beginRemoveRows( newParent, targetStart, targetEnd ); 0911 0912 Node* parentNode; 0913 0914 if ( parent.isValid() ) 0915 parentNode = place->createNodeForOriginalIndex( parent ); 0916 else 0917 parentNode = place; 0918 0919 // parentNode->children may be empty if one of 0920 // the previous remove ended up causing a reset 0921 if (!parentNode->children.isEmpty()) { 0922 // remove the contents of pointers 0923 for (int i = start; i <= end; ++i) 0924 delete parentNode->children[i]; 0925 0926 // and remove the pointers themselves 0927 parentNode->children.remove( start, (end - start + 1) ); 0928 } 0929 } 0930 0931 0932 void K3b::MetaItemModel::slotRowsRemoved( const QModelIndex&, int, int ) 0933 { 0934 Place* place = d->placeForModel( qobject_cast<QAbstractItemModel*>( sender() ) ); 0935 Q_ASSERT( place != 0 ); 0936 0937 if ( place->flat ) { 0938 d->updatePlaceRows(); 0939 } 0940 0941 endRemoveRows(); 0942 } 0943 0944 0945 void K3b::MetaItemModel::slotDataChanged( const QModelIndex& topLeft, const QModelIndex& bottomRight ) 0946 { 0947 //qDebug(); 0948 0949 Q_ASSERT( topLeft.isValid() ); 0950 Q_ASSERT( bottomRight.isValid() ); 0951 0952 emit dataChanged( mapFromSubModel( topLeft ), mapFromSubModel( bottomRight ) ); 0953 } 0954 0955 0956 void K3b::MetaItemModel::slotAboutToBeReset() 0957 { 0958 beginResetModel(); 0959 } 0960 0961 0962 void K3b::MetaItemModel::slotReset() 0963 { 0964 // clean out any cached nodes 0965 for (auto &place : d->places) { 0966 place.reset(); 0967 } 0968 d->updatePlaceRows(); 0969 0970 endResetModel(); 0971 } 0972 0973 #include "moc_k3bmetaitemmodel.cpp"