| 1 | /**************************************************************************** | 
| 2 | ** | 
| 3 | ** Copyright (C) 2016 The Qt Company Ltd. | 
| 4 | ** Contact: https://www.qt.io/licensing/ | 
| 5 | ** | 
| 6 | ** This file is part of the test suite of the Qt Toolkit. | 
| 7 | ** | 
| 8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ | 
| 9 | ** Commercial License Usage | 
| 10 | ** Licensees holding valid commercial Qt licenses may use this file in | 
| 11 | ** accordance with the commercial license agreement provided with the | 
| 12 | ** Software or, alternatively, in accordance with the terms contained in | 
| 13 | ** a written agreement between you and The Qt Company. For licensing terms | 
| 14 | ** and conditions see https://www.qt.io/terms-conditions. For further | 
| 15 | ** information use the contact form at https://www.qt.io/contact-us. | 
| 16 | ** | 
| 17 | ** GNU General Public License Usage | 
| 18 | ** Alternatively, this file may be used under the terms of the GNU | 
| 19 | ** General Public License version 3 as published by the Free Software | 
| 20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT | 
| 21 | ** included in the packaging of this file. Please review the following | 
| 22 | ** information to ensure the GNU General Public License requirements will | 
| 23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. | 
| 24 | ** | 
| 25 | ** $QT_END_LICENSE$ | 
| 26 | ** | 
| 27 | ****************************************************************************/ | 
| 28 |  | 
| 29 | #include "../../../../shared/fakedirmodel.h" | 
| 30 |  | 
| 31 | #include <QDesktopWidget> | 
| 32 | #include <QHeaderView> | 
| 33 | #include <QLabel> | 
| 34 | #include <QLineEdit> | 
| 35 | #include <QMainWindow> | 
| 36 | #include <QProxyStyle> | 
| 37 | #include <QPushButton> | 
| 38 | #include <QScrollBar> | 
| 39 | #include <QSignalSpy> | 
| 40 | #include <QSortFilterProxyModel> | 
| 41 | #include <QStatusBar> | 
| 42 | #include <QStringListModel> | 
| 43 | #include <QStyledItemDelegate> | 
| 44 | #include <QTextEdit> | 
| 45 | #include <QTimer> | 
| 46 | #include <QToolButton> | 
| 47 | #include <QTreeWidget> | 
| 48 | #include <QTest> | 
| 49 | #include <QVBoxLayout> | 
| 50 | #include <private/qtreeview_p.h> | 
| 51 | #include <private/qtesthelpers_p.h> | 
| 52 |  | 
| 53 | using namespace QTestPrivate; | 
| 54 |  | 
| 55 | #if QT_CONFIG(draganddrop) | 
| 56 | Q_DECLARE_METATYPE(QAbstractItemView::DragDropMode) | 
| 57 | #endif | 
| 58 | Q_DECLARE_METATYPE(QAbstractItemView::EditTriggers) | 
| 59 | Q_DECLARE_METATYPE(QAbstractItemView::EditTrigger) | 
| 60 |  | 
| 61 | using IntBounds = std::numeric_limits<int>; | 
| 62 | static void initStandardTreeModel(QStandardItemModel *model) | 
| 63 | { | 
| 64 |     QStandardItem *item; | 
| 65 |     item = new QStandardItem(QLatin1String("Row 1 Item" )); | 
| 66 |     model->insertRow(arow: 0, aitem: item); | 
| 67 |  | 
| 68 |     item = new QStandardItem(QLatin1String("Row 2 Item" )); | 
| 69 |     item->setCheckable(true); | 
| 70 |     model->insertRow(arow: 1, aitem: item); | 
| 71 |  | 
| 72 |     QStandardItem *childItem = new QStandardItem(QLatin1String("Row 2 Child Item" )); | 
| 73 |     item->setChild(arow: 0, aitem: childItem); | 
| 74 |  | 
| 75 |     item = new QStandardItem(QLatin1String("Row 3 Item" )); | 
| 76 |     item->setIcon(QIcon()); | 
| 77 |     model->insertRow(arow: 2, aitem: item); | 
| 78 | } | 
| 79 |  | 
| 80 | class TreeView : public QTreeView | 
| 81 | { | 
| 82 |     Q_OBJECT | 
| 83 | public: | 
| 84 |     using QTreeView::QTreeView; | 
| 85 |     using QTreeView::selectedIndexes; | 
| 86 |  | 
| 87 |     void paintEvent(QPaintEvent *event) override | 
| 88 |     { | 
| 89 |         QTreeView::paintEvent(event); | 
| 90 |         wasPainted = true; | 
| 91 |     } | 
| 92 |     bool wasPainted = false; | 
| 93 | public slots: | 
| 94 |     void handleSelectionChanged() | 
| 95 |     { | 
| 96 |         //let's select the last item | 
| 97 |         QModelIndex idx = model()->index(row: 0, column: 0); | 
| 98 |         selectionModel()->select(selection: QItemSelection(idx, idx), command: QItemSelectionModel::Select); | 
| 99 |         disconnect(sender: selectionModel(), signal: &QItemSelectionModel::selectionChanged, | 
| 100 |                    receiver: this, slot: &TreeView::handleSelectionChanged); | 
| 101 |     } | 
| 102 | }; | 
| 103 |  | 
| 104 | class tst_QTreeView : public QObject | 
| 105 | { | 
| 106 |     Q_OBJECT | 
| 107 |  | 
| 108 | public slots: | 
| 109 |     void selectionOrderTest(); | 
| 110 |  | 
| 111 | private slots: | 
| 112 |     void initTestCase() { QApplication::setKeyboardInputInterval(100); } | 
| 113 |     void getSetCheck(); | 
| 114 |  | 
| 115 |     // one test per QTreeView property | 
| 116 |     void construction(); | 
| 117 |     void alternatingRowColors(); | 
| 118 |     void currentIndex_data(); | 
| 119 |     void currentIndex(); | 
| 120 | #if QT_CONFIG(draganddrop) | 
| 121 |     void dragDropMode_data(); | 
| 122 |     void dragDropMode(); | 
| 123 |     void dragDropModeFromDragEnabledAndAcceptDrops_data(); | 
| 124 |     void dragDropModeFromDragEnabledAndAcceptDrops(); | 
| 125 |     void dragDropOverwriteMode(); | 
| 126 | #endif | 
| 127 |     void editTriggers_data(); | 
| 128 |     void editTriggers(); | 
| 129 |     void hasAutoScroll(); | 
| 130 |     void horizontalScrollMode(); | 
| 131 |     void iconSize(); | 
| 132 |     void indexAt(); | 
| 133 |     void indexWidget(); | 
| 134 |     void itemDelegate(); | 
| 135 |     void itemDelegateForColumnOrRow(); | 
| 136 |     void keyboardSearch(); | 
| 137 |     void keyboardSearchMultiColumn(); | 
| 138 |     void setModel(); | 
| 139 |     void openPersistentEditor(); | 
| 140 |     void rootIndex(); | 
| 141 |  | 
| 142 |     // specialized tests below | 
| 143 |     void setHeader(); | 
| 144 |     void columnHidden(); | 
| 145 |     void rowHidden(); | 
| 146 |     void noDelegate(); | 
| 147 |     void noModel(); | 
| 148 |     void emptyModel(); | 
| 149 |     void removeRows(); | 
| 150 |     void removeCols(); | 
| 151 |     void limitedExpand(); | 
| 152 |     void expandAndCollapse_data(); | 
| 153 |     void expandAndCollapse(); | 
| 154 |     void expandAndCollapseAll(); | 
| 155 |     void expandWithNoChildren(); | 
| 156 | #if QT_CONFIG(animation) | 
| 157 |     void quickExpandCollapse(); | 
| 158 | #endif | 
| 159 |     void keyboardNavigation(); | 
| 160 |     void headerSections(); | 
| 161 |     void moveCursor_data(); | 
| 162 |     void moveCursor(); | 
| 163 |     void setSelection_data(); | 
| 164 |     void setSelection(); | 
| 165 |     void extendedSelection_data(); | 
| 166 |     void extendedSelection(); | 
| 167 |     void indexAbove(); | 
| 168 |     void indexBelow(); | 
| 169 |     void clicked(); | 
| 170 |     void mouseDoubleClick(); | 
| 171 |     void rowsAboutToBeRemoved(); | 
| 172 |     void headerSections_unhideSection(); | 
| 173 |     void columnAt(); | 
| 174 |     void scrollTo(); | 
| 175 |     void rowsAboutToBeRemoved_move(); | 
| 176 |     void resizeColumnToContents(); | 
| 177 |     void insertAfterSelect(); | 
| 178 |     void removeAfterSelect(); | 
| 179 |     void hiddenItems(); | 
| 180 |     void spanningItems(); | 
| 181 |     void rowSizeHint(); | 
| 182 |     void setSortingEnabledTopLevel(); | 
| 183 |     void setSortingEnabledChild(); | 
| 184 |     void headerHidden(); | 
| 185 |     void indentation(); | 
| 186 |  | 
| 187 |     void selection(); | 
| 188 |     void removeAndInsertExpandedCol0(); | 
| 189 |     void selectionWithHiddenItems(); | 
| 190 |     void selectAll(); | 
| 191 |  | 
| 192 |     void disabledButCheckable(); | 
| 193 |     void sortByColumn_data(); | 
| 194 |     void sortByColumn(); | 
| 195 |  | 
| 196 |     void evilModel_data(); | 
| 197 |     void evilModel(); | 
| 198 |  | 
| 199 |     void indexRowSizeHint(); | 
| 200 |     void addRowsWhileSectionsAreHidden(); | 
| 201 |     void filterProxyModelCrash(); | 
| 202 |     void renderToPixmap_data(); | 
| 203 |     void renderToPixmap(); | 
| 204 |     void styleOptionViewItem(); | 
| 205 |     void keyboardNavigationWithDisabled(); | 
| 206 |     void saveRestoreState(); | 
| 207 |  | 
| 208 |     void statusTip_data(); | 
| 209 |     void statusTip(); | 
| 210 |     void fetchMoreOnScroll(); | 
| 211 |  | 
| 212 |     // task-specific tests: | 
| 213 |     void task174627_moveLeftToRoot(); | 
| 214 |     void task171902_expandWith1stColHidden(); | 
| 215 |     void task203696_hidingColumnsAndRowsn(); | 
| 216 |     void task211293_removeRootIndex(); | 
| 217 |     void task216717_updateChildren(); | 
| 218 |     void task220298_selectColumns(); | 
| 219 |     void task224091_appendColumns(); | 
| 220 |     void task225539_deleteModel(); | 
| 221 |     void task230123_setItemsExpandable(); | 
| 222 |     void task202039_closePersistentEditor(); | 
| 223 |     void task238873_avoidAutoReopening(); | 
| 224 |     void task244304_clickOnDecoration(); | 
| 225 |     void task246536_scrollbarsNotWorking(); | 
| 226 |     void task250683_wrongSectionSize(); | 
| 227 |     void task239271_addRowsWithFirstColumnHidden(); | 
| 228 |     void task254234_proxySort(); | 
| 229 |     void task248022_changeSelection(); | 
| 230 |     void task245654_changeModelAndExpandAll(); | 
| 231 |     void doubleClickedWithSpans(); | 
| 232 |     void taskQTBUG_6450_selectAllWith1stColumnHidden(); | 
| 233 |     void taskQTBUG_9216_setSizeAndUniformRowHeightsWrongRepaint(); | 
| 234 |     void taskQTBUG_11466_keyboardNavigationRegression(); | 
| 235 |     void taskQTBUG_13567_removeLastItemRegression(); | 
| 236 |     void taskQTBUG_25333_adjustViewOptionsForIndex(); | 
| 237 |     void taskQTBUG_18539_emitLayoutChanged(); | 
| 238 |     void taskQTBUG_8176_emitOnExpandAll(); | 
| 239 |     void taskQTBUG_37813_crash(); | 
| 240 |     void taskQTBUG_45697_crash(); | 
| 241 |     void taskQTBUG_7232_AllowUserToControlSingleStep(); | 
| 242 |     void taskQTBUG_8376(); | 
| 243 |     void taskQTBUG_61476(); | 
| 244 |     void taskQTBUG_42469_crash(); | 
| 245 |     void testInitialFocus(); | 
| 246 |     void fetchUntilScreenFull(); | 
| 247 | }; | 
| 248 |  | 
| 249 | class QtTestModel: public QAbstractItemModel | 
| 250 | { | 
| 251 |     Q_OBJECT | 
| 252 | public: | 
| 253 |     QtTestModel(int _rows, int _cols, QObject *parent = nullptr) | 
| 254 |         : QAbstractItemModel(parent), rows(_rows), cols(_cols) | 
| 255 |     {} | 
| 256 |  | 
| 257 |     inline qint32 level(const QModelIndex &index) const | 
| 258 |     { | 
| 259 |         return index.isValid() ? qint32(index.internalId()) : qint32(-1); | 
| 260 |     } | 
| 261 |  | 
| 262 |     bool canFetchMore(const QModelIndex &) const override { return !fetched; } | 
| 263 |  | 
| 264 |     void fetchMore(const QModelIndex &) override { fetched = true; } | 
| 265 |  | 
| 266 |     bool hasChildren(const QModelIndex &parent = QModelIndex()) const override | 
| 267 |     { | 
| 268 |         bool hasFetched = fetched; | 
| 269 |         fetched = true; | 
| 270 |         bool r = QAbstractItemModel::hasChildren(parent); | 
| 271 |         fetched = hasFetched; | 
| 272 |         return r; | 
| 273 |     } | 
| 274 |  | 
| 275 |     int rowCount(const QModelIndex& parent = QModelIndex()) const override | 
| 276 |     { | 
| 277 |         if (!fetched) | 
| 278 |             qFatal(msg: "%s: rowCount should not be called before fetching" , Q_FUNC_INFO); | 
| 279 |         if ((parent.column() > 0) || (level(index: parent) > levels)) | 
| 280 |             return 0; | 
| 281 |         return rows; | 
| 282 |     } | 
| 283 |     int columnCount(const QModelIndex& parent = QModelIndex()) const override | 
| 284 |     { | 
| 285 |         if ((parent.column() > 0) || (level(index: parent) > levels)) | 
| 286 |             return 0; | 
| 287 |         return cols; | 
| 288 |     } | 
| 289 |  | 
| 290 |     bool isEditable(const QModelIndex &index) const | 
| 291 |     { | 
| 292 |         if (index.isValid()) | 
| 293 |             return true; | 
| 294 |         return false; | 
| 295 |     } | 
| 296 |  | 
| 297 |     QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override | 
| 298 |     { | 
| 299 |         if (onlyValidCalls) { | 
| 300 |             Q_ASSERT(row >= 0); | 
| 301 |             Q_ASSERT(column >= 0); | 
| 302 |             Q_ASSERT(row < rows); | 
| 303 |             Q_ASSERT(column < cols); | 
| 304 |         } | 
| 305 |         if (row < 0 || column < 0 || (level(index: parent) > levels) || column >= cols || row >= rows) { | 
| 306 |             return QModelIndex(); | 
| 307 |         } | 
| 308 |         QModelIndex i = createIndex(arow: row, acolumn: column, aid: quintptr(level(index: parent) + 1)); | 
| 309 |         parentHash[i] = parent; | 
| 310 |         return i; | 
| 311 |     } | 
| 312 |  | 
| 313 |     QModelIndex parent(const QModelIndex &index) const override | 
| 314 |     { | 
| 315 |         if (!parentHash.contains(key: index)) | 
| 316 |             return QModelIndex(); | 
| 317 |         return parentHash[index]; | 
| 318 |     } | 
| 319 |  | 
| 320 |     QVariant data(const QModelIndex &idx, int role) const override | 
| 321 |     { | 
| 322 |         if (!idx.isValid()) | 
| 323 |             return QVariant(); | 
| 324 |  | 
| 325 |         if (role == Qt::DisplayRole) { | 
| 326 |             if (idx.row() < 0 || idx.column() < 0 || idx.column() >= cols || idx.row() >= rows) { | 
| 327 |                 wrongIndex = true; | 
| 328 |                 qWarning(msg: "Invalid modelIndex [%d,%d,%p]" , idx.row(), idx.column(), | 
| 329 |                          idx.internalPointer()); | 
| 330 |             } | 
| 331 |             QString result = QLatin1Char('[') + QString::number(idx.row()) + QLatin1Char(',') | 
| 332 |                 + QString::number(idx.column()) + QLatin1Char(',') +  QString::number(level(index: idx)) | 
| 333 |                 + QLatin1Char(']'); | 
| 334 |             if (idx.row() & 1) | 
| 335 |                 result += QLatin1String(" - this item is extra wide" ); | 
| 336 |             return result; | 
| 337 |         } | 
| 338 |         if (decorationsEnabled && role == Qt::DecorationRole) { | 
| 339 |             QPixmap pm(16,16); | 
| 340 |             pm.fill(fillColor: QColor::fromHsv(h: (idx.column() % 16)*8 + 64, s: 254, v: (idx.row() % 16)*8 + 32)); | 
| 341 |             return pm; | 
| 342 |         } | 
| 343 |         if (statusTipsEnabled && role == Qt::StatusTipRole) | 
| 344 |             return QString("[%1,%2,%3] -- Status" ).arg(a: idx.row()).arg(a: idx.column()).arg(a: level(index: idx)); | 
| 345 |         return QVariant(); | 
| 346 |     } | 
| 347 |  | 
| 348 |     QVariant (int section, Qt::Orientation orientation, | 
| 349 |                         int role = Qt::DisplayRole) const override | 
| 350 |     { | 
| 351 |         Q_UNUSED(orientation); | 
| 352 |         if (section < 0 || section >= columnCount()) | 
| 353 |             return QVariant(); | 
| 354 |         if (statusTipsEnabled && role == Qt::StatusTipRole) | 
| 355 |             return QString("Header %1 -- Status" ).arg(a: section); | 
| 356 |         return QVariant(); | 
| 357 |     } | 
| 358 |  | 
| 359 |     void simulateMoveRows() | 
| 360 |     { | 
| 361 |         beginMoveRows(sourceParent: QModelIndex(), sourceFirst: 0, sourceLast: 0, destinationParent: QModelIndex(), destinationRow: 2); | 
| 362 |         endMoveRows(); | 
| 363 |     } | 
| 364 |  | 
| 365 |     void removeLastRow() | 
| 366 |     { | 
| 367 |         beginRemoveRows(parent: QModelIndex(), first: rows - 1, last: rows - 1); | 
| 368 |         --rows; | 
| 369 |         endRemoveRows(); | 
| 370 |     } | 
| 371 |  | 
| 372 |     void removeAllRows() | 
| 373 |     { | 
| 374 |         beginRemoveRows(parent: QModelIndex(), first: 0, last: rows - 1); | 
| 375 |         rows = 0; | 
| 376 |         endRemoveRows(); | 
| 377 |     } | 
| 378 |  | 
| 379 |     void removeLastColumn() | 
| 380 |     { | 
| 381 |         beginRemoveColumns(parent: QModelIndex(), first: cols - 1, last: cols - 1); | 
| 382 |         --cols; | 
| 383 |         endRemoveColumns(); | 
| 384 |     } | 
| 385 |  | 
| 386 |     void removeAllColumns() | 
| 387 |     { | 
| 388 |         beginRemoveColumns(parent: QModelIndex(), first: 0, last: cols - 1); | 
| 389 |         cols = 0; | 
| 390 |         endRemoveColumns(); | 
| 391 |     } | 
| 392 |  | 
| 393 |     void insertNewRow() | 
| 394 |     { | 
| 395 |         beginInsertRows(parent: QModelIndex(), first: rows - 1, last: rows - 1); | 
| 396 |         ++rows; | 
| 397 |         endInsertRows(); | 
| 398 |     } | 
| 399 |  | 
| 400 |     void setDecorationsEnabled(bool enable) | 
| 401 |     { | 
| 402 |         decorationsEnabled = enable; | 
| 403 |     } | 
| 404 |  | 
| 405 |     mutable QMap<QModelIndex,QModelIndex> parentHash; | 
| 406 |     int rows = 0; | 
| 407 |     int cols = 0; | 
| 408 |     int levels = IntBounds::max(); | 
| 409 |     mutable bool wrongIndex = false; | 
| 410 |     mutable bool fetched = false; | 
| 411 |     bool decorationsEnabled = false; | 
| 412 |     bool statusTipsEnabled = false; | 
| 413 |     bool onlyValidCalls = false; | 
| 414 | }; | 
| 415 |  | 
| 416 | // Testing get/set functions | 
| 417 | void tst_QTreeView::getSetCheck() | 
| 418 | { | 
| 419 |     QTreeView obj1; | 
| 420 |  | 
| 421 |     // int QTreeView::indentation() | 
| 422 |     // void QTreeView::setIndentation(int) | 
| 423 |     const int styledIndentation = obj1.style()->pixelMetric( | 
| 424 |           metric: QStyle::PM_TreeViewIndentation, option: nullptr, widget: &obj1); | 
| 425 |     QCOMPARE(obj1.indentation(), styledIndentation); | 
| 426 |     obj1.setIndentation(0); | 
| 427 |     QCOMPARE(obj1.indentation(), 0); | 
| 428 |     obj1.setIndentation(IntBounds::min()); | 
| 429 |     QCOMPARE(obj1.indentation(), IntBounds::min()); | 
| 430 |     obj1.setIndentation(IntBounds::max()); | 
| 431 |     QCOMPARE(obj1.indentation(), IntBounds::max()); | 
| 432 |  | 
| 433 |     // bool QTreeView::rootIsDecorated() | 
| 434 |     // void QTreeView::setRootIsDecorated(bool) | 
| 435 |     QCOMPARE(obj1.rootIsDecorated(), true); | 
| 436 |     obj1.setRootIsDecorated(false); | 
| 437 |     QCOMPARE(obj1.rootIsDecorated(), false); | 
| 438 |     obj1.setRootIsDecorated(true); | 
| 439 |     QCOMPARE(obj1.rootIsDecorated(), true); | 
| 440 |  | 
| 441 |     // bool QTreeView::uniformRowHeights() | 
| 442 |     // void QTreeView::setUniformRowHeights(bool) | 
| 443 |     QCOMPARE(obj1.uniformRowHeights(), false); | 
| 444 |     obj1.setUniformRowHeights(false); | 
| 445 |     QCOMPARE(obj1.uniformRowHeights(), false); | 
| 446 |     obj1.setUniformRowHeights(true); | 
| 447 |     QCOMPARE(obj1.uniformRowHeights(), true); | 
| 448 |  | 
| 449 |     // bool QTreeView::itemsExpandable() | 
| 450 |     // void QTreeView::setItemsExpandable(bool) | 
| 451 |     QCOMPARE(obj1.itemsExpandable(), true); | 
| 452 |     obj1.setItemsExpandable(false); | 
| 453 |     QCOMPARE(obj1.itemsExpandable(), false); | 
| 454 |     obj1.setItemsExpandable(true); | 
| 455 |     QCOMPARE(obj1.itemsExpandable(), true); | 
| 456 |  | 
| 457 |     // bool QTreeView::allColumnsShowFocus | 
| 458 |     // void QTreeView::setAllColumnsShowFocus | 
| 459 |     QCOMPARE(obj1.allColumnsShowFocus(), false); | 
| 460 |     obj1.setAllColumnsShowFocus(false); | 
| 461 |     QCOMPARE(obj1.allColumnsShowFocus(), false); | 
| 462 |     obj1.setAllColumnsShowFocus(true); | 
| 463 |     QCOMPARE(obj1.allColumnsShowFocus(), true); | 
| 464 |  | 
| 465 |     // bool QTreeView::isAnimated | 
| 466 |     // void QTreeView::setAnimated | 
| 467 |     QCOMPARE(obj1.isAnimated(), false); | 
| 468 |     obj1.setAnimated(false); | 
| 469 |     QCOMPARE(obj1.isAnimated(), false); | 
| 470 |     obj1.setAnimated(true); | 
| 471 |     QCOMPARE(obj1.isAnimated(), true); | 
| 472 |  | 
| 473 |     // bool QTreeView::setSortingEnabled | 
| 474 |     // void QTreeView::isSortingEnabled | 
| 475 |     QCOMPARE(obj1.isSortingEnabled(), false); | 
| 476 |     obj1.setSortingEnabled(false); | 
| 477 |     QCOMPARE(obj1.isSortingEnabled(), false); | 
| 478 |     obj1.setSortingEnabled(true); | 
| 479 |     QCOMPARE(obj1.isSortingEnabled(), true); | 
| 480 | } | 
| 481 |  | 
| 482 | void tst_QTreeView::construction() | 
| 483 | { | 
| 484 |     QTreeView view; | 
| 485 |  | 
| 486 |     // QAbstractItemView properties | 
| 487 |     QVERIFY(!view.alternatingRowColors()); | 
| 488 |     QCOMPARE(view.currentIndex(), QModelIndex()); | 
| 489 | #if QT_CONFIG(draganddrop) | 
| 490 |     QCOMPARE(view.dragDropMode(), QAbstractItemView::NoDragDrop); | 
| 491 |     QVERIFY(!view.dragDropOverwriteMode()); | 
| 492 |     QVERIFY(!view.dragEnabled()); | 
| 493 | #endif | 
| 494 |     QCOMPARE(view.editTriggers(), QAbstractItemView::EditKeyPressed | QAbstractItemView::DoubleClicked); | 
| 495 |     QVERIFY(view.hasAutoScroll()); | 
| 496 |     QCOMPARE(view.horizontalScrollMode(), QAbstractItemView::ScrollPerPixel); | 
| 497 |     QCOMPARE(view.iconSize(), QSize()); | 
| 498 |     QCOMPARE(view.indexAt(QPoint()), QModelIndex()); | 
| 499 |     QVERIFY(!view.indexWidget(QModelIndex())); | 
| 500 |     QVERIFY(qobject_cast<QStyledItemDelegate *>(view.itemDelegate())); | 
| 501 |     QVERIFY(!view.itemDelegateForColumn(-1)); | 
| 502 |     QVERIFY(!view.itemDelegateForColumn(0)); | 
| 503 |     QVERIFY(!view.itemDelegateForColumn(1)); | 
| 504 |     QVERIFY(!view.itemDelegateForRow(-1)); | 
| 505 |     QVERIFY(!view.itemDelegateForRow(0)); | 
| 506 |     QVERIFY(!view.itemDelegateForRow(1)); | 
| 507 |     QVERIFY(!view.model()); | 
| 508 |     QCOMPARE(view.rootIndex(), QModelIndex()); | 
| 509 |     QCOMPARE(view.selectionBehavior(), QAbstractItemView::SelectRows); | 
| 510 |     QCOMPARE(view.selectionMode(), QAbstractItemView::SingleSelection); | 
| 511 |     QVERIFY(!view.selectionModel()); | 
| 512 | #if QT_CONFIG(draganddrop) | 
| 513 |     QVERIFY(view.showDropIndicator()); | 
| 514 | #endif | 
| 515 |     QCOMPARE(view.QAbstractItemView::sizeHintForColumn(-1), -1); // <- protected in QTreeView | 
| 516 |     QCOMPARE(view.QAbstractItemView::sizeHintForColumn(0), -1); // <- protected in QTreeView | 
| 517 |     QCOMPARE(view.QAbstractItemView::sizeHintForColumn(1), -1); // <- protected in QTreeView | 
| 518 |     QCOMPARE(view.sizeHintForIndex(QModelIndex()), QSize()); | 
| 519 |     QCOMPARE(view.sizeHintForRow(-1), -1); | 
| 520 |     QCOMPARE(view.sizeHintForRow(0), -1); | 
| 521 |     QCOMPARE(view.sizeHintForRow(1), -1); | 
| 522 |     QVERIFY(!view.tabKeyNavigation()); | 
| 523 |     QCOMPARE(view.textElideMode(), Qt::ElideRight); | 
| 524 |     QCOMPARE(static_cast<int>(view.verticalScrollMode()), | 
| 525 |              view.style()->styleHint(QStyle::SH_ItemView_ScrollMode, nullptr, &view)); | 
| 526 |     QCOMPARE(view.visualRect(QModelIndex()), QRect()); | 
| 527 |  | 
| 528 |     // QTreeView properties | 
| 529 |     QVERIFY(!view.allColumnsShowFocus()); | 
| 530 |     QCOMPARE(view.autoExpandDelay(), -1); | 
| 531 |     QCOMPARE(view.columnAt(-1), -1); | 
| 532 |     QCOMPARE(view.columnAt(0), -1); | 
| 533 |     QCOMPARE(view.columnAt(1), -1); | 
| 534 |     QCOMPARE(view.columnViewportPosition(-1), -1); | 
| 535 |     QCOMPARE(view.columnViewportPosition(0), -1); | 
| 536 |     QCOMPARE(view.columnViewportPosition(1), -1); | 
| 537 |     QCOMPARE(view.columnWidth(-1), 0); | 
| 538 |     QCOMPARE(view.columnWidth(0), 0); | 
| 539 |     QCOMPARE(view.columnWidth(1), 0); | 
| 540 |     QVERIFY(view.header()); | 
| 541 |     QCOMPARE(view.indentation(), | 
| 542 |              view.style()->pixelMetric(QStyle::PM_TreeViewIndentation, nullptr, &view)); | 
| 543 |     QCOMPARE(view.indexAbove(QModelIndex()), QModelIndex()); | 
| 544 |     QCOMPARE(view.indexBelow(QModelIndex()), QModelIndex()); | 
| 545 |     QVERIFY(!view.isAnimated()); | 
| 546 |     QVERIFY(!view.isColumnHidden(-1)); | 
| 547 |     QVERIFY(!view.isColumnHidden(0)); | 
| 548 |     QVERIFY(!view.isColumnHidden(1)); | 
| 549 |     QVERIFY(!view.isExpanded(QModelIndex())); | 
| 550 |     QVERIFY(!view.isRowHidden(-1, QModelIndex())); | 
| 551 |     QVERIFY(!view.isRowHidden(0, QModelIndex())); | 
| 552 |     QVERIFY(!view.isRowHidden(1, QModelIndex())); | 
| 553 |     QVERIFY(!view.isFirstColumnSpanned(-1, QModelIndex())); | 
| 554 |     QVERIFY(!view.isFirstColumnSpanned(0, QModelIndex())); | 
| 555 |     QVERIFY(!view.isFirstColumnSpanned(1, QModelIndex())); | 
| 556 |     QVERIFY(!view.isSortingEnabled()); | 
| 557 |     QVERIFY(view.itemsExpandable()); | 
| 558 |     QVERIFY(view.rootIsDecorated()); | 
| 559 |     QVERIFY(!view.uniformRowHeights()); | 
| 560 |     QCOMPARE(view.visualRect(QModelIndex()), QRect()); | 
| 561 |     QVERIFY(!view.wordWrap()); | 
| 562 | } | 
| 563 |  | 
| 564 | void tst_QTreeView::alternatingRowColors() | 
| 565 | { | 
| 566 |     QTreeView view; | 
| 567 |     QVERIFY(!view.alternatingRowColors()); | 
| 568 |     view.setAlternatingRowColors(true); | 
| 569 |     QVERIFY(view.alternatingRowColors()); | 
| 570 |     view.setAlternatingRowColors(false); | 
| 571 |     QVERIFY(!view.alternatingRowColors()); | 
| 572 |  | 
| 573 |     // ### Test visual effect. | 
| 574 | } | 
| 575 |  | 
| 576 | void tst_QTreeView::currentIndex_data() | 
| 577 | { | 
| 578 |     QTest::addColumn<int>(name: "row" ); | 
| 579 |     QTest::addColumn<int>(name: "column" ); | 
| 580 |     QTest::addColumn<int>(name: "indexRow" ); | 
| 581 |     QTest::addColumn<int>(name: "indexColumn" ); | 
| 582 |     QTest::addColumn<int>(name: "parentIndexRow" ); | 
| 583 |     QTest::addColumn<int>(name: "parentIndexColumn" ); | 
| 584 |  | 
| 585 |     QTest::newRow(dataTag: "-1, -1" ) << -1 << -1 << -1 << -1 << -1 << -1; | 
| 586 |     QTest::newRow(dataTag: "-1, 0" ) << -1 << 0 << -1 << -1 << -1 << -1; | 
| 587 |     QTest::newRow(dataTag: "0, -1" ) << 0 << -1 << -1 << -1 << -1 << -1; | 
| 588 |     QTest::newRow(dataTag: "0, 0" ) << 0 << 0 << 0 << 0 << -1 << -1; | 
| 589 |     QTest::newRow(dataTag: "0, 1" ) << 0 << 0 << 0 << 0 << -1 << -1; | 
| 590 |     QTest::newRow(dataTag: "1, 0" ) << 1 << 0 << 1 << 0 << -1 << -1; | 
| 591 |     QTest::newRow(dataTag: "1, 1" ) << 1 << 1 << -1 << -1 << -1 << -1; | 
| 592 |     QTest::newRow(dataTag: "2, 0" ) << 2 << 0 << 2 << 0 << -1 << -1; | 
| 593 |     QTest::newRow(dataTag: "2, 1" ) << 2 << 1 << -1 << -1 << -1 << -1; | 
| 594 |     QTest::newRow(dataTag: "3, -1" ) << 3 << -1 << -1 << -1 << -1 << -1; | 
| 595 |     QTest::newRow(dataTag: "3, 0" ) << 3 << 0 << -1 << -1 << -1 << -1; | 
| 596 |     QTest::newRow(dataTag: "3, 1" ) << 3 << 1 << -1 << -1 << -1 << -1; | 
| 597 | } | 
| 598 |  | 
| 599 | void tst_QTreeView::currentIndex() | 
| 600 | { | 
| 601 |     QFETCH(int, row); | 
| 602 |     QFETCH(int, column); | 
| 603 |     QFETCH(int, indexRow); | 
| 604 |     QFETCH(int, indexColumn); | 
| 605 |     QFETCH(int, parentIndexRow); | 
| 606 |     QFETCH(int, parentIndexColumn); | 
| 607 |  | 
| 608 |     QTreeView view; | 
| 609 |     QStandardItemModel treeModel; | 
| 610 |     initStandardTreeModel(model: &treeModel); | 
| 611 |     view.setModel(&treeModel); | 
| 612 |  | 
| 613 |     QCOMPARE(view.currentIndex(), QModelIndex()); | 
| 614 |     view.setCurrentIndex(view.model()->index(row, column)); | 
| 615 |     QCOMPARE(view.currentIndex().row(), indexRow); | 
| 616 |     QCOMPARE(view.currentIndex().column(), indexColumn); | 
| 617 |     QCOMPARE(view.currentIndex().parent().row(), parentIndexRow); | 
| 618 |     QCOMPARE(view.currentIndex().parent().column(), parentIndexColumn); | 
| 619 |  | 
| 620 |     // ### Test child and grandChild indexes. | 
| 621 | } | 
| 622 |  | 
| 623 | #if QT_CONFIG(draganddrop) | 
| 624 |  | 
| 625 | void tst_QTreeView::dragDropMode_data() | 
| 626 | { | 
| 627 |     QTest::addColumn<QAbstractItemView::DragDropMode>(name: "dragDropMode" ); | 
| 628 |     QTest::addColumn<bool>(name: "acceptDrops" ); | 
| 629 |     QTest::addColumn<bool>(name: "dragEnabled" ); | 
| 630 |     QTest::newRow(dataTag: "NoDragDrop" ) << QAbstractItemView::NoDragDrop << false << false; | 
| 631 |     QTest::newRow(dataTag: "DragOnly" ) << QAbstractItemView::DragOnly << false << true; | 
| 632 |     QTest::newRow(dataTag: "DropOnly" ) << QAbstractItemView::DropOnly << true << false; | 
| 633 |     QTest::newRow(dataTag: "DragDrop" ) << QAbstractItemView::DragDrop << true << true; | 
| 634 |     QTest::newRow(dataTag: "InternalMove" ) << QAbstractItemView::InternalMove << true << true; | 
| 635 | } | 
| 636 |  | 
| 637 | void tst_QTreeView::dragDropMode() | 
| 638 | { | 
| 639 |     QFETCH(QAbstractItemView::DragDropMode, dragDropMode); | 
| 640 |     QFETCH(bool, acceptDrops); | 
| 641 |     QFETCH(bool, dragEnabled); | 
| 642 |  | 
| 643 |     QTreeView view; | 
| 644 |     QCOMPARE(view.dragDropMode(), QAbstractItemView::NoDragDrop); | 
| 645 |     QVERIFY(!view.acceptDrops()); | 
| 646 |     QVERIFY(!view.dragEnabled()); | 
| 647 |  | 
| 648 |     view.setDragDropMode(dragDropMode); | 
| 649 |     QCOMPARE(view.dragDropMode(), dragDropMode); | 
| 650 |     QCOMPARE(view.acceptDrops(), acceptDrops); | 
| 651 |     QCOMPARE(view.dragEnabled(), dragEnabled); | 
| 652 |  | 
| 653 |     // ### Test effects of this mode | 
| 654 | } | 
| 655 |  | 
| 656 | void tst_QTreeView::dragDropModeFromDragEnabledAndAcceptDrops_data() | 
| 657 | { | 
| 658 |     QTest::addColumn<bool>(name: "dragEnabled" ); | 
| 659 |     QTest::addColumn<bool>(name: "acceptDrops" ); | 
| 660 |     QTest::addColumn<QAbstractItemView::DragDropMode>(name: "dragDropMode" ); | 
| 661 |     QTest::addColumn<bool>(name: "setBehavior" ); | 
| 662 |     QTest::addColumn<QAbstractItemView::DragDropMode>(name: "behavior" ); | 
| 663 |  | 
| 664 |     QTest::newRow(dataTag: "NoDragDrop -1" ) << false << false << QAbstractItemView::NoDragDrop << false << QAbstractItemView::DragDropMode(); | 
| 665 |     QTest::newRow(dataTag: "NoDragDrop 0" ) << false << false << QAbstractItemView::NoDragDrop << true << QAbstractItemView::NoDragDrop; | 
| 666 |     QTest::newRow(dataTag: "NoDragDrop 1" ) << false << false << QAbstractItemView::NoDragDrop << true << QAbstractItemView::DragOnly; | 
| 667 |     QTest::newRow(dataTag: "NoDragDrop 2" ) << false << false << QAbstractItemView::NoDragDrop << true << QAbstractItemView::DropOnly; | 
| 668 |     QTest::newRow(dataTag: "NoDragDrop 3" ) << false << false << QAbstractItemView::NoDragDrop << true << QAbstractItemView::DragDrop; | 
| 669 |     QTest::newRow(dataTag: "NoDragDrop 4" ) << false << false << QAbstractItemView::NoDragDrop << true << QAbstractItemView::InternalMove; | 
| 670 |     QTest::newRow(dataTag: "DragOnly -1" ) << true << false << QAbstractItemView::DragOnly << false << QAbstractItemView::DragDropMode(); | 
| 671 |     QTest::newRow(dataTag: "DragOnly 0" ) << true << false << QAbstractItemView::DragOnly << true << QAbstractItemView::NoDragDrop; | 
| 672 |     QTest::newRow(dataTag: "DragOnly 1" ) << true << false << QAbstractItemView::DragOnly << true << QAbstractItemView::DragOnly; | 
| 673 |     QTest::newRow(dataTag: "DragOnly 2" ) << true << false << QAbstractItemView::DragOnly << true << QAbstractItemView::DropOnly; | 
| 674 |     QTest::newRow(dataTag: "DragOnly 3" ) << true << false << QAbstractItemView::DragOnly << true << QAbstractItemView::DragDrop; | 
| 675 |     QTest::newRow(dataTag: "DragOnly 4" ) << true << false << QAbstractItemView::DragOnly << true << QAbstractItemView::InternalMove; | 
| 676 |     QTest::newRow(dataTag: "DropOnly -1" ) << false << true << QAbstractItemView::DropOnly << false << QAbstractItemView::DragDropMode(); | 
| 677 |     QTest::newRow(dataTag: "DropOnly 0" ) << false << true << QAbstractItemView::DropOnly << true << QAbstractItemView::NoDragDrop; | 
| 678 |     QTest::newRow(dataTag: "DropOnly 1" ) << false << true << QAbstractItemView::DropOnly << true << QAbstractItemView::DragOnly; | 
| 679 |     QTest::newRow(dataTag: "DropOnly 2" ) << false << true << QAbstractItemView::DropOnly << true << QAbstractItemView::DropOnly; | 
| 680 |     QTest::newRow(dataTag: "DropOnly 3" ) << false << true << QAbstractItemView::DropOnly << true << QAbstractItemView::DragDrop; | 
| 681 |     QTest::newRow(dataTag: "DropOnly 4" ) << false << true << QAbstractItemView::DropOnly << true << QAbstractItemView::InternalMove; | 
| 682 |     QTest::newRow(dataTag: "DragDrop -1" ) << true << true << QAbstractItemView::DragDrop << false << QAbstractItemView::DragDropMode(); | 
| 683 |     QTest::newRow(dataTag: "DragDrop 0" ) << true << true << QAbstractItemView::DragDrop << false << QAbstractItemView::DragDropMode(); | 
| 684 |     QTest::newRow(dataTag: "DragDrop 1" ) << true << true << QAbstractItemView::DragDrop << true << QAbstractItemView::NoDragDrop; | 
| 685 |     QTest::newRow(dataTag: "DragDrop 2" ) << true << true << QAbstractItemView::DragDrop << true << QAbstractItemView::DragOnly; | 
| 686 |     QTest::newRow(dataTag: "DragDrop 3" ) << true << true << QAbstractItemView::DragDrop << true << QAbstractItemView::DropOnly; | 
| 687 |     QTest::newRow(dataTag: "DragDrop 4" ) << true << true << QAbstractItemView::DragDrop << true << QAbstractItemView::DragDrop; | 
| 688 |     QTest::newRow(dataTag: "DragDrop 5" ) << true << true << QAbstractItemView::InternalMove << true << QAbstractItemView::InternalMove; | 
| 689 | } | 
| 690 |  | 
| 691 | void tst_QTreeView::dragDropModeFromDragEnabledAndAcceptDrops() | 
| 692 | { | 
| 693 |     QFETCH(bool, acceptDrops); | 
| 694 |     QFETCH(bool, dragEnabled); | 
| 695 |     QFETCH(QAbstractItemView::DragDropMode, dragDropMode); | 
| 696 |     QFETCH(bool, setBehavior); | 
| 697 |     QFETCH(QAbstractItemView::DragDropMode, behavior); | 
| 698 |  | 
| 699 |     QTreeView view; | 
| 700 |     QCOMPARE(view.dragDropMode(), QAbstractItemView::NoDragDrop); | 
| 701 |  | 
| 702 |     if (setBehavior) | 
| 703 |         view.setDragDropMode(behavior); | 
| 704 |  | 
| 705 |     view.setAcceptDrops(acceptDrops); | 
| 706 |     view.setDragEnabled(dragEnabled); | 
| 707 |     QCOMPARE(view.dragDropMode(), dragDropMode); | 
| 708 |  | 
| 709 |     // ### Test effects of this mode | 
| 710 | } | 
| 711 |  | 
| 712 | void tst_QTreeView::dragDropOverwriteMode() | 
| 713 | { | 
| 714 |     QTreeView view; | 
| 715 |     QVERIFY(!view.dragDropOverwriteMode()); | 
| 716 |     view.setDragDropOverwriteMode(true); | 
| 717 |     QVERIFY(view.dragDropOverwriteMode()); | 
| 718 |     view.setDragDropOverwriteMode(false); | 
| 719 |     QVERIFY(!view.dragDropOverwriteMode()); | 
| 720 |  | 
| 721 |     // ### This property changes the behavior of dropIndicatorPosition(), | 
| 722 |     // which is protected and called only from within QListWidget and | 
| 723 |     // QTableWidget, from their reimplementations of dropMimeData(). Hard to | 
| 724 |     // test. | 
| 725 | } | 
| 726 | #endif | 
| 727 |  | 
| 728 | void tst_QTreeView::editTriggers_data() | 
| 729 | { | 
| 730 |     QTest::addColumn<QAbstractItemView::EditTriggers>(name: "editTriggers" ); | 
| 731 |     QTest::addColumn<QAbstractItemView::EditTrigger>(name: "triggeredTrigger" ); | 
| 732 |     QTest::addColumn<bool>(name: "editorOpened" ); | 
| 733 |  | 
| 734 |     // NoEditTriggers | 
| 735 |     QTest::newRow(dataTag: "NoEditTriggers 0" ) << QAbstractItemView::EditTriggers(QAbstractItemView::NoEditTriggers) | 
| 736 |                                       << QAbstractItemView::NoEditTriggers << false; | 
| 737 |     QTest::newRow(dataTag: "NoEditTriggers 1" ) << QAbstractItemView::EditTriggers(QAbstractItemView::NoEditTriggers) | 
| 738 |                                       << QAbstractItemView::CurrentChanged << false; | 
| 739 |     QTest::newRow(dataTag: "NoEditTriggers 2" ) << QAbstractItemView::EditTriggers(QAbstractItemView::NoEditTriggers) | 
| 740 |                                       << QAbstractItemView::DoubleClicked << false; | 
| 741 |     QTest::newRow(dataTag: "NoEditTriggers 3" ) << QAbstractItemView::EditTriggers(QAbstractItemView::NoEditTriggers) | 
| 742 |                                       << QAbstractItemView::SelectedClicked << false; | 
| 743 |     QTest::newRow(dataTag: "NoEditTriggers 4" ) << QAbstractItemView::EditTriggers(QAbstractItemView::NoEditTriggers) | 
| 744 |                                       << QAbstractItemView::EditKeyPressed << false; | 
| 745 |  | 
| 746 |     // CurrentChanged | 
| 747 |     QTest::newRow(dataTag: "CurrentChanged 0" ) << QAbstractItemView::EditTriggers(QAbstractItemView::CurrentChanged) | 
| 748 |                                       << QAbstractItemView::NoEditTriggers << false; | 
| 749 |     QTest::newRow(dataTag: "CurrentChanged 1" ) << QAbstractItemView::EditTriggers(QAbstractItemView::CurrentChanged) | 
| 750 |                                       << QAbstractItemView::CurrentChanged << true; | 
| 751 |     QTest::newRow(dataTag: "CurrentChanged 2" ) << QAbstractItemView::EditTriggers(QAbstractItemView::CurrentChanged) | 
| 752 |                                       << QAbstractItemView::DoubleClicked << false; | 
| 753 |     QTest::newRow(dataTag: "CurrentChanged 3" ) << QAbstractItemView::EditTriggers(QAbstractItemView::CurrentChanged) | 
| 754 |                                       << QAbstractItemView::SelectedClicked << false; | 
| 755 |     QTest::newRow(dataTag: "CurrentChanged 4" ) << QAbstractItemView::EditTriggers(QAbstractItemView::CurrentChanged) | 
| 756 |                                       << QAbstractItemView::EditKeyPressed << false; | 
| 757 |  | 
| 758 |     // DoubleClicked | 
| 759 |     QTest::newRow(dataTag: "DoubleClicked 0" ) << QAbstractItemView::EditTriggers(QAbstractItemView::DoubleClicked) | 
| 760 |                                      << QAbstractItemView::NoEditTriggers << false; | 
| 761 |     QTest::newRow(dataTag: "DoubleClicked 1" ) << QAbstractItemView::EditTriggers(QAbstractItemView::DoubleClicked) | 
| 762 |                                      << QAbstractItemView::CurrentChanged << false; | 
| 763 |     QTest::newRow(dataTag: "DoubleClicked 2" ) << QAbstractItemView::EditTriggers(QAbstractItemView::DoubleClicked) | 
| 764 |                                      << QAbstractItemView::DoubleClicked << true; | 
| 765 |     QTest::newRow(dataTag: "DoubleClicked 3" ) << QAbstractItemView::EditTriggers(QAbstractItemView::DoubleClicked) | 
| 766 |                                      << QAbstractItemView::SelectedClicked << false; | 
| 767 |     QTest::newRow(dataTag: "DoubleClicked 4" ) << QAbstractItemView::EditTriggers(QAbstractItemView::DoubleClicked) | 
| 768 |                                      << QAbstractItemView::EditKeyPressed << false; | 
| 769 |  | 
| 770 |     // SelectedClicked | 
| 771 |     QTest::newRow(dataTag: "SelectedClicked 0" ) << QAbstractItemView::EditTriggers(QAbstractItemView::SelectedClicked) | 
| 772 |                                        << QAbstractItemView::NoEditTriggers << false; | 
| 773 |     QTest::newRow(dataTag: "SelectedClicked 1" ) << QAbstractItemView::EditTriggers(QAbstractItemView::SelectedClicked) | 
| 774 |                                        << QAbstractItemView::CurrentChanged << false; | 
| 775 |     QTest::newRow(dataTag: "SelectedClicked 2" ) << QAbstractItemView::EditTriggers(QAbstractItemView::SelectedClicked) | 
| 776 |                                        << QAbstractItemView::DoubleClicked << false; | 
| 777 |     QTest::newRow(dataTag: "SelectedClicked 3" ) << QAbstractItemView::EditTriggers(QAbstractItemView::SelectedClicked) | 
| 778 |                                        << QAbstractItemView::SelectedClicked << true; | 
| 779 |     QTest::newRow(dataTag: "SelectedClicked 4" ) << QAbstractItemView::EditTriggers(QAbstractItemView::SelectedClicked) | 
| 780 |                                        << QAbstractItemView::EditKeyPressed << false; | 
| 781 |  | 
| 782 |     // EditKeyPressed | 
| 783 |     QTest::newRow(dataTag: "EditKeyPressed 0" ) << QAbstractItemView::EditTriggers(QAbstractItemView::EditKeyPressed) | 
| 784 |                                       << QAbstractItemView::NoEditTriggers << false; | 
| 785 |     QTest::newRow(dataTag: "EditKeyPressed 1" ) << QAbstractItemView::EditTriggers(QAbstractItemView::EditKeyPressed) | 
| 786 |                                       << QAbstractItemView::CurrentChanged << false; | 
| 787 |     QTest::newRow(dataTag: "EditKeyPressed 2" ) << QAbstractItemView::EditTriggers(QAbstractItemView::EditKeyPressed) | 
| 788 |                                       << QAbstractItemView::DoubleClicked << false; | 
| 789 |     QTest::newRow(dataTag: "EditKeyPressed 3" ) << QAbstractItemView::EditTriggers(QAbstractItemView::EditKeyPressed) | 
| 790 |                                       << QAbstractItemView::SelectedClicked << false; | 
| 791 |     QTest::newRow(dataTag: "EditKeyPressed 4" ) << QAbstractItemView::EditTriggers(QAbstractItemView::EditKeyPressed) | 
| 792 |                                       << QAbstractItemView::EditKeyPressed << true; | 
| 793 | } | 
| 794 |  | 
| 795 | void tst_QTreeView::editTriggers() | 
| 796 | { | 
| 797 |     QFETCH(QAbstractItemView::EditTriggers, editTriggers); | 
| 798 |     QFETCH(QAbstractItemView::EditTrigger, triggeredTrigger); | 
| 799 |     QFETCH(bool, editorOpened); | 
| 800 |  | 
| 801 |     QTreeView view; | 
| 802 |     QStandardItemModel treeModel; | 
| 803 |     initStandardTreeModel(model: &treeModel); | 
| 804 |     view.setModel(&treeModel); | 
| 805 |     view.show(); | 
| 806 |  | 
| 807 |     QCOMPARE(view.editTriggers(), QAbstractItemView::EditKeyPressed | QAbstractItemView::DoubleClicked); | 
| 808 |  | 
| 809 |     // Initialize the first index | 
| 810 |     view.setCurrentIndex(view.model()->index(row: 0, column: 0)); | 
| 811 |  | 
| 812 |     // Verify that we don't have any editor initially | 
| 813 |     QVERIFY(!view.findChild<QLineEdit *>(QString())); | 
| 814 |  | 
| 815 |     // Set the triggers | 
| 816 |     view.setEditTriggers(editTriggers); | 
| 817 |  | 
| 818 |     // Interact with the view | 
| 819 |     switch (triggeredTrigger) { | 
| 820 |     case QAbstractItemView::NoEditTriggers: | 
| 821 |         // Do nothing, the editor shouldn't be there | 
| 822 |         break; | 
| 823 |     case QAbstractItemView::CurrentChanged: | 
| 824 |         // Change the index to open an editor | 
| 825 |         view.setCurrentIndex(view.model()->index(row: 1, column: 0)); | 
| 826 |         break; | 
| 827 |     case QAbstractItemView::DoubleClicked: | 
| 828 |         // Doubleclick the center of the current cell | 
| 829 |         QTest::mouseClick(widget: view.viewport(), button: Qt::LeftButton, stateKey: {}, | 
| 830 |                           pos: view.visualRect(index: view.model()->index(row: 0, column: 0)).center()); | 
| 831 |         QTest::mouseDClick(widget: view.viewport(), button: Qt::LeftButton, stateKey: {}, | 
| 832 |                            pos: view.visualRect(index: view.model()->index(row: 0, column: 0)).center()); | 
| 833 |         break; | 
| 834 |     case QAbstractItemView::SelectedClicked: | 
| 835 |         // Click the center of the current cell | 
| 836 |         view.selectionModel()->select(index: view.model()->index(row: 0, column: 0), command: QItemSelectionModel::Select); | 
| 837 |         QTest::mouseClick(widget: view.viewport(), button: Qt::LeftButton, stateKey: {}, | 
| 838 |                           pos: view.visualRect(index: view.model()->index(row: 0, column: 0)).center()); | 
| 839 |         QTest::qWait(ms: qRound(d: QApplication::doubleClickInterval() * 1.5)); | 
| 840 |         break; | 
| 841 |     case QAbstractItemView::EditKeyPressed: | 
| 842 |         view.setFocus(); | 
| 843 | #ifdef Q_OS_MAC | 
| 844 |         // OS X uses Enter for editing | 
| 845 |         QTest::keyPress(&view, Qt::Key_Enter); | 
| 846 | #else | 
| 847 |         // All other platforms use F2 | 
| 848 |         QTest::keyPress(widget: &view, key: Qt::Key_F2); | 
| 849 | #endif | 
| 850 |         break; | 
| 851 |     default: | 
| 852 |         break; | 
| 853 |     } | 
| 854 |  | 
| 855 |     // Check if we got an editor | 
| 856 |     QTRY_COMPARE(view.findChild<QLineEdit *>(QString()) != nullptr, editorOpened); | 
| 857 | } | 
| 858 |  | 
| 859 | void tst_QTreeView::hasAutoScroll() | 
| 860 | { | 
| 861 |     QTreeView view; | 
| 862 |     QVERIFY(view.hasAutoScroll()); | 
| 863 |     view.setAutoScroll(false); | 
| 864 |     QVERIFY(!view.hasAutoScroll()); | 
| 865 |     view.setAutoScroll(true); | 
| 866 |     QVERIFY(view.hasAutoScroll()); | 
| 867 | } | 
| 868 |  | 
| 869 | void tst_QTreeView::horizontalScrollMode() | 
| 870 | { | 
| 871 |     QStandardItemModel model; | 
| 872 |     for (int i = 0; i < 100; ++i) { | 
| 873 |         model.appendRow(items: QList<QStandardItem *>() | 
| 874 |                         << new QStandardItem("An item that has very long text and should"  | 
| 875 |                                              " cause the horizontal scroll bar to appear." ) | 
| 876 |                         << new QStandardItem("An item that has very long text and should"  | 
| 877 |                                              " cause the horizontal scroll bar to appear." )); | 
| 878 |     } | 
| 879 |  | 
| 880 |     QTreeView view; | 
| 881 |     setFrameless(&view); | 
| 882 |     view.setModel(&model); | 
| 883 |     view.setFixedSize(w: 100, h: 100); | 
| 884 |     view.header()->resizeSection(logicalIndex: 0, size: 200); | 
| 885 |     view.show(); | 
| 886 |  | 
| 887 |     QCOMPARE(view.horizontalScrollMode(), QAbstractItemView::ScrollPerPixel); | 
| 888 |     QCOMPARE(view.horizontalScrollBar()->minimum(), 0); | 
| 889 | #ifdef Q_OS_WINRT | 
| 890 |     QEXPECT_FAIL("" , "setFixedSize does not work on WinRT - QTBUG-68297" , Abort); | 
| 891 | #endif | 
| 892 |     QVERIFY(view.horizontalScrollBar()->maximum() > 2); | 
| 893 |  | 
| 894 |     view.setHorizontalScrollMode(QAbstractItemView::ScrollPerItem); | 
| 895 |     QCOMPARE(view.horizontalScrollMode(), QAbstractItemView::ScrollPerItem); | 
| 896 |     QCOMPARE(view.horizontalScrollBar()->minimum(), 0); | 
| 897 |     QCOMPARE(view.horizontalScrollBar()->maximum(), 1); | 
| 898 |  | 
| 899 |     view.setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel); | 
| 900 |     QCOMPARE(view.horizontalScrollMode(), QAbstractItemView::ScrollPerPixel); | 
| 901 |     QCOMPARE(view.horizontalScrollBar()->minimum(), 0); | 
| 902 |     QVERIFY(view.horizontalScrollBar()->maximum() > 2); | 
| 903 | } | 
| 904 |  | 
| 905 | class RepaintTreeView : public QTreeView | 
| 906 | { | 
| 907 | public: | 
| 908 |     using QTreeView::QTreeView; | 
| 909 |     bool repainted = false; | 
| 910 |  | 
| 911 | protected: | 
| 912 |     void paintEvent(QPaintEvent *event) override | 
| 913 |     { repainted = true; QTreeView::paintEvent(event); } | 
| 914 | }; | 
| 915 |  | 
| 916 | void tst_QTreeView::iconSize() | 
| 917 | { | 
| 918 |     RepaintTreeView view; | 
| 919 |     QCOMPARE(view.iconSize(), QSize()); | 
| 920 |  | 
| 921 |     QStandardItemModel treeModel; | 
| 922 |     initStandardTreeModel(model: &treeModel); | 
| 923 |     view.setModel(&treeModel); | 
| 924 |     QCOMPARE(view.iconSize(), QSize()); | 
| 925 |     QVERIFY(!view.repainted); | 
| 926 |  | 
| 927 |     view.show(); | 
| 928 |     view.update(); | 
| 929 |     QVERIFY(QTest::qWaitForWindowExposed(&view)); | 
| 930 |     QTRY_VERIFY(view.repainted); | 
| 931 |     QCOMPARE(view.iconSize(), QSize()); | 
| 932 |  | 
| 933 |     view.repainted = false; | 
| 934 |     view.setIconSize(QSize()); | 
| 935 |     QTRY_VERIFY(!view.repainted); | 
| 936 |     QCOMPARE(view.iconSize(), QSize()); | 
| 937 |  | 
| 938 |     view.setIconSize(QSize(10, 10)); | 
| 939 |     QTRY_VERIFY(view.repainted); | 
| 940 |     QCOMPARE(view.iconSize(), QSize(10, 10)); | 
| 941 |  | 
| 942 |     view.repainted = false; | 
| 943 |     view.setIconSize(QSize(10000, 10000)); | 
| 944 |     QTRY_VERIFY(view.repainted); | 
| 945 |     QCOMPARE(view.iconSize(), QSize(10000, 10000)); | 
| 946 | } | 
| 947 |  | 
| 948 | void tst_QTreeView::indexAt() | 
| 949 | { | 
| 950 |     QtTestModel model(5, 5); | 
| 951 |  | 
| 952 |     QTreeView view; | 
| 953 |     QCOMPARE(view.indexAt(QPoint()), QModelIndex()); | 
| 954 |     view.setModel(&model); | 
| 955 |     QVERIFY(view.indexAt(QPoint()) != QModelIndex()); | 
| 956 |  | 
| 957 |     QSize itemSize = view.visualRect(index: model.index(row: 0, column: 0)).size(); | 
| 958 |     for (int i = 0; i < model.rowCount(); ++i) { | 
| 959 |         QPoint pos(itemSize.width() / 2, (i * itemSize.height()) + (itemSize.height() / 2)); | 
| 960 |         QModelIndex index = view.indexAt(p: pos); | 
| 961 |         QCOMPARE(index, model.index(i, 0)); | 
| 962 |     } | 
| 963 |  | 
| 964 |     /* | 
| 965 |       // ### this is wrong; the widget _will_ affect the item size | 
| 966 |     for (int j = 0; j < model.rowCount(); ++j) | 
| 967 |         view.setIndexWidget(model.index(j, 0), new QPushButton); | 
| 968 |     */ | 
| 969 |  | 
| 970 |     for (int k = 0; k < model.rowCount(); ++k) { | 
| 971 |         QPoint pos(itemSize.width() / 2, (k * itemSize.height()) + (itemSize.height() / 2)); | 
| 972 |         QModelIndex index = view.indexAt(p: pos); | 
| 973 |         QCOMPARE(index, model.index(k, 0)); | 
| 974 |     } | 
| 975 |  | 
| 976 |     view.show(); | 
| 977 |     view.resize(w: 600, h: 600); | 
| 978 |     view.header()->setStretchLastSection(false); | 
| 979 |     QCOMPARE(view.indexAt(QPoint(550, 20)), QModelIndex()); | 
| 980 | } | 
| 981 |  | 
| 982 | void tst_QTreeView::indexWidget() | 
| 983 | { | 
| 984 |     QTreeView view; | 
| 985 |     QStandardItemModel treeModel; | 
| 986 |     initStandardTreeModel(model: &treeModel); | 
| 987 |     view.setModel(&treeModel); | 
| 988 |     view.resize(w: 300, h: 400);  // make sure the width of the view is larger than the widgets below | 
| 989 |  | 
| 990 |     QModelIndex index = view.model()->index(row: 0, column: 0); | 
| 991 |  | 
| 992 |     QVERIFY(!view.indexWidget(QModelIndex())); | 
| 993 |     QVERIFY(!view.indexWidget(index)); | 
| 994 |  | 
| 995 |     QString text = QLatin1String("TestLabel" ); | 
| 996 |  | 
| 997 |     QWidget *label = new QLabel(text); | 
| 998 |     view.setIndexWidget(index: QModelIndex(), widget: label); | 
| 999 |     QVERIFY(!view.indexWidget(QModelIndex())); | 
| 1000 |     QVERIFY(!label->parent()); | 
| 1001 |     view.setIndexWidget(index, widget: label); | 
| 1002 |     QCOMPARE(view.indexWidget(index), label); | 
| 1003 |     QCOMPARE(label->parentWidget(), view.viewport()); | 
| 1004 |  | 
| 1005 |  | 
| 1006 |     QTextEdit *widget = new QTextEdit(text); | 
| 1007 |     widget->setFixedSize(w: 200,h: 100); | 
| 1008 |     view.setIndexWidget(index, widget); | 
| 1009 |     QCOMPARE(view.indexWidget(index), static_cast<QWidget *>(widget)); | 
| 1010 |  | 
| 1011 |     QCOMPARE(widget->parentWidget(), view.viewport()); | 
| 1012 |     QCOMPARE(widget->geometry(), view.visualRect(index).intersected(widget->geometry())); | 
| 1013 |     QCOMPARE(widget->toPlainText(), text); | 
| 1014 |  | 
| 1015 |     //now let's try to do that later when the widget is already shown | 
| 1016 |     view.show(); | 
| 1017 |     QVERIFY(QTest::qWaitForWindowExposed(&view)); | 
| 1018 |     index = view.model()->index(row: 1, column: 0); | 
| 1019 |     QVERIFY(!view.indexWidget(index)); | 
| 1020 |  | 
| 1021 |     widget = new QTextEdit(text); | 
| 1022 |     widget->setFixedSize(w: 200,h: 100); | 
| 1023 |     view.setIndexWidget(index, widget); | 
| 1024 |     QCOMPARE(view.indexWidget(index), static_cast<QWidget *>(widget)); | 
| 1025 |  | 
| 1026 |     QCOMPARE(widget->parentWidget(), view.viewport()); | 
| 1027 |     QCOMPARE(widget->geometry(), view.visualRect(index).intersected(widget->geometry())); | 
| 1028 |     QCOMPARE(widget->toPlainText(), text); | 
| 1029 | } | 
| 1030 |  | 
| 1031 | void tst_QTreeView::itemDelegate() | 
| 1032 | { | 
| 1033 |     QPointer<QAbstractItemDelegate> oldDelegate; | 
| 1034 |     QPointer<QStyledItemDelegate> otherItemDelegate; | 
| 1035 |  | 
| 1036 |     { | 
| 1037 |         QTreeView view; | 
| 1038 |         QVERIFY(qobject_cast<QStyledItemDelegate *>(view.itemDelegate())); | 
| 1039 |         QPointer<QAbstractItemDelegate> oldDelegate = view.itemDelegate(); | 
| 1040 |  | 
| 1041 |         otherItemDelegate = new QStyledItemDelegate; | 
| 1042 |         view.setItemDelegate(otherItemDelegate); | 
| 1043 |         QVERIFY(!otherItemDelegate->parent()); | 
| 1044 |         QVERIFY(oldDelegate); | 
| 1045 |  | 
| 1046 |         QCOMPARE(view.itemDelegate(), otherItemDelegate); | 
| 1047 |  | 
| 1048 |         view.setItemDelegate(nullptr); | 
| 1049 |         QVERIFY(!view.itemDelegate()); // <- view does its own drawing? | 
| 1050 |         QVERIFY(otherItemDelegate); | 
| 1051 |     } | 
| 1052 |  | 
| 1053 |     // This is strange. Why doesn't setItemDelegate() reparent the delegate? | 
| 1054 |     QVERIFY(!oldDelegate); | 
| 1055 |     QVERIFY(otherItemDelegate); | 
| 1056 |  | 
| 1057 |     delete otherItemDelegate; | 
| 1058 | } | 
| 1059 |  | 
| 1060 | void tst_QTreeView::itemDelegateForColumnOrRow() | 
| 1061 | { | 
| 1062 |     QTreeView view; | 
| 1063 |     QAbstractItemDelegate *defaultDelegate = view.itemDelegate(); | 
| 1064 |     QVERIFY(defaultDelegate); | 
| 1065 |  | 
| 1066 |     QVERIFY(!view.itemDelegateForRow(0)); | 
| 1067 |     QVERIFY(!view.itemDelegateForColumn(0)); | 
| 1068 |     QCOMPARE(view.itemDelegate(QModelIndex()), defaultDelegate); | 
| 1069 |  | 
| 1070 |     QStandardItemModel model; | 
| 1071 |     for (int i = 0; i < 100; ++i) { | 
| 1072 |         model.appendRow(items: QList<QStandardItem *>() | 
| 1073 |                         << new QStandardItem("An item that has very long text and should"  | 
| 1074 |                                              " cause the horizontal scroll bar to appear." ) | 
| 1075 |                         << new QStandardItem("An item that has very long text and should"  | 
| 1076 |                                              " cause the horizontal scroll bar to appear." ) | 
| 1077 |                         << new QStandardItem("An item that has very long text and should"  | 
| 1078 |                                              " cause the horizontal scroll bar to appear." )); | 
| 1079 |     } | 
| 1080 |     view.setModel(&model); | 
| 1081 |  | 
| 1082 |     QVERIFY(!view.itemDelegateForRow(0)); | 
| 1083 |     QVERIFY(!view.itemDelegateForColumn(0)); | 
| 1084 |     QCOMPARE(view.itemDelegate(QModelIndex()), defaultDelegate); | 
| 1085 |     QCOMPARE(view.itemDelegate(view.model()->index(0, 0)), defaultDelegate); | 
| 1086 |  | 
| 1087 |     QPointer<QAbstractItemDelegate> rowDelegate = new QStyledItemDelegate; | 
| 1088 |     view.setItemDelegateForRow(row: 0, delegate: rowDelegate); | 
| 1089 |     QVERIFY(!rowDelegate->parent()); | 
| 1090 |     QCOMPARE(view.itemDelegateForRow(0), rowDelegate); | 
| 1091 |     QCOMPARE(view.itemDelegate(view.model()->index(0, 0)), rowDelegate); | 
| 1092 |     QCOMPARE(view.itemDelegate(view.model()->index(0, 1)), rowDelegate); | 
| 1093 |     QCOMPARE(view.itemDelegate(view.model()->index(1, 0)), defaultDelegate); | 
| 1094 |     QCOMPARE(view.itemDelegate(view.model()->index(1, 1)), defaultDelegate); | 
| 1095 |  | 
| 1096 |     QPointer<QAbstractItemDelegate> columnDelegate = new QStyledItemDelegate; | 
| 1097 |     view.setItemDelegateForColumn(column: 1, delegate: columnDelegate); | 
| 1098 |     QVERIFY(!columnDelegate->parent()); | 
| 1099 |     QCOMPARE(view.itemDelegateForColumn(1), columnDelegate); | 
| 1100 |     QCOMPARE(view.itemDelegate(view.model()->index(0, 0)), rowDelegate); | 
| 1101 |     QCOMPARE(view.itemDelegate(view.model()->index(0, 1)), rowDelegate); // row wins | 
| 1102 |     QCOMPARE(view.itemDelegate(view.model()->index(1, 0)), defaultDelegate); | 
| 1103 |     QCOMPARE(view.itemDelegate(view.model()->index(1, 1)), columnDelegate); | 
| 1104 |  | 
| 1105 |     view.setItemDelegateForRow(row: 0, delegate: nullptr); | 
| 1106 |     QVERIFY(!view.itemDelegateForRow(0)); | 
| 1107 |     QVERIFY(rowDelegate); // <- wasn't deleted | 
| 1108 |  | 
| 1109 |     view.setItemDelegateForColumn(column: 1, delegate: nullptr); | 
| 1110 |     QVERIFY(!view.itemDelegateForColumn(1)); | 
| 1111 |     QVERIFY(columnDelegate); // <- wasn't deleted | 
| 1112 |  | 
| 1113 |     delete rowDelegate; | 
| 1114 |     delete columnDelegate; | 
| 1115 | } | 
| 1116 |  | 
| 1117 | void tst_QTreeView::keyboardSearch() | 
| 1118 | { | 
| 1119 |     QTreeView view; | 
| 1120 |     QStandardItemModel model; | 
| 1121 |     model.appendRow(aitem: new QStandardItem("Andreas" )); | 
| 1122 |     model.appendRow(aitem: new QStandardItem("Baldrian" )); | 
| 1123 |     model.appendRow(aitem: new QStandardItem("Cecilie" )); | 
| 1124 |     view.setModel(&model); | 
| 1125 |     view.show(); | 
| 1126 |  | 
| 1127 |     // Nothing is selected | 
| 1128 |     QVERIFY(!view.selectionModel()->hasSelection()); | 
| 1129 |     QVERIFY(!view.selectionModel()->isSelected(model.index(0, 0))); | 
| 1130 |  | 
| 1131 |     // First item is selected | 
| 1132 |     view.keyboardSearch(search: QLatin1String("A" )); | 
| 1133 |     QTRY_VERIFY(view.selectionModel()->isSelected(model.index(0, 0))); | 
| 1134 |  | 
| 1135 |     // First item is still selected | 
| 1136 |     view.keyboardSearch(search: QLatin1String("n" )); | 
| 1137 |     QVERIFY(view.selectionModel()->isSelected(model.index(0, 0))); | 
| 1138 |  | 
| 1139 |     // No "AnB" item - keep the same selection. | 
| 1140 |     view.keyboardSearch(search: QLatin1String("B" )); | 
| 1141 |     QVERIFY(view.selectionModel()->isSelected(model.index(0, 0))); | 
| 1142 |  | 
| 1143 |     // Wait a bit. | 
| 1144 |     QTest::qWait(ms: QApplication::keyboardInputInterval() * 2); | 
| 1145 |  | 
| 1146 |     // The item that starts with B is selected. | 
| 1147 |     view.keyboardSearch(search: QLatin1String("B" )); | 
| 1148 |     QVERIFY(view.selectionModel()->isSelected(model.index(1, 0))); | 
| 1149 |  | 
| 1150 |     // Test that it wraps round | 
| 1151 |     model.appendRow(aitem: new QStandardItem("Andy" )); | 
| 1152 |     QTest::qWait(ms: QApplication::keyboardInputInterval() * 2); | 
| 1153 |     view.keyboardSearch(search: QLatin1String("A" )); | 
| 1154 |     QVERIFY(view.selectionModel()->isSelected(model.index(3, 0))); | 
| 1155 |     QTest::qWait(ms: QApplication::keyboardInputInterval() * 2); | 
| 1156 |     view.keyboardSearch(search: QLatin1String("A" )); | 
| 1157 |     QVERIFY(view.selectionModel()->isSelected(model.index(0, 0))); | 
| 1158 |     QTest::qWait(ms: QApplication::keyboardInputInterval() * 2); | 
| 1159 |     view.keyboardSearch(search: QLatin1String("A" )); | 
| 1160 |     QVERIFY(view.selectionModel()->isSelected(model.index(3, 0))); | 
| 1161 |  | 
| 1162 |     // Test that it handles the case where the first item is hidden correctly | 
| 1163 |     model.insertRow(arow: 0, aitem: new QStandardItem("Hidden item" )); | 
| 1164 |     view.setRowHidden(row: 0, parent: QModelIndex(), hide: true); | 
| 1165 |  | 
| 1166 |     QTest::qWait(ms: QApplication::keyboardInputInterval() * 2); | 
| 1167 |     view.keyboardSearch(search: QLatin1String("A" )); | 
| 1168 |     QVERIFY(view.selectionModel()->isSelected(model.index(1, 0))); | 
| 1169 |     QTest::qWait(ms: QApplication::keyboardInputInterval() * 2); | 
| 1170 |     view.keyboardSearch(search: QLatin1String("A" )); | 
| 1171 |     QVERIFY(view.selectionModel()->isSelected(model.index(4, 0))); | 
| 1172 |     QTest::qWait(ms: QApplication::keyboardInputInterval() * 2); | 
| 1173 |     view.keyboardSearch(search: QLatin1String("A" )); | 
| 1174 |     QVERIFY(view.selectionModel()->isSelected(model.index(1, 0))); | 
| 1175 |  | 
| 1176 |     QTest::qWait(ms: QApplication::keyboardInputInterval() * 2); | 
| 1177 |     model.clear(); | 
| 1178 |     view.setCurrentIndex(QModelIndex()); | 
| 1179 |     model.appendRow(items: { new QStandardItem("Andreas" ), new QStandardItem("Alicia" ) }); | 
| 1180 |     model.appendRow(items: { new QStandardItem("Baldrian" ), new QStandardItem("Belinda" ) }); | 
| 1181 |     model.appendRow(items: { new QStandardItem("Cecilie" ), new QStandardItem("Claire" ) }); | 
| 1182 |     QVERIFY(!view.selectionModel()->hasSelection()); | 
| 1183 |     QVERIFY(!view.selectionModel()->isSelected(model.index(0, 0))); | 
| 1184 |  | 
| 1185 |     // We want to search on the 2nd column so we have to force it to have | 
| 1186 |     // an index in that column as a starting point | 
| 1187 |     view.setCurrentIndex(QModelIndex(model.index(row: 0, column: 1))); | 
| 1188 |     // Second item in first row is selected | 
| 1189 |     view.keyboardSearch(search: QLatin1String("A" )); | 
| 1190 |     QTRY_VERIFY(view.selectionModel()->isSelected(model.index(0, 1))); | 
| 1191 |     QVERIFY(view.currentIndex() == model.index(0, 1)); | 
| 1192 |  | 
| 1193 |     // Second item in first row is still selected | 
| 1194 |     view.keyboardSearch(search: QLatin1String("l" )); | 
| 1195 |     QVERIFY(view.selectionModel()->isSelected(model.index(0, 1))); | 
| 1196 |     QCOMPARE(view.currentIndex(), model.index(0, 1)); | 
| 1197 |  | 
| 1198 |     // No "AnB" item - keep the same selection. | 
| 1199 |     view.keyboardSearch(search: QLatin1String("B" )); | 
| 1200 |     QVERIFY(view.selectionModel()->isSelected(model.index(0, 1))); | 
| 1201 |     QCOMPARE(view.currentIndex(), model.index(0, 1)); | 
| 1202 |  | 
| 1203 |     // Wait a bit. | 
| 1204 |     QTest::qWait(ms: QApplication::keyboardInputInterval() * 2); | 
| 1205 |  | 
| 1206 |     // The item that starts with B is selected. | 
| 1207 |     view.keyboardSearch(search: QLatin1String("B" )); | 
| 1208 |     QVERIFY(view.selectionModel()->isSelected(model.index(1, 1))); | 
| 1209 |     QCOMPARE(view.currentIndex(), model.index(1, 1)); | 
| 1210 |  | 
| 1211 |     // Test that it wraps round | 
| 1212 |     model.appendRow(items: { new QStandardItem("Andy" ), new QStandardItem("Adele" ) }); | 
| 1213 |     QTest::qWait(ms: QApplication::keyboardInputInterval() * 2); | 
| 1214 |     view.keyboardSearch(search: QLatin1String("A" )); | 
| 1215 |     QVERIFY(view.selectionModel()->isSelected(model.index(3, 1))); | 
| 1216 |     QCOMPARE(view.currentIndex(), model.index(3, 1)); | 
| 1217 |     QTest::qWait(ms: QApplication::keyboardInputInterval() * 2); | 
| 1218 |     view.keyboardSearch(search: QLatin1String("A" )); | 
| 1219 |     QVERIFY(view.selectionModel()->isSelected(model.index(0, 1))); | 
| 1220 |     QCOMPARE(view.currentIndex(), model.index(0, 1)); | 
| 1221 |     QTest::qWait(ms: QApplication::keyboardInputInterval() * 2); | 
| 1222 |     view.keyboardSearch(search: QLatin1String("A" )); | 
| 1223 |     QVERIFY(view.selectionModel()->isSelected(model.index(3, 1))); | 
| 1224 |     QCOMPARE(view.currentIndex(), model.index(3, 1)); | 
| 1225 |  | 
| 1226 |     // Test that it handles the case where the first item is hidden correctly | 
| 1227 |     model.insertRow(arow: 0, aitem: new QStandardItem("Hidden item" )); | 
| 1228 |     view.setRowHidden(row: 0, parent: QModelIndex(), hide: true); | 
| 1229 |  | 
| 1230 |     QTest::qWait(ms: QApplication::keyboardInputInterval() * 2); | 
| 1231 |     view.keyboardSearch(search: QLatin1String("A" )); | 
| 1232 |     QVERIFY(view.selectionModel()->isSelected(model.index(1, 1))); | 
| 1233 |     QCOMPARE(view.currentIndex(), model.index(1, 1)); | 
| 1234 |     QTest::qWait(ms: QApplication::keyboardInputInterval() * 2); | 
| 1235 |     view.keyboardSearch(search: QLatin1String("A" )); | 
| 1236 |     QVERIFY(view.selectionModel()->isSelected(model.index(4, 1))); | 
| 1237 |     QCOMPARE(view.currentIndex(), model.index(4, 1)); | 
| 1238 |     QTest::qWait(ms: QApplication::keyboardInputInterval() * 2); | 
| 1239 |     view.keyboardSearch(search: QLatin1String("A" )); | 
| 1240 |     QVERIFY(view.selectionModel()->isSelected(model.index(1, 1))); | 
| 1241 |     QCOMPARE(view.currentIndex(), model.index(1, 1)); | 
| 1242 | } | 
| 1243 |  | 
| 1244 | void tst_QTreeView::keyboardSearchMultiColumn() | 
| 1245 | { | 
| 1246 |     if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) | 
| 1247 |         QSKIP("Wayland: This fails. Figure out why." ); | 
| 1248 |  | 
| 1249 |     QTreeView view; | 
| 1250 |     QStandardItemModel model(4, 2); | 
| 1251 |  | 
| 1252 |     model.setItem(row: 0, column: 0, item: new QStandardItem("1" ));    model.setItem(row: 0, column: 1, item: new QStandardItem("green" )); | 
| 1253 |     model.setItem(row: 1, column: 0, item: new QStandardItem("bad" ));  model.setItem(row: 1, column: 1, item: new QStandardItem("eggs" )); | 
| 1254 |     model.setItem(row: 2, column: 0, item: new QStandardItem("moof" )); model.setItem(row: 2, column: 1, item: new QStandardItem("and" )); | 
| 1255 |     model.setItem(row: 3, column: 0, item: new QStandardItem("elf" ));  model.setItem(row: 3, column: 1, item: new QStandardItem("ham" )); | 
| 1256 |  | 
| 1257 |     view.setModel(&model); | 
| 1258 |     view.show(); | 
| 1259 |     QApplication::setActiveWindow(&view); | 
| 1260 |     QVERIFY(QTest::qWaitForWindowActive(&view)); | 
| 1261 |  | 
| 1262 |     view.setCurrentIndex(model.index(row: 0, column: 1)); | 
| 1263 |  | 
| 1264 |     // First item is selected | 
| 1265 |     view.keyboardSearch(search: QLatin1String("eggs" )); | 
| 1266 |     QVERIFY(view.selectionModel()->isSelected(model.index(1, 1))); | 
| 1267 |  | 
| 1268 |     QTest::qWait(ms: QApplication::keyboardInputInterval() * 2); | 
| 1269 |  | 
| 1270 |     // 'ham' is selected | 
| 1271 |     view.keyboardSearch(search: QLatin1String("h" )); | 
| 1272 |     QVERIFY(view.selectionModel()->isSelected(model.index(3, 1))); | 
| 1273 | } | 
| 1274 |  | 
| 1275 | void tst_QTreeView::setModel() | 
| 1276 | { | 
| 1277 |     QTreeView view; | 
| 1278 |     view.show(); | 
| 1279 |     QCOMPARE(view.model(), nullptr); | 
| 1280 |     QCOMPARE(view.selectionModel(), nullptr); | 
| 1281 |     QCOMPARE(view.header()->model(), nullptr); | 
| 1282 |     QCOMPARE(view.header()->selectionModel(), nullptr); | 
| 1283 |  | 
| 1284 |     for (int x = 0; x < 2; ++x) { | 
| 1285 |         QtTestModel *model = new QtTestModel(10, 8); | 
| 1286 |         QAbstractItemModel *oldModel = view.model(); | 
| 1287 |         QSignalSpy modelDestroyedSpy(oldModel ? oldModel : model, &QObject::destroyed); | 
| 1288 |         // set the same model twice | 
| 1289 |         for (int i = 0; i < 2; ++i) { | 
| 1290 |             QItemSelectionModel *oldSelectionModel = view.selectionModel(); | 
| 1291 |             QItemSelectionModel *dummy = new QItemSelectionModel(model); | 
| 1292 |             QSignalSpy selectionModelDestroyedSpy( | 
| 1293 |                 oldSelectionModel ? oldSelectionModel : dummy, &QObject::destroyed); | 
| 1294 |             view.setModel(model); | 
| 1295 | //                QCOMPARE(selectionModelDestroyedSpy.count(), (x == 0 || i == 1) ? 0 : 1); | 
| 1296 |             QCOMPARE(view.model(), model); | 
| 1297 |             QCOMPARE(view.header()->model(), model); | 
| 1298 |             QCOMPARE(view.selectionModel() != oldSelectionModel, (i == 0)); | 
| 1299 |         } | 
| 1300 |         QTRY_COMPARE(modelDestroyedSpy.count(), 0); | 
| 1301 |  | 
| 1302 |         view.setModel(nullptr); | 
| 1303 |         QCOMPARE(view.model(), nullptr); | 
| 1304 |         // ### shouldn't selectionModel also be 0 now? | 
| 1305 | //        QCOMPARE(view.selectionModel(), nullptr); | 
| 1306 |         delete model; | 
| 1307 |     } | 
| 1308 | } | 
| 1309 |  | 
| 1310 | void tst_QTreeView::openPersistentEditor() | 
| 1311 | { | 
| 1312 |     QTreeView view; | 
| 1313 |     QStandardItemModel treeModel; | 
| 1314 |     initStandardTreeModel(model: &treeModel); | 
| 1315 |     view.setModel(&treeModel); | 
| 1316 |     view.show(); | 
| 1317 |  | 
| 1318 |     QVERIFY(!view.viewport()->findChild<QLineEdit *>()); | 
| 1319 |     view.openPersistentEditor(index: view.model()->index(row: 0, column: 0)); | 
| 1320 |     QVERIFY(view.viewport()->findChild<QLineEdit *>()); | 
| 1321 |  | 
| 1322 |     view.closePersistentEditor(index: view.model()->index(row: 0, column: 0)); | 
| 1323 |     QVERIFY(!view.viewport()->findChild<QLineEdit *>()->isVisible()); | 
| 1324 |  | 
| 1325 |     QCoreApplication::sendPostedEvents(receiver: nullptr, event_type: QEvent::DeferredDelete); | 
| 1326 |     QVERIFY(!view.viewport()->findChild<QLineEdit *>()); | 
| 1327 | } | 
| 1328 |  | 
| 1329 | void tst_QTreeView::rootIndex() | 
| 1330 | { | 
| 1331 |     QTreeView view; | 
| 1332 |     QCOMPARE(view.rootIndex(), QModelIndex()); | 
| 1333 |     QStandardItemModel treeModel; | 
| 1334 |     initStandardTreeModel(model: &treeModel); | 
| 1335 |     view.setModel(&treeModel); | 
| 1336 |     QCOMPARE(view.rootIndex(), QModelIndex()); | 
| 1337 |  | 
| 1338 |     view.setRootIndex(view.model()->index(row: 1, column: 0)); | 
| 1339 |  | 
| 1340 |     QCOMPARE(view.model()->data(view.model()->index(0, view.header()->visualIndex(0), view.rootIndex()), Qt::DisplayRole) | 
| 1341 |              .toString(), QString("Row 2 Child Item" )); | 
| 1342 | } | 
| 1343 |  | 
| 1344 | void tst_QTreeView::() | 
| 1345 | { | 
| 1346 |     QTreeView view; | 
| 1347 |     QVERIFY(view.header() != nullptr); | 
| 1348 |     QCOMPARE(view.header()->orientation(), Qt::Horizontal); | 
| 1349 |     QCOMPARE(view.header()->parent(), &view); | 
| 1350 |     for (int x = 0; x < 2; ++x) { | 
| 1351 |         QSignalSpy destroyedSpy(view.header(), &QObject::destroyed); | 
| 1352 |         Qt::Orientation orient = x ? Qt::Vertical : Qt::Horizontal; | 
| 1353 |         QHeaderView *head = new QHeaderView(orient); | 
| 1354 |         view.setHeader(head); | 
| 1355 |         QCOMPARE(destroyedSpy.count(), 1); | 
| 1356 |         QCOMPARE(head->parent(), &view); | 
| 1357 |         QCOMPARE(view.header(), head); | 
| 1358 |         view.setHeader(head); | 
| 1359 |         QCOMPARE(view.header(), head); | 
| 1360 |         view.setHeader(nullptr); | 
| 1361 |         QCOMPARE(view.header(), head); | 
| 1362 |     } | 
| 1363 | } | 
| 1364 |  | 
| 1365 | void tst_QTreeView::columnHidden() | 
| 1366 | { | 
| 1367 |     QTreeView view; | 
| 1368 |     QtTestModel model(10, 8); | 
| 1369 |     view.setModel(&model); | 
| 1370 |     view.show(); | 
| 1371 |     for (int c = 0; c < model.columnCount(); ++c) | 
| 1372 |         QCOMPARE(view.isColumnHidden(c), false); | 
| 1373 |     // hide even columns | 
| 1374 |     for (int c = 0; c < model.columnCount(); c += 2) | 
| 1375 |         view.setColumnHidden(column: c, hide: true); | 
| 1376 |     for (int c = 0; c < model.columnCount(); ++c) | 
| 1377 |         QCOMPARE(view.isColumnHidden(c), (c & 1) == 0); | 
| 1378 |     view.update(); | 
| 1379 |     // hide odd columns too | 
| 1380 |     for (int c = 1; c < model.columnCount(); c += 2) | 
| 1381 |         view.setColumnHidden(column: c, hide: true); | 
| 1382 |     for (int c = 0; c < model.columnCount(); ++c) | 
| 1383 |         QCOMPARE(view.isColumnHidden(c), true); | 
| 1384 |     view.update(); | 
| 1385 |  | 
| 1386 |     // QTBUG 54610 | 
| 1387 |     // QAbstractItemViewPrivate::_q_layoutChanged() is called on | 
| 1388 |     // rows/columnMoved and because this function is virtual, | 
| 1389 |     // QHeaderViewPrivate::_q_layoutChanged() was called and unhided | 
| 1390 |     // all sections because QHeaderViewPrivate::_q_layoutAboutToBeChanged() | 
| 1391 |     // could not fill persistentHiddenSections (and is not needed) | 
| 1392 |     view.hideColumn(column: model.cols - 1); | 
| 1393 |     QCOMPARE(view.isColumnHidden(model.cols - 1), true); | 
| 1394 |     model.simulateMoveRows(); | 
| 1395 |     QCOMPARE(view.isColumnHidden(model.cols - 1), true); | 
| 1396 | } | 
| 1397 |  | 
| 1398 | void tst_QTreeView::rowHidden() | 
| 1399 | { | 
| 1400 |     QtTestModel model(4, 6); | 
| 1401 |     model.levels = 3; | 
| 1402 |     QTreeView view; | 
| 1403 |     view.resize(w: 500,h: 500); | 
| 1404 |     view.setModel(&model); | 
| 1405 |     view.show(); | 
| 1406 |  | 
| 1407 |     QCOMPARE(view.isRowHidden(-1, QModelIndex()), false); | 
| 1408 |     QCOMPARE(view.isRowHidden(999999, QModelIndex()), false); | 
| 1409 |     view.setRowHidden(row: -1, parent: QModelIndex(), hide: true); | 
| 1410 |     view.setRowHidden(row: 999999, parent: QModelIndex(), hide: true); | 
| 1411 |     QCOMPARE(view.isRowHidden(-1, QModelIndex()), false); | 
| 1412 |     QCOMPARE(view.isRowHidden(999999, QModelIndex()), false); | 
| 1413 |  | 
| 1414 |     view.setRowHidden(row: 0, parent: QModelIndex(), hide: true); | 
| 1415 |     QCOMPARE(view.isRowHidden(0, QModelIndex()), true); | 
| 1416 |     view.setRowHidden(row: 0, parent: QModelIndex(), hide: false); | 
| 1417 |     QCOMPARE(view.isRowHidden(0, QModelIndex()), false); | 
| 1418 |  | 
| 1419 |     QStack<QModelIndex> parents; | 
| 1420 |     parents.push(t: QModelIndex()); | 
| 1421 |     while (!parents.isEmpty()) { | 
| 1422 |         QModelIndex p = parents.pop(); | 
| 1423 |         if (model.canFetchMore(p)) | 
| 1424 |             model.fetchMore(p); | 
| 1425 |         int rows = model.rowCount(parent: p); | 
| 1426 |         // hide all | 
| 1427 |         for (int r = 0; r < rows; ++r) { | 
| 1428 |             view.setRowHidden(row: r, parent: p, hide: true); | 
| 1429 |             QCOMPARE(view.isRowHidden(r, p), true); | 
| 1430 |         } | 
| 1431 |         // hide none | 
| 1432 |         for (int r = 0; r < rows; ++r) { | 
| 1433 |             view.setRowHidden(row: r, parent: p, hide: false); | 
| 1434 |             QCOMPARE(view.isRowHidden(r, p), false); | 
| 1435 |         } | 
| 1436 |         // hide only even rows | 
| 1437 |         for (int r = 0; r < rows; ++r) { | 
| 1438 |             bool hide = (r & 1) == 0; | 
| 1439 |             view.setRowHidden(row: r, parent: p, hide); | 
| 1440 |             QCOMPARE(view.isRowHidden(r, p), hide); | 
| 1441 |         } | 
| 1442 |         for (int r = 0; r < rows; ++r) | 
| 1443 |             parents.push(t: model.index(row: r, column: 0, parent: p)); | 
| 1444 |     } | 
| 1445 |  | 
| 1446 |     parents.push(t: QModelIndex()); | 
| 1447 |     while (!parents.isEmpty()) { | 
| 1448 |         QModelIndex p = parents.pop(); | 
| 1449 |         // all even rows should still be hidden | 
| 1450 |         for (int r = 0; r < model.rowCount(parent: p); ++r) | 
| 1451 |             QCOMPARE(view.isRowHidden(r, p), (r & 1) == 0); | 
| 1452 |         if (model.rowCount(parent: p) > 0) { | 
| 1453 |             for (int r = 0; r < model.rowCount(parent: p); ++r) | 
| 1454 |                 parents.push(t: model.index(row: r, column: 0, parent: p)); | 
| 1455 |         } | 
| 1456 |     } | 
| 1457 | } | 
| 1458 |  | 
| 1459 | void tst_QTreeView::noDelegate() | 
| 1460 | { | 
| 1461 |     QtTestModel model(10, 7); | 
| 1462 |     QTreeView view; | 
| 1463 |     view.setModel(&model); | 
| 1464 |     view.setItemDelegate(nullptr); | 
| 1465 |     QCOMPARE(view.itemDelegate(), nullptr); | 
| 1466 | } | 
| 1467 |  | 
| 1468 | void tst_QTreeView::noModel() | 
| 1469 | { | 
| 1470 |     QTreeView view; | 
| 1471 |     view.show(); | 
| 1472 |     view.setRowHidden(row: 0, parent: QModelIndex(), hide: true); | 
| 1473 |     // no model -> not able to hide a row | 
| 1474 |     QVERIFY(!view.isRowHidden(0, QModelIndex())); | 
| 1475 | } | 
| 1476 |  | 
| 1477 | void tst_QTreeView::emptyModel() | 
| 1478 | { | 
| 1479 |     QtTestModel model(0, 0); | 
| 1480 |     QTreeView view; | 
| 1481 |     view.setModel(&model); | 
| 1482 |     view.show(); | 
| 1483 |     QVERIFY(!model.wrongIndex); | 
| 1484 | } | 
| 1485 |  | 
| 1486 | void tst_QTreeView::removeRows() | 
| 1487 | { | 
| 1488 |     QtTestModel model(7, 10); | 
| 1489 |  | 
| 1490 |     QTreeView view; | 
| 1491 |  | 
| 1492 |     view.setModel(&model); | 
| 1493 |     view.show(); | 
| 1494 |  | 
| 1495 |     model.removeLastRow(); | 
| 1496 |     QVERIFY(!model.wrongIndex); | 
| 1497 |  | 
| 1498 |     model.removeAllRows(); | 
| 1499 |     QVERIFY(!model.wrongIndex); | 
| 1500 | } | 
| 1501 |  | 
| 1502 | void tst_QTreeView::removeCols() | 
| 1503 | { | 
| 1504 |     QtTestModel model(5, 8); | 
| 1505 |  | 
| 1506 |     QTreeView view; | 
| 1507 |     view.setModel(&model); | 
| 1508 |     view.show(); | 
| 1509 |     model.fetched = true; | 
| 1510 |     model.removeLastColumn(); | 
| 1511 |     QVERIFY(!model.wrongIndex); | 
| 1512 |     QCOMPARE(view.header()->count(), model.cols); | 
| 1513 |  | 
| 1514 |     model.removeAllColumns(); | 
| 1515 |     QVERIFY(!model.wrongIndex); | 
| 1516 |     QCOMPARE(view.header()->count(), model.cols); | 
| 1517 | } | 
| 1518 |  | 
| 1519 | void tst_QTreeView::limitedExpand() | 
| 1520 | { | 
| 1521 |     { | 
| 1522 |         QStandardItemModel model; | 
| 1523 |         QStandardItem *parentItem = model.invisibleRootItem(); | 
| 1524 |         parentItem->appendRow(aitem: new QStandardItem); | 
| 1525 |         parentItem->appendRow(aitem: new QStandardItem); | 
| 1526 |         parentItem->appendRow(aitem: new QStandardItem); | 
| 1527 |  | 
| 1528 |         QStandardItem *firstItem = model.item(row: 0, column: 0); | 
| 1529 |         firstItem->setFlags(firstItem->flags() | Qt::ItemNeverHasChildren); | 
| 1530 |  | 
| 1531 |         QTreeView view; | 
| 1532 |         view.setModel(&model); | 
| 1533 |  | 
| 1534 |         QSignalSpy spy(&view, &QTreeView::expanded); | 
| 1535 |         QVERIFY(spy.isValid()); | 
| 1536 |  | 
| 1537 |         view.expand(index: model.index(row: 0, column: 0)); | 
| 1538 |         QCOMPARE(spy.count(), 0); | 
| 1539 |  | 
| 1540 |         view.expand(index: model.index(row: 1, column: 0)); | 
| 1541 |         QCOMPARE(spy.count(), 1); | 
| 1542 |     } | 
| 1543 |     { | 
| 1544 |         QStringListModel model(QStringList() << "one"  << "two" ); | 
| 1545 |         QTreeView view; | 
| 1546 |         view.setModel(&model); | 
| 1547 |  | 
| 1548 |         QSignalSpy spy(&view, &QTreeView::expanded); | 
| 1549 |         QVERIFY(spy.isValid()); | 
| 1550 |  | 
| 1551 |         view.expand(index: model.index(row: 0, column: 0)); | 
| 1552 |         QCOMPARE(spy.count(), 0); | 
| 1553 |         view.expandAll(); | 
| 1554 |         QCOMPARE(spy.count(), 0); | 
| 1555 |     } | 
| 1556 | } | 
| 1557 |  | 
| 1558 | void tst_QTreeView::expandAndCollapse_data() | 
| 1559 | { | 
| 1560 |     QTest::addColumn<bool>(name: "animationEnabled" ); | 
| 1561 |     QTest::newRow(dataTag: "normal" ) << false; | 
| 1562 |     QTest::newRow(dataTag: "animated" ) << true; | 
| 1563 | } | 
| 1564 |  | 
| 1565 | void tst_QTreeView::expandAndCollapse() | 
| 1566 | { | 
| 1567 |     QFETCH(bool, animationEnabled); | 
| 1568 |  | 
| 1569 |     QtTestModel model(10, 9); | 
| 1570 |  | 
| 1571 |     QTreeView view; | 
| 1572 |     view.setUniformRowHeights(true); | 
| 1573 |     view.setModel(&model); | 
| 1574 |     view.setAnimated(animationEnabled); | 
| 1575 |     view.show(); | 
| 1576 |  | 
| 1577 |     QModelIndex a = model.index(row: 0, column: 0, parent: QModelIndex()); | 
| 1578 |     QModelIndex b = model.index(row: 0, column: 0, parent: a); | 
| 1579 |  | 
| 1580 |     QSignalSpy expandedSpy(&view, &QTreeView::expanded); | 
| 1581 |     QSignalSpy collapsedSpy(&view, &QTreeView::collapsed); | 
| 1582 |     QVariantList args; | 
| 1583 |  | 
| 1584 |     for (int y = 0; y < 2; ++y) { | 
| 1585 |         view.setVisible(y == 0); | 
| 1586 |         for (int x = 0; x < 2; ++x) { | 
| 1587 |             view.setItemsExpandable(x == 0); | 
| 1588 |  | 
| 1589 |             // Test bad args | 
| 1590 |             view.expand(index: QModelIndex()); | 
| 1591 |             QCOMPARE(view.isExpanded(QModelIndex()), false); | 
| 1592 |             view.collapse(index: QModelIndex()); | 
| 1593 |             QCOMPARE(expandedSpy.count(), 0); | 
| 1594 |             QCOMPARE(collapsedSpy.count(), 0); | 
| 1595 |  | 
| 1596 |             // expand a first level item | 
| 1597 |             QVERIFY(!view.isExpanded(a)); | 
| 1598 |             view.expand(index: a); | 
| 1599 |             QVERIFY(view.isExpanded(a)); | 
| 1600 |             QCOMPARE(expandedSpy.count(), 1); | 
| 1601 |             QCOMPARE(collapsedSpy.count(), 0); | 
| 1602 |             args = expandedSpy.takeFirst(); | 
| 1603 |             QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), a); | 
| 1604 |  | 
| 1605 |             view.expand(index: a); | 
| 1606 |             QVERIFY(view.isExpanded(a)); | 
| 1607 |             QCOMPARE(expandedSpy.count(), 0); | 
| 1608 |             QCOMPARE(collapsedSpy.count(), 0); | 
| 1609 |  | 
| 1610 |             // expand a second level item | 
| 1611 |             QVERIFY(!view.isExpanded(b)); | 
| 1612 |             view.expand(index: b); | 
| 1613 |             QVERIFY(view.isExpanded(a)); | 
| 1614 |             QVERIFY(view.isExpanded(b)); | 
| 1615 |             QCOMPARE(expandedSpy.count(), 1); | 
| 1616 |             QCOMPARE(collapsedSpy.count(), 0); | 
| 1617 |             args = expandedSpy.takeFirst(); | 
| 1618 |             QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), b); | 
| 1619 |  | 
| 1620 |             view.expand(index: b); | 
| 1621 |             QVERIFY(view.isExpanded(b)); | 
| 1622 |             QCOMPARE(expandedSpy.count(), 0); | 
| 1623 |             QCOMPARE(collapsedSpy.count(), 0); | 
| 1624 |  | 
| 1625 |             // collapse the first level item | 
| 1626 |             view.collapse(index: a); | 
| 1627 |             QVERIFY(!view.isExpanded(a)); | 
| 1628 |             QVERIFY(view.isExpanded(b)); | 
| 1629 |             QCOMPARE(expandedSpy.count(), 0); | 
| 1630 |             QCOMPARE(collapsedSpy.count(), 1); | 
| 1631 |             args = collapsedSpy.takeFirst(); | 
| 1632 |             QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), a); | 
| 1633 |  | 
| 1634 |             view.collapse(index: a); | 
| 1635 |             QVERIFY(!view.isExpanded(a)); | 
| 1636 |             QCOMPARE(expandedSpy.count(), 0); | 
| 1637 |             QCOMPARE(collapsedSpy.count(), 0); | 
| 1638 |  | 
| 1639 |             // expand the first level item again | 
| 1640 |             view.expand(index: a); | 
| 1641 |             QVERIFY(view.isExpanded(a)); | 
| 1642 |             QVERIFY(view.isExpanded(b)); | 
| 1643 |             QCOMPARE(expandedSpy.count(), 1); | 
| 1644 |             QCOMPARE(collapsedSpy.count(), 0); | 
| 1645 |             args = expandedSpy.takeFirst(); | 
| 1646 |             QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), a); | 
| 1647 |  | 
| 1648 |             // collapse the second level item | 
| 1649 |             view.collapse(index: b); | 
| 1650 |             QVERIFY(view.isExpanded(a)); | 
| 1651 |             QVERIFY(!view.isExpanded(b)); | 
| 1652 |             QCOMPARE(expandedSpy.count(), 0); | 
| 1653 |             QCOMPARE(collapsedSpy.count(), 1); | 
| 1654 |             args = collapsedSpy.takeFirst(); | 
| 1655 |             QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), b); | 
| 1656 |  | 
| 1657 |             // collapse the first level item | 
| 1658 |             view.collapse(index: a); | 
| 1659 |             QVERIFY(!view.isExpanded(a)); | 
| 1660 |             QVERIFY(!view.isExpanded(b)); | 
| 1661 |             QCOMPARE(expandedSpy.count(), 0); | 
| 1662 |             QCOMPARE(collapsedSpy.count(), 1); | 
| 1663 |             args = collapsedSpy.takeFirst(); | 
| 1664 |             QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), a); | 
| 1665 |  | 
| 1666 |             // expand and remove row | 
| 1667 |             QPersistentModelIndex c = model.index(row: 9, column: 0, parent: b); | 
| 1668 |             view.expand(index: a); | 
| 1669 |             view.expand(index: b); | 
| 1670 |             model.removeLastRow(); // remove c | 
| 1671 |             QVERIFY(view.isExpanded(a)); | 
| 1672 |             QVERIFY(view.isExpanded(b)); | 
| 1673 |             QVERIFY(!view.isExpanded(c)); | 
| 1674 |             QCOMPARE(expandedSpy.count(), 2); | 
| 1675 |             QCOMPARE(collapsedSpy.count(), 0); | 
| 1676 |             args = expandedSpy.takeFirst(); | 
| 1677 |             QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), a); | 
| 1678 |             args = expandedSpy.takeFirst(); | 
| 1679 |             QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), b); | 
| 1680 |  | 
| 1681 |             view.collapse(index: a); | 
| 1682 |             view.collapse(index: b); | 
| 1683 |             QVERIFY(!view.isExpanded(a)); | 
| 1684 |             QVERIFY(!view.isExpanded(b)); | 
| 1685 |             QVERIFY(!view.isExpanded(c)); | 
| 1686 |             QCOMPARE(expandedSpy.count(), 0); | 
| 1687 |             QCOMPARE(collapsedSpy.count(), 2); | 
| 1688 |             args = collapsedSpy.takeFirst(); | 
| 1689 |             QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), a); | 
| 1690 |             args = collapsedSpy.takeFirst(); | 
| 1691 |             QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), b); | 
| 1692 |         } | 
| 1693 |     } | 
| 1694 | } | 
| 1695 |  | 
| 1696 | static void checkExpandState(const QAbstractItemModel &model, const QTreeView &view, | 
| 1697 |                              const QModelIndex &startIdx, bool bIsExpanded, int *count) | 
| 1698 | { | 
| 1699 |     *count = 0; | 
| 1700 |     QStack<QModelIndex> parents; | 
| 1701 |     parents.push(t: startIdx); | 
| 1702 |     if (startIdx.isValid()) { | 
| 1703 |         QCOMPARE(view.isExpanded(startIdx), bIsExpanded); | 
| 1704 |         *count += 1; | 
| 1705 |     } | 
| 1706 |     while (!parents.isEmpty()) { | 
| 1707 |         const QModelIndex p = parents.pop(); | 
| 1708 |         const int rows = model.rowCount(parent: p); | 
| 1709 |         for (int r = 0; r < rows; ++r) { | 
| 1710 |             const QModelIndex c = model.index(row: r, column: 0, parent: p); | 
| 1711 |             QCOMPARE(view.isExpanded(c), bIsExpanded); | 
| 1712 |             parents.push(t: c); | 
| 1713 |         } | 
| 1714 |         *count += rows; | 
| 1715 |     } | 
| 1716 | } | 
| 1717 |  | 
| 1718 | void tst_QTreeView::expandAndCollapseAll() | 
| 1719 | { | 
| 1720 |     QStandardItemModel model; | 
| 1721 |     // QtTestModel has a broken parent/child handling which will break the test | 
| 1722 |     for (int i1 = 0; i1 < 3; ++i1) { | 
| 1723 |         QStandardItem *s1 = new QStandardItem; | 
| 1724 |         s1->setText(QString::number(i1)); | 
| 1725 |         model.appendRow(aitem: s1); | 
| 1726 |         for (int i2 = 0; i2 < 3; ++i2) { | 
| 1727 |             QStandardItem *s2 = new QStandardItem; | 
| 1728 |             s2->setText(QStringLiteral("%1 - %2" ).arg(a: i1).arg(a: i2)); | 
| 1729 |             s1->appendRow(aitem: s2); | 
| 1730 |             for (int i3 = 0; i3 < 3; ++i3) { | 
| 1731 |                 QStandardItem *s3 = new QStandardItem; | 
| 1732 |                 s3->setText(QStringLiteral("%1 - %2 - %3" ).arg(a: i1).arg(a: i2).arg(a: i3)); | 
| 1733 |                 s2->appendRow(aitem: s3); | 
| 1734 |             } | 
| 1735 |         } | 
| 1736 |     } | 
| 1737 |     QTreeView view; | 
| 1738 |     view.setUniformRowHeights(true); | 
| 1739 |     view.setModel(&model); | 
| 1740 |     view.show(); | 
| 1741 |     QVERIFY(QTest::qWaitForWindowExposed(&view)); | 
| 1742 |  | 
| 1743 |     QSignalSpy expandedSpy(&view, &QTreeView::expanded); | 
| 1744 |     QSignalSpy collapsedSpy(&view, &QTreeView::collapsed); | 
| 1745 |     int count; | 
| 1746 |  | 
| 1747 |     view.expandAll(); | 
| 1748 |     checkExpandState(model, view, startIdx: QModelIndex(), bIsExpanded: true, count: &count); | 
| 1749 |     QCOMPARE(collapsedSpy.count(), 0); | 
| 1750 |     QCOMPARE(expandedSpy.count(),  39); // == 3 (first) + 9 (second) + 27 (third level) | 
| 1751 |     QCOMPARE(count, 39); | 
| 1752 |  | 
| 1753 |     collapsedSpy.clear(); | 
| 1754 |     expandedSpy.clear(); | 
| 1755 |     view.collapseAll(); | 
| 1756 |     checkExpandState(model, view, startIdx: QModelIndex(), bIsExpanded: false, count: &count); | 
| 1757 |     QCOMPARE(collapsedSpy.count(), 39); | 
| 1758 |     QCOMPARE(expandedSpy.count(), 0); | 
| 1759 |     QCOMPARE(count, 39); | 
| 1760 |  | 
| 1761 |     collapsedSpy.clear(); | 
| 1762 |     expandedSpy.clear(); | 
| 1763 |     view.expandRecursively(index: model.index(row: 0, column: 0)); | 
| 1764 |     QCOMPARE(expandedSpy.count(), 13); // 1 + 3 + 9 | 
| 1765 |  | 
| 1766 |     checkExpandState(model, view, startIdx: model.index(row: 0, column: 0), bIsExpanded: true, count: &count); | 
| 1767 |     QCOMPARE(count, 13); | 
| 1768 |     checkExpandState(model, view, startIdx: model.index(row: 1, column: 0), bIsExpanded: false, count: &count); | 
| 1769 |     QCOMPARE(count, 13); | 
| 1770 |     checkExpandState(model, view, startIdx: model.index(row: 2, column: 0), bIsExpanded: false, count: &count); | 
| 1771 |     QCOMPARE(count, 13); | 
| 1772 |  | 
| 1773 |     expandedSpy.clear(); | 
| 1774 |     view.collapseAll(); | 
| 1775 |     view.expandRecursively(index: model.index(row: 0, column: 0), depth: 1); | 
| 1776 |     QCOMPARE(expandedSpy.count(), 4); // 1 + 3 | 
| 1777 |     view.expandRecursively(index: model.index(row: 0, column: 0), depth: 2); | 
| 1778 |     QCOMPARE(expandedSpy.count(), 13); // (1 + 3) + 9 | 
| 1779 |  | 
| 1780 |     checkExpandState(model, view, startIdx: model.index(row: 0, column: 0), bIsExpanded: true, count: &count); | 
| 1781 |     QCOMPARE(count, 13); | 
| 1782 |     checkExpandState(model, view, startIdx: model.index(row: 1, column: 0), bIsExpanded: false, count: &count); | 
| 1783 |     QCOMPARE(count, 13); | 
| 1784 |     checkExpandState(model, view, startIdx: model.index(row: 2, column: 0), bIsExpanded: false, count: &count); | 
| 1785 |     QCOMPARE(count, 13); | 
| 1786 | } | 
| 1787 |  | 
| 1788 | void tst_QTreeView::expandWithNoChildren() | 
| 1789 | { | 
| 1790 |     QTreeView tree; | 
| 1791 |     QStandardItemModel model(1, 1); | 
| 1792 |     tree.setModel(&model); | 
| 1793 |     tree.setAnimated(true); | 
| 1794 |     tree.doItemsLayout(); | 
| 1795 |     //this test should not output warnings | 
| 1796 |     tree.expand(index: model.index(row: 0,column: 0)); | 
| 1797 | } | 
| 1798 |  | 
| 1799 |  | 
| 1800 |  | 
| 1801 | void tst_QTreeView::keyboardNavigation() | 
| 1802 | { | 
| 1803 |     const int rows = 10; | 
| 1804 |     const int columns = 7; | 
| 1805 |  | 
| 1806 |     QtTestModel model(rows, columns); | 
| 1807 |  | 
| 1808 |     QTreeView view; | 
| 1809 |     view.setModel(&model); | 
| 1810 |     view.show(); | 
| 1811 |  | 
| 1812 |     const auto keymoves = { | 
| 1813 |         Qt::Key_Down, Qt::Key_Right, Qt::Key_Right, Qt::Key_Right, | 
| 1814 |         Qt::Key_Down, Qt::Key_Down, Qt::Key_Down, Qt::Key_Down, | 
| 1815 |         Qt::Key_Right, Qt::Key_Right, Qt::Key_Right, | 
| 1816 |         Qt::Key_Left, Qt::Key_Up, Qt::Key_Left, Qt::Key_Left, | 
| 1817 |         Qt::Key_Up, Qt::Key_Down, Qt::Key_Up, Qt::Key_Up, | 
| 1818 |         Qt::Key_Up, Qt::Key_Up, Qt::Key_Up, Qt::Key_Up, | 
| 1819 |         Qt::Key_Left, Qt::Key_Left, Qt::Key_Up, Qt::Key_Down | 
| 1820 |     }; | 
| 1821 |  | 
| 1822 |     int row    = 0; | 
| 1823 |     int column = 0; | 
| 1824 |     QModelIndex index = model.index(row, column, parent: QModelIndex()); | 
| 1825 |     view.setCurrentIndex(index); | 
| 1826 |     QCOMPARE(view.currentIndex(), index); | 
| 1827 |  | 
| 1828 |     for (Qt::Key key : keymoves) { | 
| 1829 |         QTest::keyClick(widget: &view, key); | 
| 1830 |  | 
| 1831 |         switch (key) { | 
| 1832 |         case Qt::Key_Up: | 
| 1833 |             if (row > 0) { | 
| 1834 |                 index = index.sibling(arow: row - 1, acolumn: column); | 
| 1835 |                 row -= 1; | 
| 1836 |             } else if (index.parent() != QModelIndex()) { | 
| 1837 |                 index = index.parent(); | 
| 1838 |                 row = index.row(); | 
| 1839 |             } | 
| 1840 |             break; | 
| 1841 |         case Qt::Key_Down: | 
| 1842 |             if (view.isExpanded(index)) { | 
| 1843 |                 row = 0; | 
| 1844 |                 index = model.index(row, column, parent: index); | 
| 1845 |             } else { | 
| 1846 |                 row = qMin(a: rows - 1, b: row + 1); | 
| 1847 |                 index = index.sibling(arow: row, acolumn: column); | 
| 1848 |             } | 
| 1849 |             break; | 
| 1850 |         case Qt::Key_Left: { | 
| 1851 |             QScrollBar *b = view.horizontalScrollBar(); | 
| 1852 |             if (b->value() == b->minimum()) | 
| 1853 |                 QVERIFY(!view.isExpanded(index)); | 
| 1854 |             // windows style right will walk to the parent | 
| 1855 |             if (view.currentIndex() != index) { | 
| 1856 |                 QCOMPARE(view.currentIndex(), index.parent()); | 
| 1857 |                 index = view.currentIndex(); | 
| 1858 |                 row = index.row(); | 
| 1859 |                 column = index.column(); | 
| 1860 |             } | 
| 1861 |             break; | 
| 1862 |         } | 
| 1863 |         case Qt::Key_Right: | 
| 1864 |             QVERIFY(view.isExpanded(index)); | 
| 1865 |             // windows style right will walk to the first child | 
| 1866 |             if (view.currentIndex() != index) { | 
| 1867 |                 QCOMPARE(view.currentIndex().parent(), index); | 
| 1868 |                 row = view.currentIndex().row(); | 
| 1869 |                 column = view.currentIndex().column(); | 
| 1870 |                 index = view.currentIndex(); | 
| 1871 |             } | 
| 1872 |             break; | 
| 1873 |         default: | 
| 1874 |             QVERIFY(false); | 
| 1875 |         } | 
| 1876 |  | 
| 1877 |         QCOMPARE(view.currentIndex().row(), row); | 
| 1878 |         QCOMPARE(view.currentIndex().column(), column); | 
| 1879 |         QCOMPARE(view.currentIndex(), index); | 
| 1880 |     } | 
| 1881 | } | 
| 1882 |  | 
| 1883 | class Dmodel : public QtTestModel | 
| 1884 | { | 
| 1885 |     Q_OBJECT | 
| 1886 | public: | 
| 1887 |     using QtTestModel::QtTestModel; | 
| 1888 |     int columnCount(const QModelIndex &parent) const override | 
| 1889 |     { | 
| 1890 |         if (parent.row() == 5) | 
| 1891 |             return 1; | 
| 1892 |         return QtTestModel::columnCount(parent); | 
| 1893 |     } | 
| 1894 | }; | 
| 1895 |  | 
| 1896 | void tst_QTreeView::() | 
| 1897 | { | 
| 1898 |     Dmodel model(10, 10); | 
| 1899 |  | 
| 1900 |     QTreeView view; | 
| 1901 |     QHeaderView * = view.header(); | 
| 1902 |  | 
| 1903 |     view.setModel(&model); | 
| 1904 |     QModelIndex index = model.index(row: 5, column: 0); | 
| 1905 |     view.setRootIndex(index); | 
| 1906 |     QCOMPARE(model.columnCount(QModelIndex()), 10); | 
| 1907 |     QCOMPARE(model.columnCount(index), 1); | 
| 1908 |     QCOMPARE(header->count(), model.columnCount(index)); | 
| 1909 | } | 
| 1910 |  | 
| 1911 | void tst_QTreeView::moveCursor_data() | 
| 1912 | { | 
| 1913 |     QTest::addColumn<bool>(name: "uniformRowHeights" ); | 
| 1914 |     QTest::addColumn<bool>(name: "scrollPerPixel" ); | 
| 1915 |     QTest::newRow(dataTag: "uniformRowHeights = false, scrollPerPixel = false" ) | 
| 1916 |         << false << false; | 
| 1917 |     QTest::newRow(dataTag: "uniformRowHeights = true, scrollPerPixel = false" ) | 
| 1918 |         << true << false; | 
| 1919 |     QTest::newRow(dataTag: "uniformRowHeights = false, scrollPerPixel = true" ) | 
| 1920 |         << false << true; | 
| 1921 |     QTest::newRow(dataTag: "uniformRowHeights = true, scrollPerPixel = true" ) | 
| 1922 |         << true << true; | 
| 1923 | } | 
| 1924 |  | 
| 1925 | void tst_QTreeView::moveCursor() | 
| 1926 | { | 
| 1927 |     if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) | 
| 1928 |         QSKIP("Wayland: This fails. Figure out why." ); | 
| 1929 |  | 
| 1930 |     QFETCH(bool, uniformRowHeights); | 
| 1931 |     QFETCH(bool, scrollPerPixel); | 
| 1932 |     QtTestModel model(8, 6); | 
| 1933 |  | 
| 1934 |     QTreeView view; | 
| 1935 |     view.setUniformRowHeights(uniformRowHeights); | 
| 1936 |     view.setModel(&model); | 
| 1937 |     view.setRowHidden(row: 0, parent: QModelIndex(), hide: true); | 
| 1938 |     view.setVerticalScrollMode(scrollPerPixel ? | 
| 1939 |             QAbstractItemView::ScrollPerPixel : | 
| 1940 |             QAbstractItemView::ScrollPerItem); | 
| 1941 |     QVERIFY(view.isRowHidden(0, QModelIndex())); | 
| 1942 |     view.setColumnHidden(column: 0, hide: true); | 
| 1943 |     QVERIFY(view.isColumnHidden(0)); | 
| 1944 |     view.show(); | 
| 1945 |     QApplication::setActiveWindow(&view); | 
| 1946 |     QVERIFY(QTest::qWaitForWindowActive(&view)); | 
| 1947 |  | 
| 1948 |     //here the first visible index should be selected | 
| 1949 |     //because the view got the focus | 
| 1950 |     QModelIndex expected = model.index(row: 1, column: 1, parent: QModelIndex()); | 
| 1951 |     QCOMPARE(view.currentIndex(), expected); | 
| 1952 |  | 
| 1953 |     //then pressing down should go to the next line | 
| 1954 |     QModelIndex actual = view.moveCursor(cursorAction: QTreeView::MoveDown, modifiers: Qt::NoModifier); | 
| 1955 |     expected = model.index(row: 2, column: 1, parent: QModelIndex()); | 
| 1956 |     QCOMPARE(actual, expected); | 
| 1957 |  | 
| 1958 |     view.setRowHidden(row: 0, parent: QModelIndex(), hide: false); | 
| 1959 |     view.setColumnHidden(column: 0, hide: false); | 
| 1960 |  | 
| 1961 |     // PageUp was broken with uniform row heights turned on | 
| 1962 |     view.setCurrentIndex(model.index(row: 1, column: 0)); | 
| 1963 |     actual = view.moveCursor(cursorAction: QTreeView::MovePageUp, modifiers: Qt::NoModifier); | 
| 1964 |     expected = model.index(row: 0, column: 0, parent: QModelIndex()); | 
| 1965 |     QCOMPARE(actual, expected); | 
| 1966 |  | 
| 1967 |     //let's try another column | 
| 1968 |     view.setCurrentIndex(model.index(row: 1, column: 1)); | 
| 1969 |     view.setSelectionBehavior(QAbstractItemView::SelectItems); | 
| 1970 |     QTest::keyClick(widget: view.viewport(), key: Qt::Key_Up); | 
| 1971 |     expected = model.index(row: 0, column: 1, parent: QModelIndex()); | 
| 1972 |     QCOMPARE(view.currentIndex(), expected); | 
| 1973 |     QTest::keyClick(widget: view.viewport(), key: Qt::Key_Down); | 
| 1974 |     expected = model.index(row: 1, column: 1, parent: QModelIndex()); | 
| 1975 |     QCOMPARE(view.currentIndex(), expected); | 
| 1976 |     QTest::keyClick(widget: view.viewport(), key: Qt::Key_Up); | 
| 1977 |     expected = model.index(row: 0, column: 1, parent: QModelIndex()); | 
| 1978 |     QCOMPARE(view.currentIndex(), expected); | 
| 1979 |     view.setColumnHidden(column: 0, hide: true); | 
| 1980 |     QTest::keyClick(widget: view.viewport(), key: Qt::Key_Left); | 
| 1981 |     expected = model.index(row: 0, column: 1, parent: QModelIndex()); //it shouldn't have changed | 
| 1982 |     QCOMPARE(view.currentIndex(), expected); | 
| 1983 |     view.setColumnHidden(column: 0, hide: false); | 
| 1984 |     QTest::keyClick(widget: view.viewport(), key: Qt::Key_Left); | 
| 1985 |     expected = model.index(row: 0, column: 0, parent: QModelIndex()); | 
| 1986 |     QCOMPARE(view.currentIndex(), expected); | 
| 1987 | } | 
| 1988 |  | 
| 1989 | class TestDelegate : public QStyledItemDelegate | 
| 1990 | { | 
| 1991 |     Q_OBJECT | 
| 1992 | public: | 
| 1993 |     using QStyledItemDelegate::QStyledItemDelegate; | 
| 1994 |     QSize sizeHint(const QStyleOptionViewItem &, const QModelIndex &) const override | 
| 1995 |     { return QSize(200, 50); } | 
| 1996 | }; | 
| 1997 |  | 
| 1998 | typedef QVector<QPoint> PointList; | 
| 1999 |  | 
| 2000 | void tst_QTreeView::setSelection_data() | 
| 2001 | { | 
| 2002 |     QTest::addColumn<QRect>(name: "selectionRect" ); | 
| 2003 |     QTest::addColumn<QAbstractItemView::SelectionMode>(name: "selectionMode" ); | 
| 2004 |     QTest::addColumn<QItemSelectionModel::SelectionFlags>(name: "selectionCommand" ); | 
| 2005 |     QTest::addColumn<PointList>(name: "expectedItems" ); | 
| 2006 |     QTest::addColumn<int>(name: "verticalOffset" ); | 
| 2007 |  | 
| 2008 |     const PointList pl1{QPoint(0, 0), QPoint(1, 0), QPoint(2, 0), QPoint(3, 0), QPoint(4, 0)}; | 
| 2009 |     const PointList pl2{QPoint(0, 0), QPoint(1, 0), QPoint(2, 0), QPoint(3, 0), QPoint(4, 0), | 
| 2010 |                         QPoint(0, 1), QPoint(1, 1), QPoint(2, 1), QPoint(3, 1), QPoint(4, 1)}; | 
| 2011 |     const QItemSelectionModel::SelectionFlags selFlags(QItemSelectionModel::ClearAndSelect | | 
| 2012 |                                                        QItemSelectionModel::Rows); | 
| 2013 |     QTest::newRow(dataTag: "(0,0,50,20),rows" ) | 
| 2014 |        << QRect(0, 0, 50, 20) | 
| 2015 |        << QAbstractItemView::SingleSelection | 
| 2016 |        << selFlags << pl1 << 0; | 
| 2017 |  | 
| 2018 |     QTest::newRow(dataTag: "(0,0,50,90),rows" ) | 
| 2019 |        << QRect(0, 0, 50, 90) | 
| 2020 |        << QAbstractItemView::ExtendedSelection | 
| 2021 |        << selFlags << pl2 << 0; | 
| 2022 |  | 
| 2023 |     QTest::newRow(dataTag: "(50,0,0,90),rows,invalid rect" ) | 
| 2024 |        << QRect(QPoint(50, 0), QPoint(0, 90)) | 
| 2025 |        << QAbstractItemView::ExtendedSelection | 
| 2026 |        << selFlags << pl2 << 0; | 
| 2027 |  | 
| 2028 |     QTest::newRow(dataTag: "(0,-20,20,50),rows" ) | 
| 2029 |        << QRect(0, -20, 20, 50) | 
| 2030 |        << QAbstractItemView::ExtendedSelection | 
| 2031 |        << selFlags << pl2 << 1; | 
| 2032 |     QTest::newRow(dataTag: "(0,-50,20,90),rows" ) | 
| 2033 |        << QRect(0, -50, 20, 90) | 
| 2034 |        << QAbstractItemView::ExtendedSelection | 
| 2035 |        << selFlags << pl2 << 1; | 
| 2036 | } | 
| 2037 |  | 
| 2038 | void tst_QTreeView::setSelection() | 
| 2039 | { | 
| 2040 |     QFETCH(QRect, selectionRect); | 
| 2041 |     QFETCH(QAbstractItemView::SelectionMode, selectionMode); | 
| 2042 |     QFETCH(QItemSelectionModel::SelectionFlags, selectionCommand); | 
| 2043 |     QFETCH(PointList, expectedItems); | 
| 2044 |     QFETCH(int, verticalOffset); | 
| 2045 |  | 
| 2046 |     QtTestModel model(10, 5); | 
| 2047 |     model.levels = 1; | 
| 2048 |     model.setDecorationsEnabled(true); | 
| 2049 |     QTreeView view; | 
| 2050 |     view.resize(w: 400, h: 300); | 
| 2051 |     view.show(); | 
| 2052 |     view.setRootIsDecorated(false); | 
| 2053 |     view.setItemDelegate(new TestDelegate(&view)); | 
| 2054 |     view.setSelectionMode(selectionMode); | 
| 2055 |     view.setModel(&model); | 
| 2056 |     view.setUniformRowHeights(true); | 
| 2057 |     view.setVerticalScrollMode(QAbstractItemView::ScrollPerItem); | 
| 2058 |     view.scrollTo(index: model.index(row: verticalOffset, column: 0), hint: QAbstractItemView::PositionAtTop); | 
| 2059 |     view.setSelection(rect: selectionRect, command: selectionCommand); | 
| 2060 |     QItemSelectionModel *selectionModel = view.selectionModel(); | 
| 2061 |     QVERIFY(selectionModel); | 
| 2062 |  | 
| 2063 |     const QModelIndexList selectedIndexes = selectionModel->selectedIndexes(); | 
| 2064 | #ifdef Q_OS_WINRT | 
| 2065 |     QEXPECT_FAIL("(0,-20,20,50),rows" , "Fails on WinRT - QTBUG-68297" , Abort); | 
| 2066 |     QEXPECT_FAIL("(0,-50,20,90),rows" , "Fails on WinRT - QTBUG-68297" , Abort); | 
| 2067 | #endif | 
| 2068 |     QCOMPARE(selectedIndexes.count(), expectedItems.count()); | 
| 2069 |     for (const QModelIndex &idx : selectedIndexes) | 
| 2070 |         QVERIFY(expectedItems.contains(QPoint(idx.column(), idx.row()))); | 
| 2071 | } | 
| 2072 |  | 
| 2073 | void tst_QTreeView::indexAbove() | 
| 2074 | { | 
| 2075 |     QtTestModel model(6, 7); | 
| 2076 |     model.levels = 2; | 
| 2077 |     QTreeView view; | 
| 2078 |  | 
| 2079 |     QCOMPARE(view.indexAbove(QModelIndex()), QModelIndex()); | 
| 2080 |     view.setModel(&model); | 
| 2081 |     QCOMPARE(view.indexAbove(QModelIndex()), QModelIndex()); | 
| 2082 |  | 
| 2083 |     QStack<QModelIndex> parents; | 
| 2084 |     parents.push(t: QModelIndex()); | 
| 2085 |     while (!parents.isEmpty()) { | 
| 2086 |         QModelIndex p = parents.pop(); | 
| 2087 |         if (model.canFetchMore(p)) | 
| 2088 |             model.fetchMore(p); | 
| 2089 |         int rows = model.rowCount(parent: p); | 
| 2090 |         for (int r = rows - 1; r > 0; --r) { | 
| 2091 |             for (int column = 0; column < 3; ++column) { | 
| 2092 |                 QModelIndex idx = model.index(row: r, column, parent: p); | 
| 2093 |                 QModelIndex expected = model.index(row: r - 1, column, parent: p); | 
| 2094 |                 QCOMPARE(view.indexAbove(idx), expected); | 
| 2095 |             } | 
| 2096 |         } | 
| 2097 |         // hide even rows | 
| 2098 |         for (int r = 0; r < rows; r+=2) | 
| 2099 |             view.setRowHidden(row: r, parent: p, hide: true); | 
| 2100 |         for (int r = rows - 1; r > 0; r-=2) { | 
| 2101 |             for (int column = 0; column < 3; ++column) { | 
| 2102 |                 QModelIndex idx = model.index(row: r, column, parent: p); | 
| 2103 |                 QModelIndex expected = model.index(row: r - 2, column, parent: p); | 
| 2104 |                 QCOMPARE(view.indexAbove(idx), expected); | 
| 2105 |             } | 
| 2106 |         } | 
| 2107 | //        for (int r = 0; r < rows; ++r) | 
| 2108 | //            parents.push(model.index(r, 0, p)); | 
| 2109 |     } | 
| 2110 | } | 
| 2111 |  | 
| 2112 | void tst_QTreeView::indexBelow() | 
| 2113 | { | 
| 2114 |     QtTestModel model(2, 2); | 
| 2115 |  | 
| 2116 |     QTreeView view; | 
| 2117 |     view.setModel(&model); | 
| 2118 |     view.show(); | 
| 2119 |  | 
| 2120 |     { | 
| 2121 |         QModelIndex i = model.index(row: 0, column: 0, parent: view.rootIndex()); | 
| 2122 |         QVERIFY(i.isValid()); | 
| 2123 |         QCOMPARE(i.row(), 0); | 
| 2124 |         QCOMPARE(i.column(), 0); | 
| 2125 |  | 
| 2126 |         i = view.indexBelow(index: i); | 
| 2127 |         QVERIFY(i.isValid()); | 
| 2128 |         QCOMPARE(i.row(), 1); | 
| 2129 |         QCOMPARE(i.column(), 0); | 
| 2130 |         i = view.indexBelow(index: i); | 
| 2131 |         QVERIFY(!i.isValid()); | 
| 2132 |     } | 
| 2133 |  | 
| 2134 |     { | 
| 2135 |         QModelIndex i = model.index(row: 0, column: 1, parent: view.rootIndex()); | 
| 2136 |         QVERIFY(i.isValid()); | 
| 2137 |         QCOMPARE(i.row(), 0); | 
| 2138 |         QCOMPARE(i.column(), 1); | 
| 2139 |  | 
| 2140 |         i = view.indexBelow(index: i); | 
| 2141 |         QVERIFY(i.isValid()); | 
| 2142 |         QCOMPARE(i.row(), 1); | 
| 2143 |         QCOMPARE(i.column(), 1); | 
| 2144 |         i = view.indexBelow(index: i); | 
| 2145 |         QVERIFY(!i.isValid()); | 
| 2146 |     } | 
| 2147 | } | 
| 2148 |  | 
| 2149 | void tst_QTreeView::clicked() | 
| 2150 | { | 
| 2151 |     QtTestModel model(10, 2); | 
| 2152 |  | 
| 2153 |     QTreeView view; | 
| 2154 |     view.setModel(&model); | 
| 2155 |     view.show(); | 
| 2156 |  | 
| 2157 |     QVERIFY(QTest::qWaitForWindowExposed(&view)); | 
| 2158 |  | 
| 2159 |     QModelIndex firstIndex = model.index(row: 0, column: 0, parent: QModelIndex()); | 
| 2160 |     QVERIFY(firstIndex.isValid()); | 
| 2161 |     int itemHeight = view.visualRect(index: firstIndex).height(); | 
| 2162 |     int itemOffset = view.visualRect(index: firstIndex).width() / 2; | 
| 2163 |     view.resize(w: 200, h: itemHeight * (model.rows + 2)); | 
| 2164 |  | 
| 2165 |     for (int i = 0; i < model.rowCount(); ++i) { | 
| 2166 |         QPoint p(itemOffset, 1 + itemHeight * i); | 
| 2167 |         QModelIndex index = view.indexAt(p); | 
| 2168 |         if (!index.isValid()) | 
| 2169 |             continue; | 
| 2170 |         QSignalSpy spy(&view, &QTreeView::clicked); | 
| 2171 |         QTest::mouseClick(widget: view.viewport(), button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: p); | 
| 2172 |         QTRY_COMPARE(spy.count(), 1); | 
| 2173 |     } | 
| 2174 | } | 
| 2175 |  | 
| 2176 | void tst_QTreeView::mouseDoubleClick() | 
| 2177 | { | 
| 2178 |     // Test double clicks outside the viewport. | 
| 2179 |     // (Should be a no-op and should not expand any item.) | 
| 2180 |  | 
| 2181 |     QStandardItemModel model(20, 2); | 
| 2182 |     for (int i = 0; i < model.rowCount(); i++) { | 
| 2183 |         QModelIndex index = model.index(row: i, column: 0, parent: QModelIndex()); | 
| 2184 |         model.insertRows(row: 0, count: 20, parent: index); | 
| 2185 |         model.insertColumns(column: 0, count: 2,parent: index); | 
| 2186 |         for (int i1 = 0; i1 <  model.rowCount(parent: index); i1++) { | 
| 2187 |             QVERIFY(model.index(i1, 0, index).isValid()); | 
| 2188 |         } | 
| 2189 |     } | 
| 2190 |  | 
| 2191 |     QTreeView view; | 
| 2192 |     view.setModel(&model); | 
| 2193 |  | 
| 2194 |     // make sure the viewport height is smaller than the contents height. | 
| 2195 |     view.resize(w: 200, h: 200); | 
| 2196 |     view.move(ax: 0, ay: 0); | 
| 2197 |     view.show(); | 
| 2198 |     QModelIndex index = model.index(row: 0, column: 0, parent: QModelIndex()); | 
| 2199 |     view.setCurrentIndex(index); | 
| 2200 |  | 
| 2201 |     view.setExpanded(index: model.index(row: 0,column: 0, parent: QModelIndex()), expand: true); | 
| 2202 |     view.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); | 
| 2203 |     view.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); | 
| 2204 |  | 
| 2205 |     // Make sure all items are collapsed | 
| 2206 |     for (int i = 0; i < model.rowCount(parent: QModelIndex()); i++) | 
| 2207 |         view.setExpanded(index: model.index(row: i, column: 0, parent: QModelIndex()), expand: false); | 
| 2208 |  | 
| 2209 |     int maximum = view.verticalScrollBar()->maximum(); | 
| 2210 |  | 
| 2211 |     // Doubleclick in the bottom right corner, in the unused area between the vertical and horizontal scrollbar. | 
| 2212 |     int vsw = view.verticalScrollBar()->width(); | 
| 2213 |     int hsh = view.horizontalScrollBar()->height(); | 
| 2214 |     QTest::mouseDClick(widget: &view, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: QPoint(view.width() - vsw + 1, view.height() - hsh + 1)); | 
| 2215 |     // Should not have expanded, thus maximum() should have the same value. | 
| 2216 |     QCOMPARE(maximum, view.verticalScrollBar()->maximum()); | 
| 2217 |  | 
| 2218 |     view.setExpandsOnDoubleClick(false); | 
| 2219 |     QTest::mouseDClick(widget: &view, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: view.visualRect(index).center()); | 
| 2220 |     QVERIFY(!view.isExpanded(index)); | 
| 2221 | } | 
| 2222 |  | 
| 2223 | void tst_QTreeView::rowsAboutToBeRemoved() | 
| 2224 | { | 
| 2225 |     QStandardItemModel model(3, 1); | 
| 2226 |     for (int i = 0; i < model.rowCount(); i++) { | 
| 2227 |         const QString iS = QString::number(i); | 
| 2228 |         QModelIndex index = model.index(row: i, column: 0, parent: QModelIndex()); | 
| 2229 |         model.setData(index, value: iS); | 
| 2230 |         model.insertRows(row: 0, count: 4, parent: index); | 
| 2231 |         model.insertColumns(column: 0,count: 1,parent: index); | 
| 2232 |         for (int i1 = 0; i1 <  model.rowCount(parent: index); i1++) { | 
| 2233 |             QModelIndex index2 = model.index(row: i1, column: 0, parent: index); | 
| 2234 |             model.setData(index: index2, value: iS + QString::number(i1)); | 
| 2235 |         } | 
| 2236 |     } | 
| 2237 |  | 
| 2238 |     QTreeView view; | 
| 2239 |     view.setModel(&model); | 
| 2240 |     view.show(); | 
| 2241 |     QModelIndex index = model.index(row: 0,column: 0, parent: QModelIndex()); | 
| 2242 |     view.setCurrentIndex(index); | 
| 2243 |     view.setExpanded(index: model.index(row: 0,column: 0, parent: QModelIndex()), expand: true); | 
| 2244 |  | 
| 2245 |     for (int i = 0; i < model.rowCount(parent: QModelIndex()); i++) | 
| 2246 |         view.setExpanded(index: model.index(row: i, column: 0, parent: QModelIndex()), expand: true); | 
| 2247 |  | 
| 2248 |     QSignalSpy spy1(&model, &QAbstractItemModel::rowsAboutToBeRemoved); | 
| 2249 |  | 
| 2250 |     model.removeRows(row: 1,count: 1); | 
| 2251 |     QCOMPARE((view.state()), 0); | 
| 2252 |     // Should not be 5 (or any other number for that sake :) | 
| 2253 |     QCOMPARE(spy1.count(), 1); | 
| 2254 |  | 
| 2255 | } | 
| 2256 |  | 
| 2257 | void tst_QTreeView::() | 
| 2258 | { | 
| 2259 |     QtTestModel model(10, 7); | 
| 2260 |  | 
| 2261 |     QTreeView view; | 
| 2262 |  | 
| 2263 |     view.setModel(&model); | 
| 2264 |     view.show(); | 
| 2265 |     int size = view.header()->sectionSize(logicalIndex: 0); | 
| 2266 |     view.setColumnHidden(column: 0, hide: true); | 
| 2267 |  | 
| 2268 |     // should go back to old size | 
| 2269 |     view.setColumnHidden(column: 0, hide: false); | 
| 2270 |     QCOMPARE(size, view.header()->sectionSize(0)); | 
| 2271 | } | 
| 2272 |  | 
| 2273 | void tst_QTreeView::columnAt() | 
| 2274 | { | 
| 2275 |     QtTestModel model(10, 10); | 
| 2276 |     QTreeView view; | 
| 2277 |     view.resize(w: 500,h: 500); | 
| 2278 |     view.setModel(&model); | 
| 2279 |  | 
| 2280 |     QCOMPARE(view.columnAt(0), 0); | 
| 2281 |     // really this is testing the header... so not much more should be needed if the header is working... | 
| 2282 | } | 
| 2283 |  | 
| 2284 | void tst_QTreeView::scrollTo() | 
| 2285 | { | 
| 2286 | #define CHECK_VISIBLE(ROW,COL) QVERIFY(QRect(QPoint(),view.viewport()->size()).contains(\ | 
| 2287 |                     view.visualRect(model.index((ROW),(COL),QModelIndex())))) | 
| 2288 |  | 
| 2289 |     QtTestModel model(100, 100); | 
| 2290 |     QTreeView view; | 
| 2291 |     view.setUniformRowHeights(true); | 
| 2292 |     view.scrollTo(index: QModelIndex(), hint: QTreeView::PositionAtTop); | 
| 2293 |     view.setModel(&model); | 
| 2294 |  | 
| 2295 |     // ### check the scrollbar values an make sure it actually scrolls to the item | 
| 2296 |     // ### check for bot item based and pixel based scrolling | 
| 2297 |     // ### create a data function for this test | 
| 2298 |  | 
| 2299 |     view.scrollTo(index: QModelIndex()); | 
| 2300 |     view.scrollTo(index: model.index(row: 0, column: 0, parent: QModelIndex())); | 
| 2301 |     view.scrollTo(index: model.index(row: 0, column: 0, parent: QModelIndex()), hint: QTreeView::PositionAtTop); | 
| 2302 |     view.scrollTo(index: model.index(row: 0, column: 0, parent: QModelIndex()), hint: QTreeView::PositionAtBottom); | 
| 2303 |  | 
| 2304 |     view.show(); | 
| 2305 |     view.setVerticalScrollMode(QAbstractItemView::ScrollPerItem); //some styles change that in Polish | 
| 2306 |     view.resize(w: 300, h: 200); | 
| 2307 |  | 
| 2308 |     QVERIFY(QTest::qWaitForWindowExposed(&view)); | 
| 2309 |     //view.verticalScrollBar()->setValue(0); | 
| 2310 |  | 
| 2311 |     view.scrollTo(index: model.index(row: 0, column: 0, parent: QModelIndex())); | 
| 2312 |     CHECK_VISIBLE(0,0); | 
| 2313 |     QCOMPARE(view.verticalScrollBar()->value(), 0); | 
| 2314 |  | 
| 2315 |     view.header()->resizeSection(logicalIndex: 0, size: 5); // now we only see the branches | 
| 2316 |     view.scrollTo(index: model.index(row: 5, column: 0, parent: QModelIndex()), hint: QTreeView::PositionAtTop); | 
| 2317 |     QCOMPARE(view.verticalScrollBar()->value(), 5); | 
| 2318 |  | 
| 2319 |     view.scrollTo(index: model.index(row: 60, column: 60, parent: QModelIndex())); | 
| 2320 |  | 
| 2321 |     CHECK_VISIBLE(60,60); | 
| 2322 |     view.scrollTo(index: model.index(row: 60, column: 30, parent: QModelIndex())); | 
| 2323 |     CHECK_VISIBLE(60,30); | 
| 2324 |     view.scrollTo(index: model.index(row: 30, column: 30, parent: QModelIndex())); | 
| 2325 |     CHECK_VISIBLE(30,30); | 
| 2326 |  | 
| 2327 |     // TODO force it to move to the left and then the right | 
| 2328 | } | 
| 2329 |  | 
| 2330 | void tst_QTreeView::rowsAboutToBeRemoved_move() | 
| 2331 | { | 
| 2332 |     QStandardItemModel model(3,1); | 
| 2333 |     QTreeView view; | 
| 2334 |     view.setModel(&model); | 
| 2335 |     QModelIndex indexThatWantsToLiveButWillDieDieITellYou; | 
| 2336 |     QModelIndex parent = model.index(row: 2, column: 0); | 
| 2337 |     view.expand(index: parent); | 
| 2338 |     for (int i = 0; i < 6; ++i) { | 
| 2339 |         model.insertRows(row: 0, count: 1, parent); | 
| 2340 |         model.insertColumns(column: 0, count: 1, parent); | 
| 2341 |         QModelIndex index = model.index(row: 0, column: 0, parent); | 
| 2342 |         view.expand(index); | 
| 2343 |         if (i == 3) | 
| 2344 |             indexThatWantsToLiveButWillDieDieITellYou = index; | 
| 2345 |         model.setData(index, value: i); | 
| 2346 |         parent = index; | 
| 2347 |     } | 
| 2348 |     view.resize(w: 600,h: 800); | 
| 2349 |     view.show(); | 
| 2350 |     QVERIFY(QTest::qWaitForWindowExposed(&view)); | 
| 2351 |     view.doItemsLayout(); | 
| 2352 |     view.executeDelayedItemsLayout(); | 
| 2353 |     parent = indexThatWantsToLiveButWillDieDieITellYou.parent(); | 
| 2354 |     QCOMPARE(view.isExpanded(indexThatWantsToLiveButWillDieDieITellYou), true); | 
| 2355 |     QCOMPARE(parent.isValid(), true); | 
| 2356 |     QCOMPARE(parent.parent().isValid(), true); | 
| 2357 |     view.expand(index: parent); | 
| 2358 |     QCOMPARE(view.isExpanded(parent), true); | 
| 2359 |     QCOMPARE(view.isExpanded(indexThatWantsToLiveButWillDieDieITellYou), true); | 
| 2360 |     model.removeRow(arow: 0, aparent: indexThatWantsToLiveButWillDieDieITellYou); | 
| 2361 |     QCOMPARE(view.isExpanded(parent), true); | 
| 2362 |     QCOMPARE(view.isExpanded(indexThatWantsToLiveButWillDieDieITellYou), true); | 
| 2363 | } | 
| 2364 |  | 
| 2365 | void tst_QTreeView::resizeColumnToContents() | 
| 2366 | { | 
| 2367 |     QStandardItemModel model(50,2); | 
| 2368 |     for (int r = 0; r < model.rowCount(); ++r) { | 
| 2369 |         const QString rS = QString::number(r); | 
| 2370 |         for (int c = 0; c < model.columnCount(); ++c) { | 
| 2371 |             QModelIndex idx = model.index(row: r, column: c); | 
| 2372 |             model.setData(index: idx, value: rS + QLatin1Char(',') + QString::number(c)); | 
| 2373 |             model.insertColumns(column: 0, count: 2, parent: idx); | 
| 2374 |             model.insertRows(row: 0, count: 6, parent: idx); | 
| 2375 |             for (int i = 0; i < 6; ++i) { | 
| 2376 |                 const QString iS = QString::number(i); | 
| 2377 |                 for (int j = 0; j < 2 ; ++j) { | 
| 2378 |                     model.setData(index: model.index(row: i, column: j, parent: idx), value: QLatin1String("child" ) + iS + QString::number(j)); | 
| 2379 |                 } | 
| 2380 |             } | 
| 2381 |         } | 
| 2382 |     } | 
| 2383 |     QTreeView view; | 
| 2384 |     view.setModel(&model); | 
| 2385 |     view.show(); | 
| 2386 |     QVERIFY(QTest::qWaitForWindowExposed(&view)); | 
| 2387 |  | 
| 2388 |     view.scrollToBottom(); | 
| 2389 |     view.resizeColumnToContents(column: 0); | 
| 2390 |     int oldColumnSize = view.header()->sectionSize(logicalIndex: 0); | 
| 2391 |     view.setRootIndex(model.index(row: 0, column: 0)); | 
| 2392 |     view.resizeColumnToContents(column: 0);        //Earlier, this gave an assert | 
| 2393 |     QVERIFY(view.header()->sectionSize(0) > oldColumnSize); | 
| 2394 | } | 
| 2395 |  | 
| 2396 | void tst_QTreeView::insertAfterSelect() | 
| 2397 | { | 
| 2398 |     QtTestModel model(10, 10); | 
| 2399 |     QTreeView view; | 
| 2400 |     view.setModel(&model); | 
| 2401 |     view.show(); | 
| 2402 |     QVERIFY(QTest::qWaitForWindowExposed(&view)); | 
| 2403 |  | 
| 2404 |     QModelIndex firstIndex = model.index(row: 0, column: 0, parent: QModelIndex()); | 
| 2405 |     QVERIFY(firstIndex.isValid()); | 
| 2406 |     int itemOffset = view.visualRect(index: firstIndex).width() / 2; | 
| 2407 |     QPoint p(itemOffset, 1); | 
| 2408 |     QTest::mouseClick(widget: view.viewport(), button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: p); | 
| 2409 |     QVERIFY(view.selectionModel()->isSelected(firstIndex)); | 
| 2410 |     model.insertNewRow(); | 
| 2411 |     QVERIFY(view.selectionModel()->isSelected(firstIndex)); // Should still be selected | 
| 2412 | } | 
| 2413 |  | 
| 2414 | void tst_QTreeView::removeAfterSelect() | 
| 2415 | { | 
| 2416 |     QtTestModel model(10, 10); | 
| 2417 |     QTreeView view; | 
| 2418 |     view.setModel(&model); | 
| 2419 |     view.show(); | 
| 2420 |     QVERIFY(QTest::qWaitForWindowExposed(&view)); | 
| 2421 |  | 
| 2422 |     QModelIndex firstIndex = model.index(row: 0, column: 0, parent: QModelIndex()); | 
| 2423 |     QVERIFY(firstIndex.isValid()); | 
| 2424 |     int itemOffset = view.visualRect(index: firstIndex).width() / 2; | 
| 2425 |     QPoint p(itemOffset, 1); | 
| 2426 |     QTest::mouseClick(widget: view.viewport(), button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: p); | 
| 2427 |     QVERIFY(view.selectionModel()->isSelected(firstIndex)); | 
| 2428 |     model.removeLastRow(); | 
| 2429 |     QVERIFY(view.selectionModel()->isSelected(firstIndex)); // Should still be selected | 
| 2430 | } | 
| 2431 |  | 
| 2432 | void tst_QTreeView::hiddenItems() | 
| 2433 | { | 
| 2434 |     QtTestModel model(10, 10); | 
| 2435 |     QTreeView view; | 
| 2436 |     view.setModel(&model); | 
| 2437 |     view.show(); | 
| 2438 |     QVERIFY(QTest::qWaitForWindowExposed(&view)); | 
| 2439 |  | 
| 2440 |     QModelIndex firstIndex = model.index(row: 1, column: 0, parent: QModelIndex()); | 
| 2441 |     QVERIFY(firstIndex.isValid()); | 
| 2442 |     if (model.canFetchMore(firstIndex)) | 
| 2443 |         model.fetchMore(firstIndex); | 
| 2444 |     for (int i = 0; i < model.rowCount(parent: firstIndex); i++) | 
| 2445 |         view.setRowHidden(row: i , parent: firstIndex, hide: true ); | 
| 2446 |  | 
| 2447 |     int itemOffset = view.visualRect(index: firstIndex).width() / 2; | 
| 2448 |     int itemHeight = view.visualRect(index: firstIndex).height(); | 
| 2449 |     QPoint p(itemOffset, itemHeight + 1); | 
| 2450 |     view.setExpanded(index: firstIndex, expand: false); | 
| 2451 |     QTest::mouseDClick(widget: view.viewport(), button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: p); | 
| 2452 |     QCOMPARE(view.isExpanded(firstIndex), false); | 
| 2453 |  | 
| 2454 |     p.setX(5); | 
| 2455 |     QTest::mouseClick(widget: view.viewport(), button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: p); | 
| 2456 |     QCOMPARE(view.isExpanded(firstIndex), false); | 
| 2457 | } | 
| 2458 |  | 
| 2459 | void tst_QTreeView::spanningItems() | 
| 2460 | { | 
| 2461 |     QtTestModel model(10, 10); | 
| 2462 |     model.onlyValidCalls = true; | 
| 2463 |     QTreeView view; | 
| 2464 |     view.setModel(&model); | 
| 2465 |     view.show(); | 
| 2466 |     QVERIFY(QTest::qWaitForWindowExposed(&view)); | 
| 2467 |  | 
| 2468 |     int itemWidth = view.header()->sectionSize(logicalIndex: 0); | 
| 2469 |     int itemHeight = view.visualRect(index: model.index(row: 0, column: 0, parent: QModelIndex())).height(); | 
| 2470 |  | 
| 2471 |     // every second row is spanning | 
| 2472 |     for (int i = 1; i < model.rowCount(parent: QModelIndex()); i += 2) | 
| 2473 |         view.setFirstColumnSpanned(row: i , parent: QModelIndex(), span: true); | 
| 2474 |  | 
| 2475 |     // non-spanning item | 
| 2476 |     QPoint p(itemWidth / 2, itemHeight / 2); // column 0, row 0 | 
| 2477 |     view.setCurrentIndex(QModelIndex()); | 
| 2478 |     QTest::mouseClick(widget: view.viewport(), button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: p); | 
| 2479 |     QCOMPARE(view.currentIndex(), model.index(0, 0, QModelIndex())); | 
| 2480 |     QCOMPARE(view.header()->sectionSize(0) - view.indentation(), | 
| 2481 |              view.visualRect(model.index(0, 0, QModelIndex())).width()); | 
| 2482 |  | 
| 2483 |     // spanning item | 
| 2484 |     p.setX(itemWidth + (itemWidth / 2)); // column 1 | 
| 2485 |     p.setY(itemHeight + (itemHeight / 2)); // row 1 | 
| 2486 |     QTest::mouseClick(widget: view.viewport(), button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: p); | 
| 2487 |     QCOMPARE(view.currentIndex(), model.index(1, 0, QModelIndex())); | 
| 2488 |     QCOMPARE(view.header()->length() - view.indentation(), | 
| 2489 |              view.visualRect(model.index(1, 0, QModelIndex())).width()); | 
| 2490 |  | 
| 2491 |     // size hint | 
| 2492 |     // every second row is un-spanned | 
| 2493 |     QStyleOptionViewItem option = view.viewOptions(); | 
| 2494 |     int w = view.header()->sectionSizeHint(logicalIndex: 0); | 
| 2495 |     for (int i = 0; i < model.rowCount(parent: QModelIndex()); ++i) { | 
| 2496 |         if (!view.isFirstColumnSpanned(row: i, parent: QModelIndex())) { | 
| 2497 |             QModelIndex index = model.index(row: i, column: 0, parent: QModelIndex()); | 
| 2498 |             w = qMax(a: w, b: view.itemDelegate(index)->sizeHint(option, index).width() + view.indentation()); | 
| 2499 |         } | 
| 2500 |     } | 
| 2501 |     QCOMPARE(view.sizeHintForColumn(0), w); | 
| 2502 |  | 
| 2503 |     view.repaint(); // to check that this doesn't hit any assert | 
| 2504 | } | 
| 2505 |  | 
| 2506 | void tst_QTreeView::selectionOrderTest() | 
| 2507 | { | 
| 2508 |     QVERIFY(static_cast<QItemSelectionModel*>(sender())->currentIndex().row() != -1); | 
| 2509 | } | 
| 2510 |  | 
| 2511 | void tst_QTreeView::selection() | 
| 2512 | { | 
| 2513 |     if (!QGuiApplication::platformName().compare(other: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) | 
| 2514 |         QSKIP("Wayland: This causes a crash triggered by setVisible(false)" ); | 
| 2515 |  | 
| 2516 |     QTreeView treeView; | 
| 2517 |     QStandardItemModel m(10, 2); | 
| 2518 |     for (int i = 0;i < 10; ++i) | 
| 2519 |         m.setData(index: m.index(row: i, column: 0), value: i); | 
| 2520 |     treeView.setModel(&m); | 
| 2521 |     treeView.show(); | 
| 2522 |     QVERIFY(QTest::qWaitForWindowExposed(&treeView)); | 
| 2523 |  | 
| 2524 |     treeView.setSelectionBehavior(QAbstractItemView::SelectRows); | 
| 2525 |     treeView.setSelectionMode(QAbstractItemView::ExtendedSelection); | 
| 2526 |  | 
| 2527 |     connect(sender: treeView.selectionModel(), signal: &QItemSelectionModel::selectionChanged, | 
| 2528 |             receiver: this, slot: &tst_QTreeView::selectionOrderTest); | 
| 2529 |  | 
| 2530 |     QTest::mousePress(widget: treeView.viewport(), button: Qt::LeftButton, stateKey: {}, | 
| 2531 |                       pos: treeView.visualRect(index: m.index(row: 1, column: 0)).center()); | 
| 2532 |     QTest::keyPress(widget: treeView.viewport(), key: Qt::Key_Down); | 
| 2533 |     auto selectedRows = treeView.selectionModel()->selectedRows(); | 
| 2534 |     QCOMPARE(selectedRows.size(), 1); | 
| 2535 |     QCOMPARE(selectedRows.first(), m.index(2, 0, QModelIndex())); | 
| 2536 |     QTest::keyPress(widget: treeView.viewport(), key: Qt::Key_5); | 
| 2537 |     selectedRows = treeView.selectionModel()->selectedRows(); | 
| 2538 |     QCOMPARE(selectedRows.size(), 1); | 
| 2539 |     QCOMPARE(selectedRows.first(), m.index(5, 0, QModelIndex())); | 
| 2540 | } | 
| 2541 |  | 
| 2542 | //From task 151686 QTreeView ExtendedSelection selects hidden rows | 
| 2543 | void tst_QTreeView::selectionWithHiddenItems() | 
| 2544 | { | 
| 2545 |     QStandardItemModel model; | 
| 2546 |  | 
| 2547 |     QStandardItem item0("row 0" ); | 
| 2548 |     QStandardItem item1("row 1" ); | 
| 2549 |     QStandardItem item2("row 2" ); | 
| 2550 |     QStandardItem item3("row 3" ); | 
| 2551 |     model.appendColumn(items: {&item0, &item1, &item2, &item3}); | 
| 2552 |  | 
| 2553 |     QStandardItem child("child" ); | 
| 2554 |     item1.appendRow(aitem: &child); | 
| 2555 |  | 
| 2556 |     QTreeView view; | 
| 2557 |     view.setModel(&model); | 
| 2558 |     view.setSelectionMode(QAbstractItemView::ExtendedSelection); | 
| 2559 |     view.show(); | 
| 2560 |     QVERIFY(QTest::qWaitForWindowExposed(&view)); | 
| 2561 |  | 
| 2562 |     //child should not be selected as it is hidden (its parent is not expanded) | 
| 2563 |     view.selectAll(); | 
| 2564 |     QCOMPARE(view.selectionModel()->selection().count(), 1); //one range | 
| 2565 |     QCOMPARE(view.selectionModel()->selectedRows().count(), 4); | 
| 2566 |     view.expandAll(); | 
| 2567 |     QVERIFY(view.isExpanded(item1.index())); | 
| 2568 |     QCOMPARE(view.selectionModel()->selection().count(), 1); | 
| 2569 |     QCOMPARE(view.selectionModel()->selectedRows().count(), 4); | 
| 2570 |     QVERIFY( !view.selectionModel()->isSelected(model.indexFromItem(&child))); | 
| 2571 |     view.clearSelection(); | 
| 2572 |     QVERIFY(view.isExpanded(item1.index())); | 
| 2573 |  | 
| 2574 |     //child should be selected as it is visible (its parent is expanded) | 
| 2575 |     view.selectAll(); | 
| 2576 |     QCOMPARE(view.selectionModel()->selection().count(), 2); | 
| 2577 |     QCOMPARE(view.selectionModel()->selectedRows().count(), 5); //everything is selected | 
| 2578 |     view.clearSelection(); | 
| 2579 |  | 
| 2580 |     //we hide the node with a child (there should then be 3 items selected in 2 ranges) | 
| 2581 |     view.setRowHidden(row: 1, parent: QModelIndex(), hide: true); | 
| 2582 |     QVERIFY(view.isExpanded(item1.index())); | 
| 2583 |     view.selectAll(); | 
| 2584 |     QCOMPARE(view.selectionModel()->selection().count(), 2); | 
| 2585 |     QCOMPARE(view.selectionModel()->selectedRows().count(), 3); | 
| 2586 |     QVERIFY(!view.selectionModel()->isSelected(model.indexFromItem(&item1))); | 
| 2587 |     QVERIFY(!view.selectionModel()->isSelected(model.indexFromItem(&child))); | 
| 2588 |  | 
| 2589 |     view.setRowHidden(row: 1, parent: QModelIndex(), hide: false); | 
| 2590 |     QVERIFY(view.isExpanded(item1.index())); | 
| 2591 |     view.clearSelection(); | 
| 2592 |  | 
| 2593 |     //we hide a node without children (there should then be 4 items selected in 3 ranges) | 
| 2594 |     view.setRowHidden(row: 2, parent: QModelIndex(), hide: true); | 
| 2595 |     QVERIFY(view.isExpanded(item1.index())); | 
| 2596 |     view.selectAll(); | 
| 2597 |     QVERIFY(view.isExpanded(item1.index())); | 
| 2598 |     QCOMPARE(view.selectionModel()->selection().count(), 3); | 
| 2599 |     QCOMPARE(view.selectionModel()->selectedRows().count(), 4); | 
| 2600 |     QVERIFY( !view.selectionModel()->isSelected(model.indexFromItem(&item2))); | 
| 2601 |     view.setRowHidden(row: 2, parent: QModelIndex(), hide: false); | 
| 2602 |     QVERIFY(view.isExpanded(item1.index())); | 
| 2603 |     view.clearSelection(); | 
| 2604 | } | 
| 2605 |  | 
| 2606 | void tst_QTreeView::selectAll() | 
| 2607 | { | 
| 2608 |     QStandardItemModel model(4, 4); | 
| 2609 |     QTreeView view2; | 
| 2610 |     view2.setModel(&model); | 
| 2611 |     view2.setSelectionMode(QAbstractItemView::ExtendedSelection); | 
| 2612 |     view2.selectAll();  // Should work with an empty model | 
| 2613 |     //everything should be selected since we are in ExtendedSelection mode | 
| 2614 |     QCOMPARE(view2.selectedIndexes().count(), model.rowCount() * model.columnCount()); | 
| 2615 |  | 
| 2616 |     for (int i = 0; i < model.rowCount(); ++i) | 
| 2617 |         model.setData(index: model.index(row: i,column: 0), value: QLatin1String("row " ) + QString::number(i)); | 
| 2618 |     QTreeView view; | 
| 2619 |     view.setModel(&model); | 
| 2620 |     int selectedCount = view.selectedIndexes().count(); | 
| 2621 |     view.selectAll(); | 
| 2622 |     QCOMPARE(view.selectedIndexes().count(), selectedCount); | 
| 2623 |  | 
| 2624 |     QTreeView view3; | 
| 2625 |     view3.setModel(&model); | 
| 2626 |     view3.setSelectionMode(QAbstractItemView::NoSelection); | 
| 2627 |     view3.selectAll(); | 
| 2628 |     QCOMPARE(view3.selectedIndexes().count(), 0); | 
| 2629 | } | 
| 2630 |  | 
| 2631 | void tst_QTreeView::extendedSelection_data() | 
| 2632 | { | 
| 2633 |     QTest::addColumn<QPoint>(name: "mousePressPos" ); | 
| 2634 |     QTest::addColumn<int>(name: "selectedCount" ); | 
| 2635 |  | 
| 2636 |     QTest::newRow(dataTag: "select" ) << QPoint(10, 10) << 2; | 
| 2637 |     QTest::newRow(dataTag: "unselect" ) << QPoint(10, 300) << 0; | 
| 2638 | } | 
| 2639 |  | 
| 2640 | void tst_QTreeView::extendedSelection() | 
| 2641 | { | 
| 2642 |     QFETCH(QPoint, mousePressPos); | 
| 2643 |     QFETCH(int, selectedCount); | 
| 2644 |  | 
| 2645 |     QStandardItemModel model(5, 2); | 
| 2646 |     QWidget topLevel; | 
| 2647 |     QTreeView view(&topLevel); | 
| 2648 |     view.resize(w: qMax(a: mousePressPos.x() * 2, b: 300), h: qMax(a: mousePressPos.y() * 2, b: 350)); | 
| 2649 |     view.setModel(&model); | 
| 2650 |     view.setSelectionMode(QAbstractItemView::ExtendedSelection); | 
| 2651 |     topLevel.show(); | 
| 2652 |     QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); | 
| 2653 |     QTest::mousePress(widget: view.viewport(), button: Qt::LeftButton, stateKey: {}, pos: mousePressPos); | 
| 2654 |     QCOMPARE(view.selectionModel()->selectedIndexes().count(), selectedCount); | 
| 2655 | } | 
| 2656 |  | 
| 2657 | void tst_QTreeView::rowSizeHint() | 
| 2658 | { | 
| 2659 |     //tests whether the correct visible columns are taken into account when | 
| 2660 |     //calculating the height of a line | 
| 2661 |     QStandardItemModel model(1, 3); | 
| 2662 |     model.setData(index: model.index(row: 0, column: 0), value: QSize(20, 40), role: Qt::SizeHintRole); | 
| 2663 |     model.setData(index: model.index(row: 0, column: 1), value: QSize(20, 10), role: Qt::SizeHintRole); | 
| 2664 |     model.setData(index: model.index(row: 0, column: 2), value: QSize(20, 10), role: Qt::SizeHintRole); | 
| 2665 |     QTreeView view; | 
| 2666 |     view.setModel(&model); | 
| 2667 |  | 
| 2668 |     view.header()->moveSection(from: 1, to: 0); //the 2nd column goes to the 1st place | 
| 2669 |  | 
| 2670 |     view.show(); | 
| 2671 |     QVERIFY(QTest::qWaitForWindowExposed(&view)); | 
| 2672 |  | 
| 2673 |     //it must be 40 since the tallest item that defines the height of a line | 
| 2674 |     QCOMPARE(view.visualRect(model.index(0,0)).height(), 40); | 
| 2675 |     QCOMPARE(view.visualRect(model.index(0,1)).height(), 40); | 
| 2676 |     QCOMPARE(view.visualRect(model.index(0,2)).height(), 40); | 
| 2677 | } | 
| 2678 |  | 
| 2679 |  | 
| 2680 | //From task 155449 (QTreeWidget has a large width for the first section when sorting | 
| 2681 | //is turned on before items are added) | 
| 2682 |  | 
| 2683 | void tst_QTreeView::setSortingEnabledTopLevel() | 
| 2684 | { | 
| 2685 |     QTreeView view; | 
| 2686 |     QStandardItemModel model(1, 1); | 
| 2687 |     view.setModel(&model); | 
| 2688 |     const int size = view.header()->sectionSize(logicalIndex: 0); | 
| 2689 |     view.setSortingEnabled(true); | 
| 2690 |     model.setColumnCount(3); | 
| 2691 |     //we test that changing the column count doesn't change the 1st column size | 
| 2692 |     QCOMPARE(view.header()->sectionSize(0), size); | 
| 2693 | } | 
| 2694 |  | 
| 2695 | void tst_QTreeView::setSortingEnabledChild() | 
| 2696 | { | 
| 2697 |     QMainWindow win; | 
| 2698 |     QTreeView view; | 
| 2699 |     // two columns to not get in trouble with stretchLastSection | 
| 2700 |     QStandardItemModel model(1, 2); | 
| 2701 |     view.setModel(&model); | 
| 2702 |     view.header()->setDefaultSectionSize(92); | 
| 2703 |     win.setCentralWidget(&view); | 
| 2704 |     const int size = view.header()->sectionSize(logicalIndex: 0); | 
| 2705 |     view.setSortingEnabled(true); | 
| 2706 |     model.setColumnCount(3); | 
| 2707 |     //we test that changing the column count doesn't change the 1st column size | 
| 2708 |     QCOMPARE(view.header()->sectionSize(0), size); | 
| 2709 | } | 
| 2710 |  | 
| 2711 | void tst_QTreeView::() | 
| 2712 | { | 
| 2713 |     QTreeView view; | 
| 2714 |     QStandardItemModel model; | 
| 2715 |     view.setModel(&model); | 
| 2716 |     QCOMPARE(view.isHeaderHidden(), false); | 
| 2717 |     QCOMPARE(view.header()->isHidden(), false); | 
| 2718 |     view.setHeaderHidden(true); | 
| 2719 |     QCOMPARE(view.isHeaderHidden(), true); | 
| 2720 |     QCOMPARE(view.header()->isHidden(), true); | 
| 2721 | } | 
| 2722 |  | 
| 2723 | class TestTreeViewStyle : public QProxyStyle | 
| 2724 | { | 
| 2725 |     Q_OBJECT | 
| 2726 | public: | 
| 2727 |     using QProxyStyle::QProxyStyle; | 
| 2728 |     int pixelMetric(PixelMetric metric, const QStyleOption *option = nullptr, | 
| 2729 |                     const QWidget *widget = nullptr) const override | 
| 2730 |     { | 
| 2731 |         if (metric == QStyle::PM_TreeViewIndentation) | 
| 2732 |             return indentation; | 
| 2733 |         else | 
| 2734 |             return QProxyStyle::pixelMetric(metric, option, widget); | 
| 2735 |     } | 
| 2736 |     int indentation = 20; | 
| 2737 | }; | 
| 2738 |  | 
| 2739 | void tst_QTreeView::indentation() | 
| 2740 | { | 
| 2741 |     TestTreeViewStyle style1; | 
| 2742 |     TestTreeViewStyle style2; | 
| 2743 |     style1.indentation = 20; | 
| 2744 |     style2.indentation = 30; | 
| 2745 |  | 
| 2746 |     QTreeView view; | 
| 2747 |     view.setStyle(&style1); | 
| 2748 |     QCOMPARE(view.indentation(), style1.indentation); | 
| 2749 |     view.setStyle(&style2); | 
| 2750 |     QCOMPARE(view.indentation(), style2.indentation); | 
| 2751 |     view.setIndentation(70); | 
| 2752 |     QCOMPARE(view.indentation(), 70); | 
| 2753 |     view.setStyle(&style1); | 
| 2754 |     QCOMPARE(view.indentation(), 70); | 
| 2755 |     view.resetIndentation(); | 
| 2756 |     QCOMPARE(view.indentation(), style1.indentation); | 
| 2757 |     view.setStyle(&style2); | 
| 2758 |     QCOMPARE(view.indentation(), style2.indentation); | 
| 2759 | } | 
| 2760 |  | 
| 2761 | // From Task 145199 (crash when column 0 having at least one expanded item is removed and then | 
| 2762 | // inserted). The test passes simply if it doesn't crash, hence there are no calls | 
| 2763 | // to QCOMPARE() or QVERIFY(). | 
| 2764 | void tst_QTreeView::removeAndInsertExpandedCol0() | 
| 2765 | { | 
| 2766 |     QTreeView view; | 
| 2767 |     QStandardItemModel model; | 
| 2768 |     view.setModel(&model); | 
| 2769 |  | 
| 2770 |     model.setColumnCount(1); | 
| 2771 |  | 
| 2772 |     QStandardItem *item0 = new QStandardItem(QString("item 0" )); | 
| 2773 |     model.invisibleRootItem()->appendRow(aitem: item0); | 
| 2774 |     view.expand(index: item0->index()); | 
| 2775 |     QStandardItem *item1 = new QStandardItem(QString("item 1" )); | 
| 2776 |     item0->appendRow(aitem: item1); | 
| 2777 |  | 
| 2778 |     model.removeColumns(column: 0, count: 1); | 
| 2779 |     model.insertColumns(column: 0, count: 1); | 
| 2780 |  | 
| 2781 |     view.show(); | 
| 2782 |     QVERIFY(QTest::qWaitForWindowExposed(&view)); | 
| 2783 | } | 
| 2784 |  | 
| 2785 | void tst_QTreeView::disabledButCheckable() | 
| 2786 | { | 
| 2787 |     QTreeView view; | 
| 2788 |     QStandardItemModel model; | 
| 2789 |     QStandardItem *item; | 
| 2790 |     item = new QStandardItem(QLatin1String("Row 1 Item" )); | 
| 2791 |     model.insertRow(arow: 0, aitem: item); | 
| 2792 |  | 
| 2793 |     item = new QStandardItem(QLatin1String("Row 2 Item" )); | 
| 2794 |     item->setCheckable(true); | 
| 2795 |     item->setEnabled(false); | 
| 2796 |     model.insertRow(arow: 1, aitem: item); | 
| 2797 |  | 
| 2798 |     view.setModel(&model); | 
| 2799 |     view.setCurrentIndex(model.index(row: 1,column: 0)); | 
| 2800 |     QCOMPARE(item->checkState(), Qt::Unchecked); | 
| 2801 |     view.show(); | 
| 2802 |  | 
| 2803 |     QTest::keyClick(widget: &view, key: Qt::Key_Space); | 
| 2804 |     QCOMPARE(item->checkState(), Qt::Unchecked); | 
| 2805 | } | 
| 2806 |  | 
| 2807 | void tst_QTreeView::sortByColumn_data() | 
| 2808 | { | 
| 2809 |     QTest::addColumn<bool>(name: "sortingEnabled" ); | 
| 2810 |     QTest::newRow(dataTag: "sorting enabled" ) << true; | 
| 2811 |     QTest::newRow(dataTag: "sorting disabled" ) << false; | 
| 2812 | } | 
| 2813 |  | 
| 2814 | // Checks sorting and that sortByColumn also sets the sortIndicator | 
| 2815 | void tst_QTreeView::sortByColumn() | 
| 2816 | { | 
| 2817 |     QFETCH(bool, sortingEnabled); | 
| 2818 |     QTreeView view; | 
| 2819 |     QStandardItemModel model(4, 2); | 
| 2820 |     QSortFilterProxyModel sfpm; // default QStandardItemModel does not support 'unsorted' state | 
| 2821 |     sfpm.setSourceModel(&model); | 
| 2822 |     model.setItem(row: 0, column: 0, item: new QStandardItem("b" )); | 
| 2823 |     model.setItem(row: 1, column: 0, item: new QStandardItem("d" )); | 
| 2824 |     model.setItem(row: 2, column: 0, item: new QStandardItem("c" )); | 
| 2825 |     model.setItem(row: 3, column: 0, item: new QStandardItem("a" )); | 
| 2826 |     model.setItem(row: 0, column: 1, item: new QStandardItem("e" )); | 
| 2827 |     model.setItem(row: 1, column: 1, item: new QStandardItem("g" )); | 
| 2828 |     model.setItem(row: 2, column: 1, item: new QStandardItem("h" )); | 
| 2829 |     model.setItem(row: 3, column: 1, item: new QStandardItem("f" )); | 
| 2830 |  | 
| 2831 |     view.setSortingEnabled(sortingEnabled); | 
| 2832 |     view.setModel(&sfpm); | 
| 2833 |  | 
| 2834 |     view.sortByColumn(column: 1, order: Qt::DescendingOrder); | 
| 2835 |     QCOMPARE(view.header()->sortIndicatorSection(), 1); | 
| 2836 |     QCOMPARE(view.model()->data(view.model()->index(0, 0)).toString(), QString::fromLatin1("c" )); | 
| 2837 |     QCOMPARE(view.model()->data(view.model()->index(1, 0)).toString(), QString::fromLatin1("d" )); | 
| 2838 |     QCOMPARE(view.model()->data(view.model()->index(0, 1)).toString(), QString::fromLatin1("h" )); | 
| 2839 |     QCOMPARE(view.model()->data(view.model()->index(1, 1)).toString(), QString::fromLatin1("g" )); | 
| 2840 |  | 
| 2841 |     view.sortByColumn(column: 0, order: Qt::AscendingOrder); | 
| 2842 |     QCOMPARE(view.header()->sortIndicatorSection(), 0); | 
| 2843 |     QCOMPARE(view.model()->data(view.model()->index(0, 0)).toString(), QString::fromLatin1("a" )); | 
| 2844 |     QCOMPARE(view.model()->data(view.model()->index(1, 0)).toString(), QString::fromLatin1("b" )); | 
| 2845 |     QCOMPARE(view.model()->data(view.model()->index(0, 1)).toString(), QString::fromLatin1("f" )); | 
| 2846 |     QCOMPARE(view.model()->data(view.model()->index(1, 1)).toString(), QString::fromLatin1("e" )); | 
| 2847 |  | 
| 2848 |     view.sortByColumn(column: -1, order: Qt::AscendingOrder); | 
| 2849 |     QCOMPARE(view.header()->sortIndicatorSection(), -1); | 
| 2850 |     QCOMPARE(view.model()->data(view.model()->index(0, 0)).toString(), QString::fromLatin1("b" )); | 
| 2851 |     QCOMPARE(view.model()->data(view.model()->index(1, 0)).toString(), QString::fromLatin1("d" )); | 
| 2852 |     QCOMPARE(view.model()->data(view.model()->index(0, 1)).toString(), QString::fromLatin1("e" )); | 
| 2853 |     QCOMPARE(view.model()->data(view.model()->index(1, 1)).toString(), QString::fromLatin1("g" )); | 
| 2854 |  | 
| 2855 |     // a new 'sortByColumn()' should do a re-sort (e.g. due to the data changed), QTBUG-86268 | 
| 2856 |     view.setModel(&model); | 
| 2857 |     view.sortByColumn(column: 0, order: Qt::AscendingOrder); | 
| 2858 |     QCOMPARE(view.model()->data(view.model()->index(0, 0)).toString(), QString::fromLatin1("a" )); | 
| 2859 |     model.setItem(row: 0, column: 0, item: new QStandardItem("x" )); | 
| 2860 |     view.sortByColumn(column: 0, order: Qt::AscendingOrder); | 
| 2861 |     QCOMPARE(view.model()->data(view.model()->index(0, 0)).toString(), QString::fromLatin1("b" )); | 
| 2862 | } | 
| 2863 |  | 
| 2864 | /* | 
| 2865 |     This is a model that every time kill() is called it will completely change | 
| 2866 |     all of its nodes for new nodes.  It then qFatal's if you later use a dead node. | 
| 2867 |  */ | 
| 2868 | class EvilModel: public QAbstractItemModel | 
| 2869 | { | 
| 2870 |     Q_OBJECT | 
| 2871 | public: | 
| 2872 |     class Node | 
| 2873 |     { | 
| 2874 |     public: | 
| 2875 |         Node(Node *p = nullptr, int level = 0) : parent(p) | 
| 2876 |         { | 
| 2877 |             populate(level); | 
| 2878 |         } | 
| 2879 |         ~Node() | 
| 2880 |         { | 
| 2881 |             qDeleteAll(begin: children.begin(), end: children.end()); | 
| 2882 |             qDeleteAll(begin: deadChildren.begin(), end: deadChildren.end()); | 
| 2883 |         } | 
| 2884 |  | 
| 2885 |         void populate(int level = 0) | 
| 2886 |         { | 
| 2887 |             if (level < 4) { | 
| 2888 |                 for (int i = 0; i < 5; ++i) | 
| 2889 |                     children.append(t: new Node(this, level + 1)); | 
| 2890 |             } | 
| 2891 |         } | 
| 2892 |         void kill() | 
| 2893 |         { | 
| 2894 |             for (int i = children.count() -1; i >= 0; --i) { | 
| 2895 |                 children.at(i)->kill(); | 
| 2896 |                 if (parent == nullptr) { | 
| 2897 |                     deadChildren.append(t: children.at(i)); | 
| 2898 |                     children.removeAt(i); | 
| 2899 |                 } | 
| 2900 |             } | 
| 2901 |             if (parent == nullptr) { | 
| 2902 |                 if (!children.isEmpty()) | 
| 2903 |                     qFatal(msg: "%s: children should be empty when parent is null" , Q_FUNC_INFO); | 
| 2904 |                 populate(); | 
| 2905 |             } else { | 
| 2906 |                 isDead = true; | 
| 2907 |             } | 
| 2908 |         } | 
| 2909 |  | 
| 2910 |         QVector<Node *> children; | 
| 2911 |         QVector<Node *> deadChildren; | 
| 2912 |         Node *parent; | 
| 2913 |         bool isDead = false; | 
| 2914 |     }; | 
| 2915 |  | 
| 2916 |     Node *root; | 
| 2917 |     bool crash = false; | 
| 2918 |  | 
| 2919 |     EvilModel(QObject *parent = nullptr): QAbstractItemModel(parent), root(new Node) | 
| 2920 |     {} | 
| 2921 |     ~EvilModel() | 
| 2922 |     { | 
| 2923 |         delete root; | 
| 2924 |     } | 
| 2925 |  | 
| 2926 |     void setCrash() | 
| 2927 |     { | 
| 2928 |         crash = true; | 
| 2929 |     } | 
| 2930 |  | 
| 2931 |     void change() | 
| 2932 |     { | 
| 2933 |         emit layoutAboutToBeChanged(); | 
| 2934 |         QModelIndexList oldList = persistentIndexList(); | 
| 2935 |         QVector<QStack<int>> oldListPath; | 
| 2936 |         for (int i = 0; i < oldList.count(); ++i) { | 
| 2937 |             QModelIndex idx = oldList.at(i); | 
| 2938 |             QStack<int> path; | 
| 2939 |             while (idx.isValid()) { | 
| 2940 |                 path.push(t: idx.row()); | 
| 2941 |                 idx = idx.parent(); | 
| 2942 |             } | 
| 2943 |             oldListPath.append(t: path); | 
| 2944 |         } | 
| 2945 |         root->kill(); | 
| 2946 |  | 
| 2947 |         QModelIndexList newList; | 
| 2948 |         for (auto path : qAsConst(t&: oldListPath)) { | 
| 2949 |             QModelIndex idx; | 
| 2950 |             while (!path.isEmpty()) | 
| 2951 |                 idx = index(row: path.pop(), column: 0, parent: idx); | 
| 2952 |             newList.append(t: idx); | 
| 2953 |         } | 
| 2954 |  | 
| 2955 |         changePersistentIndexList(from: oldList, to: newList); | 
| 2956 |         emit layoutChanged(); | 
| 2957 |     } | 
| 2958 |  | 
| 2959 |     int rowCount(const QModelIndex &parent = QModelIndex()) const override | 
| 2960 |     { | 
| 2961 |         Node *parentNode = root; | 
| 2962 |         if (parent.isValid()) { | 
| 2963 |             parentNode = static_cast<Node*>(parent.internalPointer()); | 
| 2964 |             if (parentNode->isDead) | 
| 2965 |                 qFatal(msg: "%s: parentNode is dead!" , Q_FUNC_INFO); | 
| 2966 |         } | 
| 2967 |         return parentNode->children.count(); | 
| 2968 |     } | 
| 2969 |     int columnCount(const QModelIndex &parent = QModelIndex()) const override | 
| 2970 |     { | 
| 2971 |         return parent.column() > 0 ? 0 : 1; | 
| 2972 |     } | 
| 2973 |  | 
| 2974 |     QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override | 
| 2975 |     { | 
| 2976 |         Node *grandparentNode = static_cast<Node*>(parent.internalPointer()); | 
| 2977 |         Node *parentNode = root; | 
| 2978 |         if (parent.isValid()) { | 
| 2979 |             if (grandparentNode->isDead) | 
| 2980 |                 qFatal(msg: "%s: grandparentNode is dead!" , Q_FUNC_INFO); | 
| 2981 |             parentNode = grandparentNode->children[parent.row()]; | 
| 2982 |             if (parentNode->isDead) | 
| 2983 |                 qFatal(msg: "%s: grandparentNode is dead!" , Q_FUNC_INFO); | 
| 2984 |         } | 
| 2985 |         return createIndex(arow: row, acolumn: column, adata: parentNode); | 
| 2986 |     } | 
| 2987 |  | 
| 2988 |     QModelIndex parent(const QModelIndex &index) const override | 
| 2989 |     { | 
| 2990 |         Node *parent = static_cast<Node*>(index.internalPointer()); | 
| 2991 |         Node *grandparent = parent->parent; | 
| 2992 |         if (!grandparent) | 
| 2993 |             return QModelIndex(); | 
| 2994 |         return createIndex(arow: grandparent->children.indexOf(t: parent), acolumn: 0, adata: grandparent); | 
| 2995 |     } | 
| 2996 |  | 
| 2997 |     QVariant data(const QModelIndex &idx, int role) const override | 
| 2998 |     { | 
| 2999 |         if (crash) { | 
| 3000 |             QTest::qFail(statementStr: "Should not get here..." , __FILE__, __LINE__); | 
| 3001 |             return QVariant(); | 
| 3002 |         } | 
| 3003 |         if (idx.isValid() && role == Qt::DisplayRole) { | 
| 3004 |             Node *parentNode = root; | 
| 3005 |             if (idx.isValid()) { | 
| 3006 |                 parentNode = static_cast<Node*>(idx.internalPointer()); | 
| 3007 |                 if (parentNode->isDead) | 
| 3008 |                     qFatal(msg: "%s: grandparentNode is dead!" , Q_FUNC_INFO); | 
| 3009 |             } | 
| 3010 |             return QLatin1Char('[') + QString::number(idx.row()) + QLatin1Char(',') | 
| 3011 |                 + QString::number(idx.column()) + QLatin1Char(',') | 
| 3012 |                 + QLatin1String(parentNode->isDead ? "dead"  : "alive" ) + QLatin1Char(']'); | 
| 3013 |         } | 
| 3014 |         return QVariant(); | 
| 3015 |     } | 
| 3016 | }; | 
| 3017 |  | 
| 3018 | void tst_QTreeView::evilModel_data() | 
| 3019 | { | 
| 3020 |     QTest::addColumn<bool>(name: "visible" ); | 
| 3021 |     QTest::newRow(dataTag: "visible" ) << false; | 
| 3022 |     QTest::newRow(dataTag: "visible" ) << true; | 
| 3023 | } | 
| 3024 |  | 
| 3025 | void tst_QTreeView::evilModel() | 
| 3026 | { | 
| 3027 |     QFETCH(bool, visible); | 
| 3028 |     // init | 
| 3029 |     TreeView view; | 
| 3030 |     EvilModel model; | 
| 3031 |     view.setModel(&model); | 
| 3032 |     view.setVisible(visible); | 
| 3033 |     QPersistentModelIndex firstLevel = model.index(row: 0, column: 0); | 
| 3034 |     QPersistentModelIndex secondLevel = model.index(row: 1, column: 0, parent: firstLevel); | 
| 3035 |     QPersistentModelIndex thirdLevel = model.index(row: 2, column: 0, parent: secondLevel); | 
| 3036 |     view.setExpanded(index: firstLevel, expand: true); | 
| 3037 |     view.setExpanded(index: secondLevel, expand: true); | 
| 3038 |     view.setExpanded(index: thirdLevel, expand: true); | 
| 3039 |     model.change(); | 
| 3040 |  | 
| 3041 |     // tests | 
| 3042 |     view.setRowHidden(row: 0, parent: firstLevel, hide: true); | 
| 3043 |     model.change(); | 
| 3044 |  | 
| 3045 |     view.setFirstColumnSpanned(row: 1, parent: QModelIndex(), span: true); | 
| 3046 |     model.change(); | 
| 3047 |  | 
| 3048 |     view.expand(index: secondLevel); | 
| 3049 |     model.change(); | 
| 3050 |  | 
| 3051 |     view.collapse(index: secondLevel); | 
| 3052 |     model.change(); | 
| 3053 |  | 
| 3054 |     view.isExpanded(index: secondLevel); | 
| 3055 |     view.setCurrentIndex(firstLevel); | 
| 3056 |     model.change(); | 
| 3057 |  | 
| 3058 |     view.keyboardSearch(search: "foo" ); | 
| 3059 |     model.change(); | 
| 3060 |  | 
| 3061 |     view.visualRect(index: secondLevel); | 
| 3062 |     model.change(); | 
| 3063 |  | 
| 3064 |     view.scrollTo(index: thirdLevel); | 
| 3065 |     model.change(); | 
| 3066 |  | 
| 3067 |     view.update();  // will not do anything since view is not visible | 
| 3068 |     model.change(); | 
| 3069 |  | 
| 3070 |     QTest::mouseDClick(widget: view.viewport(), button: Qt::LeftButton); | 
| 3071 |     model.change(); | 
| 3072 |  | 
| 3073 |     view.indexAt(p: QPoint(10, 10)); | 
| 3074 |     model.change(); | 
| 3075 |  | 
| 3076 |     view.indexAbove(index: model.index(row: 2, column: 0)); | 
| 3077 |     model.change(); | 
| 3078 |  | 
| 3079 |     view.indexBelow(index: model.index(row: 1, column: 0)); | 
| 3080 |     model.change(); | 
| 3081 |  | 
| 3082 |     QRect rect(0, 0, 10, 10); | 
| 3083 |     view.setSelection(rect, command: QItemSelectionModel::Select); | 
| 3084 |     model.change(); | 
| 3085 |  | 
| 3086 |     view.moveCursor(cursorAction: QTreeView::MoveDown, modifiers: Qt::NoModifier); | 
| 3087 |     model.change(); | 
| 3088 |  | 
| 3089 |     view.resizeColumnToContents(column: 1); | 
| 3090 |     model.change(); | 
| 3091 |  | 
| 3092 |     view.QAbstractItemView::sizeHintForColumn(column: 1); | 
| 3093 |     model.change(); | 
| 3094 |  | 
| 3095 |     view.rowHeight(index: secondLevel); | 
| 3096 |     model.change(); | 
| 3097 |  | 
| 3098 |     view.setRootIsDecorated(true); | 
| 3099 |     model.change(); | 
| 3100 |  | 
| 3101 |     view.setItemsExpandable(false); | 
| 3102 |     model.change(); | 
| 3103 |  | 
| 3104 |     view.columnViewportPosition(column: 0); | 
| 3105 |     model.change(); | 
| 3106 |  | 
| 3107 |     view.columnWidth(column: 0); | 
| 3108 |     model.change(); | 
| 3109 |  | 
| 3110 |     view.setColumnWidth(column: 0, width: 30); | 
| 3111 |     model.change(); | 
| 3112 |  | 
| 3113 |     view.columnAt(x: 15); | 
| 3114 |     model.change(); | 
| 3115 |  | 
| 3116 |     view.isColumnHidden(column: 1); | 
| 3117 |     model.change(); | 
| 3118 |  | 
| 3119 |     view.setColumnHidden(column: 2, hide: true); | 
| 3120 |     model.change(); | 
| 3121 |  | 
| 3122 |     view.isHeaderHidden(); | 
| 3123 |     model.change(); | 
| 3124 |  | 
| 3125 |     view.setHeaderHidden(true); | 
| 3126 |     model.change(); | 
| 3127 |  | 
| 3128 |     view.isRowHidden(row: 2, parent: secondLevel); | 
| 3129 |     model.change(); | 
| 3130 |  | 
| 3131 |     view.setRowHidden(row: 3, parent: secondLevel, hide: true); | 
| 3132 |     model.change(); | 
| 3133 |  | 
| 3134 |     view.isFirstColumnSpanned(row: 3, parent: thirdLevel); | 
| 3135 |     model.change(); | 
| 3136 |  | 
| 3137 |     view.setSortingEnabled(true); | 
| 3138 |     model.change(); | 
| 3139 |  | 
| 3140 |     view.isSortingEnabled(); | 
| 3141 |     model.change(); | 
| 3142 |  | 
| 3143 |     view.setAnimated(true); | 
| 3144 |     model.change(); | 
| 3145 |  | 
| 3146 |     view.isAnimated(); | 
| 3147 |     model.change(); | 
| 3148 |  | 
| 3149 |     view.setAllColumnsShowFocus(true); | 
| 3150 |     model.change(); | 
| 3151 |  | 
| 3152 |     view.allColumnsShowFocus(); | 
| 3153 |     model.change(); | 
| 3154 |  | 
| 3155 |     view.doItemsLayout(); | 
| 3156 |     model.change(); | 
| 3157 |  | 
| 3158 |     view.reset(); | 
| 3159 |     model.change(); | 
| 3160 |  | 
| 3161 |     view.sortByColumn(column: 1, order: Qt::AscendingOrder); | 
| 3162 |     model.change(); | 
| 3163 |  | 
| 3164 |     view.dataChanged(topLeft: secondLevel, bottomRight: secondLevel); | 
| 3165 |     model.change(); | 
| 3166 |  | 
| 3167 |     view.hideColumn(column: 1); | 
| 3168 |     model.change(); | 
| 3169 |  | 
| 3170 |     view.showColumn(column: 1); | 
| 3171 |     model.change(); | 
| 3172 |  | 
| 3173 |     view.resizeColumnToContents(column: 1); | 
| 3174 |     model.change(); | 
| 3175 |  | 
| 3176 |     view.sortByColumn(column: 1, order: Qt::DescendingOrder); | 
| 3177 |     model.change(); | 
| 3178 |  | 
| 3179 |     view.selectAll(); | 
| 3180 |     model.change(); | 
| 3181 |  | 
| 3182 |     view.expandAll(); | 
| 3183 |     model.change(); | 
| 3184 |  | 
| 3185 |     view.collapseAll(); | 
| 3186 |     model.change(); | 
| 3187 |  | 
| 3188 |     view.expandToDepth(depth: 3); | 
| 3189 |     model.change(); | 
| 3190 |  | 
| 3191 |     view.setRootIndex(secondLevel); | 
| 3192 |  | 
| 3193 |     model.setCrash(); | 
| 3194 |     view.setModel(nullptr); | 
| 3195 | } | 
| 3196 |  | 
| 3197 | void tst_QTreeView::indexRowSizeHint() | 
| 3198 | { | 
| 3199 |     QStandardItemModel model(10, 1); | 
| 3200 |     QTreeView view; | 
| 3201 |  | 
| 3202 |     view.setModel(&model); | 
| 3203 |  | 
| 3204 |     QModelIndex index = model.index(row: 5, column: 0); | 
| 3205 |     QPushButton *w = new QPushButton("Test" ); | 
| 3206 |     view.setIndexWidget(index, widget: w); | 
| 3207 |  | 
| 3208 |     view.show(); | 
| 3209 |  | 
| 3210 |     QCOMPARE(view.indexRowSizeHint(index), w->sizeHint().height()); | 
| 3211 | } | 
| 3212 |  | 
| 3213 | void tst_QTreeView::filterProxyModelCrash() | 
| 3214 | { | 
| 3215 |     QStandardItemModel model; | 
| 3216 |     QList<QStandardItem *> items; | 
| 3217 |     for (int i = 0; i < 100; i++) | 
| 3218 |         items << new QStandardItem(QLatin1String("item " ) + QString::number(i)); | 
| 3219 |     model.appendColumn(items); | 
| 3220 |  | 
| 3221 |     QSortFilterProxyModel proxy; | 
| 3222 |     proxy.setSourceModel(&model); | 
| 3223 |  | 
| 3224 |     TreeView view; | 
| 3225 |     view.setModel(&proxy); | 
| 3226 |     view.show(); | 
| 3227 |     QVERIFY(QTest::qWaitForWindowExposed(&view)); | 
| 3228 |     proxy.invalidate(); | 
| 3229 |     view.verticalScrollBar()->setValue(15); | 
| 3230 |     QTest::qWait(ms: 20); | 
| 3231 |  | 
| 3232 |     proxy.invalidate(); | 
| 3233 |     view.update(); //used to crash | 
| 3234 |     QTRY_VERIFY(view.wasPainted); | 
| 3235 | } | 
| 3236 |  | 
| 3237 | void tst_QTreeView::renderToPixmap_data() | 
| 3238 | { | 
| 3239 |     QTest::addColumn<int>(name: "row" ); | 
| 3240 |     QTest::newRow(dataTag: "row-0" ) << 0; | 
| 3241 |     QTest::newRow(dataTag: "row-1" ) << 1; | 
| 3242 | } | 
| 3243 |  | 
| 3244 | void tst_QTreeView::renderToPixmap() | 
| 3245 | { | 
| 3246 |     QFETCH(int, row); | 
| 3247 |     QTreeView view; | 
| 3248 |     QStandardItemModel model; | 
| 3249 |  | 
| 3250 |     model.appendRow(aitem: new QStandardItem("Spanning" )); | 
| 3251 |     model.appendRow(items: { new QStandardItem("Not" ), new QStandardItem("Spanning" ) }); | 
| 3252 |  | 
| 3253 |     view.setModel(&model); | 
| 3254 |     view.setFirstColumnSpanned(row: 0, parent: QModelIndex(), span: true); | 
| 3255 |  | 
| 3256 | #ifdef QT_BUILD_INTERNAL | 
| 3257 |     { | 
| 3258 |         // We select the index at row=0 because it spans the | 
| 3259 |         // column (regression test for an assert) | 
| 3260 |         // We select the index at row=1 for coverage. | 
| 3261 |         QItemSelection sel(model.index(row,column: 0), model.index(row,column: 1)); | 
| 3262 |         QRect rect; | 
| 3263 |         view.d_func()->renderToPixmap(indexes: sel.indexes(), r: &rect); | 
| 3264 |     } | 
| 3265 | #endif | 
| 3266 | } | 
| 3267 |  | 
| 3268 | void tst_QTreeView::styleOptionViewItem() | 
| 3269 | { | 
| 3270 |     class MyDelegate : public QStyledItemDelegate | 
| 3271 |     { | 
| 3272 |         static QString posToString(QStyleOptionViewItem::ViewItemPosition pos) | 
| 3273 |         { | 
| 3274 |             static const char* s_pos[] = { "Invalid" , "Beginning" , "Middle" , "End" , "OnlyOne"  }; | 
| 3275 |             return s_pos[pos]; | 
| 3276 |         } | 
| 3277 |     public: | 
| 3278 |         using QStyledItemDelegate::QStyledItemDelegate; | 
| 3279 |         void paint(QPainter *painter, const QStyleOptionViewItem &option, | 
| 3280 |                    const QModelIndex &index) const override | 
| 3281 |         { | 
| 3282 |             QStyleOptionViewItem opt(option); | 
| 3283 |             initStyleOption(option: &opt, index); | 
| 3284 |  | 
| 3285 |             QVERIFY(!opt.text.isEmpty()); | 
| 3286 |             QCOMPARE(opt.index, index); | 
| 3287 |             //qDebug() << index << opt.text; | 
| 3288 |  | 
| 3289 |             if (allCollapsed) { | 
| 3290 |                 QCOMPARE(!opt.features.testFlag(QStyleOptionViewItem::Alternate), | 
| 3291 |                          !(index.row() % 2)); | 
| 3292 |             } | 
| 3293 |             QCOMPARE(!opt.features.testFlag(QStyleOptionViewItem::HasCheckIndicator), | 
| 3294 |                      !opt.text.contains("Checkable" )); | 
| 3295 |  | 
| 3296 |             const QString posStr(posToString(pos: opt.viewItemPosition)); | 
| 3297 |             if (opt.text.contains(s: "Beginning" )) | 
| 3298 |                 QCOMPARE(posStr, posToString(QStyleOptionViewItem::Beginning)); | 
| 3299 |  | 
| 3300 |             if (opt.text.contains(s: "Middle" )) | 
| 3301 |                 QCOMPARE(posStr, posToString(QStyleOptionViewItem::Middle)); | 
| 3302 |  | 
| 3303 |             if (opt.text.contains(s: "End" )) | 
| 3304 |                 QCOMPARE(posStr, posToString(QStyleOptionViewItem::End)); | 
| 3305 |  | 
| 3306 |             if (opt.text.contains(s: "OnlyOne" )) | 
| 3307 |                 QCOMPARE(posStr, posToString(QStyleOptionViewItem::OnlyOne)); | 
| 3308 |  | 
| 3309 |             if (opt.text.contains(s: "Checked" )) | 
| 3310 |                 QCOMPARE(opt.checkState, Qt::Checked); | 
| 3311 |             else | 
| 3312 |                 QCOMPARE(opt.checkState, Qt::Unchecked); | 
| 3313 |  | 
| 3314 |             QCOMPARE(!opt.state.testFlag(QStyle::State_Children), | 
| 3315 |                      !opt.text.contains("HasChildren" )); | 
| 3316 |             QCOMPARE(opt.state.testFlag(QStyle::State_Sibling), | 
| 3317 |                      !opt.text.contains("Last" )); | 
| 3318 |  | 
| 3319 |             QVERIFY(!opt.text.contains("Assert" )); | 
| 3320 |  | 
| 3321 |             QStyledItemDelegate::paint(painter, option, index); | 
| 3322 |             count++; | 
| 3323 |         } | 
| 3324 |         mutable int count = 0; | 
| 3325 |         bool allCollapsed = false; | 
| 3326 |     }; | 
| 3327 |  | 
| 3328 |     QTreeView view; | 
| 3329 |     QStandardItemModel model; | 
| 3330 |     view.setModel(&model); | 
| 3331 |     MyDelegate delegate; | 
| 3332 |     view.setItemDelegate(&delegate); | 
| 3333 |     model.appendRow(items: { new QStandardItem("Beginning" ), | 
| 3334 |                       new QStandardItem("Hidden" ), | 
| 3335 |                       new QStandardItem("Middle" ), | 
| 3336 |                       new QStandardItem("Middle" ), | 
| 3337 |                       new QStandardItem("End" ) }); | 
| 3338 |     QStandardItem *par1 = new QStandardItem("Beginning HasChildren" ); | 
| 3339 |     model.appendRow(items: { par1, | 
| 3340 |                       new QStandardItem("Hidden" ), | 
| 3341 |                       new QStandardItem("Middle HasChildren" ), | 
| 3342 |                       new QStandardItem("Middle HasChildren" ), | 
| 3343 |                       new QStandardItem("End HasChildren" ) }); | 
| 3344 |     model.appendRow(items: { new QStandardItem("OnlyOne" ), | 
| 3345 |                       new QStandardItem("Hidden" ), | 
| 3346 |                       new QStandardItem("Assert" ), | 
| 3347 |                       new QStandardItem("Assert" ), | 
| 3348 |                       new QStandardItem("Assert" ) }); | 
| 3349 |     QStandardItem *checkable = new QStandardItem("Checkable" ); | 
| 3350 |     checkable->setCheckable(true); | 
| 3351 |     QStandardItem *checked = new QStandardItem("Checkable Checked" ); | 
| 3352 |     checked->setCheckable(true); | 
| 3353 |     checked->setCheckState(Qt::Checked); | 
| 3354 |     model.appendRow(items: { new QStandardItem("Beginning" ), | 
| 3355 |                       new QStandardItem("Hidden" ), | 
| 3356 |                       checkable, checked, | 
| 3357 |                       new QStandardItem("End" ) }); | 
| 3358 |     model.appendRow(items: { new QStandardItem("Beginning Last" ), | 
| 3359 |                       new QStandardItem("Hidden" ), | 
| 3360 |                       new QStandardItem("Middle Last" ), | 
| 3361 |                       new QStandardItem("Middle Last" ), | 
| 3362 |                       new QStandardItem("End Last" ) }); | 
| 3363 |     par1->appendRow(aitems: { new QStandardItem("Beginning" ), | 
| 3364 |                       new QStandardItem("Hidden" ), | 
| 3365 |                       new QStandardItem("Middle" ), | 
| 3366 |                       new QStandardItem("Middle" ), | 
| 3367 |                       new QStandardItem("End" ) }); | 
| 3368 |     QStandardItem *par2 = new QStandardItem("Beginning HasChildren" ); | 
| 3369 |     par1->appendRow(aitems: { par2, | 
| 3370 |                       new QStandardItem("Hidden" ), | 
| 3371 |                       new QStandardItem("Middle HasChildren" ), | 
| 3372 |                       new QStandardItem("Middle HasChildren" ), | 
| 3373 |                       new QStandardItem("End HasChildren" ) }); | 
| 3374 |     par2->appendRow(aitems: { new QStandardItem("Beginning Last" ), | 
| 3375 |                       new QStandardItem("Hidden" ), | 
| 3376 |                       new QStandardItem("Middle Last" ), | 
| 3377 |                       new QStandardItem("Middle Last" ), | 
| 3378 |                       new QStandardItem("End Last" ) }); | 
| 3379 |     QStandardItem *par3 = new QStandardItem("Beginning Last" ); | 
| 3380 |     par1->appendRow(aitems: { par3, new QStandardItem("Hidden" ), | 
| 3381 |                       new QStandardItem("Middle Last" ), | 
| 3382 |                       new QStandardItem("Middle Last" ), | 
| 3383 |                       new QStandardItem("End Last" ) }); | 
| 3384 |     par3->appendRow(aitems: { new QStandardItem("Assert" ), | 
| 3385 |                       new QStandardItem("Hidden" ), | 
| 3386 |                       new QStandardItem("Assert" ), | 
| 3387 |                       new QStandardItem("Assert" ), | 
| 3388 |                       new QStandardItem("Asser" ) }); | 
| 3389 |     view.setRowHidden(row: 0, parent: par3->index(), hide: true); | 
| 3390 |     par1->appendRow(aitems: { new QStandardItem("Assert" ), | 
| 3391 |                       new QStandardItem("Hidden" ), | 
| 3392 |                       new QStandardItem("Assert" ), | 
| 3393 |                       new QStandardItem("Assert" ), | 
| 3394 |                       new QStandardItem("Asser" ) }); | 
| 3395 |     view.setRowHidden(row: 3, parent: par1->index(), hide: true); | 
| 3396 |  | 
| 3397 |     view.setColumnHidden(column: 1, hide: true); | 
| 3398 |     const int visibleColumns = 4; | 
| 3399 |     const int modelColumns = 5; | 
| 3400 |  | 
| 3401 |     view.header()->swapSections(first: 2, second: 3); | 
| 3402 |     view.setFirstColumnSpanned(row: 2, parent: QModelIndex(), span: true); | 
| 3403 |     view.setAlternatingRowColors(true); | 
| 3404 |  | 
| 3405 | #ifdef QT_BUILD_INTERNAL | 
| 3406 |     { | 
| 3407 |         // Test the rendering to pixmap before painting the widget. | 
| 3408 |         // The rendering to pixmap should not depend on having been | 
| 3409 |         // painted already yet. | 
| 3410 |         delegate.count = 0; | 
| 3411 |         QItemSelection sel(model.index(row: 0,column: 0), model.index(row: 0,column: modelColumns-1)); | 
| 3412 |         QRect rect; | 
| 3413 |         view.d_func()->renderToPixmap(indexes: sel.indexes(), r: &rect); | 
| 3414 |         if (delegate.count != visibleColumns) { | 
| 3415 |             qDebug() << rect << view.rect() << view.isVisible(); | 
| 3416 |         } | 
| 3417 |         QTRY_COMPARE(delegate.count, visibleColumns); | 
| 3418 |     } | 
| 3419 | #endif | 
| 3420 |  | 
| 3421 |     delegate.count = 0; | 
| 3422 |     delegate.allCollapsed = true; | 
| 3423 |     view.showMaximized(); | 
| 3424 |     QVERIFY(QTest::qWaitForWindowExposed(&view)); | 
| 3425 |     QTRY_VERIFY(delegate.count >= 13); | 
| 3426 |     delegate.count = 0; | 
| 3427 |     delegate.allCollapsed = false; | 
| 3428 |     view.expandAll(); | 
| 3429 |     QTRY_VERIFY(delegate.count >= 13); | 
| 3430 |     delegate.count = 0; | 
| 3431 |     view.collapse(index: par2->index()); | 
| 3432 |     QTRY_VERIFY(delegate.count >= 4); | 
| 3433 |  | 
| 3434 |     // test that the rendering of drag pixmap sets the correct options too (QTBUG-15834) | 
| 3435 | #ifdef QT_BUILD_INTERNAL | 
| 3436 |     delegate.count = 0; | 
| 3437 |     QItemSelection sel(model.index(row: 0,column: 0), model.index(row: 0,column: modelColumns-1)); | 
| 3438 |     QRect rect; | 
| 3439 |     view.d_func()->renderToPixmap(indexes: sel.indexes(), r: &rect); | 
| 3440 |     if (delegate.count != visibleColumns) { | 
| 3441 |         qDebug() << rect << view.rect() << view.isVisible(); | 
| 3442 |     } | 
| 3443 |     QTRY_COMPARE(delegate.count, visibleColumns); | 
| 3444 | #endif | 
| 3445 |  | 
| 3446 |     //test dynamic models | 
| 3447 |     { | 
| 3448 |         delegate.count = 0; | 
| 3449 |         QStandardItemModel model2; | 
| 3450 |         QStandardItem *item0 = new QStandardItem("OnlyOne Last" ); | 
| 3451 |         model2.appendRow(aitem: item0); | 
| 3452 |         view.setModel(&model2); | 
| 3453 |         QTRY_VERIFY(delegate.count >= 1); | 
| 3454 |  | 
| 3455 |         QStandardItem *item00 = new QStandardItem("OnlyOne Last" ); | 
| 3456 |         item0->appendRow(aitem: item00); | 
| 3457 |         item0->setText("OnlyOne Last HasChildren" ); | 
| 3458 |         delegate.count = 0; | 
| 3459 |         view.expandAll(); | 
| 3460 |         QTRY_VERIFY(delegate.count >= 2); | 
| 3461 |  | 
| 3462 |         QStandardItem *item1 = new QStandardItem("OnlyOne Last" ); | 
| 3463 |         delegate.count = 0; | 
| 3464 |         item0->setText("OnlyOne HasChildren" ); | 
| 3465 |         model2.appendRow(aitem: item1); | 
| 3466 |         QTRY_VERIFY(delegate.count >= 3); | 
| 3467 |  | 
| 3468 |         QStandardItem *item01 = new QStandardItem("OnlyOne Last" ); | 
| 3469 |         delegate.count = 0; | 
| 3470 |         item00->setText("OnlyOne" ); | 
| 3471 |         item0->appendRow(aitem: item01); | 
| 3472 |         QTRY_VERIFY(delegate.count >= 4); | 
| 3473 |  | 
| 3474 |         QStandardItem *item000 = new QStandardItem("OnlyOne Last" ); | 
| 3475 |         delegate.count = 0; | 
| 3476 |         item00->setText("OnlyOne HasChildren" ); | 
| 3477 |         item00->appendRow(aitem: item000); | 
| 3478 |         QTRY_VERIFY(delegate.count >= 5); | 
| 3479 |  | 
| 3480 |         delegate.count = 0; | 
| 3481 |         item0->removeRow(row: 0); | 
| 3482 |         QTRY_VERIFY(delegate.count >= 3); | 
| 3483 |  | 
| 3484 |         item00 = new QStandardItem("OnlyOne" ); | 
| 3485 |         item0->insertRow(arow: 0, aitem: item00); | 
| 3486 |  | 
| 3487 |         delegate.count = 0; | 
| 3488 |         view.expandAll(); | 
| 3489 |         QTRY_VERIFY(delegate.count >= 4); | 
| 3490 |  | 
| 3491 |         delegate.count = 0; | 
| 3492 |         item0->removeRow(row: 1); | 
| 3493 |         item00->setText("OnlyOne Last" ); | 
| 3494 |         QTRY_VERIFY(delegate.count >= 3); | 
| 3495 |  | 
| 3496 |         delegate.count = 0; | 
| 3497 |         item0->removeRow(row: 0); | 
| 3498 |         item0->setText("OnlyOne" ); | 
| 3499 |         QTRY_VERIFY(delegate.count >= 2); | 
| 3500 |  | 
| 3501 |         //with hidden items | 
| 3502 |         item0->setText("OnlyOne HasChildren" ); | 
| 3503 |         item00 = new QStandardItem("OnlyOne" ); | 
| 3504 |         item0->appendRow(aitem: item00); | 
| 3505 |         item01 = new QStandardItem("Assert" ); | 
| 3506 |         item0->appendRow(aitem: item01); | 
| 3507 |         view.setRowHidden(row: 1, parent: item0->index(), hide: true); | 
| 3508 |         view.expandAll(); | 
| 3509 |         QStandardItem *item02 = new QStandardItem("OnlyOne Last" ); | 
| 3510 |         item0->appendRow(aitem: item02); | 
| 3511 |         delegate.count = 0; | 
| 3512 |         QTRY_VERIFY(delegate.count >= 4); | 
| 3513 |  | 
| 3514 |         item0->removeRow(row: 2); | 
| 3515 |         item00->setText("OnlyOne Last" ); | 
| 3516 |         delegate.count = 0; | 
| 3517 |         QTRY_VERIFY(delegate.count >= 3); | 
| 3518 |  | 
| 3519 |         item00->setText("OnlyOne" ); | 
| 3520 |         item0->insertRow(arow: 2, aitem: new QStandardItem("OnlyOne Last" )); | 
| 3521 |         view.collapse(index: item0->index()); | 
| 3522 |         item0->removeRow(row: 0); | 
| 3523 |         delegate.count = 0; | 
| 3524 |         QTRY_VERIFY(delegate.count >= 2); | 
| 3525 |  | 
| 3526 |         item0->removeRow(row: 1); | 
| 3527 |         item0->setText("OnlyOne" ); | 
| 3528 |         delegate.count = 0; | 
| 3529 |         QTRY_VERIFY(delegate.count >= 2); | 
| 3530 |     } | 
| 3531 | } | 
| 3532 |  | 
| 3533 | class task174627_TreeView : public QTreeView | 
| 3534 | { | 
| 3535 |     Q_OBJECT | 
| 3536 | protected slots: | 
| 3537 |     void currentChanged(const QModelIndex ¤t, const QModelIndex &) override | 
| 3538 |     { emit signalCurrentChanged(current); } | 
| 3539 | signals: | 
| 3540 |     void signalCurrentChanged(const QModelIndex &); | 
| 3541 | }; | 
| 3542 |  | 
| 3543 | void tst_QTreeView::task174627_moveLeftToRoot() | 
| 3544 | { | 
| 3545 |     QStandardItemModel model; | 
| 3546 |     QStandardItem *item1 = new QStandardItem(QString("item 1" )); | 
| 3547 |     model.invisibleRootItem()->appendRow(aitem: item1); | 
| 3548 |     QStandardItem *item2 = new QStandardItem(QString("item 2" )); | 
| 3549 |     item1->appendRow(aitem: item2); | 
| 3550 |  | 
| 3551 |     task174627_TreeView view; | 
| 3552 |     view.setModel(&model); | 
| 3553 |     view.setRootIndex(item1->index()); | 
| 3554 |     view.setCurrentIndex(item2->index()); | 
| 3555 |  | 
| 3556 |     QSignalSpy spy(&view, &task174627_TreeView::signalCurrentChanged); | 
| 3557 |     QTest::keyClick(widget: &view, key: Qt::Key_Left); | 
| 3558 |     QCOMPARE(spy.count(), 0); | 
| 3559 | } | 
| 3560 |  | 
| 3561 | void tst_QTreeView::task171902_expandWith1stColHidden() | 
| 3562 | { | 
| 3563 |     //the task was: if the first column of a treeview is hidden, the expanded state is not correctly restored | 
| 3564 |     QStandardItemModel model; | 
| 3565 |     QStandardItem root("root" ), root2("root" ), | 
| 3566 |         subitem("subitem" ), subitem2("subitem" ), | 
| 3567 |         subsubitem("subsubitem" ), subsubitem2("subsubitem" ); | 
| 3568 |  | 
| 3569 |     model.appendRow(items: { &root, &root2 }); | 
| 3570 |     root.appendRow(aitems: { &subitem, &subitem2 }); | 
| 3571 |     subitem.appendRow(aitems: { &subsubitem, &subsubitem2 }); | 
| 3572 |  | 
| 3573 |     QTreeView view; | 
| 3574 |     view.setModel(&model); | 
| 3575 |  | 
| 3576 |     view.setColumnHidden(column: 0, hide: true); | 
| 3577 |     view.expandAll(); | 
| 3578 |     view.collapse(index: root.index()); | 
| 3579 |     view.expand(index: root.index()); | 
| 3580 |  | 
| 3581 |     QCOMPARE(view.isExpanded(root.index()), true); | 
| 3582 |     QCOMPARE(view.isExpanded(subitem.index()), true); | 
| 3583 |  | 
| 3584 | } | 
| 3585 |  | 
| 3586 | void tst_QTreeView::task203696_hidingColumnsAndRowsn() | 
| 3587 | { | 
| 3588 |     QTreeView view; | 
| 3589 |     QStandardItemModel model(0, 3); | 
| 3590 |     for (int i = 0; i < 3; ++i) { | 
| 3591 |         const QString prefix = QLatin1String("row " ) + QString::number(i) + QLatin1String(" col " ); | 
| 3592 |         model.insertRow(arow: model.rowCount()); | 
| 3593 |         for (int j = 0; j < model.columnCount(); ++j) | 
| 3594 |             model.setData(index: model.index(row: i, column: j), value: prefix + QString::number(j)); | 
| 3595 |     } | 
| 3596 |     view.setModel(&model); | 
| 3597 |     view.show(); | 
| 3598 |     view.setColumnHidden(column: 0, hide: true); | 
| 3599 |     view.setRowHidden(row: 0, parent: QModelIndex(), hide: true); | 
| 3600 |     QCOMPARE(view.indexAt(QPoint(0, 0)), model.index(1, 1)); | 
| 3601 | } | 
| 3602 |  | 
| 3603 |  | 
| 3604 | void tst_QTreeView::addRowsWhileSectionsAreHidden() | 
| 3605 | { | 
| 3606 |     if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) | 
| 3607 |         QSKIP("Wayland: This fails. Figure out why." ); | 
| 3608 |  | 
| 3609 |     QTreeView view; | 
| 3610 |     for (int pass = 1; pass <= 2; ++pass) { | 
| 3611 |         QStandardItemModel *model = new QStandardItemModel(6, pass, &view); | 
| 3612 |         view.setModel(model); | 
| 3613 |         view.show(); | 
| 3614 |         QVERIFY(QTest::qWaitForWindowActive(&view)); | 
| 3615 |  | 
| 3616 |         for (int i = 0; i < 3; ++i) | 
| 3617 |         { | 
| 3618 |             model->insertRow(arow: model->rowCount()); | 
| 3619 |             const QString prefix = QLatin1String("row " ) + QString::number(i) + QLatin1String(" col " ); | 
| 3620 |             for (int j = 0; j < model->columnCount(); ++j) | 
| 3621 |                 model->setData(index: model->index(row: i, column: j), value: prefix + QString::number(j)); | 
| 3622 |         } | 
| 3623 |         for (int col = 0; col < pass; ++col) | 
| 3624 |             view.setColumnHidden(column: col, hide: true); | 
| 3625 |         for (int i = 3; i < 6; ++i) | 
| 3626 |         { | 
| 3627 |             model->insertRow(arow: model->rowCount()); | 
| 3628 |             const QString prefix = QLatin1String("row " ) + QString::number(i) + QLatin1String(" col " ); | 
| 3629 |             for (int j = 0; j < model->columnCount(); ++j) | 
| 3630 |                 model->setData(index: model->index(row: i, column: j), value: prefix + QString::number(j)); | 
| 3631 |         } | 
| 3632 |         for (int col = 0; col < pass; ++col) | 
| 3633 |             view.setColumnHidden(column: col, hide: false); | 
| 3634 |  | 
| 3635 |         auto allVisualRectsValid = [](QTreeView *view, QStandardItemModel *model) { | 
| 3636 |             for (int i = 0; i < 6; ++i) { | 
| 3637 |                 if (!view->visualRect(index: model->index(row: i, column: 0)).isValid()) | 
| 3638 |                     return false; | 
| 3639 |             } | 
| 3640 |             return true; | 
| 3641 |         }; | 
| 3642 |         QTRY_VERIFY(allVisualRectsValid(&view, model)); | 
| 3643 |  | 
| 3644 |         delete model; | 
| 3645 |     } | 
| 3646 | } | 
| 3647 |  | 
| 3648 | void tst_QTreeView::task216717_updateChildren() | 
| 3649 | { | 
| 3650 |     class Tree : public QTreeWidget | 
| 3651 |     { | 
| 3652 |         protected: | 
| 3653 |             void paintEvent(QPaintEvent *e) override | 
| 3654 |             { | 
| 3655 |                 QTreeWidget::paintEvent(event: e); | 
| 3656 |                 refreshed = true; | 
| 3657 |             } | 
| 3658 |         public: | 
| 3659 |             bool refreshed = false; | 
| 3660 |     } tree; | 
| 3661 |     tree.show(); | 
| 3662 |     QVERIFY(QTest::qWaitForWindowExposed(&tree)); | 
| 3663 |     tree.refreshed = false; | 
| 3664 |     QTreeWidgetItem *parent = new QTreeWidgetItem({ "parent"  }); | 
| 3665 |     tree.addTopLevelItem(item: parent); | 
| 3666 |     QTRY_VERIFY(tree.refreshed); | 
| 3667 |     tree.refreshed = false; | 
| 3668 |     parent->addChild(child: new QTreeWidgetItem({ "child"  })); | 
| 3669 |     QTRY_VERIFY(tree.refreshed); | 
| 3670 |  | 
| 3671 | } | 
| 3672 |  | 
| 3673 | void tst_QTreeView::task220298_selectColumns() | 
| 3674 | { | 
| 3675 |     if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) | 
| 3676 |         QSKIP("Wayland: This fails. Figure out why." ); | 
| 3677 |  | 
| 3678 |     //this is a very simple 3x3 model where the internalId of the index are different for each cell | 
| 3679 |     class Model : public QAbstractTableModel | 
| 3680 |     { | 
| 3681 |         public: | 
| 3682 |             int columnCount(const QModelIndex & parent = QModelIndex()) const override | 
| 3683 |             { return parent.isValid() ? 0 : 3; } | 
| 3684 |             int rowCount(const QModelIndex & parent = QModelIndex()) const override | 
| 3685 |             { return parent.isValid() ? 0 : 3; } | 
| 3686 |  | 
| 3687 |             QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const override | 
| 3688 |             { | 
| 3689 |                 if (role == Qt::DisplayRole) { | 
| 3690 |                     return QVariant(QString::number(index.column()) + QLatin1Char('-') | 
| 3691 |                         + QString::number(index.row())); | 
| 3692 |                 } | 
| 3693 |                 return QVariant(); | 
| 3694 |             } | 
| 3695 |  | 
| 3696 |             QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const override | 
| 3697 |             { | 
| 3698 |                 return hasIndex(row, column, parent) ? createIndex(arow: row, acolumn: column, aid: quintptr(column * 10 + row)) : QModelIndex(); | 
| 3699 |             } | 
| 3700 |     }; | 
| 3701 |  | 
| 3702 |     TreeView view; | 
| 3703 |     Model model; | 
| 3704 |     view.setModel(&model); | 
| 3705 |     view.show(); | 
| 3706 |     QVERIFY(QTest::qWaitForWindowActive(&view)); | 
| 3707 |     QTest::mouseClick(widget: view.viewport(), button: Qt::LeftButton, stateKey: {}, | 
| 3708 |                       pos: view.visualRect(index: view.model()->index(row: 1, column: 1)).center()); | 
| 3709 |     QTRY_VERIFY(view.selectedIndexes().contains(view.model()->index(1, 2))); | 
| 3710 |     QVERIFY(view.selectedIndexes().contains(view.model()->index(1, 1))); | 
| 3711 |     QVERIFY(view.selectedIndexes().contains(view.model()->index(1, 0))); | 
| 3712 | } | 
| 3713 |  | 
| 3714 |  | 
| 3715 | void tst_QTreeView::task224091_appendColumns() | 
| 3716 | { | 
| 3717 |     if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) | 
| 3718 |         QSKIP("Wayland: This fails. Figure out why." ); | 
| 3719 |  | 
| 3720 |     QStandardItemModel *model = new QStandardItemModel(); | 
| 3721 |     QWidget* topLevel= new QWidget; | 
| 3722 |     setFrameless(topLevel); | 
| 3723 |     QTreeView *treeView = new QTreeView(topLevel); | 
| 3724 |     treeView->setModel(model); | 
| 3725 |     topLevel->show(); | 
| 3726 |     treeView->resize(w: 50, h: 50); | 
| 3727 |     QApplication::setActiveWindow(topLevel); | 
| 3728 |     QVERIFY(QTest::qWaitForWindowActive(topLevel)); | 
| 3729 |  | 
| 3730 |     QVERIFY(!treeView->verticalScrollBar()->isVisible()); | 
| 3731 |  | 
| 3732 |     QList<QStandardItem *> projlist; | 
| 3733 |     for (int k = 0; k < 10; ++k) | 
| 3734 |         projlist.append(t: new QStandardItem(QLatin1String("Top Level " ) + QString::number(k))); | 
| 3735 |     model->appendColumn(items: projlist); | 
| 3736 |     model->invisibleRootItem()->appendRow(aitem: new QStandardItem("end" )); | 
| 3737 |  | 
| 3738 |     QTRY_VERIFY(treeView->verticalScrollBar()->isVisible()); | 
| 3739 |  | 
| 3740 |     delete topLevel; | 
| 3741 |     delete model; | 
| 3742 | } | 
| 3743 |  | 
| 3744 | void tst_QTreeView::task211293_removeRootIndex() | 
| 3745 | { | 
| 3746 |     QTreeView view; | 
| 3747 |     QStandardItemModel model; | 
| 3748 |     QStandardItem *A1 = new QStandardItem("A1" ); | 
| 3749 |     QStandardItem *B11 = new QStandardItem("B1.1" ); | 
| 3750 |     QStandardItem *C111 = new QStandardItem("C1.1.1" ); | 
| 3751 |     QStandardItem *C112 = new QStandardItem("C1.1.2" ); | 
| 3752 |     QStandardItem *C113 = new QStandardItem("C1.1.3" ); | 
| 3753 |     QStandardItem *D1131 = new QStandardItem("D1.1.3.1" ); | 
| 3754 |     QStandardItem *E11311 = new QStandardItem("E1.1.3.1.1" ); | 
| 3755 |     QStandardItem *E11312 = new QStandardItem("E1.1.3.1.2" ); | 
| 3756 |     QStandardItem *E11313 = new QStandardItem("E1.1.3.1.3" ); | 
| 3757 |     QStandardItem *E11314 = new QStandardItem("E1.1.3.1.4" ); | 
| 3758 |     QStandardItem *D1132 = new QStandardItem("D1.1.3.2" ); | 
| 3759 |     QStandardItem *E11321 = new QStandardItem("E1.1.3.2.1" ); | 
| 3760 |     D1132->appendRow(aitem: E11321); | 
| 3761 |     D1131->appendRow(aitem: E11311); | 
| 3762 |     D1131->appendRow(aitem: E11312); | 
| 3763 |     D1131->appendRow(aitem: E11313); | 
| 3764 |     D1131->appendRow(aitem: E11314); | 
| 3765 |     C113->appendRow(aitem: D1131); | 
| 3766 |     C113->appendRow(aitem: D1132); | 
| 3767 |     B11->appendRow(aitem: C111); | 
| 3768 |     B11->appendRow(aitem: C112); | 
| 3769 |     B11->appendRow(aitem: C113); | 
| 3770 |     A1->appendRow(aitem: B11); | 
| 3771 |     model.appendRow(aitem: A1); | 
| 3772 |     view.setModel(&model); | 
| 3773 |     view.setRootIndex(model.indexFromItem(item: B11)); | 
| 3774 |     view.setExpanded(index: model.indexFromItem(item: B11), expand: true); | 
| 3775 |     view.setCurrentIndex(model.indexFromItem(item: E11314)); | 
| 3776 |     view.setExpanded(index: model.indexFromItem(item: E11314), expand: true); | 
| 3777 |     view.show(); | 
| 3778 |     QVERIFY(QTest::qWaitForWindowExposed(&view)); | 
| 3779 |     QVERIFY(model.removeRows(0, 1)); | 
| 3780 | } | 
| 3781 |  | 
| 3782 | void tst_QTreeView::task225539_deleteModel() | 
| 3783 | { | 
| 3784 |     QTreeView treeView; | 
| 3785 |     treeView.show(); | 
| 3786 |     QStandardItemModel *model = new QStandardItemModel(&treeView); | 
| 3787 |  | 
| 3788 |     QStandardItem *parentItem = model->invisibleRootItem(); | 
| 3789 |     QStandardItem *item = new QStandardItem(QString("item" )); | 
| 3790 |     parentItem->appendRow(aitem: item); | 
| 3791 |  | 
| 3792 |     treeView.setModel(model); | 
| 3793 |  | 
| 3794 |     QCOMPARE(item->index(), treeView.indexAt(QPoint())); | 
| 3795 |  | 
| 3796 |     delete model; | 
| 3797 |  | 
| 3798 |     QVERIFY(!treeView.indexAt(QPoint()).isValid()); | 
| 3799 | } | 
| 3800 |  | 
| 3801 | void tst_QTreeView::task230123_setItemsExpandable() | 
| 3802 | { | 
| 3803 |     //let's check that we prevent the expansion inside a treeview | 
| 3804 |     //when the property is set. | 
| 3805 |     QTreeWidget tree; | 
| 3806 |  | 
| 3807 |     QTreeWidgetItem root; | 
| 3808 |     QTreeWidgetItem child; | 
| 3809 |     root.addChild(child: &child); | 
| 3810 |     tree.addTopLevelItem(item: &root); | 
| 3811 |  | 
| 3812 |     tree.setCurrentItem(&root); | 
| 3813 |  | 
| 3814 |     tree.setItemsExpandable(false); | 
| 3815 |  | 
| 3816 |     QTest::keyClick(widget: &tree, key: Qt::Key_Plus); | 
| 3817 |     QVERIFY(!root.isExpanded()); | 
| 3818 |  | 
| 3819 |     QTest::keyClick(widget: &tree, key: Qt::Key_Right); | 
| 3820 |     QVERIFY(!root.isExpanded()); | 
| 3821 |  | 
| 3822 |     tree.setItemsExpandable(true); | 
| 3823 |  | 
| 3824 |     QTest::keyClick(widget: &tree, key: Qt::Key_Plus); | 
| 3825 |     QVERIFY(root.isExpanded()); | 
| 3826 |  | 
| 3827 |     QTest::keyClick(widget: &tree, key: Qt::Key_Minus); | 
| 3828 |     QVERIFY(!root.isExpanded()); | 
| 3829 |  | 
| 3830 |     QTest::keyClick(widget: &tree, key: Qt::Key_Right); | 
| 3831 |     QVERIFY(root.isExpanded()); | 
| 3832 |  | 
| 3833 |     QTest::keyClick(widget: &tree, key: Qt::Key_Left); | 
| 3834 |     QVERIFY(!root.isExpanded()); | 
| 3835 |  | 
| 3836 |     QTest::keyClick(widget: &tree, key: Qt::Key_Right); | 
| 3837 |     QVERIFY(root.isExpanded()); | 
| 3838 |  | 
| 3839 |     const bool navToChild = tree.style()->styleHint(stylehint: QStyle::SH_ItemView_ArrowKeysNavigateIntoChildren, opt: nullptr, widget: &tree); | 
| 3840 |     QTest::keyClick(widget: &tree, key: Qt::Key_Right); | 
| 3841 |     QCOMPARE(tree.currentItem(), navToChild ? &child : &root); | 
| 3842 |  | 
| 3843 |     QTest::keyClick(widget: &tree, key: Qt::Key_Right); | 
| 3844 |     //it should not be expanded: it has no leaf | 
| 3845 |     QCOMPARE(child.isExpanded(), false); | 
| 3846 |  | 
| 3847 |     QTest::keyClick(widget: &tree, key: Qt::Key_Left); | 
| 3848 |     QCOMPARE(tree.currentItem(), &root); | 
| 3849 |  | 
| 3850 |     QTest::keyClick(widget: &tree, key: Qt::Key_Left); | 
| 3851 |     QVERIFY(!root.isExpanded()); | 
| 3852 | } | 
| 3853 |  | 
| 3854 | void tst_QTreeView::task202039_closePersistentEditor() | 
| 3855 | { | 
| 3856 |     QStandardItemModel model(1, 1); | 
| 3857 |     QTreeView view; | 
| 3858 |     view.setModel(&model); | 
| 3859 |  | 
| 3860 |     QModelIndex current = model.index(row: 0,column: 0); | 
| 3861 |     QTest::mousePress(widget: view.viewport(), button: Qt::LeftButton, stateKey: {}, pos: view.visualRect(index: current).center()); | 
| 3862 |     QTest::mouseDClick(widget: view.viewport(), button: Qt::LeftButton, stateKey: {}, pos: view.visualRect(index: current).center()); | 
| 3863 |     QCOMPARE(view.currentIndex(), current); | 
| 3864 |     QVERIFY(view.indexWidget(current)); | 
| 3865 |  | 
| 3866 |     view.closePersistentEditor(index: current); | 
| 3867 |     QVERIFY(!view.indexWidget(current)); | 
| 3868 |  | 
| 3869 |     //here was the bug: closing the persistent editor would not reset the state | 
| 3870 |     //and it was impossible to go into editinon again | 
| 3871 |     QTest::mousePress(widget: view.viewport(), button: Qt::LeftButton, stateKey: {}, pos: view.visualRect(index: current).center()); | 
| 3872 |     QTest::mouseDClick(widget: view.viewport(), button: Qt::LeftButton, stateKey: {}, pos: view.visualRect(index: current).center()); | 
| 3873 |     QCOMPARE(view.currentIndex(), current); | 
| 3874 |     QVERIFY(view.indexWidget(current)); | 
| 3875 | } | 
| 3876 |  | 
| 3877 | void tst_QTreeView::task238873_avoidAutoReopening() | 
| 3878 | { | 
| 3879 |     if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) | 
| 3880 |         QSKIP("Wayland: This fails. Figure out why." ); | 
| 3881 |  | 
| 3882 |     QStandardItemModel model; | 
| 3883 |  | 
| 3884 |     QStandardItem item0("row 0" ); | 
| 3885 |     QStandardItem item1("row 1" ); | 
| 3886 |     QStandardItem item2("row 2" ); | 
| 3887 |     QStandardItem item3("row 3" ); | 
| 3888 |     model.appendColumn( items: QList<QStandardItem*>() << &item0 << &item1 << &item2 << &item3); | 
| 3889 |  | 
| 3890 |     QStandardItem child("child" ); | 
| 3891 |     item1.appendRow( aitem: &child); | 
| 3892 |  | 
| 3893 |     QTreeView view; | 
| 3894 |     view.setModel(&model); | 
| 3895 |     view.show(); | 
| 3896 |     view.expandAll(); | 
| 3897 |     QVERIFY(QTest::qWaitForWindowActive(&view)); | 
| 3898 |  | 
| 3899 |     QTest::mouseClick(widget: view.viewport(), button: Qt::LeftButton, stateKey: {}, pos: view.visualRect(index: child.index()).center()); | 
| 3900 |     QTRY_COMPARE(view.currentIndex(), child.index()); | 
| 3901 |  | 
| 3902 |     view.setExpanded(index: item1.index(), expand: false); | 
| 3903 |  | 
| 3904 |     QTRY_VERIFY(!view.isExpanded(item1.index())); | 
| 3905 | } | 
| 3906 |  | 
| 3907 | void tst_QTreeView::task244304_clickOnDecoration() | 
| 3908 | { | 
| 3909 |     QTreeView view; | 
| 3910 |     QStandardItemModel model; | 
| 3911 |     QStandardItem item0("row 0" ); | 
| 3912 |     QStandardItem item00("row 0" ); | 
| 3913 |     item0.appendRow(aitem: &item00); | 
| 3914 |     QStandardItem item1("row 1" ); | 
| 3915 |     model.appendColumn(items: { &item0, &item1 }); | 
| 3916 |     view.setModel(&model); | 
| 3917 |  | 
| 3918 |     QVERIFY(!view.currentIndex().isValid()); | 
| 3919 |     QRect rect = view.visualRect(index: item0.index()); | 
| 3920 |     //we click on the decoration | 
| 3921 |     QTest::mouseClick(widget: view.viewport(), button: Qt::LeftButton, stateKey: {}, | 
| 3922 |                       pos: rect.topLeft() + QPoint(-rect.left() / 2, rect.height() / 2)); | 
| 3923 |     QVERIFY(!view.currentIndex().isValid()); | 
| 3924 |     QVERIFY(view.isExpanded(item0.index())); | 
| 3925 |  | 
| 3926 |     rect = view.visualRect(index: item1.index()); | 
| 3927 |     //the item has no decoration, it should get selected | 
| 3928 |     QTest::mouseClick(widget: view.viewport(), button: Qt::LeftButton, stateKey: {}, | 
| 3929 |                       pos: rect.topLeft() + QPoint(-rect.left() / 2, rect.height() / 2)); | 
| 3930 |     QCOMPARE(view.currentIndex(), item1.index()); | 
| 3931 | } | 
| 3932 |  | 
| 3933 | void tst_QTreeView::task246536_scrollbarsNotWorking() | 
| 3934 | { | 
| 3935 |     class MyObject : public QObject | 
| 3936 |     { | 
| 3937 |     public: | 
| 3938 |         using QObject::QObject; | 
| 3939 |         bool eventFilter(QObject*, QEvent *e) override | 
| 3940 |         { | 
| 3941 |             if (e->type() == QEvent::Paint) | 
| 3942 |                 count++; | 
| 3943 |  | 
| 3944 |             return false; | 
| 3945 |         } | 
| 3946 |         int count = 0; | 
| 3947 |     }; | 
| 3948 |     QTreeView tree; | 
| 3949 |     MyObject o; | 
| 3950 |     tree.viewport()->installEventFilter(filterObj: &o); | 
| 3951 |     QStandardItemModel model; | 
| 3952 |     tree.setModel(&model); | 
| 3953 |     tree.show(); | 
| 3954 |     QVERIFY(QTest::qWaitForWindowExposed(&tree)); | 
| 3955 |     QList<QStandardItem *> items; | 
| 3956 |     for (int i = 0; i < 100; ++i) | 
| 3957 |         items << new QStandardItem(QLatin1String("item " ) + QString::number(i)); | 
| 3958 |     o.count = 0; | 
| 3959 |     model.invisibleRootItem()->appendColumn(aitems: items); | 
| 3960 |     QTRY_VERIFY(o.count > 0); | 
| 3961 |     o.count = 0; | 
| 3962 |     tree.verticalScrollBar()->setValue(50); | 
| 3963 |     QTRY_VERIFY(o.count > 0); | 
| 3964 | } | 
| 3965 |  | 
| 3966 | void tst_QTreeView::task250683_wrongSectionSize() | 
| 3967 | { | 
| 3968 |     if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) | 
| 3969 |         QSKIP("Wayland: This fails. Figure out why." ); | 
| 3970 |  | 
| 3971 |     QStandardItemModel model; | 
| 3972 |     populateFakeDirModel(model: &model); | 
| 3973 |  | 
| 3974 |     QTreeView treeView; | 
| 3975 |     treeView.header()->setSectionResizeMode(QHeaderView::ResizeToContents); | 
| 3976 |     treeView.setModel(&model); | 
| 3977 |     treeView.setColumnHidden(column: 2, hide: true); | 
| 3978 |     treeView.setColumnHidden(column: 3, hide: true); | 
| 3979 |  | 
| 3980 |     treeView.show(); | 
| 3981 |     QVERIFY(QTest::qWaitForWindowActive(&treeView)); | 
| 3982 |  | 
| 3983 |     QCOMPARE(treeView.header()->sectionSize(0) + treeView.header()->sectionSize(1), treeView.viewport()->width()); | 
| 3984 | } | 
| 3985 |  | 
| 3986 | void tst_QTreeView::task239271_addRowsWithFirstColumnHidden() | 
| 3987 | { | 
| 3988 |     class MyDelegate : public QStyledItemDelegate | 
| 3989 |     { | 
| 3990 |     public: | 
| 3991 |         void paint(QPainter *painter, const QStyleOptionViewItem &option, | 
| 3992 |                    const QModelIndex &index) const override | 
| 3993 |         { | 
| 3994 |             paintedIndexes << index; | 
| 3995 |             QStyledItemDelegate::paint(painter, option, index); | 
| 3996 |         } | 
| 3997 |         mutable QSet<QModelIndex> paintedIndexes; | 
| 3998 |     }; | 
| 3999 |  | 
| 4000 |     QTreeView view; | 
| 4001 |     QStandardItemModel model; | 
| 4002 |     view.setModel(&model); | 
| 4003 |     MyDelegate delegate; | 
| 4004 |     view.setItemDelegate(&delegate); | 
| 4005 |     QStandardItem root0("root0" ), root1("root1" ); | 
| 4006 |     model.invisibleRootItem()->appendRow(aitems: QList<QStandardItem*>() << &root0 << &root1); | 
| 4007 |     QStandardItem sub0("sub0" ), sub00("sub00" ); | 
| 4008 |     root0.appendRow(aitems: QList<QStandardItem*>() << &sub0 << &sub00); | 
| 4009 |     view.expand(index: root0.index()); | 
| 4010 |  | 
| 4011 |     view.hideColumn(column: 0); | 
| 4012 |     view.show(); | 
| 4013 |     QVERIFY(QTest::qWaitForWindowExposed(&view)); | 
| 4014 |     delegate.paintedIndexes.clear(); | 
| 4015 |     QStandardItem sub1("sub1" ), sub11("sub11" ); | 
| 4016 |     root0.appendRow(aitems: QList<QStandardItem*>() << &sub1 << &sub11); | 
| 4017 |  | 
| 4018 |     //items in the 2nd column should have been painted | 
| 4019 |     QTRY_VERIFY(!delegate.paintedIndexes.isEmpty()); | 
| 4020 |     QVERIFY(delegate.paintedIndexes.contains(sub00.index())); | 
| 4021 |     QVERIFY(delegate.paintedIndexes.contains(sub11.index())); | 
| 4022 | } | 
| 4023 |  | 
| 4024 | void tst_QTreeView::task254234_proxySort() | 
| 4025 | { | 
| 4026 |     //based on tst_QTreeView::sortByColumn | 
| 4027 |     // it used not to work when setting the source of a proxy after enabling sorting | 
| 4028 |     QTreeView view; | 
| 4029 |     QStandardItemModel model(4, 2); | 
| 4030 |     model.setItem(row: 0, column: 0, item: new QStandardItem("b" )); | 
| 4031 |     model.setItem(row: 1, column: 0, item: new QStandardItem("d" )); | 
| 4032 |     model.setItem(row: 2, column: 0, item: new QStandardItem("c" )); | 
| 4033 |     model.setItem(row: 3, column: 0, item: new QStandardItem("a" )); | 
| 4034 |     model.setItem(row: 0, column: 1, item: new QStandardItem("e" )); | 
| 4035 |     model.setItem(row: 1, column: 1, item: new QStandardItem("g" )); | 
| 4036 |     model.setItem(row: 2, column: 1, item: new QStandardItem("h" )); | 
| 4037 |     model.setItem(row: 3, column: 1, item: new QStandardItem("f" )); | 
| 4038 |  | 
| 4039 |     view.sortByColumn(column: 1, order: Qt::DescendingOrder); | 
| 4040 |     view.setSortingEnabled(true); | 
| 4041 |  | 
| 4042 |     QSortFilterProxyModel proxy; | 
| 4043 |     proxy.setDynamicSortFilter(true); | 
| 4044 |     view.setModel(&proxy); | 
| 4045 |     proxy.setSourceModel(&model); | 
| 4046 |     QCOMPARE(view.header()->sortIndicatorSection(), 1); | 
| 4047 |     QCOMPARE(view.model()->data(view.model()->index(0, 1)).toString(), QString::fromLatin1("h" )); | 
| 4048 |     QCOMPARE(view.model()->data(view.model()->index(1, 1)).toString(), QString::fromLatin1("g" )); | 
| 4049 | } | 
| 4050 |  | 
| 4051 | void tst_QTreeView::task248022_changeSelection() | 
| 4052 | { | 
| 4053 |     //we check that changing the selection between the mouse press and the mouse release | 
| 4054 |     //works correctly | 
| 4055 |     TreeView view; | 
| 4056 |     const QStringList list({"1" , "2" }); | 
| 4057 |     QStringListModel model(list); | 
| 4058 |     view.setSelectionMode(QAbstractItemView::ExtendedSelection); | 
| 4059 |     view.setModel(&model); | 
| 4060 |     connect(sender: view.selectionModel(), signal: &QItemSelectionModel::selectionChanged, | 
| 4061 |             receiver: &view, slot: &TreeView::handleSelectionChanged); | 
| 4062 |     QTest::mouseClick(widget: view.viewport(), button: Qt::LeftButton, stateKey: {}, | 
| 4063 |                       pos: view.visualRect(index: model.index(row: 1)).center()); | 
| 4064 |     QCOMPARE(view.selectionModel()->selectedIndexes().count(), list.count()); | 
| 4065 | } | 
| 4066 |  | 
| 4067 | void tst_QTreeView::task245654_changeModelAndExpandAll() | 
| 4068 | { | 
| 4069 |     QTreeView view; | 
| 4070 |     QScopedPointer<QStandardItemModel> model(new QStandardItemModel); | 
| 4071 |     QStandardItem *top = new QStandardItem("top" ); | 
| 4072 |     QStandardItem *sub = new QStandardItem("sub" ); | 
| 4073 |     top->appendRow(aitem: sub); | 
| 4074 |     model->appendRow(aitem: top); | 
| 4075 |     view.setModel(model.data()); | 
| 4076 |     view.expandAll(); | 
| 4077 |     view.show(); | 
| 4078 |     QVERIFY(QTest::qWaitForWindowExposed(&view)); | 
| 4079 |     QTRY_VERIFY(view.isExpanded(top->index())); | 
| 4080 |  | 
| 4081 |     //now let's try to delete the model | 
| 4082 |     //then repopulate and expand again | 
| 4083 |     model.reset(other: new QStandardItemModel); | 
| 4084 |     top = new QStandardItem("top" ); | 
| 4085 |     sub = new QStandardItem("sub" ); | 
| 4086 |     top->appendRow(aitem: sub); | 
| 4087 |     model->appendRow(aitem: top); | 
| 4088 |     view.setModel(model.data()); | 
| 4089 |     view.expandAll(); | 
| 4090 |     QTRY_VERIFY(view.isExpanded(top->index())); | 
| 4091 | } | 
| 4092 |  | 
| 4093 | void tst_QTreeView::doubleClickedWithSpans() | 
| 4094 | { | 
| 4095 |     if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) | 
| 4096 |         QSKIP("Wayland: This fails. Figure out why." ); | 
| 4097 |  | 
| 4098 |     QTreeView view; | 
| 4099 |     QStandardItemModel model(1, 2); | 
| 4100 |     view.setModel(&model); | 
| 4101 |     view.setFirstColumnSpanned(row: 0, parent: QModelIndex(), span: true); | 
| 4102 |     view.show(); | 
| 4103 |     QApplication::setActiveWindow(&view); | 
| 4104 |     QVERIFY(QTest::qWaitForWindowActive(&view)); | 
| 4105 |     QVERIFY(view.isActiveWindow()); | 
| 4106 |  | 
| 4107 |     QPoint p(10, 10); | 
| 4108 |     QCOMPARE(view.indexAt(p), model.index(0, 0)); | 
| 4109 |     QSignalSpy spy(&view, &QAbstractItemView::doubleClicked); | 
| 4110 |     QTest::mousePress(widget: view.viewport(), button: Qt::LeftButton, stateKey: {}, pos: p); | 
| 4111 |     QTest::mouseDClick(widget: view.viewport(), button: Qt::LeftButton, stateKey: {}, pos: p); | 
| 4112 |     QTest::mouseRelease(widget: view.viewport(), button: Qt::LeftButton, stateKey: {}, pos: p); | 
| 4113 |     QCOMPARE(spy.count(), 1); | 
| 4114 |  | 
| 4115 |     //let's click on the 2nd column | 
| 4116 |     p.setX(p.x() + view.header()->sectionSize(logicalIndex: 0)); | 
| 4117 |     QCOMPARE(view.indexAt(p), model.index(0, 0)); | 
| 4118 |  | 
| 4119 |     //end the previous edition | 
| 4120 |     QTest::mouseClick(widget: view.viewport(), button: Qt::LeftButton, stateKey: {}, pos: p); | 
| 4121 |     QTest::mousePress(widget: view.viewport(), button: Qt::LeftButton, stateKey: {}, pos: p); | 
| 4122 |     QTest::mouseDClick(widget: view.viewport(), button: Qt::LeftButton, stateKey: {}, pos: p); | 
| 4123 |     QTest::mouseRelease(widget: view.viewport(), button: Qt::LeftButton, stateKey: {}, pos: p); | 
| 4124 |     QTRY_COMPARE(spy.count(), 2); | 
| 4125 | } | 
| 4126 |  | 
| 4127 | void tst_QTreeView::taskQTBUG_6450_selectAllWith1stColumnHidden() | 
| 4128 | { | 
| 4129 |     QTreeWidget tree; | 
| 4130 |     tree.setSelectionMode(QAbstractItemView::MultiSelection); | 
| 4131 |     tree.setColumnCount(2); | 
| 4132 |     QList<QTreeWidgetItem *> items; | 
| 4133 |     const int nrRows = 10; | 
| 4134 |     for (int i = 0; i < nrRows; ++i) { | 
| 4135 |         const QString text = QLatin1String("item: " ) + QString::number(i); | 
| 4136 |         items.append(t: new QTreeWidgetItem(static_cast<QTreeWidget *>(nullptr), | 
| 4137 |                                          QStringList(text))); | 
| 4138 |         items.last()->setText(column: 1, atext: QString("is an item" )); | 
| 4139 |     } | 
| 4140 |     tree.insertTopLevelItems(index: 0, items); | 
| 4141 |  | 
| 4142 |     tree.hideColumn(column: 0); | 
| 4143 |     tree.selectAll(); | 
| 4144 |  | 
| 4145 |     QVERIFY(tree.selectionModel()->hasSelection()); | 
| 4146 |     for (int i = 0; i < nrRows; ++i) | 
| 4147 |         QVERIFY(tree.selectionModel()->isRowSelected(i, QModelIndex())); | 
| 4148 | } | 
| 4149 |  | 
| 4150 | class TreeViewQTBUG_9216 : public QTreeView | 
| 4151 | { | 
| 4152 |     Q_OBJECT | 
| 4153 | public: | 
| 4154 |     void paintEvent(QPaintEvent *event) override | 
| 4155 |     { | 
| 4156 |         if (doCompare) | 
| 4157 |             QCOMPARE(event->rect(), viewport()->rect()); | 
| 4158 |         QTreeView::paintEvent(event); | 
| 4159 |         painted++; | 
| 4160 |     } | 
| 4161 |     int painted = 0; | 
| 4162 |     bool doCompare = false; | 
| 4163 | }; | 
| 4164 |  | 
| 4165 | void tst_QTreeView::taskQTBUG_9216_setSizeAndUniformRowHeightsWrongRepaint() | 
| 4166 | { | 
| 4167 |     QStandardItemModel model(10, 10, this); | 
| 4168 |     for (int row = 0; row < 10; row++) { | 
| 4169 |         const QString prefix = QLatin1String("row " ) + QString::number(row) + QLatin1String(", col " ); | 
| 4170 |         for (int col = 0; col < 10; col++) | 
| 4171 |             model.setItem(row, column: col, item: new QStandardItem(prefix + QString::number(col))); | 
| 4172 |     } | 
| 4173 |     TreeViewQTBUG_9216 view; | 
| 4174 |     view.setUniformRowHeights(true); | 
| 4175 |     view.setModel(&model); | 
| 4176 |     view.painted = 0; | 
| 4177 |     view.doCompare = false; | 
| 4178 |     view.show(); | 
| 4179 |     QVERIFY(QTest::qWaitForWindowExposed(&view)); | 
| 4180 |     QTRY_VERIFY(view.painted > 0); | 
| 4181 |  | 
| 4182 |     QTest::qWait(ms: 100);  // This one is needed to make the test fail before the patch. | 
| 4183 |     view.painted = 0; | 
| 4184 |     view.doCompare = true; | 
| 4185 |     model.setData(index: model.index(row: 0, column: 0), value: QVariant(QSize(50, 50)), role: Qt::SizeHintRole); | 
| 4186 |     QTRY_VERIFY(view.painted > 0); | 
| 4187 | } | 
| 4188 |  | 
| 4189 | void tst_QTreeView::keyboardNavigationWithDisabled() | 
| 4190 | { | 
| 4191 |     if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) | 
| 4192 |         QSKIP("Wayland: This fails. Figure out why." ); | 
| 4193 |  | 
| 4194 |     QWidget topLevel; | 
| 4195 |     QTreeView view(&topLevel); | 
| 4196 |     QStandardItemModel model(90, 0); | 
| 4197 |     for (int i = 0; i < 90; i ++) { | 
| 4198 |         model.setItem(arow: i, aitem: new QStandardItem(QString::number(i))); | 
| 4199 |         model.item(row: i)->setEnabled(i % 6 == 0); | 
| 4200 |     } | 
| 4201 |     view.setModel(&model); | 
| 4202 |  | 
| 4203 |     view.resize(w: 200, h: view.visualRect(index: model.index(row: 0,column: 0)).height()*10); | 
| 4204 |     topLevel.show(); | 
| 4205 |     QApplication::setActiveWindow(&topLevel); | 
| 4206 |     QVERIFY(QTest::qWaitForWindowActive(&topLevel)); | 
| 4207 |     QVERIFY(topLevel.isActiveWindow()); | 
| 4208 |  | 
| 4209 |     view.setCurrentIndex(model.index(row: 1, column: 0)); | 
| 4210 |     QTest::keyClick(widget: view.viewport(), key: Qt::Key_Up); | 
| 4211 |     QCOMPARE(view.currentIndex(), model.index(0, 0)); | 
| 4212 |     QTest::keyClick(widget: view.viewport(), key: Qt::Key_Down); | 
| 4213 |     QCOMPARE(view.currentIndex(), model.index(6, 0)); | 
| 4214 |     QTest::keyClick(widget: view.viewport(), key: Qt::Key_PageDown); | 
| 4215 |     QCOMPARE(view.currentIndex(), model.index(18, 0)); | 
| 4216 |     QTest::keyClick(widget: view.viewport(), key: Qt::Key_Down); | 
| 4217 |     QCOMPARE(view.currentIndex(), model.index(24, 0)); | 
| 4218 |     QTest::keyClick(widget: view.viewport(), key: Qt::Key_PageUp); | 
| 4219 |     QCOMPARE(view.currentIndex(), model.index(12, 0)); | 
| 4220 |     QTest::keyClick(widget: view.viewport(), key: Qt::Key_Up); | 
| 4221 |     QCOMPARE(view.currentIndex(), model.index(6, 0)); | 
| 4222 |     // QTBUG-44746 - when first/last item is disabled, | 
| 4223 |     // Key_PageUp/Down/Home/End will not work as expected. | 
| 4224 |     model.item(row: 0)->setEnabled(false); | 
| 4225 |     model.item(row: 1)->setEnabled(true); | 
| 4226 |     model.item(row: 2)->setEnabled(true); | 
| 4227 |     model.item(row: model.rowCount() - 1)->setEnabled(false); | 
| 4228 |     model.item(row: model.rowCount() - 2)->setEnabled(true); | 
| 4229 |     model.item(row: model.rowCount() - 3)->setEnabled(true); | 
| 4230 |     // PageUp | 
| 4231 |     view.setCurrentIndex(model.index(row: 2, column: 0)); | 
| 4232 |     QCOMPARE(view.currentIndex(), model.index(2, 0)); | 
| 4233 |     QTest::keyClick(widget: view.viewport(), key: Qt::Key_PageUp); | 
| 4234 |     QCOMPARE(view.currentIndex(), model.index(1, 0)); | 
| 4235 |     // PageDown | 
| 4236 |     view.setCurrentIndex(model.index(row: model.rowCount() - 3, column: 0)); | 
| 4237 |     QCOMPARE(view.currentIndex(), model.index(model.rowCount() - 3, 0)); | 
| 4238 |     QTest::keyClick(widget: view.viewport(), key: Qt::Key_PageDown); | 
| 4239 |     QCOMPARE(view.currentIndex(), model.index(model.rowCount() - 2, 0)); | 
| 4240 |     // Key_Home | 
| 4241 |     QTest::keyClick(widget: view.viewport(), key: Qt::Key_Home); | 
| 4242 |     QCOMPARE(view.currentIndex(), model.index(1, 0)); | 
| 4243 |     // Key_End | 
| 4244 |     QTest::keyClick(widget: view.viewport(), key: Qt::Key_End); | 
| 4245 |     QCOMPARE(view.currentIndex(), model.index(model.rowCount() - 2, 0)); | 
| 4246 | } | 
| 4247 |  | 
| 4248 | class RemoveColumnOne : public QSortFilterProxyModel | 
| 4249 | { | 
| 4250 |     Q_OBJECT | 
| 4251 | public: | 
| 4252 |     bool filterAcceptsColumn(int source_column, const QModelIndex &) const override | 
| 4253 |     { | 
| 4254 |         if (m_removeColumn) | 
| 4255 |             return source_column != 1; | 
| 4256 |         return true; | 
| 4257 |     } | 
| 4258 |     void removeColumn() | 
| 4259 |     { | 
| 4260 |         m_removeColumn = true; | 
| 4261 |         invalidate(); | 
| 4262 |     } | 
| 4263 | private: | 
| 4264 |     bool m_removeColumn = false; | 
| 4265 | }; | 
| 4266 |  | 
| 4267 |  | 
| 4268 | void tst_QTreeView::saveRestoreState() | 
| 4269 | { | 
| 4270 |     QStandardItemModel model; | 
| 4271 |     for (int i = 0; i < 100; i++) { | 
| 4272 |         model.appendRow(items: {new QStandardItem(QStringLiteral("item " ) + QString::number(i)), | 
| 4273 |                          new QStandardItem(QStringLiteral("hidden by proxy" )), | 
| 4274 |                          new QStandardItem(QStringLiteral("hidden by user" )) }); | 
| 4275 |     } | 
| 4276 |     QCOMPARE(model.columnCount(), 3); | 
| 4277 |  | 
| 4278 |     RemoveColumnOne proxy; | 
| 4279 |     proxy.setSourceModel(&model); | 
| 4280 |     QCOMPARE(proxy.columnCount(), 3); | 
| 4281 |  | 
| 4282 |     QTreeView view; | 
| 4283 |     view.setModel(&proxy); | 
| 4284 |     view.resize(w: 500, h: 500); | 
| 4285 |     view.show(); | 
| 4286 |     view.header()->hideSection(alogicalIndex: 2); | 
| 4287 |     QVERIFY(view.header()->isSectionHidden(2)); | 
| 4288 |     proxy.removeColumn(); | 
| 4289 |     QCOMPARE(proxy.columnCount(), 2); | 
| 4290 |     QVERIFY(view.header()->isSectionHidden(1)); | 
| 4291 |     const QByteArray data = view.header()->saveState(); | 
| 4292 |  | 
| 4293 |     QTreeView view2; | 
| 4294 |     view2.setModel(&proxy); | 
| 4295 |     view2.resize(w: 500, h: 500); | 
| 4296 |     view2.show(); | 
| 4297 |     view2.header()->restoreState(state: data); | 
| 4298 |     QVERIFY(view2.header()->isSectionHidden(1)); | 
| 4299 | } | 
| 4300 |  | 
| 4301 | class Model_11466 : public QAbstractItemModel | 
| 4302 | { | 
| 4303 |     Q_OBJECT | 
| 4304 | public: | 
| 4305 |     Model_11466(QObject *parent = nullptr) : QAbstractItemModel(parent) | 
| 4306 |         , m_selectionModel(new QItemSelectionModel(this, this)) | 
| 4307 |     { | 
| 4308 |         connect(sender: m_selectionModel, signal: &QItemSelectionModel::currentChanged, | 
| 4309 |                 receiver: this, slot: &Model_11466::slotCurrentChanged); | 
| 4310 |     } | 
| 4311 |  | 
| 4312 |     int rowCount(const QModelIndex &parent) const override | 
| 4313 |     { | 
| 4314 |         if (parent.isValid()) | 
| 4315 |             return (parent.internalId() == 0) ? 4 : 0; | 
| 4316 |         return 2; // two top level items | 
| 4317 |     } | 
| 4318 |  | 
| 4319 |     int columnCount(const QModelIndex & /* parent */) const override | 
| 4320 |     { | 
| 4321 |         return 2; | 
| 4322 |     } | 
| 4323 |  | 
| 4324 |     QVariant data(const QModelIndex &index, int role) const override | 
| 4325 |     { | 
| 4326 |         if (role == Qt::DisplayRole && index.isValid()) { | 
| 4327 |             qint64 parentRowPlusOne = qint64(index.internalId()); | 
| 4328 |             QString str; | 
| 4329 |             QTextStream stream(&str); | 
| 4330 |             if (parentRowPlusOne > 0) | 
| 4331 |                 stream << parentRowPlusOne << " -> "  << index.row() << " : "  << index.column(); | 
| 4332 |             else | 
| 4333 |                 stream << index.row() << " : "  << index.column(); | 
| 4334 |             return QVariant(str); | 
| 4335 |         } | 
| 4336 |         return QVariant(); | 
| 4337 |     } | 
| 4338 |  | 
| 4339 |     QModelIndex parent(const QModelIndex &index) const override | 
| 4340 |     { | 
| 4341 |         if (index.isValid()) { | 
| 4342 |             qint64 parentRowPlusOne = qint64(index.internalId()); | 
| 4343 |             if (parentRowPlusOne > 0) { | 
| 4344 |                 int row = static_cast<int>(parentRowPlusOne - 1); | 
| 4345 |                 return createIndex(arow: row, acolumn: 0); | 
| 4346 |             } | 
| 4347 |         } | 
| 4348 |         return QModelIndex(); | 
| 4349 |     } | 
| 4350 |  | 
| 4351 |     void bindView(QTreeView *view) | 
| 4352 |     { | 
| 4353 |         // sets the view to this model with a shared selection model | 
| 4354 |         QItemSelectionModel *oldModel = view->selectionModel(); | 
| 4355 |         if (oldModel != m_selectionModel) | 
| 4356 |             delete oldModel; | 
| 4357 |         view->setModel(this); // this creates a new selection model for the view, but we don't want it either ... | 
| 4358 |         oldModel = view->selectionModel(); | 
| 4359 |         view->setSelectionModel(m_selectionModel); | 
| 4360 |         delete oldModel; | 
| 4361 |     } | 
| 4362 |  | 
| 4363 |     QModelIndex index(int row, int column, const QModelIndex &parent) const override | 
| 4364 |     { | 
| 4365 |         return createIndex(arow: row, acolumn: column, aid: parent.isValid() ? quintptr(parent.row() + 1) : quintptr(0)); | 
| 4366 |     } | 
| 4367 |  | 
| 4368 | public slots: | 
| 4369 |     void slotCurrentChanged(const QModelIndex ¤t,const QModelIndex &) | 
| 4370 |     { | 
| 4371 |         if (m_block) | 
| 4372 |             return; | 
| 4373 |  | 
| 4374 |         if (current.isValid()) { | 
| 4375 |             int selectedRow = current.row(); | 
| 4376 |             const quintptr parentRowPlusOne = current.internalId(); | 
| 4377 |  | 
| 4378 |             for (int i = 0; i < 2; ++i) { | 
| 4379 |                 // announce the removal of all non top level items | 
| 4380 |                 beginRemoveRows(parent: createIndex(arow: i, acolumn: 0), first: 0, last: 3); | 
| 4381 |                 // nothing to actually do for the removal | 
| 4382 |                 endRemoveRows(); | 
| 4383 |  | 
| 4384 |                 // put them back in again | 
| 4385 |                 beginInsertRows(parent: createIndex(arow: i, acolumn: 0), first: 0, last: 3); | 
| 4386 |                 // nothing to actually do for the insertion | 
| 4387 |                 endInsertRows(); | 
| 4388 |             } | 
| 4389 |             // reselect the current item ... | 
| 4390 |             QModelIndex selectedIndex = createIndex(arow: selectedRow, acolumn: 0, aid: parentRowPlusOne); | 
| 4391 |  | 
| 4392 |             m_block = true; // recursion block | 
| 4393 |             m_selectionModel->select(index: selectedIndex, command: QItemSelectionModel::ClearAndSelect|QItemSelectionModel::Current|QItemSelectionModel::Rows); | 
| 4394 |             m_selectionModel->setCurrentIndex(index: selectedIndex, command: QItemSelectionModel::NoUpdate); | 
| 4395 |             m_block = false; | 
| 4396 |         } else { | 
| 4397 |             m_selectionModel->clear(); | 
| 4398 |         } | 
| 4399 |     } | 
| 4400 |  | 
| 4401 | private: | 
| 4402 |     bool m_block = false; | 
| 4403 |     QItemSelectionModel *m_selectionModel; | 
| 4404 | }; | 
| 4405 |  | 
| 4406 | void tst_QTreeView::taskQTBUG_11466_keyboardNavigationRegression() | 
| 4407 | { | 
| 4408 |     QTreeView treeView; | 
| 4409 |     treeView.setSelectionBehavior(QAbstractItemView::SelectRows); | 
| 4410 |     treeView.setSelectionMode(QAbstractItemView::SingleSelection); | 
| 4411 |     Model_11466 model(&treeView); | 
| 4412 |     model.bindView(view: &treeView); | 
| 4413 |     treeView.expandAll(); | 
| 4414 |     treeView.show(); | 
| 4415 |     QVERIFY(QTest::qWaitForWindowExposed(&treeView)); | 
| 4416 |  | 
| 4417 |     QTest::keyPress(widget: treeView.viewport(), key: Qt::Key_Down); | 
| 4418 |     QTRY_COMPARE(treeView.currentIndex(), treeView.selectionModel()->selection().indexes().first()); | 
| 4419 | } | 
| 4420 |  | 
| 4421 | void tst_QTreeView::taskQTBUG_13567_removeLastItemRegression() | 
| 4422 | { | 
| 4423 |     QtTestModel model(200, 1); | 
| 4424 |  | 
| 4425 |     QTreeView view; | 
| 4426 |     view.setSelectionMode(QAbstractItemView::ExtendedSelection); | 
| 4427 |     view.setModel(&model); | 
| 4428 |     view.show(); | 
| 4429 |     QVERIFY(QTest::qWaitForWindowExposed(&view)); | 
| 4430 |  | 
| 4431 |     view.scrollToBottom(); | 
| 4432 |     QTest::qWait(ms: 10); | 
| 4433 |     CHECK_VISIBLE(199, 0); | 
| 4434 |  | 
| 4435 |     view.setCurrentIndex(model.index(row: 199, column: 0)); | 
| 4436 |     model.removeLastRow(); | 
| 4437 |     QTRY_COMPARE(view.currentIndex(), model.index(198, 0)); | 
| 4438 |     CHECK_VISIBLE(198, 0); | 
| 4439 | } | 
| 4440 |  | 
| 4441 | // From QTBUG-25333 (QTreeWidget drag crashes when there was a hidden item in tree) | 
| 4442 | // The test passes simply if it doesn't crash, hence there are no calls | 
| 4443 | // to QCOMPARE() or QVERIFY(). | 
| 4444 | // Note: define QT_BUILD_INTERNAL to run this test | 
| 4445 | void tst_QTreeView::taskQTBUG_25333_adjustViewOptionsForIndex() | 
| 4446 | { | 
| 4447 |     QTreeView view; | 
| 4448 |     QStandardItemModel model; | 
| 4449 |     QStandardItem *item1 = new QStandardItem("Item1" ); | 
| 4450 |     QStandardItem *item2 = new QStandardItem("Item2" ); | 
| 4451 |     QStandardItem *item3 = new QStandardItem("Item3" ); | 
| 4452 |     QStandardItem *data1 = new QStandardItem("Data1" ); | 
| 4453 |     QStandardItem *data2 = new QStandardItem("Data2" ); | 
| 4454 |     QStandardItem *data3 = new QStandardItem("Data3" ); | 
| 4455 |  | 
| 4456 |     // Create a treeview | 
| 4457 |     model.appendRow(items: { item1, data1 }); | 
| 4458 |     model.appendRow(items: { item2, data2 }); | 
| 4459 |     model.appendRow(items: { item3, data3 }); | 
| 4460 |  | 
| 4461 |     view.setModel(&model); | 
| 4462 |  | 
| 4463 |     // Hide a row | 
| 4464 |     view.setRowHidden(row: 1, parent: QModelIndex(), hide: true); | 
| 4465 |     view.expandAll(); | 
| 4466 |  | 
| 4467 |     view.show(); | 
| 4468 |  | 
| 4469 | #ifdef QT_BUILD_INTERNAL | 
| 4470 |     { | 
| 4471 |         QStyleOptionViewItem option; | 
| 4472 |  | 
| 4473 |         view.d_func()->adjustViewOptionsForIndex(option: &option, current: model.indexFromItem(item: item1)); | 
| 4474 |  | 
| 4475 |         view.d_func()->adjustViewOptionsForIndex(option: &option, current: model.indexFromItem(item: item3)); | 
| 4476 |     } | 
| 4477 | #endif | 
| 4478 |  | 
| 4479 | } | 
| 4480 |  | 
| 4481 | void tst_QTreeView::taskQTBUG_18539_emitLayoutChanged() | 
| 4482 | { | 
| 4483 |     qRegisterMetaType<QList<QPersistentModelIndex>>(); | 
| 4484 |     qRegisterMetaType<QAbstractItemModel::LayoutChangeHint>(); | 
| 4485 |  | 
| 4486 |     QTreeView view; | 
| 4487 |  | 
| 4488 |     QStandardItem* item = new QStandardItem("Orig" ); | 
| 4489 |     QStandardItem* child = new QStandardItem("Child" ); | 
| 4490 |     item->setChild(row: 0, column: 0, item: child); | 
| 4491 |  | 
| 4492 |     QStandardItemModel model; | 
| 4493 |     model.appendRow(aitem: item); | 
| 4494 |  | 
| 4495 |     view.setModel(&model); | 
| 4496 |  | 
| 4497 |     QStandardItem* replacementItem = new QStandardItem("Replacement" ); | 
| 4498 |     QStandardItem* replacementChild = new QStandardItem("ReplacementChild" ); | 
| 4499 |  | 
| 4500 |     replacementItem->setChild(row: 0, column: 0, item: replacementChild); | 
| 4501 |  | 
| 4502 |     QSignalSpy beforeSpy(&model, &QAbstractItemModel::layoutAboutToBeChanged); | 
| 4503 |     QSignalSpy afterSpy(&model, &QAbstractItemModel::layoutChanged); | 
| 4504 |  | 
| 4505 |     QSignalSpy beforeRISpy(&model, &QAbstractItemModel::rowsAboutToBeInserted); | 
| 4506 |     QSignalSpy afterRISpy(&model, &QAbstractItemModel::rowsInserted); | 
| 4507 |  | 
| 4508 |     QSignalSpy beforeRRSpy(&model, &QAbstractItemModel::rowsAboutToBeRemoved); | 
| 4509 |     QSignalSpy afterRRSpy(&model, &QAbstractItemModel::rowsRemoved); | 
| 4510 |  | 
| 4511 |     model.setItem(row: 0, column: 0, item: replacementItem); | 
| 4512 |  | 
| 4513 |     QCOMPARE(beforeSpy.size(), 1); | 
| 4514 |     QCOMPARE(afterSpy.size(), 1); | 
| 4515 |  | 
| 4516 |     QCOMPARE(beforeRISpy.size(), 0); | 
| 4517 |     QCOMPARE(afterRISpy.size(), 0); | 
| 4518 |  | 
| 4519 |     QCOMPARE(beforeRISpy.size(), 0); | 
| 4520 |     QCOMPARE(afterRISpy.size(), 0); | 
| 4521 | } | 
| 4522 |  | 
| 4523 | void tst_QTreeView::taskQTBUG_8176_emitOnExpandAll() | 
| 4524 | { | 
| 4525 |     QTreeWidget tw; | 
| 4526 |     QTreeWidgetItem *item = new QTreeWidgetItem(&tw, QStringList(QString("item 1" ))); | 
| 4527 |     QTreeWidgetItem *item2 = new QTreeWidgetItem(item, QStringList(QString("item 2" ))); | 
| 4528 |     new QTreeWidgetItem(item2, QStringList(QString("item 3" ))); | 
| 4529 |     new QTreeWidgetItem(item2, QStringList(QString("item 4" ))); | 
| 4530 |     QTreeWidgetItem *item5 = new QTreeWidgetItem(&tw, QStringList(QString("item 5" ))); | 
| 4531 |     new QTreeWidgetItem(item5, QStringList(QString("item 6" ))); | 
| 4532 |     QSignalSpy spy(&tw, &QTreeView::expanded); | 
| 4533 |  | 
| 4534 |     // expand all | 
| 4535 |     tw.expandAll(); | 
| 4536 |     QCOMPARE(spy.size(), 6); | 
| 4537 |     spy.clear(); | 
| 4538 |     tw.collapseAll(); | 
| 4539 |     item2->setExpanded(true); | 
| 4540 |     spy.clear(); | 
| 4541 |     tw.expandAll(); | 
| 4542 |     QCOMPARE(spy.size(), 5); | 
| 4543 |  | 
| 4544 |     // collapse all | 
| 4545 |     QSignalSpy spy2(&tw, &QTreeView::collapsed); | 
| 4546 |     tw.collapseAll(); | 
| 4547 |     QCOMPARE(spy2.size(), 6); | 
| 4548 |     tw.expandAll(); | 
| 4549 |     item2->setExpanded(false); | 
| 4550 |     spy2.clear(); | 
| 4551 |     tw.collapseAll(); | 
| 4552 |     QCOMPARE(spy2.size(), 5); | 
| 4553 |  | 
| 4554 |     // expand to depth | 
| 4555 |     item2->setExpanded(true); | 
| 4556 |     spy.clear(); | 
| 4557 |     spy2.clear(); | 
| 4558 |     tw.expandToDepth(depth: 0); | 
| 4559 |  | 
| 4560 |     QCOMPARE(spy.size(), 2); // item and item5 are expanded | 
| 4561 |     QCOMPARE(spy2.size(), 1); // item2 is collapsed | 
| 4562 | } | 
| 4563 |  | 
| 4564 | void tst_QTreeView::testInitialFocus() | 
| 4565 | { | 
| 4566 |     if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) | 
| 4567 |         QSKIP("Wayland: This fails. Figure out why." ); | 
| 4568 |  | 
| 4569 |     QTreeWidget treeWidget; | 
| 4570 |     treeWidget.setColumnCount(5); | 
| 4571 |     new QTreeWidgetItem(&treeWidget, QString("1;2;3;4;5" ).split(sep: QLatin1Char(';'))); | 
| 4572 |     treeWidget.setTreePosition(2); | 
| 4573 |     treeWidget.header()->hideSection(alogicalIndex: 0);      // make sure we skip hidden section(s) | 
| 4574 |     treeWidget.header()->swapSections(first: 1, second: 2);  // make sure that we look for first visual index (and not first logical) | 
| 4575 |     treeWidget.show(); | 
| 4576 |     QVERIFY(QTest::qWaitForWindowExposed(&treeWidget)); | 
| 4577 |     QTRY_COMPARE(treeWidget.currentIndex().column(), 2); | 
| 4578 | } | 
| 4579 |  | 
| 4580 | #if QT_CONFIG(animation) | 
| 4581 | void tst_QTreeView::quickExpandCollapse() | 
| 4582 | { | 
| 4583 |     //this unit tests makes sure the state after the animation is restored correctly | 
| 4584 |     //after starting a 2nd animation while the first one was still on-going | 
| 4585 |     //this tests that the stateBeforeAnimation is not set to AnimatingState | 
| 4586 |     QTreeView tree; | 
| 4587 |     tree.setAnimated(true); | 
| 4588 |     QStandardItemModel model; | 
| 4589 |     QStandardItem *root = new QStandardItem("root" ); | 
| 4590 |     root->appendRow(aitem: new QStandardItem("subnode" )); | 
| 4591 |     model.appendRow(aitem: root); | 
| 4592 |     tree.setModel(&model); | 
| 4593 |  | 
| 4594 |     QModelIndex rootIndex = root->index(); | 
| 4595 |     QVERIFY(rootIndex.isValid()); | 
| 4596 |  | 
| 4597 |     tree.show(); | 
| 4598 |     QVERIFY(QTest::qWaitForWindowExposed(&tree)); | 
| 4599 |  | 
| 4600 |     const QAbstractItemView::State initialState = tree.state(); | 
| 4601 |  | 
| 4602 |     tree.expand(index: rootIndex); | 
| 4603 |     QCOMPARE(tree.state(), QTreeView::AnimatingState); | 
| 4604 |  | 
| 4605 |     tree.collapse(index: rootIndex); | 
| 4606 |     QCOMPARE(tree.state(), QTreeView::AnimatingState); | 
| 4607 |  | 
| 4608 |     //the animation lasts for 250ms max so 5000 (default) should be enough | 
| 4609 |     QTRY_COMPARE(tree.state(), initialState); | 
| 4610 | } | 
| 4611 | #endif // animation | 
| 4612 |  | 
| 4613 | void tst_QTreeView::taskQTBUG_37813_crash() | 
| 4614 | { | 
| 4615 |     // QTBUG_37813: Crash in visual / logical index mapping in QTreeViewPrivate::adjustViewOptionsForIndex() | 
| 4616 |     // when hiding/moving columns. It is reproduceable with a QTreeWidget only. | 
| 4617 | #ifdef QT_BUILD_INTERNAL | 
| 4618 |     QTreeWidget treeWidget; | 
| 4619 |     treeWidget.setDragEnabled(true); | 
| 4620 |     treeWidget.setColumnCount(2); | 
| 4621 |     QList<QTreeWidgetItem *> items; | 
| 4622 |     for (int r = 0; r < 2; ++r) { | 
| 4623 |         const QString prefix = QLatin1String("Row " ) + QString::number(r) + QLatin1String(" Column " ); | 
| 4624 |         QTreeWidgetItem *item = new QTreeWidgetItem(); | 
| 4625 |         for (int c = 0; c < treeWidget.columnCount(); ++c) | 
| 4626 |             item->setText(column: c, atext: prefix + QString::number(c)); | 
| 4627 |         items.append(t: item); | 
| 4628 |     } | 
| 4629 |     treeWidget.addTopLevelItems(items); | 
| 4630 |     treeWidget.setColumnHidden(column: 0, hide: true); | 
| 4631 |     treeWidget.header()->moveSection(from: 0, to: 1); | 
| 4632 |     QItemSelection sel(treeWidget.model()->index(row: 0, column: 0), treeWidget.model()->index(row: 0, column: 1)); | 
| 4633 |     QRect rect; | 
| 4634 |     QAbstractItemViewPrivate *av = static_cast<QAbstractItemViewPrivate*>(qt_widget_private(widget: &treeWidget)); | 
| 4635 |     const QPixmap pixmap = av->renderToPixmap(indexes: sel.indexes(), r: &rect); | 
| 4636 |     QVERIFY(pixmap.size().isValid()); | 
| 4637 | #endif // QT_BUILD_INTERNAL | 
| 4638 | } | 
| 4639 |  | 
| 4640 | // QTBUG-45697: Using a QTreeView with a multi-column model filtered by QSortFilterProxyModel, | 
| 4641 | // when sorting the source model while the widget is not yet visible and showing the widget | 
| 4642 | // later on, corruption occurs in QTreeView. | 
| 4643 | class Qtbug45697TestWidget : public QWidget | 
| 4644 | { | 
| 4645 |    Q_OBJECT | 
| 4646 | public: | 
| 4647 |     static const int columnCount = 3; | 
| 4648 |  | 
| 4649 |     explicit Qtbug45697TestWidget(QWidget *parent = nullptr); | 
| 4650 |     int timerTick() const { return m_timerTick; } | 
| 4651 |  | 
| 4652 | public slots: | 
| 4653 |     void slotTimer(); | 
| 4654 |  | 
| 4655 | private: | 
| 4656 |    QTreeView *m_treeView; | 
| 4657 |    QStandardItemModel *m_model; | 
| 4658 |    QSortFilterProxyModel *m_sortFilterProxyModel; | 
| 4659 |    int m_timerTick = 0; | 
| 4660 | }; | 
| 4661 |  | 
| 4662 | Qtbug45697TestWidget::Qtbug45697TestWidget(QWidget *parent) | 
| 4663 |     : QWidget(parent), m_treeView(new QTreeView(this)) | 
| 4664 |     , m_model(new QStandardItemModel(0, Qtbug45697TestWidget::columnCount, this)) | 
| 4665 |     , m_sortFilterProxyModel(new QSortFilterProxyModel(this)) | 
| 4666 |  { | 
| 4667 |    QVBoxLayout *vBoxLayout = new QVBoxLayout(this); | 
| 4668 |    vBoxLayout->addWidget(m_treeView); | 
| 4669 |  | 
| 4670 |    for (char sortChar = 'z'; sortChar >= 'a' ; --sortChar) { | 
| 4671 |        QList<QStandardItem *>  items; | 
| 4672 |        for (int column = 0; column < Qtbug45697TestWidget::columnCount; ++column) { | 
| 4673 |            const QString text = QLatin1Char(sortChar) + QLatin1String(" " ) + QString::number(column); | 
| 4674 |            items.append(t: new QStandardItem(text)); | 
| 4675 |        } | 
| 4676 |        m_model->appendRow(items); | 
| 4677 |    } | 
| 4678 |  | 
| 4679 |    m_sortFilterProxyModel->setSourceModel(m_model); | 
| 4680 |    m_treeView->setModel(m_sortFilterProxyModel); | 
| 4681 |  | 
| 4682 |    QHeaderView * = m_treeView->header(); | 
| 4683 |    for (int s = 1, lastSection = headerView->count() - 1; s < lastSection; ++s) | 
| 4684 |        headerView->setSectionResizeMode(logicalIndex: s, mode: QHeaderView::ResizeToContents); | 
| 4685 |  | 
| 4686 |    QTimer *timer = new QTimer(this); | 
| 4687 |    timer->setInterval(50); | 
| 4688 |    connect(sender: timer, signal: &QTimer::timeout, receiver: this, slot: &Qtbug45697TestWidget::slotTimer); | 
| 4689 |    timer->start(); | 
| 4690 | } | 
| 4691 |  | 
| 4692 | void Qtbug45697TestWidget::slotTimer() | 
| 4693 | { | 
| 4694 |     switch (m_timerTick++) { | 
| 4695 |     case 0: | 
| 4696 |         m_model->sort(column: 0); | 
| 4697 |         break; | 
| 4698 |     case 1: | 
| 4699 |         show(); | 
| 4700 |         break; | 
| 4701 |     default: | 
| 4702 |         close(); | 
| 4703 |         break; | 
| 4704 |     } | 
| 4705 | } | 
| 4706 |  | 
| 4707 | void tst_QTreeView::taskQTBUG_45697_crash() | 
| 4708 | { | 
| 4709 |     Qtbug45697TestWidget testWidget; | 
| 4710 |     testWidget.setWindowTitle(QTest::currentTestFunction()); | 
| 4711 |     testWidget.resize(w: 400, h: 400); | 
| 4712 |     testWidget.move(QGuiApplication::primaryScreen()->availableGeometry().topLeft() + QPoint(100, 100)); | 
| 4713 |     QTRY_VERIFY(testWidget.timerTick() >= 2); | 
| 4714 | } | 
| 4715 |  | 
| 4716 | void tst_QTreeView::taskQTBUG_7232_AllowUserToControlSingleStep() | 
| 4717 | { | 
| 4718 |     // When we set the scrollMode to ScrollPerPixel it will adjust the scrollbars singleStep automatically | 
| 4719 |     // Setting a singlestep on a scrollbar should however imply that the user takes control. | 
| 4720 |     // Setting a singlestep to -1 return to an automatic control of the singleStep. | 
| 4721 |     QTreeWidget t; | 
| 4722 |     t.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); | 
| 4723 |     t.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); | 
| 4724 |     t.setColumnCount(2); | 
| 4725 |     QTreeWidgetItem *mainItem = new QTreeWidgetItem(&t, QStringList() << "Root" ); | 
| 4726 |     for (int i = 0; i < 200; ++i) { | 
| 4727 |         QTreeWidgetItem *item = new QTreeWidgetItem(mainItem, QStringList(QString("Item" ))); | 
| 4728 |         new QTreeWidgetItem(item, QStringList() << "Child"  << "1" ); | 
| 4729 |         new QTreeWidgetItem(item, QStringList() << "Child"  << "2" ); | 
| 4730 |         new QTreeWidgetItem(item, QStringList() << "Child"  << "3" ); | 
| 4731 |     } | 
| 4732 |     t.expandAll(); | 
| 4733 |  | 
| 4734 |     t.setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); | 
| 4735 |     t.setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel); | 
| 4736 |  | 
| 4737 |     t.setGeometry(ax: 200, ay: 200, aw: 200, ah: 200); | 
| 4738 |     int vStep1 = t.verticalScrollBar()->singleStep(); | 
| 4739 |     int hStep1 = t.horizontalScrollBar()->singleStep(); | 
| 4740 |     QVERIFY(vStep1 > 1); | 
| 4741 |     QVERIFY(hStep1 > 1); | 
| 4742 |  | 
| 4743 |     t.verticalScrollBar()->setSingleStep(1); | 
| 4744 |     t.setGeometry(ax: 300, ay: 300, aw: 300, ah: 300); | 
| 4745 |     QCOMPARE(t.verticalScrollBar()->singleStep(), 1); | 
| 4746 |  | 
| 4747 |     t.horizontalScrollBar()->setSingleStep(1); | 
| 4748 |     t.setGeometry(ax: 400, ay: 400, aw: 400, ah: 400); | 
| 4749 |     QCOMPARE(t.horizontalScrollBar()->singleStep(), 1); | 
| 4750 |  | 
| 4751 |     t.setGeometry(ax: 200, ay: 200, aw: 200, ah: 200); | 
| 4752 |     t.verticalScrollBar()->setSingleStep(-1); | 
| 4753 |     t.horizontalScrollBar()->setSingleStep(-1); | 
| 4754 |     QCOMPARE(vStep1, t.verticalScrollBar()->singleStep()); | 
| 4755 |     QCOMPARE(hStep1, t.horizontalScrollBar()->singleStep()); | 
| 4756 | } | 
| 4757 |  | 
| 4758 | void tst_QTreeView::statusTip_data() | 
| 4759 | { | 
| 4760 |     QTest::addColumn<bool>(name: "intermediateParent" ); | 
| 4761 |     QTest::newRow(dataTag: "noIntermediate" ) << false; | 
| 4762 |     QTest::newRow(dataTag: "intermediate" ) << true; | 
| 4763 | } | 
| 4764 |  | 
| 4765 | void tst_QTreeView::statusTip() | 
| 4766 | { | 
| 4767 |     if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) | 
| 4768 |         QSKIP("Wayland: This fails. Figure out why." ); | 
| 4769 |  | 
| 4770 |     QFETCH(bool, intermediateParent); | 
| 4771 |     QMainWindow mw; | 
| 4772 |     QtTestModel model(5, 5); | 
| 4773 |     model.statusTipsEnabled = true; | 
| 4774 |     QTreeView *view = new QTreeView; | 
| 4775 |     view->setModel(&model); | 
| 4776 |     view->viewport()->setMouseTracking(true); | 
| 4777 |     view->header()->viewport()->setMouseTracking(true); | 
| 4778 |     if (intermediateParent) { | 
| 4779 |         QWidget *inter = new QWidget; | 
| 4780 |         QVBoxLayout *vbox = new QVBoxLayout; | 
| 4781 |         inter->setLayout(vbox); | 
| 4782 |         vbox->addWidget(view); | 
| 4783 |         mw.setCentralWidget(inter); | 
| 4784 |     } else { | 
| 4785 |         mw.setCentralWidget(view); | 
| 4786 |     } | 
| 4787 |     mw.statusBar(); | 
| 4788 |     mw.setGeometry(QRect(QPoint(QApplication::desktop()->geometry().center() - QPoint(250, 250)), | 
| 4789 |                                 QSize(500, 500))); | 
| 4790 |     mw.show(); | 
| 4791 |     QApplication::setActiveWindow(&mw); | 
| 4792 |     QVERIFY(QTest::qWaitForWindowActive(&mw)); | 
| 4793 |     // Ensure it is moved away first and then moved to the relevant section | 
| 4794 |     QTest::mouseMove(window: mw.windowHandle(), pos: view->mapTo(&mw, view->rect().bottomLeft() + QPoint(20, 20))); | 
| 4795 |     QPoint centerPoint = view->viewport()->mapTo(&mw, view->visualRect(index: model.index(row: 0, column: 0)).center()); | 
| 4796 |     QTest::mouseMove(window: mw.windowHandle(), pos: centerPoint); | 
| 4797 |     QTRY_COMPARE(mw.statusBar()->currentMessage(), QLatin1String("[0,0,0] -- Status" )); | 
| 4798 |     centerPoint = view->viewport()->mapTo(&mw, view->visualRect(index: model.index(row: 0, column: 1)).center()); | 
| 4799 |     QTest::mouseMove(window: mw.windowHandle(), pos: centerPoint); | 
| 4800 |     QTRY_COMPARE(mw.statusBar()->currentMessage(), QLatin1String("[0,1,0] -- Status" )); | 
| 4801 |     centerPoint = view->header()->viewport()->mapTo(&mw, | 
| 4802 |                     QPoint(view->header()->sectionViewportPosition(logicalIndex: 0) + view->header()->sectionSize(logicalIndex: 0) / 2, | 
| 4803 |                            view->header()->height() / 2)); | 
| 4804 |     QTest::mouseMove(window: mw.windowHandle(), pos: centerPoint); | 
| 4805 |     QTRY_COMPARE(mw.statusBar()->currentMessage(), QLatin1String("Header 0 -- Status" )); | 
| 4806 | } | 
| 4807 |  | 
| 4808 | class FetchMoreModel : public QStandardItemModel | 
| 4809 | { | 
| 4810 |     Q_OBJECT | 
| 4811 | public: | 
| 4812 |     FetchMoreModel(QObject *parent = nullptr) : QStandardItemModel(parent) | 
| 4813 |     { | 
| 4814 |         for (int i = 0; i < 20; ++i) { | 
| 4815 |             QStandardItem *item = new QStandardItem("Row" ); | 
| 4816 |             item->appendRow(aitem: new QStandardItem("Child" )); | 
| 4817 |             appendRow(aitem: item); | 
| 4818 |         } | 
| 4819 |     } | 
| 4820 |     bool canFetchMore(const QModelIndex &parent) const override | 
| 4821 |     { | 
| 4822 |         if (!canFetchReady || !parent.isValid()) | 
| 4823 |             return false; | 
| 4824 |         if (!parent.parent().isValid()) | 
| 4825 |             return rowCount(parent) < 20; | 
| 4826 |         return false; | 
| 4827 |     } | 
| 4828 |     void fetchMore(const QModelIndex &parent) override | 
| 4829 |     { | 
| 4830 |         QStandardItem *item = itemFromIndex(index: parent); | 
| 4831 |         for (int i = 0; i < 19; ++i) | 
| 4832 |             item->appendRow(aitem: new QStandardItem(QStringLiteral("New Child " ) + QString::number(i))); | 
| 4833 |     } | 
| 4834 |     bool canFetchReady = false; | 
| 4835 | }; | 
| 4836 |  | 
| 4837 | void tst_QTreeView::fetchMoreOnScroll() | 
| 4838 | { | 
| 4839 |     if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) | 
| 4840 |         QSKIP("Wayland: This fails. Figure out why." ); | 
| 4841 |  | 
| 4842 |     QTreeView tw; | 
| 4843 |     FetchMoreModel im; | 
| 4844 |     tw.setModel(&im); | 
| 4845 |     tw.show(); | 
| 4846 |     tw.expandAll(); | 
| 4847 |     QVERIFY(QTest::qWaitForWindowActive(&tw)); | 
| 4848 |     // Now we can allow the fetch to happen | 
| 4849 |     im.canFetchReady = true; | 
| 4850 |     tw.verticalScrollBar()->setValue(tw.verticalScrollBar()->maximum()); | 
| 4851 |     // The item should have now fetched the other children, thus bringing the count to 20 | 
| 4852 |     QCOMPARE(im.item(19)->rowCount(), 20); | 
| 4853 | } | 
| 4854 |  | 
| 4855 | static void fillModeltaskQTBUG_8376(QAbstractItemModel &model) | 
| 4856 | { | 
| 4857 |     model.insertRow(arow: 0); | 
| 4858 |     model.insertColumn(acolumn: 0); | 
| 4859 |     model.insertColumn(acolumn: 1); | 
| 4860 |     QModelIndex index = model.index(row: 0, column: 0); | 
| 4861 |     model.setData(index, value: "Level0" ); | 
| 4862 |     { | 
| 4863 |         model.insertRow(arow: 0, aparent: index); | 
| 4864 |         model.insertRow(arow: 1, aparent: index); | 
| 4865 |         model.insertColumn(acolumn: 0, aparent: index); | 
| 4866 |         model.insertColumn(acolumn: 1, aparent: index); | 
| 4867 |  | 
| 4868 |         QModelIndex idx; | 
| 4869 |         idx = model.index(row: 0, column: 0, parent: index); | 
| 4870 |         model.setData(index: idx, value: "Level1" ); | 
| 4871 |  | 
| 4872 |         idx = model.index(row: 0, column: 1, parent: index); | 
| 4873 |         model.setData(index: idx, value: "very\nvery\nhigh\ncell" ); | 
| 4874 |     } | 
| 4875 | } | 
| 4876 |  | 
| 4877 | void tst_QTreeView::taskQTBUG_8376() | 
| 4878 | { | 
| 4879 |     QTreeView tv; | 
| 4880 |     QStandardItemModel model; | 
| 4881 |     fillModeltaskQTBUG_8376(model); | 
| 4882 |     tv.setModel(&model); | 
| 4883 |     tv.expandAll(); // init layout | 
| 4884 |  | 
| 4885 |     QModelIndex idxLvl0 = model.index(row: 0, column: 0); | 
| 4886 |     QModelIndex idxLvl1 = model.index(row: 0, column: 1, parent: idxLvl0); | 
| 4887 |     const int rowHeightLvl0 = tv.rowHeight(index: idxLvl0); | 
| 4888 |     const int rowHeightLvl1Visible = tv.rowHeight(index: idxLvl1); | 
| 4889 |     QVERIFY(rowHeightLvl0 < rowHeightLvl1Visible); | 
| 4890 |  | 
| 4891 |     tv.hideColumn(column: 1); | 
| 4892 |     const int rowHeightLvl1Hidden = tv.rowHeight(index: idxLvl1); | 
| 4893 |     QCOMPARE(rowHeightLvl0, rowHeightLvl1Hidden); | 
| 4894 |  | 
| 4895 |     tv.showColumn(column: 1); | 
| 4896 |     const int rowHeightLvl1Visible2 = tv.rowHeight(index: idxLvl1); | 
| 4897 |     QCOMPARE(rowHeightLvl1Visible, rowHeightLvl1Visible2); | 
| 4898 | } | 
| 4899 |  | 
| 4900 | void tst_QTreeView::taskQTBUG_61476() | 
| 4901 | { | 
| 4902 |     if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) | 
| 4903 |         QSKIP("Wayland: This fails. Figure out why." ); | 
| 4904 |  | 
| 4905 |     // This checks that if a user clicks on an item to collapse it that it | 
| 4906 |     // does not edit (in this case change the check state) the item that is | 
| 4907 |     // now over the mouse just because it got a release event | 
| 4908 |     QTreeView tv; | 
| 4909 |     QStandardItemModel model; | 
| 4910 |     QStandardItem *lastTopLevel = nullptr; | 
| 4911 |     { | 
| 4912 |         for (int i = 0; i < 4; ++i) { | 
| 4913 |             QStandardItem *item = new QStandardItem(QLatin1String("Row Item" )); | 
| 4914 |             item->setCheckable(true); | 
| 4915 |             item->setCheckState(Qt::Checked); | 
| 4916 |             model.appendRow(aitem: item); | 
| 4917 |             lastTopLevel = item; | 
| 4918 |             for (int j = 0; j < 2; ++j) { | 
| 4919 |                 QStandardItem *childItem = new QStandardItem(QLatin1String("Child row Item" )); | 
| 4920 |                 childItem->setCheckable(true); | 
| 4921 |                 childItem->setCheckState(Qt::Checked); | 
| 4922 |                 item->appendRow(aitem: childItem); | 
| 4923 |                 QStandardItem *grandChild = new QStandardItem(QLatin1String("Grand child row Item" )); | 
| 4924 |                 grandChild->setCheckable(true); | 
| 4925 |                 grandChild->setCheckState(Qt::Checked); | 
| 4926 |                 childItem->appendRow(aitem: grandChild); | 
| 4927 |             } | 
| 4928 |         } | 
| 4929 |     } | 
| 4930 |     tv.setModel(&model); | 
| 4931 |     tv.expandAll(); | 
| 4932 |     // We need it to be this size so that the effect of the collapsing will | 
| 4933 |     // cause the parent item to move to be under the cursor | 
| 4934 |     tv.resize(w: 200, h: 200); | 
| 4935 |     tv.show(); | 
| 4936 |     QVERIFY(QTest::qWaitForWindowActive(&tv)); | 
| 4937 |     tv.verticalScrollBar()->setValue(tv.verticalScrollBar()->maximum()); | 
| 4938 |  | 
| 4939 |     // We want to press specifically right around where a checkbox for the | 
| 4940 |     // parent item could be when collapsing | 
| 4941 |     QTreeViewPrivate *priv = static_cast<QTreeViewPrivate*>(qt_widget_private(widget: &tv)); | 
| 4942 |     const QModelIndex mi = lastTopLevel->child(row: 0)->index(); | 
| 4943 |     const QRect rect = priv->itemDecorationRect(index: mi); | 
| 4944 |     const QPoint pos = rect.center(); | 
| 4945 |  | 
| 4946 |     QTest::mousePress(widget: tv.viewport(), button: Qt::LeftButton, stateKey: {}, pos); | 
| 4947 |     const bool expandsOnPress = | 
| 4948 |         (tv.style()->styleHint(stylehint: QStyle::SH_ListViewExpand_SelectMouseType, opt: nullptr, widget: &tv) == QEvent::MouseButtonPress); | 
| 4949 |     if (expandsOnPress) | 
| 4950 |         QTRY_VERIFY(!tv.isExpanded(mi)); | 
| 4951 |  | 
| 4952 |     QTest::mouseRelease(widget: tv.viewport(), button: Qt::LeftButton, stateKey: {}, pos); | 
| 4953 |     QTRY_VERIFY(!tv.isExpanded(mi)); | 
| 4954 |     QCOMPARE(lastTopLevel->checkState(), Qt::Checked); | 
| 4955 |  | 
| 4956 |     // Test that it does not toggle the check state of a previously selected item when collapsing an | 
| 4957 |     // item causes it to position the item under the mouse to be the decoration for the selected item | 
| 4958 |     tv.expandAll(); | 
| 4959 |     tv.verticalScrollBar()->setValue(tv.verticalScrollBar()->maximum()); | 
| 4960 |     // It is not enough to programmatically select the item, we need to have it clicked on | 
| 4961 |     QTest::mouseClick(widget: tv.viewport(), button: Qt::LeftButton, stateKey: {}, pos: tv.visualRect(index: lastTopLevel->index()).center()); | 
| 4962 |     QTest::mousePress(widget: tv.viewport(), button: Qt::LeftButton, stateKey: {}, pos); | 
| 4963 |     if (expandsOnPress) | 
| 4964 |         QTRY_VERIFY(!tv.isExpanded(mi)); | 
| 4965 |     QTest::mouseRelease(widget: tv.viewport(), button: Qt::LeftButton, stateKey: nullptr, pos); | 
| 4966 |     QTRY_VERIFY(!tv.isExpanded(mi)); | 
| 4967 |     QCOMPARE(lastTopLevel->checkState(), Qt::Checked); | 
| 4968 | } | 
| 4969 |  | 
| 4970 | void tst_QTreeView::taskQTBUG_42469_crash() | 
| 4971 | { | 
| 4972 |     QTreeWidget treeWidget; | 
| 4973 |     QTreeWidgetItem *itemOne = new QTreeWidgetItem(QStringList("item1" )); | 
| 4974 |     QTreeWidgetItem *itemTwo = new QTreeWidgetItem(QStringList("item2" )); | 
| 4975 |     treeWidget.addTopLevelItem(item: itemOne); | 
| 4976 |     treeWidget.addTopLevelItem(item: itemTwo); | 
| 4977 |     treeWidget.topLevelItem(index: 1)->addChild(child: new QTreeWidgetItem(QStringList("child1" ))); | 
| 4978 |  | 
| 4979 |     treeWidget.setAnimated(true); | 
| 4980 |     QObject::connect(sender: &treeWidget, signal: &QTreeWidget::itemExpanded, slot: [&](QTreeWidgetItem* p_item) { | 
| 4981 |         auto tempCount = treeWidget.topLevelItemCount(); | 
| 4982 |         for (int j = 0; j < tempCount; ++j) | 
| 4983 |             if (treeWidget.topLevelItem(index: j) != p_item) { | 
| 4984 |                 auto temp = treeWidget.topLevelItem(index: j); | 
| 4985 |                 temp->setHidden(true); | 
| 4986 |             } | 
| 4987 |     }); | 
| 4988 |  | 
| 4989 |     treeWidget.show(); | 
| 4990 |     itemTwo->setExpanded(true); | 
| 4991 | } | 
| 4992 |  | 
| 4993 | void tst_QTreeView::fetchUntilScreenFull() | 
| 4994 | { | 
| 4995 |     class TreeModel : public QAbstractItemModel | 
| 4996 |     { | 
| 4997 |     public: | 
| 4998 |         const int maxChildren = 49; | 
| 4999 |         explicit TreeModel(QObject* parent = nullptr) : QAbstractItemModel(parent) | 
| 5000 |         { | 
| 5001 |             QVariant rootData1("Parent Col 1" ); | 
| 5002 |             QVariant rootData2("Parent Col 2" ); | 
| 5003 |             QVector<QVariant> rootData; | 
| 5004 |             rootData.append(t: rootData1); | 
| 5005 |             rootData.append(t: rootData2); | 
| 5006 |  | 
| 5007 |             m_root = new TreeItem(rootData, nullptr); | 
| 5008 |  | 
| 5009 |             QVariant childData1("Col 1" ); | 
| 5010 |             QVariant childData2("Col 2" ); | 
| 5011 |             QVector<QVariant> childData; | 
| 5012 |             childData.append(t: childData1); | 
| 5013 |             childData.append(t: childData2); | 
| 5014 |  | 
| 5015 |             TreeItem* item_1 = new TreeItem(childData, m_root); | 
| 5016 |             m_root->children.append(t: item_1); | 
| 5017 |  | 
| 5018 |             TreeItem* item_2 = new TreeItem(childData, item_1); | 
| 5019 |             item_1->children.append(t: item_2); | 
| 5020 |         } | 
| 5021 |  | 
| 5022 |         QModelIndex index(const int row, const int column, | 
| 5023 |             const QModelIndex& parent = QModelIndex()) const override | 
| 5024 |         { | 
| 5025 |             if (!hasIndex(row, column, parent)) | 
| 5026 |                 return QModelIndex(); | 
| 5027 |  | 
| 5028 |             TreeItem* parentItem = | 
| 5029 |                 parent.isValid() ? static_cast<TreeItem*>(parent.internalPointer()) : m_root; | 
| 5030 |             TreeItem* childItem = parentItem->children.at(i: row); | 
| 5031 |             return createIndex(arow: row, acolumn: column, adata: childItem); | 
| 5032 |         } | 
| 5033 |  | 
| 5034 |         int rowCount(const QModelIndex& parent) const override | 
| 5035 |         { | 
| 5036 |             if (parent.column() > 0) | 
| 5037 |                 return 0; | 
| 5038 |  | 
| 5039 |             TreeItem* parentItem = parent.isValid() ? static_cast<TreeItem*>(parent.internalPointer()) | 
| 5040 |                 : m_root; | 
| 5041 |             return parentItem->children.count(); | 
| 5042 |         } | 
| 5043 |  | 
| 5044 |         int columnCount(const QModelIndex&) const override { return 2; } | 
| 5045 |  | 
| 5046 |         QModelIndex parent(const QModelIndex& childIndex) const override | 
| 5047 |         { | 
| 5048 |             if (!childIndex.isValid()) | 
| 5049 |                 return QModelIndex(); | 
| 5050 |  | 
| 5051 |             TreeItem* parentItem = | 
| 5052 |                 static_cast<TreeItem*>(childIndex.internalPointer())->parent; | 
| 5053 |             return parentItem == m_root ? QModelIndex() | 
| 5054 |                 : createIndex(arow: parentItem->rowInParent(), acolumn: 0, adata: parentItem); | 
| 5055 |         } | 
| 5056 |  | 
| 5057 |         QVariant data(const QModelIndex& index, const int role) const override | 
| 5058 |         { | 
| 5059 |             if (!index.isValid() || role != Qt::DisplayRole) | 
| 5060 |                 return QVariant(); | 
| 5061 |  | 
| 5062 |             TreeItem* item = static_cast<TreeItem*>(index.internalPointer()); | 
| 5063 |             return item->data.at(i: index.column()); | 
| 5064 |         } | 
| 5065 |  | 
| 5066 |         bool canFetchMore(const QModelIndex& parent) const override | 
| 5067 |         { | 
| 5068 |             if (!parent.isValid()) { | 
| 5069 |                 return false; | 
| 5070 |             } else { | 
| 5071 |                 TreeItem* item = static_cast<TreeItem*>(parent.internalPointer()); | 
| 5072 |                 return item->children.size() < maxChildren; | 
| 5073 |             } | 
| 5074 |         } | 
| 5075 |  | 
| 5076 |         void fetchMore(const QModelIndex& parent) override | 
| 5077 |         { | 
| 5078 |             if (!parent.isValid()) | 
| 5079 |                 return; | 
| 5080 |  | 
| 5081 |             fetchMoreCount++; | 
| 5082 |             TreeItem* parentItem = static_cast<TreeItem*>(parent.internalPointer()); | 
| 5083 |             int childCount = parentItem->children.size(); | 
| 5084 |  | 
| 5085 |             beginInsertRows(parent, first: childCount, last: childCount); | 
| 5086 |  | 
| 5087 |             QVariant childData1("Col 1" ); | 
| 5088 |             QVariant childData2("Col 2" ); | 
| 5089 |             QVector<QVariant> childData; | 
| 5090 |             childData.append(t: childData1); | 
| 5091 |             childData.append(t: childData2); | 
| 5092 |             TreeItem* newChild = new TreeItem(childData, parentItem); | 
| 5093 |             parentItem->children.append(t: newChild); | 
| 5094 |  | 
| 5095 |             endInsertRows(); | 
| 5096 |         } | 
| 5097 |  | 
| 5098 |         int fetchMoreCount = 0; | 
| 5099 |     private: | 
| 5100 |         struct TreeItem | 
| 5101 |         { | 
| 5102 |             TreeItem(const QVector<QVariant>& values, TreeItem* parent) | 
| 5103 |                 : data(values), parent(parent) | 
| 5104 |             { | 
| 5105 |             } | 
| 5106 |             ~TreeItem() { qDeleteAll(c: children); } | 
| 5107 |             int rowInParent() const | 
| 5108 |             { | 
| 5109 |                 if (parent) | 
| 5110 |                     return parent->children.indexOf(t: const_cast<TreeItem*>(this)); | 
| 5111 |                 return 0; | 
| 5112 |             } | 
| 5113 |             QVector<QVariant> data; | 
| 5114 |             QVector<TreeItem*> children; | 
| 5115 |             TreeItem* parent = nullptr; | 
| 5116 |         }; | 
| 5117 |         TreeItem* m_root; | 
| 5118 |     }; | 
| 5119 |  | 
| 5120 |     QTreeView tv; | 
| 5121 |     TreeModel model; | 
| 5122 |     tv.setModel(&model); | 
| 5123 |  | 
| 5124 |     const int itemHeight = tv.sizeHintForRow(row: 0); | 
| 5125 |     tv.resize(w: 250, h: itemHeight * 10); | 
| 5126 |     tv.show(); | 
| 5127 |     QVERIFY(QTest::qWaitForWindowExposed(&tv)); | 
| 5128 |  | 
| 5129 |     tv.expand(index: model.index(row: 0, column: 0)); | 
| 5130 |     const int viewportHeight = tv.viewport()->height(); | 
| 5131 |     const int itemCount = viewportHeight / itemHeight; | 
| 5132 |     const int minFetchCount = itemCount - 1; | 
| 5133 |     const int maxFetchCount = itemCount + 1; | 
| 5134 |  | 
| 5135 |     const bool expectedItemNumberFetched = model.fetchMoreCount >= minFetchCount | 
| 5136 |                                          && model.fetchMoreCount <= maxFetchCount; | 
| 5137 |     if (!expectedItemNumberFetched) | 
| 5138 |         qDebug() << model.fetchMoreCount << minFetchCount << maxFetchCount; | 
| 5139 |     QVERIFY(expectedItemNumberFetched); | 
| 5140 | } | 
| 5141 |  | 
| 5142 |  | 
| 5143 | QTEST_MAIN(tst_QTreeView) | 
| 5144 | #include "tst_qtreeview.moc" | 
| 5145 |  |