Warning, file /frameworks/kitemmodels/autotests/kdescendantsproxymodeltest.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 SPDX-FileCopyrightText: 2016 Sune Vuorela <sune@debian.org> 0003 0004 SPDX-License-Identifier: LGPL-2.1-or-later 0005 */ 0006 0007 #include "kdescendantsproxymodel.h" 0008 0009 #include <QAbstractListModel> 0010 #include <QSignalSpy> 0011 #include <QStandardItemModel> 0012 #include <QTest> 0013 0014 struct Node { 0015 ~Node() 0016 { 0017 qDeleteAll(children); 0018 } 0019 0020 QString label; 0021 Node *parent = nullptr; 0022 QList<Node *> children; 0023 int knownChildren = 0; 0024 }; 0025 0026 class SimpleObjectModel : public QAbstractListModel 0027 { 0028 Q_OBJECT 0029 public: 0030 explicit SimpleObjectModel(QObject *parent = nullptr, bool incremental = false); 0031 ~SimpleObjectModel() override; 0032 0033 QModelIndex index(int, int, const QModelIndex &parent = QModelIndex()) const override; 0034 QModelIndex parent(const QModelIndex &) const override; 0035 int rowCount(const QModelIndex &parent = QModelIndex()) const override; 0036 bool hasChildren(const QModelIndex &parent = QModelIndex()) const override; 0037 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; 0038 0039 bool insert(const QModelIndex &parent, int row, const QString &text); 0040 bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) override; 0041 bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationRow) override; 0042 0043 Node *getRootNode() const 0044 { 0045 return m_root; 0046 } 0047 0048 private: 0049 Node *m_root; 0050 // simulate a model that loads in new rows with fetchMore() 0051 bool m_incremental; 0052 }; 0053 0054 SimpleObjectModel::SimpleObjectModel(QObject *parent, bool incremental) 0055 : QAbstractListModel(parent) 0056 , m_incremental(incremental) 0057 { 0058 m_root = new Node; 0059 } 0060 0061 SimpleObjectModel::~SimpleObjectModel() 0062 { 0063 delete m_root; 0064 } 0065 0066 QModelIndex SimpleObjectModel::index(int row, int col, const QModelIndex &parent) const 0067 { 0068 Node *parentItem; 0069 if (!parent.isValid()) { 0070 parentItem = static_cast<Node *>(m_root); 0071 } else { 0072 parentItem = static_cast<Node *>(parent.internalPointer()); 0073 } 0074 0075 if (row < 0 || parentItem->children.size() <= row) { 0076 return QModelIndex(); 0077 } 0078 Node *childItem = parentItem->children[row]; 0079 0080 return createIndex(row, col, childItem); 0081 } 0082 0083 QModelIndex SimpleObjectModel::parent(const QModelIndex &index) const 0084 { 0085 Node *childItem = static_cast<Node *>(index.internalPointer()); 0086 if (!childItem) { 0087 return QModelIndex(); 0088 } 0089 0090 Node *parent = childItem->parent; 0091 Node *grandParent = parent->parent; 0092 0093 int childRow = 0; 0094 if (grandParent) { 0095 childRow = grandParent->children.indexOf(parent); 0096 } 0097 0098 if (parent == m_root) { 0099 return QModelIndex(); 0100 } 0101 return createIndex(childRow, 0, parent); 0102 } 0103 0104 int SimpleObjectModel::rowCount(const QModelIndex &index) const 0105 { 0106 Node *item = static_cast<Node *>(index.internalPointer()); 0107 if (!item) { 0108 item = m_root; 0109 } 0110 0111 if (m_incremental) { 0112 return item->knownChildren; 0113 } 0114 return item->children.count(); 0115 } 0116 0117 bool SimpleObjectModel::hasChildren(const QModelIndex &index) const 0118 { 0119 Node *item = static_cast<Node *>(index.internalPointer()); 0120 if (!item) { 0121 item = m_root; 0122 } 0123 0124 return !item->children.isEmpty(); 0125 } 0126 0127 QVariant SimpleObjectModel::data(const QModelIndex &index, int role) const 0128 { 0129 if (role != Qt::DisplayRole) { 0130 return QVariant(); 0131 } 0132 0133 Node *node = static_cast<Node *>(index.internalPointer()); 0134 if (!node) { 0135 return QVariant(); 0136 } 0137 return node->label; 0138 } 0139 0140 bool SimpleObjectModel::insert(const QModelIndex &index, int row, const QString &text) 0141 { 0142 if (row < 0) { 0143 return false; 0144 } 0145 0146 Node *parent = static_cast<Node *>(index.internalPointer()); 0147 if (!parent) { 0148 parent = m_root; 0149 } 0150 0151 if (row > parent->children.count()) { 0152 return false; 0153 } 0154 0155 beginInsertRows(index, row, row); 0156 Node *child = new Node; 0157 child->parent = parent; 0158 child->label = text; 0159 parent->children.insert(row, child); 0160 endInsertRows(); 0161 0162 return true; 0163 } 0164 0165 bool SimpleObjectModel::removeRows(int row, int count, const QModelIndex &index) 0166 { 0167 if (row < 0) { 0168 return false; 0169 } 0170 0171 Node *parent = static_cast<Node *>(index.internalPointer()); 0172 if (!parent) { 0173 parent = m_root; 0174 } 0175 0176 if (row >= parent->children.count()) { 0177 return false; 0178 } 0179 0180 beginRemoveRows(index, row, row); 0181 Node *child = parent->children.takeAt(row); 0182 delete child; 0183 endRemoveRows(); 0184 0185 return true; 0186 } 0187 0188 bool SimpleObjectModel::moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationRow) 0189 { 0190 Node *sourceNode = static_cast<Node *>(sourceParent.internalPointer()); 0191 if (!sourceNode) { 0192 sourceNode = m_root; 0193 } 0194 Node *destinationNode = static_cast<Node *>(destinationParent.internalPointer()); 0195 if (!destinationNode) { 0196 destinationNode = m_root; 0197 } 0198 0199 const int sourceLast = sourceRow + count - 1; 0200 0201 if (sourceNode != destinationNode) { 0202 if (count <= 0 || sourceRow < 0 || sourceRow >= sourceNode->children.count() || destinationRow < 0 0203 || destinationRow > destinationNode->children.count()) { 0204 return false; 0205 } 0206 0207 if (!beginMoveRows(sourceParent, sourceRow, sourceLast, destinationParent, destinationRow)) { 0208 return false; 0209 } 0210 0211 Node *child = sourceNode->children.takeAt(sourceRow); 0212 child->parent = destinationNode; 0213 destinationNode->children.insert(destinationRow, child); 0214 0215 endMoveRows(); 0216 return true; 0217 } 0218 0219 if (count <= 0 || sourceRow == destinationRow || sourceRow < 0 || sourceRow >= destinationNode->children.count() || destinationRow < 0 0220 || destinationRow > destinationNode->children.count() || count - destinationRow > destinationNode->children.count() - sourceRow) { 0221 return false; 0222 } 0223 0224 // beginMoveRows wants indexes before the source rows are removed from the old order 0225 if (!beginMoveRows(sourceParent, sourceRow, sourceLast, destinationParent, destinationRow)) { 0226 return false; 0227 } 0228 0229 if (sourceRow < destinationRow) { 0230 for (int i = count - 1; i >= 0; --i) { 0231 destinationNode->children.move(sourceRow + i, destinationRow - count + i); 0232 } 0233 } else { 0234 for (int i = 0; i < count; ++i) { 0235 destinationNode->children.move(sourceRow + i, destinationRow + i); 0236 } 0237 } 0238 0239 endMoveRows(); 0240 return true; 0241 } 0242 0243 class tst_KDescendantProxyModel : public QObject 0244 { 0245 Q_OBJECT 0246 QAbstractItemModel *createTree(const QString &prefix) 0247 { 0248 /* 0249 * |- parent1 0250 * | |- child1 0251 * | `- child2 0252 * `- parent2 0253 * |- child1 0254 * `- child2 0255 */ 0256 QStandardItemModel *model = new QStandardItemModel(this); 0257 for (int i = 0; i < 2; i++) { 0258 QStandardItem *item = new QStandardItem(); 0259 item->setData(QString(prefix + QString::number(i)), Qt::DisplayRole); 0260 for (int j = 0; j < 2; j++) { 0261 QStandardItem *child = new QStandardItem(); 0262 child->setData(QString(prefix + QString::number(i) + "-" + QString::number(j)), Qt::DisplayRole); 0263 item->appendRow(child); 0264 } 0265 model->appendRow(item); 0266 } 0267 return model; 0268 } 0269 0270 private Q_SLOTS: 0271 void testResetModelContent(); 0272 void testChangeSeparator(); 0273 void testChangeInvisibleSeparator(); 0274 void testRemoveSeparator(); 0275 0276 void testResetCollapsedModelContent(); 0277 void testInsertInCollapsedModel(); 0278 void testRemoveInCollapsedModel(); 0279 void testMoveInsideCollapsed(); 0280 void testExpandInsideCollapsed(); 0281 void testEmptyModel(); 0282 void testEmptyChild(); 0283 }; 0284 0285 /// Tests that replacing the source model results in data getting changed 0286 void tst_KDescendantProxyModel::testResetModelContent() 0287 { 0288 auto model1 = createTree("FirstModel"); 0289 KDescendantsProxyModel proxy; 0290 proxy.setSourceModel(model1); 0291 QCOMPARE(proxy.rowCount(), 6); 0292 0293 { 0294 QStringList results = QStringList() << "FirstModel0" 0295 << "FirstModel0-0" 0296 << "FirstModel0-1" 0297 << "FirstModel1" 0298 << "FirstModel1-0" 0299 << "FirstModel1-1"; 0300 QCOMPARE(proxy.rowCount(), results.count()); 0301 for (int i = 0; i < proxy.rowCount(); i++) { 0302 QCOMPARE(proxy.index(i, 0).data(Qt::DisplayRole).toString(), results[i]); 0303 } 0304 } 0305 auto model2 = createTree("SecondModel"); 0306 { 0307 proxy.setSourceModel(model2); 0308 QStringList results = QStringList() << "SecondModel0" 0309 << "SecondModel0-0" 0310 << "SecondModel0-1" 0311 << "SecondModel1" 0312 << "SecondModel1-0" 0313 << "SecondModel1-1"; 0314 QCOMPARE(proxy.rowCount(), results.count()); 0315 for (int i = 0; i < proxy.rowCount(); i++) { 0316 QCOMPARE(proxy.index(i, 0).data(Qt::DisplayRole).toString(), results[i]); 0317 } 0318 } 0319 0320 delete model2; 0321 delete model1; 0322 } 0323 0324 /// tests that change separator works, as well as emits the relevant data changed signals 0325 void tst_KDescendantProxyModel::testChangeSeparator() 0326 { 0327 auto model1 = createTree("FirstModel"); 0328 KDescendantsProxyModel proxy; 0329 proxy.setSourceModel(model1); 0330 proxy.setDisplayAncestorData(true); 0331 QSignalSpy dataChangedSpy(&proxy, &QAbstractItemModel::dataChanged); 0332 QCOMPARE(proxy.rowCount(), 6); 0333 { 0334 QStringList results = QStringList() << "FirstModel0" 0335 << "FirstModel0 / FirstModel0-0" 0336 << "FirstModel0 / FirstModel0-1" 0337 << "FirstModel1" 0338 << "FirstModel1 / FirstModel1-0" 0339 << "FirstModel1 / FirstModel1-1"; 0340 QCOMPARE(proxy.rowCount(), results.count()); 0341 for (int i = 0; i < proxy.rowCount(); i++) { 0342 QCOMPARE(proxy.index(i, 0).data(Qt::DisplayRole).toString(), results[i]); 0343 } 0344 } 0345 proxy.setAncestorSeparator("LOL"); 0346 QCOMPARE(dataChangedSpy.count(), 1); 0347 { 0348 QStringList results = QStringList() << "FirstModel0" 0349 << "FirstModel0LOLFirstModel0-0" 0350 << "FirstModel0LOLFirstModel0-1" 0351 << "FirstModel1" 0352 << "FirstModel1LOLFirstModel1-0" 0353 << "FirstModel1LOLFirstModel1-1"; 0354 QCOMPARE(proxy.rowCount(), results.count()); 0355 for (int i = 0; i < proxy.rowCount(); i++) { 0356 QCOMPARE(proxy.index(i, 0).data(Qt::DisplayRole).toString(), results[i]); 0357 } 0358 } 0359 0360 delete model1; 0361 } 0362 0363 /// tests that change separator that is not shown does not change the content and does not 0364 /// emit data changed signals, since the data isn't changed 0365 void tst_KDescendantProxyModel::testChangeInvisibleSeparator() 0366 { 0367 auto model1 = createTree("FirstModel"); 0368 KDescendantsProxyModel proxy; 0369 proxy.setSourceModel(model1); 0370 QSignalSpy dataChangedSpy(&proxy, &QAbstractItemModel::dataChanged); 0371 QCOMPARE(proxy.rowCount(), 6); 0372 { 0373 QStringList results = QStringList() << "FirstModel0" 0374 << "FirstModel0-0" 0375 << "FirstModel0-1" 0376 << "FirstModel1" 0377 << "FirstModel1-0" 0378 << "FirstModel1-1"; 0379 QCOMPARE(proxy.rowCount(), results.count()); 0380 for (int i = 0; i < proxy.rowCount(); i++) { 0381 QCOMPARE(proxy.index(i, 0).data(Qt::DisplayRole).toString(), results[i]); 0382 } 0383 } 0384 proxy.setAncestorSeparator("LOL"); 0385 QCOMPARE(dataChangedSpy.count(), 0); 0386 { 0387 QStringList results = QStringList() << "FirstModel0" 0388 << "FirstModel0-0" 0389 << "FirstModel0-1" 0390 << "FirstModel1" 0391 << "FirstModel1-0" 0392 << "FirstModel1-1"; 0393 QCOMPARE(proxy.rowCount(), results.count()); 0394 for (int i = 0; i < proxy.rowCount(); i++) { 0395 QCOMPARE(proxy.index(i, 0).data(Qt::DisplayRole).toString(), results[i]); 0396 } 0397 } 0398 0399 delete model1; 0400 } 0401 0402 /// tests that data is properly updated when separator is removed/hidden 0403 /// and data changed signal is emitted 0404 void tst_KDescendantProxyModel::testRemoveSeparator() 0405 { 0406 auto model1 = createTree("FirstModel"); 0407 KDescendantsProxyModel proxy; 0408 proxy.setSourceModel(model1); 0409 QSignalSpy dataChangedSpy(&proxy, &QAbstractItemModel::dataChanged); 0410 proxy.setDisplayAncestorData(true); 0411 QCOMPARE(dataChangedSpy.count(), 1); 0412 dataChangedSpy.clear(); 0413 QCOMPARE(proxy.rowCount(), 6); 0414 { 0415 QStringList results = QStringList() << "FirstModel0" 0416 << "FirstModel0 / FirstModel0-0" 0417 << "FirstModel0 / FirstModel0-1" 0418 << "FirstModel1" 0419 << "FirstModel1 / FirstModel1-0" 0420 << "FirstModel1 / FirstModel1-1"; 0421 QCOMPARE(proxy.rowCount(), results.count()); 0422 for (int i = 0; i < proxy.rowCount(); i++) { 0423 QCOMPARE(proxy.index(i, 0).data(Qt::DisplayRole).toString(), results[i]); 0424 } 0425 } 0426 proxy.setDisplayAncestorData(false); 0427 QCOMPARE(dataChangedSpy.count(), 1); 0428 { 0429 QStringList results = QStringList() << "FirstModel0" 0430 << "FirstModel0-0" 0431 << "FirstModel0-1" 0432 << "FirstModel1" 0433 << "FirstModel1-0" 0434 << "FirstModel1-1"; 0435 QCOMPARE(proxy.rowCount(), results.count()); 0436 for (int i = 0; i < proxy.rowCount(); i++) { 0437 QCOMPARE(proxy.index(i, 0).data(Qt::DisplayRole).toString(), results[i]); 0438 } 0439 } 0440 } 0441 0442 void tst_KDescendantProxyModel::testResetCollapsedModelContent() 0443 { 0444 auto model1 = createTree("FirstModel"); 0445 KDescendantsProxyModel proxy; 0446 proxy.setExpandsByDefault(false); 0447 proxy.setSourceModel(model1); 0448 QCOMPARE(proxy.rowCount(), 2); 0449 0450 { 0451 QStringList results = QStringList() << "FirstModel0" 0452 << "FirstModel1"; 0453 QCOMPARE(proxy.rowCount(), results.count()); 0454 for (int i = 0; i < proxy.rowCount(); i++) { 0455 QCOMPARE(proxy.index(i, 0).data(Qt::DisplayRole).toString(), results[i]); 0456 } 0457 } 0458 { 0459 QModelIndex idx = model1->index(0, 0); 0460 proxy.expandSourceIndex(idx); 0461 QStringList results = QStringList() << "FirstModel0" 0462 << "FirstModel0-0" 0463 << "FirstModel0-1" 0464 << "FirstModel1"; 0465 QCOMPARE(proxy.rowCount(), results.count()); 0466 for (int i = 0; i < proxy.rowCount(); i++) { 0467 QCOMPARE(proxy.index(i, 0).data(Qt::DisplayRole).toString(), results[i]); 0468 } 0469 } 0470 { 0471 QModelIndex idx = model1->index(1, 0); 0472 proxy.expandSourceIndex(idx); 0473 QStringList results = QStringList() << "FirstModel0" 0474 << "FirstModel0-0" 0475 << "FirstModel0-1" 0476 << "FirstModel1" 0477 << "FirstModel1-0" 0478 << "FirstModel1-1"; 0479 QCOMPARE(proxy.rowCount(), results.count()); 0480 for (int i = 0; i < proxy.rowCount(); i++) { 0481 QCOMPARE(proxy.index(i, 0).data(Qt::DisplayRole).toString(), results[i]); 0482 } 0483 } 0484 0485 auto model2 = createTree("SecondModel"); 0486 { 0487 proxy.setSourceModel(model2); 0488 QModelIndex idx = model2->index(0, 0); 0489 proxy.expandSourceIndex(idx); 0490 idx = model2->index(1, 0); 0491 proxy.expandSourceIndex(idx); 0492 QStringList results = QStringList() << "SecondModel0" 0493 << "SecondModel0-0" 0494 << "SecondModel0-1" 0495 << "SecondModel1" 0496 << "SecondModel1-0" 0497 << "SecondModel1-1"; 0498 QCOMPARE(proxy.rowCount(), results.count()); 0499 for (int i = 0; i < proxy.rowCount(); i++) { 0500 QCOMPARE(proxy.index(i, 0).data(Qt::DisplayRole).toString(), results[i]); 0501 } 0502 } 0503 0504 delete model2; 0505 delete model1; 0506 } 0507 0508 void tst_KDescendantProxyModel::testInsertInCollapsedModel() 0509 { 0510 QStandardItemModel *model1 = static_cast<QStandardItemModel *>(createTree("Model")); 0511 KDescendantsProxyModel proxy; 0512 proxy.setExpandsByDefault(false); 0513 proxy.setSourceModel(model1); 0514 QCOMPARE(proxy.rowCount(), 2); 0515 0516 QSignalSpy insertSpy(&proxy, &QAbstractItemModel::rowsInserted); 0517 QCOMPARE(insertSpy.count(), 0); 0518 0519 QStandardItem *parent = model1->item(0, 0); 0520 QVERIFY(parent); 0521 0522 QStandardItem *child = new QStandardItem(); 0523 child->setData(QString(QStringLiteral("Model") + QString::number(0) + "-" + QString::number(2)), Qt::DisplayRole); 0524 parent->appendRow(child); 0525 0526 // Adding a child to the collapsed parent doesn't have an effect to the proxy 0527 QCOMPARE(proxy.rowCount(), 2); 0528 QCOMPARE(insertSpy.count(), 0); 0529 0530 // If we expand everything inserted should be here 0531 QModelIndex idx = model1->index(0, 0); 0532 proxy.expandSourceIndex(idx); 0533 0534 QCOMPARE(proxy.rowCount(), 5); 0535 QCOMPARE(insertSpy.count(), 1); 0536 0537 QCOMPARE(proxy.index(3, 0).data(Qt::DisplayRole).toString(), QStringLiteral("Model0-2")); 0538 0539 // Add another child to the expanded node, now the proxy is affected immediately 0540 child = new QStandardItem(); 0541 child->setData(QString(QStringLiteral("Model") + QString::number(0) + "-" + QString::number(3)), Qt::DisplayRole); 0542 parent->appendRow(child); 0543 0544 QCOMPARE(proxy.rowCount(), 6); 0545 QCOMPARE(insertSpy.count(), 2); 0546 } 0547 0548 void tst_KDescendantProxyModel::testRemoveInCollapsedModel() 0549 { 0550 QStandardItemModel *model1 = static_cast<QStandardItemModel *>(createTree("Model")); 0551 KDescendantsProxyModel proxy; 0552 proxy.setExpandsByDefault(false); 0553 proxy.setSourceModel(model1); 0554 QCOMPARE(proxy.rowCount(), 2); 0555 0556 QSignalSpy removeSpy(&proxy, &QAbstractItemModel::rowsRemoved); 0557 QCOMPARE(removeSpy.count(), 0); 0558 0559 QStandardItem *parent = model1->item(0, 0); 0560 QVERIFY(parent); 0561 0562 parent->removeRow(0); 0563 0564 // Adding a child to the collapsed parent doesn't have an effect to the proxy 0565 QCOMPARE(proxy.rowCount(), 2); 0566 QCOMPARE(removeSpy.count(), 0); 0567 0568 // If we expand everything inserted should be here 0569 QModelIndex idx = model1->index(0, 0); 0570 proxy.expandSourceIndex(idx); 0571 0572 QCOMPARE(proxy.rowCount(), 3); 0573 0574 QCOMPARE(proxy.index(1, 0).data(Qt::DisplayRole).toString(), QStringLiteral("Model0-1")); 0575 parent->removeRow(0); 0576 0577 QCOMPARE(proxy.rowCount(), 2); 0578 QCOMPARE(removeSpy.count(), 1); 0579 0580 idx = model1->index(1, 0); 0581 proxy.expandSourceIndex(idx); 0582 QCOMPARE(proxy.rowCount(), 4); 0583 } 0584 0585 void tst_KDescendantProxyModel::testMoveInsideCollapsed() 0586 { 0587 SimpleObjectModel *model = new SimpleObjectModel(this); 0588 model->insert(QModelIndex(), 0, QStringLiteral("Model0")); 0589 model->insert(QModelIndex(), 1, QStringLiteral("Model1")); 0590 model->insert(QModelIndex(), 2, QStringLiteral("Model2")); 0591 0592 model->insert(model->index(0, 0, QModelIndex()), 0, QStringLiteral("Model0-0")); 0593 model->insert(model->index(1, 0, QModelIndex()), 0, QStringLiteral("Model1-0")); 0594 0595 QCOMPARE(model->rowCount(), 3); 0596 0597 KDescendantsProxyModel proxy; 0598 proxy.setExpandsByDefault(false); 0599 proxy.setSourceModel(model); 0600 QCOMPARE(proxy.rowCount(), 3); 0601 0602 QSignalSpy removeSpy(&proxy, &QAbstractItemModel::rowsRemoved); 0603 QCOMPARE(removeSpy.count(), 0); 0604 QSignalSpy insertSpy(&proxy, &QAbstractItemModel::rowsInserted); 0605 QCOMPARE(insertSpy.count(), 0); 0606 0607 model->moveRows(QModelIndex(), 2, 1, model->index(0, 0, QModelIndex()), 1); 0608 0609 QCOMPARE(removeSpy.count(), 1); 0610 0611 QVERIFY(!removeSpy.first()[0].value<QModelIndex>().isValid()); 0612 QCOMPARE(removeSpy.first()[1].toInt(), 2); 0613 QCOMPARE(removeSpy.first()[2].toInt(), 2); 0614 0615 QCOMPARE(model->rowCount(), 2); 0616 QCOMPARE(proxy.rowCount(), 2); 0617 0618 model->moveRows(model->index(0, 0, QModelIndex()), 0, 1, QModelIndex(), 1); 0619 QCOMPARE(insertSpy.count(), 1); 0620 QCOMPARE(model->rowCount(), 3); 0621 QCOMPARE(proxy.rowCount(), 3); 0622 0623 QVERIFY(!insertSpy.first()[0].value<QModelIndex>().isValid()); 0624 QCOMPARE(insertSpy.first()[1].toInt(), 1); 0625 QCOMPARE(insertSpy.first()[2].toInt(), 1); 0626 0627 QModelIndex idx = model->index(0, 0); 0628 proxy.expandSourceIndex(idx); 0629 idx = model->index(1, 0); 0630 proxy.expandSourceIndex(idx); 0631 idx = model->index(2, 0); 0632 proxy.expandSourceIndex(idx); 0633 QStringList results = QStringList() << "Model0" 0634 << "Model2" 0635 << "Model0-0" 0636 << "Model1" 0637 << "Model1-0"; 0638 QCOMPARE(proxy.rowCount(), results.count()); 0639 for (int i = 0; i < proxy.rowCount(); i++) { 0640 QCOMPARE(proxy.index(i, 0).data(Qt::DisplayRole).toString(), results[i]); 0641 } 0642 } 0643 0644 void tst_KDescendantProxyModel::testExpandInsideCollapsed() 0645 { 0646 SimpleObjectModel *model = new SimpleObjectModel(this); 0647 model->insert(QModelIndex(), 0, QStringLiteral("Model0")); 0648 model->insert(QModelIndex(), 1, QStringLiteral("Model1")); 0649 model->insert(QModelIndex(), 2, QStringLiteral("Model2")); 0650 0651 auto parentIndex = model->index(0, 0, QModelIndex()); 0652 model->insert(parentIndex, 0, QStringLiteral("Model0-0")); 0653 auto childIndex = model->index(0, 0, parentIndex); 0654 model->insert(childIndex, 0, QStringLiteral("Model0-0-0")); 0655 0656 QCOMPARE(model->rowCount(), 3); 0657 0658 KDescendantsProxyModel proxy; 0659 proxy.setExpandsByDefault(false); 0660 proxy.setSourceModel(model); 0661 QCOMPARE(proxy.rowCount(), 3); 0662 0663 proxy.expandSourceIndex(childIndex); 0664 QVERIFY(proxy.isSourceIndexExpanded(childIndex)); 0665 QVERIFY(!proxy.isSourceIndexExpanded(parentIndex)); 0666 QCOMPARE(proxy.rowCount(), 3); 0667 proxy.expandSourceIndex(parentIndex); 0668 QCOMPARE(proxy.rowCount(), 5); 0669 } 0670 0671 void tst_KDescendantProxyModel::testEmptyModel() 0672 { 0673 SimpleObjectModel *model = new SimpleObjectModel(this, true); 0674 model->insert(QModelIndex(), 0, QStringLiteral("Row0")); 0675 model->insert(QModelIndex(), 0, QStringLiteral("Row1")); 0676 KDescendantsProxyModel proxy; 0677 proxy.setSourceModel(model); 0678 QCOMPARE(proxy.rowCount(), 0); 0679 } 0680 0681 void tst_KDescendantProxyModel::testEmptyChild() 0682 { 0683 SimpleObjectModel *model = new SimpleObjectModel(this, true); 0684 model->insert(QModelIndex(), 0, QStringLiteral("Row0")); 0685 auto parentIndex = model->index(0, 0, QModelIndex()); 0686 model->insert(parentIndex, 0, QStringLiteral("Row0-0")); 0687 model->insert(parentIndex, 0, QStringLiteral("Row0-1")); 0688 model->insert(QModelIndex(), 0, QStringLiteral("Row1")); 0689 0690 // simulate that the row count for the root node is known because it was listed 0691 model->getRootNode()->knownChildren = 2; 0692 0693 KDescendantsProxyModel proxy; 0694 proxy.setSourceModel(model); 0695 proxy.setExpandsByDefault(false); 0696 QCOMPARE(proxy.rowCount(), 2); 0697 0698 // remove the row that has children but a rowCount of 0 0699 model->removeRows(0, 1, QModelIndex()); 0700 QCOMPARE(proxy.rowCount(), 1); 0701 } 0702 0703 QTEST_MAIN(tst_KDescendantProxyModel) 0704 0705 #include "kdescendantsproxymodeltest.moc"