Warning, file /libraries/kquickitemviews/tests/modelviewtester.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) 2017 by Emmanuel Lepage Vallee * 0003 * Author : Emmanuel Lepage Vallee <emmanuel.lepage@kde.org> * 0004 * * 0005 * This program is free software; you can redistribute it and/or modify * 0006 * it under the terms of the GNU General Public License as published by * 0007 * the Free Software Foundation; either version 3 of the License, or * 0008 * (at your option) any later version. * 0009 * * 0010 * This program is distributed in the hope that it will be useful, * 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0013 * GNU General Public License for more details. * 0014 * * 0015 * You should have received a copy of the GNU General Public License * 0016 * along with this program. If not, see <http://www.gnu.org/licenses/>. * 0017 **************************************************************************/ 0018 #include "modelviewtester.h" 0019 0020 #include <QtCore/QDebug> 0021 #include <QMetaObject> 0022 #include <QMetaMethod> 0023 0024 #include <functional> 0025 0026 #define DO(slot) steps << QString(#slot) ; 0027 0028 struct ModelViewTesterItem 0029 { 0030 ModelViewTesterItem() {} 0031 ModelViewTesterItem(ModelViewTesterItem* p, const QHash<int, QVariant>& vals, int i = -1); 0032 0033 int m_Index {0};; 0034 ModelViewTesterItem* m_pParent {nullptr}; 0035 QHash<int, QVariant> m_hValues; 0036 QVector<ModelViewTesterItem*> m_lChildren; 0037 }; 0038 0039 ModelViewTester::ModelViewTester(QObject* parent) : QAbstractItemModel(parent) 0040 { 0041 m_pRoot = new ModelViewTesterItem; 0042 0043 // Append 0044 DO(appendSimpleRoot); 0045 DO(appendSimpleRoot); 0046 DO(appendSimpleRoot); 0047 DO(appendSimpleRoot); 0048 DO(appendSimpleRoot); 0049 0050 DO(appendRootChildren); 0051 DO(appendRootChildren); 0052 DO(appendRootChildren); 0053 DO(appendRootChildren); 0054 0055 // Prepend 0056 DO(prependSimpleRoot); 0057 0058 // Move 0059 DO(moveRootToFront); 0060 DO(moveChildByOne); 0061 DO(moveChildByParent); 0062 DO(moveToGrandChildren); 0063 //TODO moveFirst 0064 //TODO moveLast 0065 0066 // Insert 0067 DO(insertRoot); 0068 DO(insertFirst); 0069 DO(insertChild); 0070 0071 // Remove 0072 DO(removeRoot); 0073 //TODO removeMiddle 0074 //TODO removeLastChild 0075 //TODO removeWithChildren 0076 DO(resetModel); 0077 0078 // Larger tree 0079 DO(largeFrontTree); 0080 DO(removeLargeTree); 0081 DO(removeLargeTree2); 0082 DO(largeFrontTree2); 0083 DO(removeLargeTree2); 0084 DO(removeLargeTree3); 0085 //TODO move multiple 0086 0087 // Larger move (with out of view) 0088 0089 } 0090 0091 ModelViewTester::~ModelViewTester() 0092 { 0093 0094 } 0095 0096 void ModelViewTester::run() { 0097 m_pTimer->setInterval(100); 0098 0099 QObject::connect(m_pTimer, &QTimer::timeout, this, [this]() { 0100 int methodIndex = metaObject()->indexOfMethod((steps[count]+"()").toLatin1()); 0101 metaObject()->method(methodIndex).invoke(this, Qt::QueuedConnection); 0102 count++; 0103 if (count == steps.size()) { 0104 m_pTimer->stop(); 0105 count = 0; 0106 } 0107 }); 0108 0109 m_pTimer->start(); 0110 } 0111 0112 bool ModelViewTester::setData( const QModelIndex& index, const QVariant &value, int role ) 0113 { 0114 Q_UNUSED(index) 0115 Q_UNUSED(value) 0116 Q_UNUSED(role) 0117 return false; 0118 } 0119 0120 QVariant ModelViewTester::data( const QModelIndex& index, int role ) const 0121 { 0122 if (!index.isValid()) 0123 return {}; 0124 0125 auto item = static_cast<ModelViewTesterItem*>(index.internalPointer()); 0126 0127 return item->m_hValues[role]; 0128 } 0129 0130 int ModelViewTester::rowCount( const QModelIndex& parent) const 0131 { 0132 if (!parent.isValid()) 0133 return m_pRoot->m_lChildren.size(); 0134 0135 auto item = static_cast<ModelViewTesterItem*>(parent.internalPointer()); 0136 0137 return item->m_lChildren.size(); 0138 } 0139 0140 int ModelViewTester::columnCount( const QModelIndex& parent ) const 0141 { 0142 return parent.isValid() ? 0 : 1; //FIXME not really true 0143 } 0144 0145 QModelIndex ModelViewTester::parent( const QModelIndex& index ) const 0146 { 0147 if (!index.isValid()) 0148 return {}; 0149 0150 auto item = static_cast<ModelViewTesterItem*>(index.internalPointer()); 0151 0152 Q_ASSERT(item != m_pRoot); 0153 0154 if (item->m_pParent == m_pRoot) 0155 return {}; 0156 0157 return createIndex(item->m_pParent->m_Index, 0, item->m_pParent); 0158 } 0159 0160 QModelIndex ModelViewTester::index( int row, int column, const QModelIndex& parent ) const 0161 { 0162 auto parItem = parent.isValid() ? 0163 static_cast<ModelViewTesterItem*>(parent.internalPointer()): m_pRoot; 0164 0165 if (column || row >= parItem->m_lChildren.size() || row < 0) 0166 return {}; 0167 0168 return createIndex(row, column, parItem->m_lChildren[row]); 0169 } 0170 0171 QMimeData* ModelViewTester::mimeData( const QModelIndexList &indexes) const 0172 { 0173 Q_UNUSED(indexes) 0174 return nullptr; //TODO 0175 } 0176 0177 bool ModelViewTester::dropMimeData( const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) 0178 { 0179 Q_UNUSED(data) 0180 Q_UNUSED(action) 0181 Q_UNUSED(row) 0182 Q_UNUSED(column) 0183 Q_UNUSED(parent) 0184 return false; //TODO 0185 } 0186 0187 QHash<int,QByteArray> ModelViewTester::roleNames() const 0188 { 0189 return { 0190 {Qt::DisplayRole, "display"}, 0191 {Qt::UserRole, "offset"} 0192 }; 0193 } 0194 0195 // Qt::ItemFlags ModelViewTester::flags( const QModelIndex& index) const 0196 0197 ModelViewTesterItem::ModelViewTesterItem(ModelViewTesterItem* p, const QHash<int, QVariant>& vals, int i) : 0198 m_pParent(p), m_hValues(vals) 0199 { 0200 if (i == -1) { 0201 m_Index = p->m_lChildren.size(); 0202 p->m_lChildren << this; 0203 } 0204 else { 0205 m_Index = i; 0206 0207 p->m_lChildren.insert(i, this); 0208 for (int j=i+1; j < p->m_lChildren.size(); j++) 0209 p->m_lChildren[j]->m_Index++; 0210 } 0211 } 0212 0213 void ModelViewTester::prependSimpleRoot() 0214 { 0215 beginInsertRows({}, 0, 0); 0216 0217 QHash<int, QVariant> vals = { 0218 {Qt::DisplayRole, "prep root 1"}, 0219 {Qt::UserRole, 0} 0220 }; 0221 0222 new ModelViewTesterItem(m_pRoot, vals, 0); 0223 0224 endInsertRows(); 0225 beginInsertRows({}, 1, 1); 0226 0227 vals = { 0228 {Qt::DisplayRole, "prep root 2"}, 0229 {Qt::UserRole, 0} 0230 }; 0231 0232 new ModelViewTesterItem(m_pRoot, vals, 1); 0233 0234 endInsertRows(); 0235 beginInsertRows({}, 0, 0); 0236 0237 vals = { 0238 {Qt::DisplayRole, "prep root 0"}, 0239 {Qt::UserRole, 0} 0240 }; 0241 0242 new ModelViewTesterItem(m_pRoot, vals, 0); 0243 0244 endInsertRows(); 0245 } 0246 0247 void ModelViewTester::appendSimpleRoot() 0248 { 0249 beginInsertRows({}, m_pRoot->m_lChildren.size(), m_pRoot->m_lChildren.size()); 0250 0251 QHash<int, QVariant> vals = { 0252 {Qt::DisplayRole, "root "+QString::number(m_pRoot->m_lChildren.size())}, 0253 {Qt::UserRole, 0} 0254 }; 0255 0256 new ModelViewTesterItem(m_pRoot, vals); 0257 0258 endInsertRows(); 0259 } 0260 0261 void ModelViewTester::appendRootChildren() 0262 { 0263 auto par = m_pRoot->m_lChildren[1]; 0264 beginInsertRows(index(1,0), par->m_lChildren.size(), par->m_lChildren.size()); 0265 0266 QHash<int, QVariant> vals = { 0267 {Qt::DisplayRole, "child "+QString::number(par->m_lChildren.size())}, 0268 {Qt::UserRole, 10} 0269 }; 0270 0271 new ModelViewTesterItem(par, vals); 0272 0273 endInsertRows(); 0274 } 0275 0276 void ModelViewTester::moveRootToFront() 0277 { 0278 beginMoveRows({}, 2,2, {}, 0); 0279 0280 auto elem = m_pRoot->m_lChildren[2]; 0281 0282 m_pRoot->m_lChildren.remove(2); 0283 m_pRoot->m_lChildren.insert(0, elem); 0284 0285 for (int i =0; i < m_pRoot->m_lChildren.size(); i++) 0286 m_pRoot->m_lChildren[i]->m_Index = i; 0287 0288 endMoveRows(); 0289 } 0290 0291 void ModelViewTester::moveChildByOne() 0292 { 0293 auto parentIdx = index(4,0); 0294 0295 beginMoveRows(parentIdx, 2,2, parentIdx, 1); 0296 0297 auto elem = m_pRoot->m_lChildren[4]->m_lChildren[2]; 0298 0299 m_pRoot->m_lChildren[4]->m_lChildren.remove(2); 0300 m_pRoot->m_lChildren[4]->m_lChildren.insert(0, elem); 0301 0302 for (int i =0; i < m_pRoot->m_lChildren[4]->m_lChildren.size(); i++) 0303 m_pRoot->m_lChildren[4]->m_lChildren[i]->m_Index = i; 0304 0305 endMoveRows(); 0306 } 0307 0308 void ModelViewTester::moveChildByParent() 0309 { 0310 auto elem = m_pRoot->m_lChildren[4]->m_lChildren[3]; 0311 0312 auto oldParentIdx = index(4,0); 0313 auto newParentIdx = index(m_pRoot->m_lChildren.size()-1,0); 0314 0315 beginMoveRows(oldParentIdx, 3,3, newParentIdx, 0); 0316 0317 m_pRoot->m_lChildren[4]->m_lChildren.remove(3); 0318 m_pRoot->m_lChildren[m_pRoot->m_lChildren.size()-1]->m_lChildren.insert(0, elem); 0319 0320 elem->m_Index = 0; 0321 endMoveRows(); 0322 } 0323 0324 void ModelViewTester::moveToGrandChildren() 0325 { 0326 auto elem1 = m_pRoot->m_lChildren[1]; 0327 auto elem2 = m_pRoot->m_lChildren[2]; 0328 auto newPar = m_pRoot->m_lChildren[4]->m_lChildren[2]; 0329 auto newParentIdx = createIndex(newPar->m_Index, 0, newPar); 0330 0331 beginMoveRows({}, 1,2, newParentIdx, 0); 0332 0333 elem1->m_pParent = newPar; 0334 elem2->m_pParent = newPar; 0335 0336 elem1->m_hValues = { 0337 {Qt::DisplayRole, elem1->m_hValues[0].toString()+" gc"}, 0338 {Qt::UserRole, 20} 0339 }; 0340 elem2->m_hValues = { 0341 {Qt::DisplayRole, elem2->m_hValues[0].toString()+" gc"}, 0342 {Qt::UserRole, 20} 0343 }; 0344 0345 m_pRoot->m_lChildren.remove(1); 0346 m_pRoot->m_lChildren.remove(1); 0347 0348 newPar->m_lChildren << elem1 << elem2; 0349 0350 for (int i =0; i < newPar->m_lChildren.size(); i++) 0351 newPar->m_lChildren[i]->m_Index = i; 0352 0353 for (int i =0; i < m_pRoot->m_lChildren.size(); i++) 0354 m_pRoot->m_lChildren[i]->m_Index = i; 0355 0356 endMoveRows(); 0357 0358 Q_EMIT dataChanged(index(0, 0, newParentIdx), index(1, 0, newParentIdx)); 0359 } 0360 0361 0362 void ModelViewTester::insertRoot() 0363 { 0364 beginInsertRows({}, 1, 1); 0365 0366 QHash<int, QVariant> vals = { 0367 {Qt::DisplayRole, "inserted root 1"}, 0368 {Qt::UserRole, 0} 0369 }; 0370 0371 new ModelViewTesterItem(m_pRoot, vals, 1); 0372 0373 endInsertRows(); 0374 } 0375 0376 void ModelViewTester::insertFirst() 0377 { 0378 beginInsertRows({}, 0, 0); 0379 0380 QHash<int, QVariant> vals = { 0381 {Qt::DisplayRole, "inserted root 0"}, 0382 {Qt::UserRole, 0} 0383 }; 0384 0385 new ModelViewTesterItem(m_pRoot, vals, 0); 0386 0387 endInsertRows(); 0388 } 0389 0390 void ModelViewTester::insertChild() 0391 { 0392 auto newPar = m_pRoot->m_lChildren[4]; 0393 auto parIdx = createIndex(4, 0, newPar); 0394 0395 Q_ASSERT(parIdx.isValid()); 0396 0397 beginInsertRows(parIdx, 0, 0); 0398 0399 QHash<int, QVariant> vals = { 0400 {Qt::DisplayRole, "inserted child 0"}, 0401 {Qt::UserRole, 0} 0402 }; 0403 0404 new ModelViewTesterItem(newPar, vals, 0); 0405 0406 endInsertRows(); 0407 } 0408 0409 void ModelViewTester::removeRoot() 0410 { 0411 beginRemoveRows({}, 0, 0); 0412 0413 QHash<int, QVariant> vals = { 0414 {Qt::DisplayRole, "inserted root 0"}, 0415 {Qt::UserRole, 0} 0416 }; 0417 0418 m_pRoot->m_lChildren.remove(1); 0419 0420 for (int i =0; i < m_pRoot->m_lChildren.size(); i++) 0421 m_pRoot->m_lChildren[i]->m_Index = i; 0422 0423 endRemoveRows(); 0424 } 0425 0426 void ModelViewTester::resetModel() 0427 { 0428 beginResetModel(); 0429 qDeleteAll(m_pRoot->m_lChildren); 0430 m_pRoot->m_lChildren.clear(); 0431 endResetModel(); 0432 } 0433 0434 void ModelViewTester::largeFrontTree() 0435 { 0436 for (int i = 0; i < 100; i++) { 0437 beginInsertRows({}, 0, 0); 0438 0439 QHash<int, QVariant> vals = { 0440 {Qt::DisplayRole, "inserted root 1"}, 0441 {Qt::UserRole, 0} 0442 }; 0443 0444 auto itm = new ModelViewTesterItem(m_pRoot, vals, 0); 0445 0446 endInsertRows(); 0447 0448 auto p = createIndex(0, 0, itm); 0449 0450 beginInsertRows(p, 0, 4); 0451 for (int j = 0; j < 5; j++) { 0452 QHash<int, QVariant> vals2 = { 0453 {Qt::DisplayRole, "children "+QString::number(j)}, 0454 {Qt::UserRole, 0} 0455 }; 0456 0457 new ModelViewTesterItem(itm, vals2, 0); 0458 } 0459 endInsertRows(); 0460 } 0461 } 0462 0463 // Test removing elements when some are out of view 0464 void ModelViewTester::removeLargeTree() 0465 { 0466 for (int i = 0; i < 100; i++) { 0467 auto parent = m_pRoot->m_lChildren[i]; 0468 auto idx = createIndex(i, 0, parent); 0469 0470 beginRemoveRows(idx, 3, 3); 0471 delete parent->m_lChildren[3]; 0472 parent->m_lChildren.remove(3); 0473 endRemoveRows(); 0474 } 0475 } 0476 0477 // Test removing multiple item at once with out-of-view 0478 void ModelViewTester::removeLargeTree2() 0479 { 0480 for (int i = 0; i < 100; i++) { 0481 auto parent = m_pRoot->m_lChildren[i]; 0482 const int s = parent->m_lChildren.size(); 0483 auto idx = createIndex(i, 0, parent); 0484 0485 beginRemoveRows(idx, 0, s); 0486 for (int j = 0; j < s; j++) 0487 delete parent->m_lChildren[j]; 0488 parent->m_lChildren.clear(); 0489 endRemoveRows(); 0490 } 0491 } 0492 0493 // Test removing out-of-view item until the viewport is empty 0494 void ModelViewTester::removeLargeTree3() 0495 { 0496 while (m_pRoot->m_lChildren.size()) { 0497 const int pos = m_pRoot->m_lChildren.size()/2; 0498 beginRemoveRows({}, pos, pos); 0499 delete m_pRoot->m_lChildren[pos]; 0500 m_pRoot->m_lChildren.remove(pos); 0501 endRemoveRows(); 0502 } 0503 } 0504 0505 // Insert more items that can fit in the view 0506 void ModelViewTester::largeFrontTree2() 0507 { 0508 for (int i = 0; i < 100; i++) { 0509 auto parent = m_pRoot->m_lChildren[i]; 0510 auto idx = createIndex(i, 0, parent); 0511 0512 beginInsertRows(idx, 0, 19); 0513 for (int j = 0; j < 20; j++) { 0514 QHash<int, QVariant> vals = { 0515 {Qt::DisplayRole, "children v2 "+QString::number(j)}, 0516 {Qt::UserRole, 0} 0517 }; 0518 0519 new ModelViewTesterItem(parent, vals, 0); 0520 } 0521 endInsertRows(); 0522 } 0523 }