| 1 | /**************************************************************************** |
| 2 | ** |
| 3 | ** Copyright (C) 2016 The Qt Company Ltd. |
| 4 | ** Copyright (C) 2012 Thorbjørn Lund Martsum - tmartsum[at]gmail.com |
| 5 | ** Contact: https://www.qt.io/licensing/ |
| 6 | ** |
| 7 | ** This file is part of the test suite of the Qt Toolkit. |
| 8 | ** |
| 9 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
| 10 | ** Commercial License Usage |
| 11 | ** Licensees holding valid commercial Qt licenses may use this file in |
| 12 | ** accordance with the commercial license agreement provided with the |
| 13 | ** Software or, alternatively, in accordance with the terms contained in |
| 14 | ** a written agreement between you and The Qt Company. For licensing terms |
| 15 | ** and conditions see https://www.qt.io/terms-conditions. For further |
| 16 | ** information use the contact form at https://www.qt.io/contact-us. |
| 17 | ** |
| 18 | ** GNU General Public License Usage |
| 19 | ** Alternatively, this file may be used under the terms of the GNU |
| 20 | ** General Public License version 3 as published by the Free Software |
| 21 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
| 22 | ** included in the packaging of this file. Please review the following |
| 23 | ** information to ensure the GNU General Public License requirements will |
| 24 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
| 25 | ** |
| 26 | ** $QT_END_LICENSE$ |
| 27 | ** |
| 28 | ****************************************************************************/ |
| 29 | |
| 30 | #include <QDesktopWidget> |
| 31 | #include <QHeaderView> |
| 32 | #include <QProxyStyle> |
| 33 | #include <QSignalSpy> |
| 34 | #include <QSortFilterProxyModel> |
| 35 | #include <QStandardItemModel> |
| 36 | #include <QStringListModel> |
| 37 | #include <QTableView> |
| 38 | #include <QTest> |
| 39 | #include <QTreeWidget> |
| 40 | #include <QtWidgets/private/qheaderview_p.h> |
| 41 | |
| 42 | using BoolList = QVector<bool>; |
| 43 | using IntList = QVector<int>; |
| 44 | using ResizeVec = QVector<QHeaderView::ResizeMode>; |
| 45 | |
| 46 | class TestStyle : public QProxyStyle |
| 47 | { |
| 48 | Q_OBJECT |
| 49 | public: |
| 50 | void drawControl(ControlElement element, const QStyleOption *option, |
| 51 | QPainter *painter, const QWidget *widget) const override |
| 52 | { |
| 53 | if (element == CE_HeaderSection) { |
| 54 | if (const QStyleOptionHeader * = qstyleoption_cast<const QStyleOptionHeader *>(opt: option)) |
| 55 | lastPosition = header->position; |
| 56 | } |
| 57 | QProxyStyle::drawControl(element, option, painter, widget); |
| 58 | } |
| 59 | mutable QStyleOptionHeader::SectionPosition lastPosition = QStyleOptionHeader::Beginning; |
| 60 | }; |
| 61 | |
| 62 | class : public QHeaderView |
| 63 | { |
| 64 | Q_OBJECT |
| 65 | public: |
| 66 | (Qt::Orientation orientation) : QHeaderView(orientation) |
| 67 | { |
| 68 | resizeSections(); |
| 69 | } |
| 70 | |
| 71 | void testEvent(); |
| 72 | void testhorizontalOffset(); |
| 73 | void testverticalOffset(); |
| 74 | void testVisualRegionForSelection(); |
| 75 | friend class tst_QHeaderView; |
| 76 | }; |
| 77 | |
| 78 | class XResetModel : public QStandardItemModel |
| 79 | { |
| 80 | Q_OBJECT |
| 81 | public: |
| 82 | bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) override |
| 83 | { |
| 84 | blockSignals(b: true); |
| 85 | bool r = QStandardItemModel::removeRows(row, count, parent); |
| 86 | blockSignals(b: false); |
| 87 | beginResetModel(); |
| 88 | endResetModel(); |
| 89 | return r; |
| 90 | } |
| 91 | bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex()) override |
| 92 | { |
| 93 | blockSignals(b: true); |
| 94 | bool r = QStandardItemModel::insertRows(row, count, parent); |
| 95 | blockSignals(b: false); |
| 96 | beginResetModel(); |
| 97 | endResetModel(); |
| 98 | return r; |
| 99 | } |
| 100 | }; |
| 101 | |
| 102 | class : public QObject |
| 103 | { |
| 104 | Q_OBJECT |
| 105 | |
| 106 | public: |
| 107 | tst_QHeaderView(); |
| 108 | static void initMain(); |
| 109 | |
| 110 | private slots: |
| 111 | void initTestCase(); |
| 112 | void cleanupTestCase(); |
| 113 | void init(); |
| 114 | void cleanup(); |
| 115 | void getSetCheck(); |
| 116 | void visualIndex(); |
| 117 | |
| 118 | void visualIndexAt_data(); |
| 119 | void visualIndexAt(); |
| 120 | |
| 121 | void noModel(); |
| 122 | void emptyModel(); |
| 123 | void removeRows(); |
| 124 | void removeCols(); |
| 125 | |
| 126 | void clickable(); |
| 127 | void movable(); |
| 128 | void hidden(); |
| 129 | void stretch(); |
| 130 | |
| 131 | void sectionSize_data(); |
| 132 | void sectionSize(); |
| 133 | |
| 134 | void length(); |
| 135 | void offset(); |
| 136 | void sectionSizeHint(); |
| 137 | void logicalIndex(); |
| 138 | void logicalIndexAt(); |
| 139 | void swapSections(); |
| 140 | |
| 141 | void moveSection_data(); |
| 142 | void moveSection(); |
| 143 | |
| 144 | void resizeMode(); |
| 145 | |
| 146 | void resizeSection_data(); |
| 147 | void resizeSection(); |
| 148 | |
| 149 | void resizeAndMoveSection_data(); |
| 150 | void resizeAndMoveSection(); |
| 151 | void resizeHiddenSection_data(); |
| 152 | void resizeHiddenSection(); |
| 153 | void resizeAndInsertSection_data(); |
| 154 | void resizeAndInsertSection(); |
| 155 | void resizeWithResizeModes_data(); |
| 156 | void resizeWithResizeModes(); |
| 157 | void moveAndInsertSection_data(); |
| 158 | void moveAndInsertSection(); |
| 159 | void highlightSections(); |
| 160 | void showSortIndicator(); |
| 161 | void sortIndicatorTracking(); |
| 162 | void removeAndInsertRow(); |
| 163 | void unhideSection(); |
| 164 | void testEvent(); |
| 165 | void headerDataChanged(); |
| 166 | void currentChanged(); |
| 167 | void horizontalOffset(); |
| 168 | void verticalOffset(); |
| 169 | void stretchSectionCount(); |
| 170 | void hiddenSectionCount(); |
| 171 | void focusPolicy(); |
| 172 | void moveSectionAndReset(); |
| 173 | void moveSectionAndRemove(); |
| 174 | void saveRestore(); |
| 175 | void restoreQt4State(); |
| 176 | void restoreToMoreColumns(); |
| 177 | void restoreToMoreColumnsNoMovedColumns(); |
| 178 | void restoreBeforeSetModel(); |
| 179 | void defaultSectionSizeTest(); |
| 180 | void defaultSectionSizeTestStyles(); |
| 181 | |
| 182 | void defaultAlignment_data(); |
| 183 | void defaultAlignment(); |
| 184 | |
| 185 | void globalResizeMode_data(); |
| 186 | void globalResizeMode(); |
| 187 | |
| 188 | void sectionPressedSignal_data(); |
| 189 | void sectionPressedSignal(); |
| 190 | void () { sectionPressedSignal_data(); } |
| 191 | void sectionClickedSignal(); |
| 192 | |
| 193 | void defaultSectionSize_data(); |
| 194 | void defaultSectionSize(); |
| 195 | |
| 196 | void oneSectionSize(); |
| 197 | |
| 198 | void hideAndInsert_data(); |
| 199 | void hideAndInsert(); |
| 200 | |
| 201 | void removeSection(); |
| 202 | void preserveHiddenSectionWidth(); |
| 203 | void invisibleStretchLastSection(); |
| 204 | void noSectionsWithNegativeSize(); |
| 205 | |
| 206 | void emptySectionSpan(); |
| 207 | void task236450_hidden_data(); |
| 208 | void task236450_hidden(); |
| 209 | void task248050_hideRow(); |
| 210 | void QTBUG6058_reset(); |
| 211 | void QTBUG7833_sectionClicked(); |
| 212 | void checkLayoutChangeEmptyModel(); |
| 213 | void QTBUG8650_crashOnInsertSections(); |
| 214 | void QTBUG12268_hiddenMovedSectionSorting(); |
| 215 | void QTBUG14242_hideSectionAutoSize(); |
| 216 | void QTBUG50171_visualRegionForSwappedItems(); |
| 217 | void QTBUG53221_assertShiftHiddenRow(); |
| 218 | void QTBUG75615_sizeHintWithStylesheet(); |
| 219 | void ensureNoIndexAtLength(); |
| 220 | void offsetConsistent(); |
| 221 | void sectionsDontSortWhenNotClickingInThem(); |
| 222 | |
| 223 | void initialSortOrderRole(); |
| 224 | |
| 225 | void () { setupTestData(); } |
| 226 | void () { setupTestData(); } |
| 227 | void () { setupTestData(); } |
| 228 | void () { setupTestData(); } |
| 229 | void () { setupTestData(); } |
| 230 | void () { setupTestData(); } |
| 231 | void () { setupTestData(true); } |
| 232 | void () { setupTestData(true); } |
| 233 | void () { setupTestData(true); } |
| 234 | void () { setupTestData(); } |
| 235 | void logicalIndexAtTest(); |
| 236 | void visualIndexAtTest(); |
| 237 | void hideShowTest(); |
| 238 | void swapSectionsTest(); |
| 239 | void moveSectionTest(); |
| 240 | void defaultSizeTest(); |
| 241 | void removeTest(); |
| 242 | void insertTest(); |
| 243 | void mixedTests(); |
| 244 | void resizeToContentTest(); |
| 245 | void testStreamWithHide(); |
| 246 | void testStylePosition(); |
| 247 | void stretchAndRestoreLastSection(); |
| 248 | void testMinMaxSectionSize_data(); |
| 249 | void testMinMaxSectionSize(); |
| 250 | void sizeHintCrash(); |
| 251 | void testResetCachedSizeHint(); |
| 252 | void statusTips(); |
| 253 | void testRemovingColumnsViaLayoutChanged(); |
| 254 | void testModelMovingColumns(); |
| 255 | |
| 256 | protected: |
| 257 | void setupTestData(bool use_reset_model = false); |
| 258 | void additionalInit(); |
| 259 | void calculateAndCheck(int cppline, const int precalced_comparedata[]); |
| 260 | void (bool stretchLastSection); |
| 261 | |
| 262 | QWidget * = nullptr; |
| 263 | QHeaderView * = nullptr; |
| 264 | QStandardItemModel * = nullptr; |
| 265 | QTableView * = nullptr; |
| 266 | bool = false; |
| 267 | bool = false; |
| 268 | QElapsedTimer ; |
| 269 | }; |
| 270 | |
| 271 | void tst_QHeaderView::initMain() |
| 272 | { |
| 273 | #ifdef Q_OS_WIN |
| 274 | // Ensure minimum size constraints of framed windows on High DPI screens |
| 275 | QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); |
| 276 | #endif |
| 277 | } |
| 278 | |
| 279 | class QtTestModel: public QAbstractTableModel |
| 280 | { |
| 281 | Q_OBJECT |
| 282 | public: |
| 283 | QtTestModel(int rc, int cc, QObject *parent = nullptr) |
| 284 | : QAbstractTableModel(parent), rows(rc), cols(cc) {} |
| 285 | int rowCount(const QModelIndex &) const override { return rows; } |
| 286 | int columnCount(const QModelIndex &) const override { return cols; } |
| 287 | bool isEditable(const QModelIndex &) const { return true; } |
| 288 | QVariant (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override |
| 289 | { |
| 290 | if (section < 0 || (role != Qt::DisplayRole && role != Qt::StatusTipRole)) |
| 291 | return QVariant(); |
| 292 | const int row = (orientation == Qt::Vertical ? section : 0); |
| 293 | const int col = (orientation == Qt::Horizontal ? section : 0); |
| 294 | if (orientation == Qt::Vertical && row >= rows) |
| 295 | return QVariant(); |
| 296 | if (orientation == Qt::Horizontal && col >= cols) |
| 297 | return QVariant(); |
| 298 | if (m_bMultiLine) |
| 299 | return QString("%1\n%1" ).arg(a: section); |
| 300 | return QLatin1Char('[') + QString::number(row) + QLatin1Char(',') |
| 301 | + QString::number(col) + QLatin1String(",0] -- Header" ); |
| 302 | } |
| 303 | QVariant data(const QModelIndex &idx, int role = Qt::DisplayRole) const override |
| 304 | { |
| 305 | if (role != Qt::DisplayRole) |
| 306 | return QVariant(); |
| 307 | if (idx.row() < 0 || idx.column() < 0 || idx.column() >= cols || idx.row() >= rows) { |
| 308 | wrongIndex = true; |
| 309 | qWarning(msg: "Invalid modelIndex [%d,%d,%p]" , idx.row(), idx.column(), idx.internalPointer()); |
| 310 | } |
| 311 | return QLatin1Char('[') + QString::number(idx.row()) + QLatin1Char(',') |
| 312 | + QString::number(idx.column()) + QLatin1String(",0]" ); |
| 313 | } |
| 314 | |
| 315 | void insertOneColumn(int col) |
| 316 | { |
| 317 | beginInsertColumns(parent: QModelIndex(), first: col, last: col); |
| 318 | --cols; |
| 319 | endInsertColumns(); |
| 320 | } |
| 321 | |
| 322 | void removeFirstRow() |
| 323 | { |
| 324 | beginRemoveRows(parent: QModelIndex(), first: 0, last: 0); |
| 325 | --rows; |
| 326 | endRemoveRows(); |
| 327 | } |
| 328 | |
| 329 | void removeLastRow() |
| 330 | { |
| 331 | beginRemoveRows(parent: QModelIndex(), first: rows - 1, last: rows - 1); |
| 332 | --rows; |
| 333 | endRemoveRows(); |
| 334 | } |
| 335 | |
| 336 | void removeAllRows() |
| 337 | { |
| 338 | beginRemoveRows(parent: QModelIndex(), first: 0, last: rows - 1); |
| 339 | rows = 0; |
| 340 | endRemoveRows(); |
| 341 | } |
| 342 | |
| 343 | void removeOneColumn(int col) |
| 344 | { |
| 345 | beginRemoveColumns(parent: QModelIndex(), first: col, last: col); |
| 346 | --cols; |
| 347 | endRemoveColumns(); |
| 348 | } |
| 349 | |
| 350 | void removeLastColumn() |
| 351 | { |
| 352 | beginRemoveColumns(parent: QModelIndex(), first: cols - 1, last: cols - 1); |
| 353 | --cols; |
| 354 | endRemoveColumns(); |
| 355 | } |
| 356 | |
| 357 | void removeAllColumns() |
| 358 | { |
| 359 | beginRemoveColumns(parent: QModelIndex(), first: 0, last: cols - 1); |
| 360 | cols = 0; |
| 361 | endRemoveColumns(); |
| 362 | } |
| 363 | |
| 364 | void moveColumn(int from, int to) |
| 365 | { |
| 366 | beginMoveColumns(sourceParent: QModelIndex(), sourceFirst: from, sourceLast: from, destinationParent: QModelIndex(), destinationColumn: to); |
| 367 | endMoveColumns(); |
| 368 | } |
| 369 | |
| 370 | void cleanup() |
| 371 | { |
| 372 | emit layoutAboutToBeChanged(); |
| 373 | cols = 3; |
| 374 | rows = 3; |
| 375 | emit layoutChanged(); |
| 376 | } |
| 377 | |
| 378 | void emitLayoutChanged() |
| 379 | { |
| 380 | emit layoutAboutToBeChanged(); |
| 381 | emit layoutChanged(); |
| 382 | } |
| 383 | |
| 384 | void emitLayoutChangedWithRemoveFirstRow() |
| 385 | { |
| 386 | emit layoutAboutToBeChanged(); |
| 387 | QModelIndexList milNew; |
| 388 | const auto milOld = persistentIndexList(); |
| 389 | milNew.reserve(alloc: milOld.size()); |
| 390 | for (int i = 0; i < milOld.size(); ++i) |
| 391 | milNew += QModelIndex(); |
| 392 | changePersistentIndexList(from: milOld, to: milNew); |
| 393 | emit layoutChanged(); |
| 394 | } |
| 395 | |
| 396 | void (bool bEnable) |
| 397 | { |
| 398 | beginResetModel(); |
| 399 | m_bMultiLine = bEnable; |
| 400 | endResetModel(); |
| 401 | } |
| 402 | |
| 403 | int rows = 0; |
| 404 | int cols = 0; |
| 405 | mutable bool wrongIndex = false; |
| 406 | bool m_bMultiLine = false; |
| 407 | }; |
| 408 | |
| 409 | // Testing get/set functions |
| 410 | void tst_QHeaderView::() |
| 411 | { |
| 412 | protected_QHeaderView obj1(Qt::Horizontal); |
| 413 | // bool QHeaderView::highlightSections() |
| 414 | // void QHeaderView::setHighlightSections(bool) |
| 415 | obj1.setHighlightSections(false); |
| 416 | QCOMPARE(false, obj1.highlightSections()); |
| 417 | obj1.setHighlightSections(true); |
| 418 | QCOMPARE(true, obj1.highlightSections()); |
| 419 | |
| 420 | // bool QHeaderView::stretchLastSection() |
| 421 | // void QHeaderView::setStretchLastSection(bool) |
| 422 | obj1.setStretchLastSection(false); |
| 423 | QCOMPARE(false, obj1.stretchLastSection()); |
| 424 | obj1.setStretchLastSection(true); |
| 425 | QCOMPARE(true, obj1.stretchLastSection()); |
| 426 | |
| 427 | // int QHeaderView::defaultSectionSize() |
| 428 | // void QHeaderView::setDefaultSectionSize(int) |
| 429 | obj1.setMinimumSectionSize(0); |
| 430 | obj1.setDefaultSectionSize(-1); |
| 431 | QVERIFY(obj1.defaultSectionSize() >= 0); |
| 432 | obj1.setDefaultSectionSize(0); |
| 433 | QCOMPARE(0, obj1.defaultSectionSize()); |
| 434 | obj1.setDefaultSectionSize(99999); |
| 435 | QCOMPARE(99999, obj1.defaultSectionSize()); |
| 436 | |
| 437 | // int QHeaderView::minimumSectionSize() |
| 438 | // void QHeaderView::setMinimumSectionSize(int) |
| 439 | obj1.setMinimumSectionSize(-1); |
| 440 | QVERIFY(obj1.minimumSectionSize() >= 0); |
| 441 | obj1.setMinimumSectionSize(0); |
| 442 | QCOMPARE(0, obj1.minimumSectionSize()); |
| 443 | obj1.setMinimumSectionSize(99999); |
| 444 | QCOMPARE(99999, obj1.minimumSectionSize()); |
| 445 | obj1.setMinimumSectionSize(-1); |
| 446 | QVERIFY(obj1.minimumSectionSize() < 100); |
| 447 | |
| 448 | // int QHeaderView::offset() |
| 449 | // void QHeaderView::setOffset(int) |
| 450 | obj1.setOffset(0); |
| 451 | QCOMPARE(0, obj1.offset()); |
| 452 | obj1.setOffset(std::numeric_limits<int>::min()); |
| 453 | QCOMPARE(std::numeric_limits<int>::min(), obj1.offset()); |
| 454 | obj1.setOffset(std::numeric_limits<int>::max()); |
| 455 | QCOMPARE(std::numeric_limits<int>::max(), obj1.offset()); |
| 456 | |
| 457 | } |
| 458 | |
| 459 | tst_QHeaderView::() |
| 460 | { |
| 461 | qRegisterMetaType<Qt::SortOrder>(typeName: "Qt::SortOrder" ); |
| 462 | } |
| 463 | |
| 464 | void tst_QHeaderView::() |
| 465 | { |
| 466 | m_tableview = new QTableView; |
| 467 | qDebug().noquote().nospace() |
| 468 | << "default min section size is " |
| 469 | << QString::number(m_tableview->verticalHeader()->minimumSectionSize()) |
| 470 | << QLatin1Char('/') |
| 471 | << m_tableview->horizontalHeader()->minimumSectionSize() |
| 472 | << " (v/h)" ; |
| 473 | } |
| 474 | |
| 475 | void tst_QHeaderView::() |
| 476 | { |
| 477 | delete m_tableview; |
| 478 | } |
| 479 | |
| 480 | void tst_QHeaderView::() |
| 481 | { |
| 482 | topLevel = new QWidget; |
| 483 | view = new QHeaderView(Qt::Vertical, topLevel); |
| 484 | // Some initial value tests before a model is added |
| 485 | QCOMPARE(view->length(), 0); |
| 486 | QCOMPARE(view->sizeHint(), QSize(0,0)); |
| 487 | QCOMPARE(view->sectionSizeHint(0), -1); |
| 488 | view->setMinimumSectionSize(0); // system default min size can be to large |
| 489 | |
| 490 | /* |
| 491 | model = new QStandardItemModel(1, 1); |
| 492 | view->setModel(model); |
| 493 | //qDebug() << view->count(); |
| 494 | view->sizeHint(); |
| 495 | */ |
| 496 | |
| 497 | int rows = 4; |
| 498 | int columns = 4; |
| 499 | model = new QStandardItemModel(rows, columns); |
| 500 | /* |
| 501 | for (int row = 0; row < rows; ++row) { |
| 502 | for (int column = 0; column < columns; ++column) { |
| 503 | QModelIndex index = model->index(row, column, QModelIndex()); |
| 504 | model->setData(index, QVariant((row+1) * (column+1))); |
| 505 | } |
| 506 | } |
| 507 | */ |
| 508 | |
| 509 | QSignalSpy spy(view, &QHeaderView::sectionCountChanged); |
| 510 | view->setModel(model); |
| 511 | QCOMPARE(spy.count(), 1); |
| 512 | view->resize(w: 200,h: 200); |
| 513 | } |
| 514 | |
| 515 | void tst_QHeaderView::() |
| 516 | { |
| 517 | m_tableview->setUpdatesEnabled(true); |
| 518 | if (view && view->parent() != m_tableview) |
| 519 | delete view; |
| 520 | view = nullptr; |
| 521 | delete model; |
| 522 | model = nullptr; |
| 523 | delete topLevel; |
| 524 | topLevel = nullptr; |
| 525 | } |
| 526 | |
| 527 | void tst_QHeaderView::() |
| 528 | { |
| 529 | QHeaderView emptyView(Qt::Vertical); |
| 530 | QCOMPARE(emptyView.count(), 0); |
| 531 | } |
| 532 | |
| 533 | void tst_QHeaderView::() |
| 534 | { |
| 535 | QtTestModel testmodel(0, 0); |
| 536 | view->setModel(&testmodel); |
| 537 | QVERIFY(!testmodel.wrongIndex); |
| 538 | QCOMPARE(view->count(), testmodel.rows); |
| 539 | view->setModel(model); |
| 540 | } |
| 541 | |
| 542 | void tst_QHeaderView::() |
| 543 | { |
| 544 | QtTestModel model(10, 10); |
| 545 | |
| 546 | QHeaderView vertical(Qt::Vertical); |
| 547 | QHeaderView horizontal(Qt::Horizontal); |
| 548 | |
| 549 | vertical.setModel(&model); |
| 550 | horizontal.setModel(&model); |
| 551 | vertical.show(); |
| 552 | horizontal.show(); |
| 553 | QCOMPARE(vertical.count(), model.rows); |
| 554 | QCOMPARE(horizontal.count(), model.cols); |
| 555 | |
| 556 | model.removeLastRow(); |
| 557 | QVERIFY(!model.wrongIndex); |
| 558 | QCOMPARE(vertical.count(), model.rows); |
| 559 | QCOMPARE(horizontal.count(), model.cols); |
| 560 | |
| 561 | model.removeAllRows(); |
| 562 | QVERIFY(!model.wrongIndex); |
| 563 | QCOMPARE(vertical.count(), model.rows); |
| 564 | QCOMPARE(horizontal.count(), model.cols); |
| 565 | } |
| 566 | |
| 567 | |
| 568 | void tst_QHeaderView::() |
| 569 | { |
| 570 | QtTestModel model(10, 10); |
| 571 | |
| 572 | QHeaderView vertical(Qt::Vertical); |
| 573 | QHeaderView horizontal(Qt::Horizontal); |
| 574 | vertical.setModel(&model); |
| 575 | horizontal.setModel(&model); |
| 576 | vertical.show(); |
| 577 | horizontal.show(); |
| 578 | QCOMPARE(vertical.count(), model.rows); |
| 579 | QCOMPARE(horizontal.count(), model.cols); |
| 580 | |
| 581 | model.removeLastColumn(); |
| 582 | QVERIFY(!model.wrongIndex); |
| 583 | QCOMPARE(vertical.count(), model.rows); |
| 584 | QCOMPARE(horizontal.count(), model.cols); |
| 585 | |
| 586 | model.removeAllColumns(); |
| 587 | QVERIFY(!model.wrongIndex); |
| 588 | QCOMPARE(vertical.count(), model.rows); |
| 589 | QCOMPARE(horizontal.count(), model.cols); |
| 590 | } |
| 591 | |
| 592 | void tst_QHeaderView::() |
| 593 | { |
| 594 | QCOMPARE(view->sectionsMovable(), false); |
| 595 | view->setSectionsMovable(false); |
| 596 | QCOMPARE(view->sectionsMovable(), false); |
| 597 | view->setSectionsMovable(true); |
| 598 | QCOMPARE(view->sectionsMovable(), true); |
| 599 | |
| 600 | QCOMPARE(view->isFirstSectionMovable(), true); |
| 601 | view->setFirstSectionMovable(false); |
| 602 | QCOMPARE(view->isFirstSectionMovable(), false); |
| 603 | view->setFirstSectionMovable(true); |
| 604 | QCOMPARE(view->isFirstSectionMovable(), true); |
| 605 | } |
| 606 | |
| 607 | void tst_QHeaderView::() |
| 608 | { |
| 609 | QCOMPARE(view->sectionsClickable(), false); |
| 610 | view->setSectionsClickable(false); |
| 611 | QCOMPARE(view->sectionsClickable(), false); |
| 612 | view->setSectionsClickable(true); |
| 613 | QCOMPARE(view->sectionsClickable(), true); |
| 614 | } |
| 615 | |
| 616 | void tst_QHeaderView::() |
| 617 | { |
| 618 | //hideSection() & showSection call setSectionHidden |
| 619 | // Test bad arguments |
| 620 | QCOMPARE(view->isSectionHidden(-1), false); |
| 621 | QCOMPARE(view->isSectionHidden(view->count()), false); |
| 622 | QCOMPARE(view->isSectionHidden(999999), false); |
| 623 | |
| 624 | view->setSectionHidden(logicalIndex: -1, hide: true); |
| 625 | view->setSectionHidden(logicalIndex: view->count(), hide: true); |
| 626 | view->setSectionHidden(logicalIndex: 999999, hide: true); |
| 627 | view->setSectionHidden(logicalIndex: -1, hide: false); |
| 628 | view->setSectionHidden(logicalIndex: view->count(), hide: false); |
| 629 | view->setSectionHidden(logicalIndex: 999999, hide: false); |
| 630 | |
| 631 | // Hidden sections shouldn't have visual properties (except position) |
| 632 | int pos = view->defaultSectionSize(); |
| 633 | view->setSectionHidden(logicalIndex: 1, hide: true); |
| 634 | QCOMPARE(view->sectionSize(1), 0); |
| 635 | QCOMPARE(view->sectionPosition(1), pos); |
| 636 | view->resizeSection(logicalIndex: 1, size: 100); |
| 637 | QCOMPARE(view->sectionViewportPosition(1), pos); |
| 638 | QCOMPARE(view->sectionSize(1), 0); |
| 639 | view->setSectionHidden(logicalIndex: 1, hide: false); |
| 640 | QCOMPARE(view->isSectionHidden(0), false); |
| 641 | QCOMPARE(view->sectionSize(0), view->defaultSectionSize()); |
| 642 | |
| 643 | // d->hiddenSectionSize could go out of sync when a new model |
| 644 | // was set which has fewer sections than before and some of them |
| 645 | // were hidden |
| 646 | QStandardItemModel model2(model->rowCount() - 1, model->columnCount()); |
| 647 | |
| 648 | for (int i = 0; i < model->rowCount(); ++i) |
| 649 | view->setSectionHidden(logicalIndex: i, hide: true); |
| 650 | view->setModel(&model2); |
| 651 | QVERIFY(view->sectionsHidden()); |
| 652 | for (int i = 0; i < model2.rowCount(); ++i) |
| 653 | QVERIFY(view->isSectionHidden(i)); |
| 654 | |
| 655 | view->setModel(model); |
| 656 | for (int i = 0; i < model2.rowCount(); ++i) |
| 657 | QVERIFY(view->isSectionHidden(i)); |
| 658 | QCOMPARE(view->isSectionHidden(model->rowCount() - 1), false); |
| 659 | for (int i = 0; i < model->rowCount(); ++i) |
| 660 | view->setSectionHidden(logicalIndex: i, hide: false); |
| 661 | } |
| 662 | |
| 663 | void tst_QHeaderView::() |
| 664 | { |
| 665 | // Show before resize and setStretchLastSection |
| 666 | QSize viewSize(500, 500); |
| 667 | view->resize(viewSize); |
| 668 | view->setStretchLastSection(true); |
| 669 | QCOMPARE(view->stretchLastSection(), true); |
| 670 | topLevel->show(); |
| 671 | QVERIFY(QTest::qWaitForWindowExposed(topLevel)); |
| 672 | QCOMPARE(view->width(), viewSize.width()); |
| 673 | QCOMPARE(view->visualIndexAt(view->viewport()->height() - 5), 3); |
| 674 | |
| 675 | view->setSectionHidden(logicalIndex: 3, hide: true); |
| 676 | QCOMPARE(view->visualIndexAt(view->viewport()->height() - 5), 2); |
| 677 | |
| 678 | view->setStretchLastSection(false); |
| 679 | QCOMPARE(view->stretchLastSection(), false); |
| 680 | } |
| 681 | |
| 682 | void tst_QHeaderView::() |
| 683 | { |
| 684 | //this ensures that if there is only one section, it gets a correct width (more than 0) |
| 685 | QHeaderView view (Qt::Vertical); |
| 686 | QtTestModel model(1, 1); |
| 687 | |
| 688 | view.setSectionResizeMode(QHeaderView::Interactive); |
| 689 | view.setModel(&model); |
| 690 | view.show(); |
| 691 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
| 692 | |
| 693 | QVERIFY(view.sectionSize(0) > 0); |
| 694 | } |
| 695 | |
| 696 | |
| 697 | void tst_QHeaderView::() |
| 698 | { |
| 699 | QTest::addColumn<IntList>(name: "boundsCheck" ); |
| 700 | QTest::addColumn<IntList>(name: "defaultSizes" ); |
| 701 | QTest::addColumn<int>(name: "initialDefaultSize" ); |
| 702 | QTest::addColumn<int>(name: "lastVisibleSectionSize" ); |
| 703 | QTest::addColumn<int>(name: "persistentSectionSize" ); |
| 704 | |
| 705 | QTest::newRow(dataTag: "data set one" ) |
| 706 | << (IntList{ -1, 0, 4, 9999 }) |
| 707 | << (IntList{ 10, 30, 30 }) |
| 708 | << 30 |
| 709 | << 300 |
| 710 | << 20; |
| 711 | } |
| 712 | |
| 713 | void tst_QHeaderView::() |
| 714 | { |
| 715 | #if defined Q_OS_QNX |
| 716 | QSKIP("The section size is dpi dependent on QNX" ); |
| 717 | #elif defined Q_OS_WINRT |
| 718 | QSKIP("Fails on WinRT - QTBUG-68297" ); |
| 719 | #endif |
| 720 | QFETCH(const IntList, boundsCheck); |
| 721 | QFETCH(const IntList, defaultSizes); |
| 722 | QFETCH(int, initialDefaultSize); |
| 723 | QFETCH(int, lastVisibleSectionSize); |
| 724 | QFETCH(int, persistentSectionSize); |
| 725 | |
| 726 | // bounds check |
| 727 | for (int val : boundsCheck) |
| 728 | view->sectionSize(logicalIndex: val); |
| 729 | |
| 730 | // default size |
| 731 | QCOMPARE(view->defaultSectionSize(), initialDefaultSize); |
| 732 | for (int def : defaultSizes) { |
| 733 | view->setDefaultSectionSize(def); |
| 734 | QCOMPARE(view->defaultSectionSize(), def); |
| 735 | } |
| 736 | |
| 737 | view->setDefaultSectionSize(initialDefaultSize); |
| 738 | for (int s = 0; s < view->count(); ++s) |
| 739 | QCOMPARE(view->sectionSize(s), initialDefaultSize); |
| 740 | view->doItemsLayout(); |
| 741 | |
| 742 | // stretch last section |
| 743 | view->setStretchLastSection(true); |
| 744 | int lastSection = view->count() - 1; |
| 745 | |
| 746 | //test that when hiding the last column, |
| 747 | //resizing the new last visible columns still works |
| 748 | view->hideSection(alogicalIndex: lastSection); |
| 749 | view->resizeSection(logicalIndex: lastSection - 1, size: lastVisibleSectionSize); |
| 750 | QCOMPARE(view->sectionSize(lastSection - 1), lastVisibleSectionSize); |
| 751 | view->showSection(alogicalIndex: lastSection); |
| 752 | |
| 753 | // turn off stretching |
| 754 | view->setStretchLastSection(false); |
| 755 | QCOMPARE(view->sectionSize(lastSection), initialDefaultSize); |
| 756 | |
| 757 | // test persistence |
| 758 | int sectionCount = view->count(); |
| 759 | for (int i = 0; i < sectionCount; ++i) |
| 760 | view->resizeSection(logicalIndex: i, size: persistentSectionSize); |
| 761 | QtTestModel model(sectionCount * 2, sectionCount * 2); |
| 762 | view->setModel(&model); |
| 763 | for (int j = 0; j < sectionCount; ++j) |
| 764 | QCOMPARE(view->sectionSize(j), persistentSectionSize); |
| 765 | for (int k = sectionCount; k < view->count(); ++k) |
| 766 | QCOMPARE(view->sectionSize(k), initialDefaultSize); |
| 767 | } |
| 768 | |
| 769 | void tst_QHeaderView::() |
| 770 | { |
| 771 | // Test bad arguments |
| 772 | QCOMPARE(view->visualIndex(999999), -1); |
| 773 | QCOMPARE(view->visualIndex(-1), -1); |
| 774 | QCOMPARE(view->visualIndex(1), 1); |
| 775 | view->setSectionHidden(logicalIndex: 1, hide: true); |
| 776 | QCOMPARE(view->visualIndex(1), 1); |
| 777 | QCOMPARE(view->visualIndex(2), 2); |
| 778 | |
| 779 | view->setSectionHidden(logicalIndex: 1, hide: false); |
| 780 | QCOMPARE(view->visualIndex(1), 1); |
| 781 | QCOMPARE(view->visualIndex(2), 2); |
| 782 | } |
| 783 | |
| 784 | void tst_QHeaderView::() |
| 785 | { |
| 786 | QTest::addColumn<IntList>(name: "hidden" ); |
| 787 | QTest::addColumn<IntList>(name: "from" ); |
| 788 | QTest::addColumn<IntList>(name: "to" ); |
| 789 | QTest::addColumn<IntList>(name: "coordinate" ); |
| 790 | QTest::addColumn<IntList>(name: "visual" ); |
| 791 | |
| 792 | const IntList coordinateList{ -1, 0, 31, 91, 99999 }; |
| 793 | |
| 794 | QTest::newRow(dataTag: "no hidden, no moved sections" ) |
| 795 | << IntList() |
| 796 | << IntList() |
| 797 | << IntList() |
| 798 | << coordinateList |
| 799 | << (IntList{ -1, 0, 1, 3, -1 }); |
| 800 | |
| 801 | QTest::newRow(dataTag: "no hidden, moved sections" ) |
| 802 | << IntList() |
| 803 | << (IntList{ 0 }) |
| 804 | << (IntList{ 1 }) |
| 805 | << coordinateList |
| 806 | << (IntList{ -1, 0, 1, 3, -1 }); |
| 807 | |
| 808 | QTest::newRow(dataTag: "hidden, no moved sections" ) |
| 809 | << (IntList{ 0 }) |
| 810 | << IntList() |
| 811 | << IntList() |
| 812 | << coordinateList |
| 813 | << (IntList{ -1, 1, 2, 3, -1 }); |
| 814 | } |
| 815 | |
| 816 | void tst_QHeaderView::() |
| 817 | { |
| 818 | #if defined Q_OS_QNX |
| 819 | QSKIP("The section size is dpi dependent on QNX" ); |
| 820 | #elif defined Q_OS_WINRT |
| 821 | QSKIP("Fails on WinRT - QTBUG-68297" ); |
| 822 | #endif |
| 823 | QFETCH(const IntList, hidden); |
| 824 | QFETCH(const IntList, from); |
| 825 | QFETCH(const IntList, to); |
| 826 | QFETCH(const IntList, coordinate); |
| 827 | QFETCH(const IntList, visual); |
| 828 | |
| 829 | view->setStretchLastSection(true); |
| 830 | topLevel->show(); |
| 831 | QVERIFY(QTest::qWaitForWindowExposed(topLevel)); |
| 832 | |
| 833 | for (int i : hidden) |
| 834 | view->setSectionHidden(logicalIndex: i, hide: true); |
| 835 | |
| 836 | for (int j = 0; j < from.count(); ++j) |
| 837 | view->moveSection(from: from.at(i: j), to: to.at(i: j)); |
| 838 | |
| 839 | for (int k = 0; k < coordinate.count(); ++k) |
| 840 | QTRY_COMPARE(view->visualIndexAt(coordinate.at(k)), visual.at(k)); |
| 841 | } |
| 842 | |
| 843 | void tst_QHeaderView::() |
| 844 | { |
| 845 | view->setStretchLastSection(true); |
| 846 | topLevel->show(); |
| 847 | QVERIFY(QTest::qWaitForWindowExposed(topLevel)); |
| 848 | |
| 849 | //minimumSectionSize should be the size of the last section of the widget is not tall enough |
| 850 | int length = view->minimumSectionSize(); |
| 851 | for (int i = 0; i < view->count() - 1; i++) |
| 852 | length += view->sectionSize(logicalIndex: i); |
| 853 | |
| 854 | length = qMax(a: length, b: view->viewport()->height()); |
| 855 | QCOMPARE(length, view->length()); |
| 856 | |
| 857 | view->setStretchLastSection(false); |
| 858 | topLevel->show(); |
| 859 | QVERIFY(QTest::qWaitForWindowExposed(topLevel)); |
| 860 | |
| 861 | QVERIFY(length != view->length()); |
| 862 | |
| 863 | // layoutChanged might mean rows have been removed |
| 864 | QtTestModel model(10, 10); |
| 865 | view->setModel(&model); |
| 866 | int oldLength = view->length(); |
| 867 | model.cleanup(); |
| 868 | QCOMPARE(model.rows, view->count()); |
| 869 | QVERIFY(oldLength != view->length()); |
| 870 | } |
| 871 | |
| 872 | void tst_QHeaderView::() |
| 873 | { |
| 874 | QCOMPARE(view->offset(), 0); |
| 875 | view->setOffset(10); |
| 876 | QCOMPARE(view->offset(), 10); |
| 877 | view->setOffset(0); |
| 878 | QCOMPARE(view->offset(), 0); |
| 879 | |
| 880 | // Test odd arguments |
| 881 | view->setOffset(-1); |
| 882 | } |
| 883 | |
| 884 | void tst_QHeaderView::() |
| 885 | { |
| 886 | QCOMPARE(view->sectionSizeHint(-1), -1); |
| 887 | QCOMPARE(view->sectionSizeHint(99999), -1); |
| 888 | QVERIFY(view->sectionSizeHint(0) >= 0); |
| 889 | } |
| 890 | |
| 891 | void tst_QHeaderView::() |
| 892 | { |
| 893 | // Test bad arguments |
| 894 | QCOMPARE(view->logicalIndex(-1), -1); |
| 895 | QCOMPARE(view->logicalIndex(99999), -1); |
| 896 | } |
| 897 | |
| 898 | void tst_QHeaderView::() |
| 899 | { |
| 900 | // Test bad arguments |
| 901 | view->logicalIndexAt(position: -1); |
| 902 | view->logicalIndexAt(position: 99999); |
| 903 | QCOMPARE(view->logicalIndexAt(0), 0); |
| 904 | QCOMPARE(view->logicalIndexAt(1), 0); |
| 905 | |
| 906 | topLevel->show(); |
| 907 | QVERIFY(QTest::qWaitForWindowExposed(topLevel)); |
| 908 | view->setStretchLastSection(true); |
| 909 | // First item |
| 910 | QCOMPARE(view->logicalIndexAt(0), 0); |
| 911 | QCOMPARE(view->logicalIndexAt(view->sectionSize(0)-1), 0); |
| 912 | QCOMPARE(view->logicalIndexAt(view->sectionSize(0)+1), 1); |
| 913 | // Last item |
| 914 | int last = view->length() - 1;//view->viewport()->height() - 10; |
| 915 | QCOMPARE(view->logicalIndexAt(last), 3); |
| 916 | // Not in widget |
| 917 | int outofbounds = view->length() + 1;//view->viewport()->height() + 1; |
| 918 | QCOMPARE(view->logicalIndexAt(outofbounds), -1); |
| 919 | |
| 920 | view->moveSection(from: 0,to: 1); |
| 921 | // First item |
| 922 | QCOMPARE(view->logicalIndexAt(0), 1); |
| 923 | QCOMPARE(view->logicalIndexAt(view->sectionSize(0)-1), 1); |
| 924 | QCOMPARE(view->logicalIndexAt(view->sectionSize(0)+1), 0); |
| 925 | // Last item |
| 926 | QCOMPARE(view->logicalIndexAt(last), 3); |
| 927 | view->moveSection(from: 1,to: 0); |
| 928 | |
| 929 | } |
| 930 | |
| 931 | void tst_QHeaderView::() |
| 932 | { |
| 933 | view->swapSections(first: -1, second: 1); |
| 934 | view->swapSections(first: 99999, second: 1); |
| 935 | view->swapSections(first: 1, second: -1); |
| 936 | view->swapSections(first: 1, second: 99999); |
| 937 | |
| 938 | IntList logical{ 0, 1, 2, 3 }; |
| 939 | |
| 940 | QSignalSpy spy1(view, &QHeaderView::sectionMoved); |
| 941 | |
| 942 | QCOMPARE(view->sectionsMoved(), false); |
| 943 | view->swapSections(first: 1, second: 1); |
| 944 | QCOMPARE(view->sectionsMoved(), false); |
| 945 | view->swapSections(first: 1, second: 2); |
| 946 | QCOMPARE(view->sectionsMoved(), true); |
| 947 | view->swapSections(first: 2, second: 1); |
| 948 | QCOMPARE(view->sectionsMoved(), true); |
| 949 | for (int i = 0; i < view->count(); ++i) |
| 950 | QCOMPARE(view->logicalIndex(i), logical.at(i)); |
| 951 | QCOMPARE(spy1.count(), 4); |
| 952 | |
| 953 | logical = { 3, 1, 2, 0 }; |
| 954 | view->swapSections(first: 3, second: 0); |
| 955 | QCOMPARE(view->sectionsMoved(), true); |
| 956 | for (int j = 0; j < view->count(); ++j) |
| 957 | QCOMPARE(view->logicalIndex(j), logical.at(j)); |
| 958 | QCOMPARE(spy1.count(), 6); |
| 959 | } |
| 960 | |
| 961 | void tst_QHeaderView::() |
| 962 | { |
| 963 | QTest::addColumn<IntList>(name: "hidden" ); |
| 964 | QTest::addColumn<IntList>(name: "from" ); |
| 965 | QTest::addColumn<IntList>(name: "to" ); |
| 966 | QTest::addColumn<BoolList>(name: "moved" ); |
| 967 | QTest::addColumn<IntList>(name: "logical" ); |
| 968 | QTest::addColumn<int>(name: "count" ); |
| 969 | |
| 970 | QTest::newRow(dataTag: "bad args, no hidden" ) |
| 971 | << IntList() |
| 972 | << (IntList{ -1, 1, 99999, 1 }) |
| 973 | << (IntList{ 1, -1, 1, 99999 }) |
| 974 | << (BoolList{ false, false, false, false }) |
| 975 | << (IntList{ 0, 1, 2, 3 }) |
| 976 | << 0; |
| 977 | |
| 978 | QTest::newRow(dataTag: "good args, no hidden" ) |
| 979 | << IntList() |
| 980 | << (IntList{ 1, 1, 2, 1 }) |
| 981 | << (IntList{ 1, 2, 1, 2 }) |
| 982 | << (BoolList{ false, true, true, true }) |
| 983 | << (IntList{ 0, 2, 1, 3 }) |
| 984 | << 3; |
| 985 | |
| 986 | QTest::newRow(dataTag: "hidden sections" ) |
| 987 | << (IntList{ 0, 3 }) |
| 988 | << (IntList{ 1, 1, 2, 1 }) |
| 989 | << (IntList{ 1, 2, 1, 2 }) |
| 990 | << (BoolList{ false, true, true, true }) |
| 991 | << (IntList{ 0, 2, 1, 3 }) |
| 992 | << 3; |
| 993 | } |
| 994 | |
| 995 | void tst_QHeaderView::() |
| 996 | { |
| 997 | QFETCH(const IntList, hidden); |
| 998 | QFETCH(const IntList, from); |
| 999 | QFETCH(const IntList, to); |
| 1000 | QFETCH(const BoolList, moved); |
| 1001 | QFETCH(const IntList, logical); |
| 1002 | QFETCH(int, count); |
| 1003 | |
| 1004 | QCOMPARE(from.count(), to.count()); |
| 1005 | QCOMPARE(from.count(), moved.count()); |
| 1006 | QCOMPARE(view->count(), logical.count()); |
| 1007 | |
| 1008 | QSignalSpy spy1(view, &QHeaderView::sectionMoved); |
| 1009 | QCOMPARE(view->sectionsMoved(), false); |
| 1010 | |
| 1011 | for (int h : hidden) |
| 1012 | view->setSectionHidden(logicalIndex: h, hide: true); |
| 1013 | |
| 1014 | for (int i = 0; i < from.count(); ++i) { |
| 1015 | view->moveSection(from: from.at(i), to: to.at(i)); |
| 1016 | QCOMPARE(view->sectionsMoved(), moved.at(i)); |
| 1017 | } |
| 1018 | |
| 1019 | for (int j = 0; j < view->count(); ++j) |
| 1020 | QCOMPARE(view->logicalIndex(j), logical.at(j)); |
| 1021 | |
| 1022 | QCOMPARE(spy1.count(), count); |
| 1023 | } |
| 1024 | |
| 1025 | void tst_QHeaderView::resizeAndMoveSection_data() |
| 1026 | { |
| 1027 | QTest::addColumn<IntList>(name: "logicalIndexes" ); |
| 1028 | QTest::addColumn<IntList>(name: "sizes" ); |
| 1029 | QTest::addColumn<int>(name: "logicalFrom" ); |
| 1030 | QTest::addColumn<int>(name: "logicalTo" ); |
| 1031 | |
| 1032 | QTest::newRow(dataTag: "resizeAndMove-1" ) |
| 1033 | << (IntList{ 0, 1 }) |
| 1034 | << (IntList{ 20, 40 }) |
| 1035 | << 0 << 1; |
| 1036 | |
| 1037 | QTest::newRow(dataTag: "resizeAndMove-2" ) |
| 1038 | << (IntList{ 0, 1, 2, 3 }) |
| 1039 | << (IntList{ 20, 60, 10, 80 }) |
| 1040 | << 0 << 2; |
| 1041 | |
| 1042 | QTest::newRow(dataTag: "resizeAndMove-3" ) |
| 1043 | << (IntList{ 0, 1, 2, 3 }) |
| 1044 | << (IntList{ 100, 60, 40, 10 }) |
| 1045 | << 0 << 3; |
| 1046 | |
| 1047 | QTest::newRow(dataTag: "resizeAndMove-4" ) |
| 1048 | << (IntList{ 0, 1, 2, 3 }) |
| 1049 | << (IntList{ 10, 40, 80, 30 }) |
| 1050 | << 1 << 2; |
| 1051 | |
| 1052 | QTest::newRow(dataTag: "resizeAndMove-5" ) |
| 1053 | << (IntList{ 2, 3 }) |
| 1054 | << (IntList{ 100, 200}) |
| 1055 | << 3 << 2; |
| 1056 | } |
| 1057 | |
| 1058 | void tst_QHeaderView::resizeAndMoveSection() |
| 1059 | { |
| 1060 | QFETCH(const IntList, logicalIndexes); |
| 1061 | QFETCH(const IntList, sizes); |
| 1062 | QFETCH(int, logicalFrom); |
| 1063 | QFETCH(int, logicalTo); |
| 1064 | |
| 1065 | // Save old visual indexes and sizes |
| 1066 | IntList oldVisualIndexes; |
| 1067 | IntList oldSizes; |
| 1068 | for (int logical : logicalIndexes) { |
| 1069 | oldVisualIndexes.append(t: view->visualIndex(logicalIndex: logical)); |
| 1070 | oldSizes.append(t: view->sectionSize(logicalIndex: logical)); |
| 1071 | } |
| 1072 | |
| 1073 | // Resize sections |
| 1074 | for (int i = 0; i < logicalIndexes.size(); ++i) { |
| 1075 | int logical = logicalIndexes.at(i); |
| 1076 | view->resizeSection(logicalIndex: logical, size: sizes.at(i)); |
| 1077 | } |
| 1078 | |
| 1079 | // Move sections |
| 1080 | int visualFrom = view->visualIndex(logicalIndex: logicalFrom); |
| 1081 | int visualTo = view->visualIndex(logicalIndex: logicalTo); |
| 1082 | view->moveSection(from: visualFrom, to: visualTo); |
| 1083 | QCOMPARE(view->visualIndex(logicalFrom), visualTo); |
| 1084 | |
| 1085 | // Check that sizes are still correct |
| 1086 | for (int i = 0; i < logicalIndexes.size(); ++i) { |
| 1087 | int logical = logicalIndexes.at(i); |
| 1088 | QCOMPARE(view->sectionSize(logical), sizes.at(i)); |
| 1089 | } |
| 1090 | |
| 1091 | // Move sections back |
| 1092 | view->moveSection(from: visualTo, to: visualFrom); |
| 1093 | |
| 1094 | // Check that sizes are still correct |
| 1095 | for (int i = 0; i < logicalIndexes.size(); ++i) { |
| 1096 | int logical = logicalIndexes.at(i); |
| 1097 | QCOMPARE(view->sectionSize(logical), sizes.at(i)); |
| 1098 | } |
| 1099 | |
| 1100 | // Put everything back as it was |
| 1101 | for (int i = 0; i < logicalIndexes.size(); ++i) { |
| 1102 | int logical = logicalIndexes.at(i); |
| 1103 | view->resizeSection(logicalIndex: logical, size: oldSizes.at(i)); |
| 1104 | QCOMPARE(view->visualIndex(logical), oldVisualIndexes.at(i)); |
| 1105 | } |
| 1106 | } |
| 1107 | |
| 1108 | void tst_QHeaderView::() |
| 1109 | { |
| 1110 | QTest::addColumn<int>(name: "section" ); |
| 1111 | QTest::addColumn<int>(name: "initialSize" ); |
| 1112 | QTest::addColumn<int>(name: "finalSize" ); |
| 1113 | |
| 1114 | QTest::newRow(dataTag: "section 0 resize 50 to 20" ) |
| 1115 | << 0 << 50 << 20; |
| 1116 | |
| 1117 | QTest::newRow(dataTag: "section 1 resize 50 to 20" ) |
| 1118 | << 1 << 50 << 20; |
| 1119 | |
| 1120 | QTest::newRow(dataTag: "section 2 resize 50 to 20" ) |
| 1121 | << 2 << 50 << 20; |
| 1122 | |
| 1123 | QTest::newRow(dataTag: "section 3 resize 50 to 20" ) |
| 1124 | << 3 << 50 << 20; |
| 1125 | } |
| 1126 | |
| 1127 | void tst_QHeaderView::() |
| 1128 | { |
| 1129 | QFETCH(int, section); |
| 1130 | QFETCH(int, initialSize); |
| 1131 | QFETCH(int, finalSize); |
| 1132 | |
| 1133 | view->resizeSection(logicalIndex: section, size: initialSize); |
| 1134 | view->setSectionHidden(logicalIndex: section, hide: true); |
| 1135 | QCOMPARE(view->sectionSize(section), 0); |
| 1136 | |
| 1137 | view->resizeSection(logicalIndex: section, size: finalSize); |
| 1138 | QCOMPARE(view->sectionSize(section), 0); |
| 1139 | |
| 1140 | view->setSectionHidden(logicalIndex: section, hide: false); |
| 1141 | QCOMPARE(view->sectionSize(section), finalSize); |
| 1142 | } |
| 1143 | |
| 1144 | void tst_QHeaderView::resizeAndInsertSection_data() |
| 1145 | { |
| 1146 | QTest::addColumn<int>(name: "section" ); |
| 1147 | QTest::addColumn<int>(name: "size" ); |
| 1148 | QTest::addColumn<int>(name: "insert" ); |
| 1149 | QTest::addColumn<int>(name: "compare" ); |
| 1150 | QTest::addColumn<int>(name: "expected" ); |
| 1151 | |
| 1152 | QTest::newRow(dataTag: "section 0 size 50 insert 0" ) |
| 1153 | << 0 << 50 << 0 << 1 << 50; |
| 1154 | |
| 1155 | QTest::newRow(dataTag: "section 1 size 50 insert 1" ) |
| 1156 | << 0 << 50 << 1 << 0 << 50; |
| 1157 | |
| 1158 | QTest::newRow(dataTag: "section 1 size 50 insert 0" ) |
| 1159 | << 1 << 50 << 0 << 2 << 50; |
| 1160 | |
| 1161 | } |
| 1162 | |
| 1163 | void tst_QHeaderView::resizeAndInsertSection() |
| 1164 | { |
| 1165 | QFETCH(int, section); |
| 1166 | QFETCH(int, size); |
| 1167 | QFETCH(int, insert); |
| 1168 | QFETCH(int, compare); |
| 1169 | QFETCH(int, expected); |
| 1170 | |
| 1171 | view->setStretchLastSection(false); |
| 1172 | |
| 1173 | view->resizeSection(logicalIndex: section, size); |
| 1174 | QCOMPARE(view->sectionSize(section), size); |
| 1175 | |
| 1176 | model->insertRow(arow: insert); |
| 1177 | |
| 1178 | QCOMPARE(view->sectionSize(compare), expected); |
| 1179 | } |
| 1180 | |
| 1181 | void tst_QHeaderView::() |
| 1182 | { |
| 1183 | QTest::addColumn<int>(name: "size" ); |
| 1184 | QTest::addColumn<IntList>(name: "sections" ); |
| 1185 | QTest::addColumn<ResizeVec>(name: "modes" ); |
| 1186 | QTest::addColumn<IntList>(name: "expected" ); |
| 1187 | |
| 1188 | QTest::newRow(dataTag: "stretch first section" ) |
| 1189 | << 600 |
| 1190 | << (IntList{ 100, 100, 100, 100 }) |
| 1191 | << (ResizeVec |
| 1192 | { QHeaderView::Stretch, |
| 1193 | QHeaderView::Interactive, |
| 1194 | QHeaderView::Interactive, |
| 1195 | QHeaderView::Interactive }) |
| 1196 | << (IntList{ 300, 100, 100, 100 }); |
| 1197 | } |
| 1198 | |
| 1199 | void tst_QHeaderView::() |
| 1200 | { |
| 1201 | QFETCH(int, size); |
| 1202 | QFETCH(const IntList, sections); |
| 1203 | QFETCH(const ResizeVec, modes); |
| 1204 | QFETCH(const IntList, expected); |
| 1205 | |
| 1206 | view->setStretchLastSection(false); |
| 1207 | for (int i = 0; i < sections.count(); ++i) { |
| 1208 | view->resizeSection(logicalIndex: i, size: sections.at(i)); |
| 1209 | view->setSectionResizeMode(logicalIndex: i, mode: modes.at(i)); |
| 1210 | } |
| 1211 | topLevel->show(); |
| 1212 | QVERIFY(QTest::qWaitForWindowExposed(topLevel)); |
| 1213 | view->resize(w: size, h: size); |
| 1214 | for (int j = 0; j < expected.count(); ++j) |
| 1215 | QCOMPARE(view->sectionSize(j), expected.at(j)); |
| 1216 | } |
| 1217 | |
| 1218 | void tst_QHeaderView::moveAndInsertSection_data() |
| 1219 | { |
| 1220 | QTest::addColumn<int>(name: "from" ); |
| 1221 | QTest::addColumn<int>(name: "to" ); |
| 1222 | QTest::addColumn<int>(name: "insert" ); |
| 1223 | QTest::addColumn<IntList>(name: "mapping" ); |
| 1224 | |
| 1225 | QTest::newRow(dataTag: "move from 1 to 3, insert 0" ) |
| 1226 | << 1 << 3 << 0 <<(IntList{ 0, 1, 3, 4, 2 }); |
| 1227 | |
| 1228 | } |
| 1229 | |
| 1230 | void tst_QHeaderView::moveAndInsertSection() |
| 1231 | { |
| 1232 | QFETCH(int, from); |
| 1233 | QFETCH(int, to); |
| 1234 | QFETCH(int, insert); |
| 1235 | QFETCH(IntList, mapping); |
| 1236 | |
| 1237 | view->setStretchLastSection(false); |
| 1238 | view->moveSection(from, to); |
| 1239 | model->insertRow(arow: insert); |
| 1240 | |
| 1241 | for (int i = 0; i < mapping.count(); ++i) |
| 1242 | QCOMPARE(view->logicalIndex(i), mapping.at(i)); |
| 1243 | } |
| 1244 | |
| 1245 | void tst_QHeaderView::() |
| 1246 | { |
| 1247 | // resizeMode must not be called with an invalid index |
| 1248 | int last = view->count() - 1; |
| 1249 | view->setSectionResizeMode(QHeaderView::Interactive); |
| 1250 | QCOMPARE(view->sectionResizeMode(last), QHeaderView::Interactive); |
| 1251 | QCOMPARE(view->sectionResizeMode(1), QHeaderView::Interactive); |
| 1252 | view->setSectionResizeMode(QHeaderView::Stretch); |
| 1253 | QCOMPARE(view->sectionResizeMode(last), QHeaderView::Stretch); |
| 1254 | QCOMPARE(view->sectionResizeMode(1), QHeaderView::Stretch); |
| 1255 | view->setSectionResizeMode(QHeaderView::Custom); |
| 1256 | QCOMPARE(view->sectionResizeMode(last), QHeaderView::Custom); |
| 1257 | QCOMPARE(view->sectionResizeMode(1), QHeaderView::Custom); |
| 1258 | |
| 1259 | // test when sections have been moved |
| 1260 | view->setStretchLastSection(false); |
| 1261 | for (int i = 0; i < (view->count() - 1); ++i) |
| 1262 | view->setSectionResizeMode(logicalIndex: i, mode: QHeaderView::Interactive); |
| 1263 | int logicalIndex = view->count() / 2; |
| 1264 | view->setSectionResizeMode(logicalIndex, mode: QHeaderView::Stretch); |
| 1265 | view->moveSection(from: view->visualIndex(logicalIndex), to: 0); |
| 1266 | for (int i = 0; i < (view->count() - 1); ++i) { |
| 1267 | if (i == logicalIndex) |
| 1268 | QCOMPARE(view->sectionResizeMode(i), QHeaderView::Stretch); |
| 1269 | else |
| 1270 | QCOMPARE(view->sectionResizeMode(i), QHeaderView::Interactive); |
| 1271 | } |
| 1272 | } |
| 1273 | |
| 1274 | void tst_QHeaderView::() |
| 1275 | { |
| 1276 | QTest::addColumn<int>(name: "initial" ); |
| 1277 | QTest::addColumn<IntList>(name: "logical" ); |
| 1278 | QTest::addColumn<IntList>(name: "size" ); |
| 1279 | QTest::addColumn<ResizeVec>(name: "mode" ); |
| 1280 | QTest::addColumn<int>(name: "resized" ); |
| 1281 | QTest::addColumn<IntList>(name: "expected" ); |
| 1282 | |
| 1283 | QTest::newRow(dataTag: "bad args" ) |
| 1284 | << 100 |
| 1285 | << (IntList{ -1, -1, 99999, 99999, 4 }) |
| 1286 | << (IntList{ -1, 0, 99999, -1, -1 }) |
| 1287 | << (ResizeVec{ |
| 1288 | QHeaderView::Interactive, |
| 1289 | QHeaderView::Interactive, |
| 1290 | QHeaderView::Interactive, |
| 1291 | QHeaderView::Interactive }) |
| 1292 | << 0 |
| 1293 | << (IntList{ 0, 0, 0, 0, 0 }); |
| 1294 | } |
| 1295 | |
| 1296 | void tst_QHeaderView::() |
| 1297 | { |
| 1298 | QFETCH(int, initial); |
| 1299 | QFETCH(const IntList, logical); |
| 1300 | QFETCH(const IntList, size); |
| 1301 | QFETCH(const ResizeVec, mode); |
| 1302 | QFETCH(int, resized); |
| 1303 | QFETCH(const IntList, expected); |
| 1304 | |
| 1305 | view->resize(w: 400, h: 400); |
| 1306 | |
| 1307 | topLevel->show(); |
| 1308 | QVERIFY(QTest::qWaitForWindowExposed(topLevel)); |
| 1309 | view->setSectionsMovable(true); |
| 1310 | view->setStretchLastSection(false); |
| 1311 | |
| 1312 | for (int i = 0; i < logical.count(); ++i) |
| 1313 | if (logical.at(i) > -1 && logical.at(i) < view->count()) // for now |
| 1314 | view->setSectionResizeMode(logicalIndex: logical.at(i), mode: mode.at(i)); |
| 1315 | |
| 1316 | for (int j = 0; j < logical.count(); ++j) |
| 1317 | view->resizeSection(logicalIndex: logical.at(i: j), size: initial); |
| 1318 | |
| 1319 | QSignalSpy spy(view, &QHeaderView::sectionResized); |
| 1320 | |
| 1321 | for (int k = 0; k < logical.count(); ++k) |
| 1322 | view->resizeSection(logicalIndex: logical.at(i: k), size: size.at(i: k)); |
| 1323 | |
| 1324 | QCOMPARE(spy.count(), resized); |
| 1325 | |
| 1326 | for (int l = 0; l < logical.count(); ++l) |
| 1327 | QCOMPARE(view->sectionSize(logical.at(l)), expected.at(l)); |
| 1328 | } |
| 1329 | |
| 1330 | void tst_QHeaderView::() |
| 1331 | { |
| 1332 | view->setHighlightSections(true); |
| 1333 | QCOMPARE(view->highlightSections(), true); |
| 1334 | view->setHighlightSections(false); |
| 1335 | QCOMPARE(view->highlightSections(), false); |
| 1336 | } |
| 1337 | |
| 1338 | void tst_QHeaderView::() |
| 1339 | { |
| 1340 | view->setSortIndicatorShown(true); |
| 1341 | QCOMPARE(view->isSortIndicatorShown(), true); |
| 1342 | QCOMPARE(view->sortIndicatorOrder(), Qt::DescendingOrder); |
| 1343 | view->setSortIndicator(logicalIndex: 1, order: Qt::AscendingOrder); |
| 1344 | QCOMPARE(view->sortIndicatorOrder(), Qt::AscendingOrder); |
| 1345 | view->setSortIndicator(logicalIndex: 1, order: Qt::DescendingOrder); |
| 1346 | QCOMPARE(view->sortIndicatorOrder(), Qt::DescendingOrder); |
| 1347 | view->setSortIndicatorShown(false); |
| 1348 | QCOMPARE(view->isSortIndicatorShown(), false); |
| 1349 | |
| 1350 | view->setSortIndicator(logicalIndex: 999999, order: Qt::DescendingOrder); |
| 1351 | // Don't segfault baby :) |
| 1352 | view->setSortIndicatorShown(true); |
| 1353 | |
| 1354 | view->setSortIndicator(logicalIndex: 0, order: Qt::DescendingOrder); |
| 1355 | // Don't assert baby :) |
| 1356 | } |
| 1357 | |
| 1358 | void tst_QHeaderView::() |
| 1359 | { |
| 1360 | QtTestModel model(10, 10); |
| 1361 | QHeaderView hv(Qt::Horizontal); |
| 1362 | |
| 1363 | hv.setModel(&model); |
| 1364 | hv.show(); |
| 1365 | hv.setSortIndicatorShown(true); |
| 1366 | hv.setSortIndicator(logicalIndex: 1, order: Qt::DescendingOrder); |
| 1367 | |
| 1368 | model.removeOneColumn(col: 8); |
| 1369 | QCOMPARE(hv.sortIndicatorSection(), 1); |
| 1370 | |
| 1371 | model.removeOneColumn(col: 2); |
| 1372 | QCOMPARE(hv.sortIndicatorSection(), 1); |
| 1373 | |
| 1374 | model.insertOneColumn(col: 2); |
| 1375 | QCOMPARE(hv.sortIndicatorSection(), 1); |
| 1376 | |
| 1377 | model.insertOneColumn(col: 1); |
| 1378 | QCOMPARE(hv.sortIndicatorSection(), 2); |
| 1379 | |
| 1380 | model.removeOneColumn(col: 0); |
| 1381 | QCOMPARE(hv.sortIndicatorSection(), 1); |
| 1382 | |
| 1383 | model.removeOneColumn(col: 1); |
| 1384 | QCOMPARE(hv.sortIndicatorSection(), -1); |
| 1385 | } |
| 1386 | |
| 1387 | void tst_QHeaderView::removeAndInsertRow() |
| 1388 | { |
| 1389 | // Check if logicalIndex returns the correct value after we have removed a row |
| 1390 | // we might as well te |
| 1391 | for (int i = 0; i < model->rowCount(); ++i) |
| 1392 | QCOMPARE(i, view->logicalIndex(i)); |
| 1393 | |
| 1394 | while (model->removeRow(arow: 0)) { |
| 1395 | for (int i = 0; i < model->rowCount(); ++i) |
| 1396 | QCOMPARE(i, view->logicalIndex(i)); |
| 1397 | } |
| 1398 | |
| 1399 | for (int pass = 0; pass < 5; pass++) { |
| 1400 | for (int i = 0; i < model->rowCount(); ++i) |
| 1401 | QCOMPARE(i, view->logicalIndex(i)); |
| 1402 | model->insertRow(arow: 0); |
| 1403 | } |
| 1404 | |
| 1405 | while (model->removeRows(row: 0, count: 2)) { |
| 1406 | for (int i = 0; i < model->rowCount(); ++i) |
| 1407 | QCOMPARE(i, view->logicalIndex(i)); |
| 1408 | } |
| 1409 | |
| 1410 | for (int pass = 0; pass < 3; pass++) { |
| 1411 | model->insertRows(row: 0, count: 2); |
| 1412 | for (int i = 0; i < model->rowCount(); ++i) { |
| 1413 | QCOMPARE(i, view->logicalIndex(i)); |
| 1414 | } |
| 1415 | } |
| 1416 | |
| 1417 | for (int pass = 0; pass < 3; pass++) { |
| 1418 | model->insertRows(row: 3, count: 2); |
| 1419 | for (int i = 0; i < model->rowCount(); ++i) |
| 1420 | QCOMPARE(i, view->logicalIndex(i)); |
| 1421 | } |
| 1422 | |
| 1423 | // Insert at end |
| 1424 | for (int pass = 0; pass < 3; pass++) { |
| 1425 | int rowCount = model->rowCount(); |
| 1426 | model->insertRows(row: rowCount, count: 1); |
| 1427 | for (int i = 0; i < rowCount; ++i) |
| 1428 | QCOMPARE(i, view->logicalIndex(i)); |
| 1429 | } |
| 1430 | |
| 1431 | } |
| 1432 | void tst_QHeaderView::() |
| 1433 | { |
| 1434 | // You should not necessarily expect the same size back again, so the best test we can do is to test if it is larger than 0 after a unhide. |
| 1435 | QCOMPARE(view->sectionsHidden(), false); |
| 1436 | view->setSectionHidden(logicalIndex: 0, hide: true); |
| 1437 | QCOMPARE(view->sectionsHidden(), true); |
| 1438 | QCOMPARE(view->sectionSize(0), 0); |
| 1439 | view->setSectionResizeMode(QHeaderView::Interactive); |
| 1440 | view->setSectionHidden(logicalIndex: 0, hide: false); |
| 1441 | QVERIFY(view->sectionSize(0) > 0); |
| 1442 | |
| 1443 | view->setSectionHidden(logicalIndex: 0, hide: true); |
| 1444 | QCOMPARE(view->sectionSize(0), 0); |
| 1445 | view->setSectionHidden(logicalIndex: 0, hide: true); |
| 1446 | QCOMPARE(view->sectionSize(0), 0); |
| 1447 | view->setSectionResizeMode(QHeaderView::Stretch); |
| 1448 | view->setSectionHidden(logicalIndex: 0, hide: false); |
| 1449 | QVERIFY(view->sectionSize(0) > 0); |
| 1450 | |
| 1451 | } |
| 1452 | |
| 1453 | void tst_QHeaderView::() |
| 1454 | { |
| 1455 | protected_QHeaderView x(Qt::Vertical); |
| 1456 | x.testEvent(); |
| 1457 | protected_QHeaderView y(Qt::Horizontal); |
| 1458 | y.testEvent(); |
| 1459 | } |
| 1460 | |
| 1461 | |
| 1462 | void protected_QHeaderView::() |
| 1463 | { |
| 1464 | // No crashy please |
| 1465 | QHoverEvent enterEvent(QEvent::HoverEnter, QPoint(), QPoint()); |
| 1466 | event(e: &enterEvent); |
| 1467 | QHoverEvent eventLeave(QEvent::HoverLeave, QPoint(), QPoint()); |
| 1468 | event(e: &eventLeave); |
| 1469 | QHoverEvent eventMove(QEvent::HoverMove, QPoint(), QPoint()); |
| 1470 | event(e: &eventMove); |
| 1471 | } |
| 1472 | |
| 1473 | void tst_QHeaderView::() |
| 1474 | { |
| 1475 | // This shouldn't assert because view is Vertical |
| 1476 | view->headerDataChanged(orientation: Qt::Horizontal, logicalFirst: -1, logicalLast: -1); |
| 1477 | #if 0 |
| 1478 | // This will assert |
| 1479 | view->headerDataChanged(Qt::Vertical, -1, -1); |
| 1480 | #endif |
| 1481 | |
| 1482 | // No crashing please |
| 1483 | view->headerDataChanged(orientation: Qt::Horizontal, logicalFirst: 0, logicalLast: 1); |
| 1484 | view->headerDataChanged(orientation: Qt::Vertical, logicalFirst: 0, logicalLast: 1); |
| 1485 | } |
| 1486 | |
| 1487 | void tst_QHeaderView::() |
| 1488 | { |
| 1489 | view->setCurrentIndex(QModelIndex()); |
| 1490 | } |
| 1491 | |
| 1492 | void tst_QHeaderView::() |
| 1493 | { |
| 1494 | protected_QHeaderView x(Qt::Vertical); |
| 1495 | x.testhorizontalOffset(); |
| 1496 | protected_QHeaderView y(Qt::Horizontal); |
| 1497 | y.testhorizontalOffset(); |
| 1498 | } |
| 1499 | |
| 1500 | void tst_QHeaderView::() |
| 1501 | { |
| 1502 | protected_QHeaderView x(Qt::Vertical); |
| 1503 | x.testverticalOffset(); |
| 1504 | protected_QHeaderView y(Qt::Horizontal); |
| 1505 | y.testverticalOffset(); |
| 1506 | } |
| 1507 | |
| 1508 | void protected_QHeaderView::() |
| 1509 | { |
| 1510 | if (orientation() == Qt::Horizontal) { |
| 1511 | QCOMPARE(horizontalOffset(), 0); |
| 1512 | setOffset(10); |
| 1513 | QCOMPARE(horizontalOffset(), 10); |
| 1514 | } |
| 1515 | else |
| 1516 | QCOMPARE(horizontalOffset(), 0); |
| 1517 | } |
| 1518 | |
| 1519 | void protected_QHeaderView::() |
| 1520 | { |
| 1521 | if (orientation() == Qt::Vertical) { |
| 1522 | QCOMPARE(verticalOffset(), 0); |
| 1523 | setOffset(10); |
| 1524 | QCOMPARE(verticalOffset(), 10); |
| 1525 | } |
| 1526 | else |
| 1527 | QCOMPARE(verticalOffset(), 0); |
| 1528 | } |
| 1529 | |
| 1530 | void tst_QHeaderView::() |
| 1531 | { |
| 1532 | view->setStretchLastSection(false); |
| 1533 | QCOMPARE(view->stretchSectionCount(), 0); |
| 1534 | view->setStretchLastSection(true); |
| 1535 | QCOMPARE(view->stretchSectionCount(), 0); |
| 1536 | |
| 1537 | view->setSectionResizeMode(logicalIndex: 0, mode: QHeaderView::Stretch); |
| 1538 | QCOMPARE(view->stretchSectionCount(), 1); |
| 1539 | } |
| 1540 | |
| 1541 | void tst_QHeaderView::() |
| 1542 | { |
| 1543 | model->clear(); |
| 1544 | model->insertRows(row: 0, count: 10); |
| 1545 | // Hide every other one |
| 1546 | for (int i = 0; i < 10; i++) |
| 1547 | view->setSectionHidden(logicalIndex: i, hide: (i & 1) == 0); |
| 1548 | |
| 1549 | QCOMPARE(view->hiddenSectionCount(), 5); |
| 1550 | |
| 1551 | view->setSectionResizeMode(QHeaderView::Stretch); |
| 1552 | QCOMPARE(view->hiddenSectionCount(), 5); |
| 1553 | |
| 1554 | // Remove some rows and make sure they are now still counted |
| 1555 | model->removeRow(arow: 9); |
| 1556 | model->removeRow(arow: 8); |
| 1557 | model->removeRow(arow: 7); |
| 1558 | model->removeRow(arow: 6); |
| 1559 | QCOMPARE(view->count(), 6); |
| 1560 | QCOMPARE(view->hiddenSectionCount(), 3); |
| 1561 | model->removeRows(row: 0, count: 5); |
| 1562 | QCOMPARE(view->count(), 1); |
| 1563 | QCOMPARE(view->hiddenSectionCount(), 0); |
| 1564 | QVERIFY(view->count() >= view->hiddenSectionCount()); |
| 1565 | } |
| 1566 | |
| 1567 | void tst_QHeaderView::() |
| 1568 | { |
| 1569 | if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) |
| 1570 | QSKIP("Wayland: This fails. Figure out why." ); |
| 1571 | |
| 1572 | QHeaderView view(Qt::Horizontal); |
| 1573 | QCOMPARE(view.focusPolicy(), Qt::NoFocus); |
| 1574 | |
| 1575 | QTreeWidget widget; |
| 1576 | QCOMPARE(widget.header()->focusPolicy(), Qt::NoFocus); |
| 1577 | QVERIFY(!widget.focusProxy()); |
| 1578 | QVERIFY(!widget.hasFocus()); |
| 1579 | QVERIFY(!widget.header()->focusProxy()); |
| 1580 | QVERIFY(!widget.header()->hasFocus()); |
| 1581 | |
| 1582 | widget.show(); |
| 1583 | widget.setFocus(Qt::OtherFocusReason); |
| 1584 | QApplication::setActiveWindow(&widget); |
| 1585 | widget.activateWindow(); |
| 1586 | QVERIFY(QTest::qWaitForWindowActive(&widget)); |
| 1587 | QVERIFY(widget.hasFocus()); |
| 1588 | QVERIFY(!widget.header()->hasFocus()); |
| 1589 | |
| 1590 | widget.setFocusPolicy(Qt::NoFocus); |
| 1591 | widget.clearFocus(); |
| 1592 | QTRY_VERIFY(!widget.hasFocus()); |
| 1593 | QVERIFY(!widget.header()->hasFocus()); |
| 1594 | |
| 1595 | QTest::keyPress(widget: &widget, key: Qt::Key_Tab); |
| 1596 | |
| 1597 | QCoreApplication::processEvents(); |
| 1598 | QCoreApplication::processEvents(); |
| 1599 | |
| 1600 | QVERIFY(!widget.hasFocus()); |
| 1601 | QVERIFY(!widget.header()->hasFocus()); |
| 1602 | } |
| 1603 | |
| 1604 | class SimpleModel : public QAbstractItemModel |
| 1605 | { |
| 1606 | Q_OBJECT |
| 1607 | public: |
| 1608 | using QAbstractItemModel::QAbstractItemModel; |
| 1609 | QModelIndex parent(const QModelIndex &/*child*/) const override |
| 1610 | { |
| 1611 | return QModelIndex(); |
| 1612 | } |
| 1613 | QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override |
| 1614 | { |
| 1615 | return hasIndex(row, column, parent) ? createIndex(arow: row, acolumn: column) : QModelIndex(); |
| 1616 | } |
| 1617 | int rowCount(const QModelIndex & /*parent*/ = QModelIndex()) const override |
| 1618 | { |
| 1619 | return 8; |
| 1620 | } |
| 1621 | int columnCount(const QModelIndex &/*parent*/ = QModelIndex()) const override |
| 1622 | { |
| 1623 | return m_col_count; |
| 1624 | } |
| 1625 | QVariant data(const QModelIndex &index, int role) const override |
| 1626 | { |
| 1627 | if (!index.isValid()) |
| 1628 | return QVariant(); |
| 1629 | if (role == Qt::DisplayRole) |
| 1630 | return QString::number(index.row()) + QLatin1Char(',') + QString::number(index.column()); |
| 1631 | return QVariant(); |
| 1632 | } |
| 1633 | void setColumnCount(int c) |
| 1634 | { |
| 1635 | m_col_count = c; |
| 1636 | } |
| 1637 | private: |
| 1638 | int m_col_count = 3; |
| 1639 | }; |
| 1640 | |
| 1641 | void tst_QHeaderView::moveSectionAndReset() |
| 1642 | { |
| 1643 | SimpleModel m; |
| 1644 | QHeaderView v(Qt::Horizontal); |
| 1645 | v.setModel(&m); |
| 1646 | int cc = 2; |
| 1647 | for (cc = 2; cc < 4; ++cc) { |
| 1648 | m.setColumnCount(cc); |
| 1649 | int movefrom = 0; |
| 1650 | int moveto; |
| 1651 | for (moveto = 1; moveto < cc; ++moveto) { |
| 1652 | v.moveSection(from: movefrom, to: moveto); |
| 1653 | m.setColumnCount(cc - 1); |
| 1654 | v.reset(); |
| 1655 | for (int i = 0; i < cc - 1; ++i) |
| 1656 | QCOMPARE(v.logicalIndex(v.visualIndex(i)), i); |
| 1657 | } |
| 1658 | } |
| 1659 | } |
| 1660 | |
| 1661 | void tst_QHeaderView::moveSectionAndRemove() |
| 1662 | { |
| 1663 | QStandardItemModel m; |
| 1664 | QHeaderView v(Qt::Horizontal); |
| 1665 | |
| 1666 | v.setModel(&m); |
| 1667 | v.model()->insertColumns(column: 0, count: 3); |
| 1668 | v.moveSection(from: 0, to: 1); |
| 1669 | |
| 1670 | QCOMPARE(v.count(), 3); |
| 1671 | v.model()->removeColumns(column: 0, count: v.model()->columnCount()); |
| 1672 | QCOMPARE(v.count(), 0); |
| 1673 | } |
| 1674 | |
| 1675 | static QByteArray savedState() |
| 1676 | { |
| 1677 | QStandardItemModel m(4, 4); |
| 1678 | QHeaderView h1(Qt::Horizontal); |
| 1679 | h1.setModel(&m); |
| 1680 | h1.setMinimumSectionSize(0); // system default min size can be to large |
| 1681 | h1.swapSections(first: 0, second: 2); |
| 1682 | h1.resizeSection(logicalIndex: 1, size: 10); |
| 1683 | h1.setSortIndicatorShown(true); |
| 1684 | h1.setSortIndicator(logicalIndex: 2, order: Qt::DescendingOrder); |
| 1685 | h1.setSectionHidden(logicalIndex: 3, hide: true); |
| 1686 | return h1.saveState(); |
| 1687 | } |
| 1688 | |
| 1689 | void tst_QHeaderView::() |
| 1690 | { |
| 1691 | QStandardItemModel m(4, 4); |
| 1692 | const QByteArray s1 = savedState(); |
| 1693 | |
| 1694 | QHeaderView h2(Qt::Vertical); |
| 1695 | QSignalSpy spy(&h2, &QHeaderView::sortIndicatorChanged); |
| 1696 | |
| 1697 | h2.setModel(&m); |
| 1698 | QVERIFY(h2.restoreState(s1)); |
| 1699 | |
| 1700 | QCOMPARE(spy.count(), 1); |
| 1701 | QCOMPARE(spy.at(0).at(0).toInt(), 2); |
| 1702 | |
| 1703 | QCOMPARE(h2.logicalIndex(0), 2); |
| 1704 | QCOMPARE(h2.logicalIndex(2), 0); |
| 1705 | QCOMPARE(h2.sectionSize(1), 10); |
| 1706 | QCOMPARE(h2.sortIndicatorSection(), 2); |
| 1707 | QCOMPARE(h2.sortIndicatorOrder(), Qt::DescendingOrder); |
| 1708 | QCOMPARE(h2.isSortIndicatorShown(), true); |
| 1709 | QVERIFY(!h2.isSectionHidden(2)); |
| 1710 | QVERIFY(h2.isSectionHidden(3)); |
| 1711 | QCOMPARE(h2.hiddenSectionCount(), 1); |
| 1712 | |
| 1713 | QByteArray s2 = h2.saveState(); |
| 1714 | QCOMPARE(s1, s2); |
| 1715 | |
| 1716 | QVERIFY(!h2.restoreState(QByteArrayLiteral("Garbage" ))); |
| 1717 | } |
| 1718 | |
| 1719 | void tst_QHeaderView::() |
| 1720 | { |
| 1721 | #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) |
| 1722 | // QTBUG-40462 |
| 1723 | // Setting from Qt4, where information about multiple sections were grouped together in one |
| 1724 | // sectionItem object |
| 1725 | QStandardItemModel m(4, 10); |
| 1726 | QHeaderView h2(Qt::Vertical); |
| 1727 | QByteArray settings_qt4 = |
| 1728 | QByteArray::fromHex(hexEncoded: "000000ff00000000000000010000000100000000010000000000000000000000000000" |
| 1729 | "0000000003e80000000a0101000100000000000000000000000064ffffffff00000081" |
| 1730 | "0000000000000001000003e80000000a00000000" ); |
| 1731 | QVERIFY(h2.restoreState(settings_qt4)); |
| 1732 | int sectionItemsLengthTotal = 0; |
| 1733 | for (int i = 0; i < h2.count(); ++i) |
| 1734 | sectionItemsLengthTotal += h2.sectionSize(logicalIndex: i); |
| 1735 | QCOMPARE(sectionItemsLengthTotal, h2.length()); |
| 1736 | |
| 1737 | // Buggy setting where sum(sectionItems) != length. Check false is returned and this corrupted |
| 1738 | // state isn't restored |
| 1739 | QByteArray settings_buggy_length = |
| 1740 | QByteArray::fromHex(hexEncoded: "000000ff000000000000000100000000000000050100000000000000000000000a4000" |
| 1741 | "000000010000000600000258000000fb0000000a010100010000000000000000000000" |
| 1742 | "0064ffffffff00000081000000000000000a000000d30000000100000000000000c800" |
| 1743 | "000001000000000000008000000001000000000000005c00000001000000000000003c" |
| 1744 | "0000000100000000000002580000000100000000000000000000000100000000000002" |
| 1745 | "580000000100000000000002580000000100000000000003c000000001000000000000" |
| 1746 | "03e8" ); |
| 1747 | int old_length = h2.length(); |
| 1748 | QByteArray old_state = h2.saveState(); |
| 1749 | // Check setting is correctly recognized as corrupted |
| 1750 | QVERIFY(!h2.restoreState(settings_buggy_length)); |
| 1751 | // Check nothing has been actually restored |
| 1752 | QCOMPARE(h2.length(), old_length); |
| 1753 | QCOMPARE(h2.saveState(), old_state); |
| 1754 | #else |
| 1755 | QSKIP("Qt4 compatibility no longer needed in Qt6" ) |
| 1756 | #endif |
| 1757 | } |
| 1758 | |
| 1759 | void tst_QHeaderView::restoreToMoreColumns() |
| 1760 | { |
| 1761 | // Restore state onto a model with more columns |
| 1762 | const QByteArray s1 = savedState(); |
| 1763 | QHeaderView h4(Qt::Horizontal); |
| 1764 | QStandardItemModel fiveColumnsModel(1, 5); |
| 1765 | h4.setModel(&fiveColumnsModel); |
| 1766 | QCOMPARE(fiveColumnsModel.columnCount(), 5); |
| 1767 | QCOMPARE(h4.count(), 5); |
| 1768 | QVERIFY(h4.restoreState(s1)); |
| 1769 | QCOMPARE(fiveColumnsModel.columnCount(), 5); |
| 1770 | QCOMPARE(h4.count(), 5); |
| 1771 | QCOMPARE(h4.sectionSize(1), 10); |
| 1772 | for (int i = 0; i < h4.count(); ++i) |
| 1773 | QVERIFY(h4.sectionSize(i) > 0 || h4.isSectionHidden(i)); |
| 1774 | QVERIFY(!h4.isSectionHidden(2)); |
| 1775 | QVERIFY(h4.isSectionHidden(3)); |
| 1776 | QCOMPARE(h4.hiddenSectionCount(), 1); |
| 1777 | QCOMPARE(h4.sortIndicatorSection(), 2); |
| 1778 | QCOMPARE(h4.sortIndicatorOrder(), Qt::DescendingOrder); |
| 1779 | QCOMPARE(h4.logicalIndex(0), 2); |
| 1780 | QCOMPARE(h4.logicalIndex(1), 1); |
| 1781 | QCOMPARE(h4.logicalIndex(2), 0); |
| 1782 | QCOMPARE(h4.visualIndex(0), 2); |
| 1783 | QCOMPARE(h4.visualIndex(1), 1); |
| 1784 | QCOMPARE(h4.visualIndex(2), 0); |
| 1785 | |
| 1786 | // Repainting shouldn't crash |
| 1787 | h4.show(); |
| 1788 | QVERIFY(QTest::qWaitForWindowExposed(&h4)); |
| 1789 | } |
| 1790 | |
| 1791 | void tst_QHeaderView::restoreToMoreColumnsNoMovedColumns() |
| 1792 | { |
| 1793 | // Given a model with 2 columns, for saving state |
| 1794 | QHeaderView h1(Qt::Horizontal); |
| 1795 | QStandardItemModel model1(1, 2); |
| 1796 | h1.setModel(&model1); |
| 1797 | QCOMPARE(h1.visualIndex(0), 0); |
| 1798 | QCOMPARE(h1.visualIndex(1), 1); |
| 1799 | QCOMPARE(h1.logicalIndex(0), 0); |
| 1800 | QCOMPARE(h1.logicalIndex(1), 1); |
| 1801 | const QByteArray savedState = h1.saveState(); |
| 1802 | |
| 1803 | // And a model with 3 columns, to apply that state upon |
| 1804 | QHeaderView h2(Qt::Horizontal); |
| 1805 | QStandardItemModel model2(1, 3); |
| 1806 | h2.setModel(&model2); |
| 1807 | QCOMPARE(h2.visualIndex(0), 0); |
| 1808 | QCOMPARE(h2.visualIndex(1), 1); |
| 1809 | QCOMPARE(h2.visualIndex(2), 2); |
| 1810 | QCOMPARE(h2.logicalIndex(0), 0); |
| 1811 | QCOMPARE(h2.logicalIndex(1), 1); |
| 1812 | QCOMPARE(h2.logicalIndex(2), 2); |
| 1813 | |
| 1814 | // When calling restoreState() |
| 1815 | QVERIFY(h2.restoreState(savedState)); |
| 1816 | |
| 1817 | // Then the index mapping should still be as default |
| 1818 | QCOMPARE(h2.visualIndex(0), 0); |
| 1819 | QCOMPARE(h2.visualIndex(1), 1); |
| 1820 | QCOMPARE(h2.visualIndex(2), 2); |
| 1821 | QCOMPARE(h2.logicalIndex(0), 0); |
| 1822 | QCOMPARE(h2.logicalIndex(1), 1); |
| 1823 | QCOMPARE(h2.logicalIndex(2), 2); |
| 1824 | |
| 1825 | // And repainting shouldn't crash |
| 1826 | h2.show(); |
| 1827 | QVERIFY(QTest::qWaitForWindowExposed(&h2)); |
| 1828 | } |
| 1829 | |
| 1830 | void tst_QHeaderView::() |
| 1831 | { |
| 1832 | QHeaderView h2(Qt::Horizontal); |
| 1833 | const QByteArray s1 = savedState(); |
| 1834 | // First restore |
| 1835 | QVERIFY(h2.restoreState(s1)); |
| 1836 | // Then setModel |
| 1837 | QStandardItemModel model(4, 4); |
| 1838 | h2.setModel(&model); |
| 1839 | |
| 1840 | // Check the result |
| 1841 | QCOMPARE(h2.logicalIndex(0), 2); |
| 1842 | QCOMPARE(h2.logicalIndex(2), 0); |
| 1843 | QCOMPARE(h2.sectionSize(1), 10); |
| 1844 | QCOMPARE(h2.sortIndicatorSection(), 2); |
| 1845 | QCOMPARE(h2.sortIndicatorOrder(), Qt::DescendingOrder); |
| 1846 | QCOMPARE(h2.isSortIndicatorShown(), true); |
| 1847 | QVERIFY(!h2.isSectionHidden(2)); |
| 1848 | QVERIFY(h2.isSectionHidden(3)); |
| 1849 | QCOMPARE(h2.hiddenSectionCount(), 1); |
| 1850 | } |
| 1851 | |
| 1852 | void tst_QHeaderView::() |
| 1853 | { |
| 1854 | #if defined Q_OS_WINRT |
| 1855 | QSKIP("Fails on WinRT - QTBUG-73309" ); |
| 1856 | #endif |
| 1857 | |
| 1858 | // Setup |
| 1859 | QTableView qtv; |
| 1860 | QHeaderView *hv = qtv.verticalHeader(); |
| 1861 | hv->setMinimumSectionSize(10); |
| 1862 | hv->setDefaultSectionSize(99); // Set it to a value different from defaultSize. |
| 1863 | QStandardItemModel amodel(4, 4); |
| 1864 | qtv.setModel(&amodel); |
| 1865 | QCOMPARE(hv->sectionSize(0), 99); |
| 1866 | QCOMPARE(hv->visualIndexAt(50), 0); // <= also make sure that indexes are calculated |
| 1867 | hv->setDefaultSectionSize(40); // Set it to a value different from defaultSize. |
| 1868 | QCOMPARE(hv->visualIndexAt(50), 1); |
| 1869 | |
| 1870 | const int defaultSize = 26; |
| 1871 | hv->setDefaultSectionSize(defaultSize + 1); // Set it to a value different from defaultSize. |
| 1872 | |
| 1873 | // no hidden Sections |
| 1874 | hv->resizeSection(logicalIndex: 1, size: 0); |
| 1875 | hv->setDefaultSectionSize(defaultSize); |
| 1876 | QCOMPARE(hv->sectionSize(1), defaultSize); |
| 1877 | |
| 1878 | // with hidden sections |
| 1879 | hv->resizeSection(logicalIndex: 1, size: 0); |
| 1880 | hv->hideSection(alogicalIndex: 2); |
| 1881 | hv->setDefaultSectionSize(defaultSize); |
| 1882 | |
| 1883 | QVERIFY(hv->sectionSize(0) == defaultSize); // trivial case. |
| 1884 | QVERIFY(hv->sectionSize(1) == defaultSize); // just sized 0. Now it should be 10 |
| 1885 | QVERIFY(hv->sectionSize(2) == 0); // section is hidden. It should not be resized. |
| 1886 | } |
| 1887 | |
| 1888 | class : public QProxyStyle |
| 1889 | { |
| 1890 | Q_OBJECT |
| 1891 | public: |
| 1892 | using QProxyStyle::QProxyStyle; |
| 1893 | int (PixelMetric metric, const QStyleOption *option = nullptr, |
| 1894 | const QWidget *widget = nullptr) const override |
| 1895 | { |
| 1896 | if (metric == QStyle::PM_HeaderDefaultSectionSizeHorizontal) |
| 1897 | return horizontalSectionSize; |
| 1898 | else |
| 1899 | return QProxyStyle::pixelMetric(metric, option, widget); |
| 1900 | } |
| 1901 | int = 100; |
| 1902 | }; |
| 1903 | |
| 1904 | void tst_QHeaderView::() |
| 1905 | { |
| 1906 | TestHeaderViewStyle style1; |
| 1907 | TestHeaderViewStyle style2; |
| 1908 | style1.horizontalSectionSize = 100; |
| 1909 | style2.horizontalSectionSize = 200; |
| 1910 | |
| 1911 | QHeaderView hv(Qt::Horizontal); |
| 1912 | hv.setStyle(&style1); |
| 1913 | QCOMPARE(hv.defaultSectionSize(), style1.horizontalSectionSize); |
| 1914 | hv.setStyle(&style2); |
| 1915 | QCOMPARE(hv.defaultSectionSize(), style2.horizontalSectionSize); |
| 1916 | hv.setDefaultSectionSize(70); |
| 1917 | QCOMPARE(hv.defaultSectionSize(), 70); |
| 1918 | hv.setStyle(&style1); |
| 1919 | QCOMPARE(hv.defaultSectionSize(), 70); |
| 1920 | hv.resetDefaultSectionSize(); |
| 1921 | QCOMPARE(hv.defaultSectionSize(), style1.horizontalSectionSize); |
| 1922 | hv.setStyle(&style2); |
| 1923 | QCOMPARE(hv.defaultSectionSize(), style2.horizontalSectionSize); |
| 1924 | } |
| 1925 | |
| 1926 | void tst_QHeaderView::() |
| 1927 | { |
| 1928 | QTest::addColumn<Qt::Orientation>(name: "direction" ); |
| 1929 | QTest::addColumn<Qt::Alignment>(name: "initial" ); |
| 1930 | QTest::addColumn<Qt::Alignment>(name: "alignment" ); |
| 1931 | |
| 1932 | QTest::newRow(dataTag: "horizontal right aligned" ) |
| 1933 | << Qt::Horizontal |
| 1934 | << Qt::Alignment(Qt::AlignCenter) |
| 1935 | << Qt::Alignment(Qt::AlignRight); |
| 1936 | |
| 1937 | QTest::newRow(dataTag: "horizontal left aligned" ) |
| 1938 | << Qt::Horizontal |
| 1939 | << Qt::Alignment(Qt::AlignCenter) |
| 1940 | << Qt::Alignment(Qt::AlignLeft); |
| 1941 | |
| 1942 | QTest::newRow(dataTag: "vertical right aligned" ) |
| 1943 | << Qt::Vertical |
| 1944 | << Qt::Alignment(Qt::AlignLeft|Qt::AlignVCenter) |
| 1945 | << Qt::Alignment(Qt::AlignRight); |
| 1946 | |
| 1947 | QTest::newRow(dataTag: "vertical left aligned" ) |
| 1948 | << Qt::Vertical |
| 1949 | << Qt::Alignment(Qt::AlignLeft|Qt::AlignVCenter) |
| 1950 | << Qt::Alignment(Qt::AlignLeft); |
| 1951 | } |
| 1952 | |
| 1953 | void tst_QHeaderView::() |
| 1954 | { |
| 1955 | QFETCH(Qt::Orientation, direction); |
| 1956 | QFETCH(Qt::Alignment, initial); |
| 1957 | QFETCH(Qt::Alignment, alignment); |
| 1958 | |
| 1959 | SimpleModel m; |
| 1960 | |
| 1961 | QHeaderView (direction); |
| 1962 | header.setModel(&m); |
| 1963 | |
| 1964 | QCOMPARE(header.defaultAlignment(), initial); |
| 1965 | header.setDefaultAlignment(alignment); |
| 1966 | QCOMPARE(header.defaultAlignment(), alignment); |
| 1967 | } |
| 1968 | |
| 1969 | void tst_QHeaderView::() |
| 1970 | { |
| 1971 | QTest::addColumn<Qt::Orientation>(name: "direction" ); |
| 1972 | QTest::addColumn<QHeaderView::ResizeMode>(name: "mode" ); |
| 1973 | QTest::addColumn<int>(name: "insert" ); |
| 1974 | |
| 1975 | QTest::newRow(dataTag: "horizontal ResizeToContents 0" ) |
| 1976 | << Qt::Horizontal |
| 1977 | << QHeaderView::ResizeToContents |
| 1978 | << 0; |
| 1979 | } |
| 1980 | |
| 1981 | void tst_QHeaderView::() |
| 1982 | { |
| 1983 | QFETCH(Qt::Orientation, direction); |
| 1984 | QFETCH(QHeaderView::ResizeMode, mode); |
| 1985 | QFETCH(int, insert); |
| 1986 | |
| 1987 | QStandardItemModel m(4, 4); |
| 1988 | QHeaderView h(direction); |
| 1989 | h.setModel(&m); |
| 1990 | |
| 1991 | h.setSectionResizeMode(mode); |
| 1992 | m.insertRow(arow: insert); |
| 1993 | for (int i = 0; i < h.count(); ++i) |
| 1994 | QCOMPARE(h.sectionResizeMode(i), mode); |
| 1995 | } |
| 1996 | |
| 1997 | |
| 1998 | void tst_QHeaderView::() |
| 1999 | { |
| 2000 | QTest::addColumn<Qt::Orientation>(name: "direction" ); |
| 2001 | QTest::addColumn<bool>(name: "clickable" ); |
| 2002 | QTest::addColumn<int>(name: "count" ); |
| 2003 | |
| 2004 | QTest::newRow(dataTag: "horizontal unclickable 0" ) |
| 2005 | << Qt::Horizontal |
| 2006 | << false |
| 2007 | << 0; |
| 2008 | |
| 2009 | QTest::newRow(dataTag: "horizontal clickable 1" ) |
| 2010 | << Qt::Horizontal |
| 2011 | << true |
| 2012 | << 1; |
| 2013 | } |
| 2014 | |
| 2015 | void tst_QHeaderView::() |
| 2016 | { |
| 2017 | QFETCH(Qt::Orientation, direction); |
| 2018 | QFETCH(bool, clickable); |
| 2019 | QFETCH(int, count); |
| 2020 | |
| 2021 | QStandardItemModel m(4, 4); |
| 2022 | QHeaderView h(direction); |
| 2023 | |
| 2024 | h.setModel(&m); |
| 2025 | h.show(); |
| 2026 | h.setSectionsClickable(clickable); |
| 2027 | |
| 2028 | QSignalSpy spy(&h, &QHeaderView::sectionPressed); |
| 2029 | |
| 2030 | QCOMPARE(spy.count(), 0); |
| 2031 | QTest::mousePress(widget: h.viewport(), button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: QPoint(5, 5)); |
| 2032 | QCOMPARE(spy.count(), count); |
| 2033 | } |
| 2034 | |
| 2035 | void tst_QHeaderView::() |
| 2036 | { |
| 2037 | QFETCH(Qt::Orientation, direction); |
| 2038 | QFETCH(bool, clickable); |
| 2039 | QFETCH(int, count); |
| 2040 | |
| 2041 | QStandardItemModel m(4, 4); |
| 2042 | QHeaderView h(direction); |
| 2043 | |
| 2044 | h.setModel(&m); |
| 2045 | h.show(); |
| 2046 | h.setSectionsClickable(clickable); |
| 2047 | h.setSortIndicatorShown(true); |
| 2048 | |
| 2049 | QSignalSpy spy(&h, &QHeaderView::sectionClicked); |
| 2050 | QSignalSpy spy2(&h, &QHeaderView::sortIndicatorChanged); |
| 2051 | |
| 2052 | QCOMPARE(spy.count(), 0); |
| 2053 | QCOMPARE(spy2.count(), 0); |
| 2054 | QTest::mouseClick(widget: h.viewport(), button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: QPoint(5, 5)); |
| 2055 | QCOMPARE(spy.count(), count); |
| 2056 | QCOMPARE(spy2.count(), count); |
| 2057 | |
| 2058 | //now let's try with the sort indicator hidden (the result should be the same |
| 2059 | spy.clear(); |
| 2060 | spy2.clear(); |
| 2061 | h.setSortIndicatorShown(false); |
| 2062 | QTest::mouseClick(widget: h.viewport(), button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: QPoint(5, 5)); |
| 2063 | QCOMPARE(spy.count(), count); |
| 2064 | QCOMPARE(spy2.count(), count); |
| 2065 | } |
| 2066 | |
| 2067 | void tst_QHeaderView::() |
| 2068 | { |
| 2069 | QTest::addColumn<Qt::Orientation>(name: "direction" ); |
| 2070 | QTest::addColumn<int>(name: "oldDefaultSize" ); |
| 2071 | QTest::addColumn<int>(name: "newDefaultSize" ); |
| 2072 | |
| 2073 | //QTest::newRow("horizontal,-5") << int(Qt::Horizontal) << 100 << -5; |
| 2074 | QTest::newRow(dataTag: "horizontal, 0" ) << Qt::Horizontal << 100 << 0; |
| 2075 | QTest::newRow(dataTag: "horizontal, 5" ) << Qt::Horizontal << 100 << 5; |
| 2076 | QTest::newRow(dataTag: "horizontal,25" ) << Qt::Horizontal << 100 << 5; |
| 2077 | } |
| 2078 | |
| 2079 | void tst_QHeaderView::() |
| 2080 | { |
| 2081 | QFETCH(Qt::Orientation, direction); |
| 2082 | QFETCH(int, oldDefaultSize); |
| 2083 | QFETCH(int, newDefaultSize); |
| 2084 | |
| 2085 | QStandardItemModel m(4, 4); |
| 2086 | QHeaderView h(direction); |
| 2087 | |
| 2088 | h.setModel(&m); |
| 2089 | h.setMinimumSectionSize(0); |
| 2090 | |
| 2091 | QCOMPARE(h.defaultSectionSize(), oldDefaultSize); |
| 2092 | h.setDefaultSectionSize(newDefaultSize); |
| 2093 | QCOMPARE(h.defaultSectionSize(), newDefaultSize); |
| 2094 | h.reset(); |
| 2095 | for (int i = 0; i < h.count(); ++i) |
| 2096 | QCOMPARE(h.sectionSize(i), newDefaultSize); |
| 2097 | } |
| 2098 | |
| 2099 | void tst_QHeaderView::hideAndInsert_data() |
| 2100 | { |
| 2101 | QTest::addColumn<Qt::Orientation>(name: "direction" ); |
| 2102 | QTest::addColumn<int>(name: "hide" ); |
| 2103 | QTest::addColumn<int>(name: "insert" ); |
| 2104 | QTest::addColumn<int>(name: "hidden" ); |
| 2105 | |
| 2106 | QTest::newRow(dataTag: "horizontal, 0, 0" ) << Qt::Horizontal << 0 << 0 << 1; |
| 2107 | } |
| 2108 | |
| 2109 | void tst_QHeaderView::hideAndInsert() |
| 2110 | { |
| 2111 | QFETCH(Qt::Orientation, direction); |
| 2112 | QFETCH(int, hide); |
| 2113 | QFETCH(int, insert); |
| 2114 | QFETCH(int, hidden); |
| 2115 | |
| 2116 | QStandardItemModel m(4, 4); |
| 2117 | QHeaderView h(direction); |
| 2118 | h.setModel(&m); |
| 2119 | h.setSectionHidden(logicalIndex: hide, hide: true); |
| 2120 | |
| 2121 | if (direction == Qt::Vertical) |
| 2122 | m.insertRow(arow: insert); |
| 2123 | else |
| 2124 | m.insertColumn(acolumn: insert); |
| 2125 | |
| 2126 | for (int i = 0; i < h.count(); ++i) |
| 2127 | QCOMPARE(h.isSectionHidden(i), i == hidden); |
| 2128 | } |
| 2129 | |
| 2130 | void tst_QHeaderView::() |
| 2131 | { |
| 2132 | const int hidden = 3; //section that will be hidden |
| 2133 | |
| 2134 | QStringListModel model({ "0" , "1" , "2" , "3" , "4" , "5" , "6" }); |
| 2135 | QHeaderView view(Qt::Vertical); |
| 2136 | view.setModel(&model); |
| 2137 | view.hideSection(alogicalIndex: hidden); |
| 2138 | view.hideSection(alogicalIndex: 1); |
| 2139 | model.removeRow(arow: 1); |
| 2140 | view.show(); |
| 2141 | |
| 2142 | for(int i = 0; i < view.count(); i++) { |
| 2143 | if (i == (hidden - 1)) { //-1 because we removed a row in the meantime |
| 2144 | QCOMPARE(view.sectionSize(i), 0); |
| 2145 | QVERIFY(view.isSectionHidden(i)); |
| 2146 | } else { |
| 2147 | QCOMPARE(view.sectionSize(i), view.defaultSectionSize() ); |
| 2148 | QVERIFY(!view.isSectionHidden(i)); |
| 2149 | } |
| 2150 | } |
| 2151 | } |
| 2152 | |
| 2153 | void tst_QHeaderView::() |
| 2154 | { |
| 2155 | QStringListModel model({ "0" , "1" , "2" , "3" }); |
| 2156 | QHeaderView view(Qt::Vertical); |
| 2157 | view.setModel(&model); |
| 2158 | view.resizeSection(logicalIndex: 0, size: 100); |
| 2159 | view.resizeSection(logicalIndex: 1, size: 10); |
| 2160 | view.resizeSection(logicalIndex: 2, size: 50); |
| 2161 | view.setSectionResizeMode(logicalIndex: 3, mode: QHeaderView::Stretch); |
| 2162 | view.show(); |
| 2163 | |
| 2164 | view.hideSection(alogicalIndex: 2); |
| 2165 | model.removeRow(arow: 1); |
| 2166 | view.showSection(alogicalIndex: 1); |
| 2167 | QCOMPARE(view.sectionSize(0), 100); |
| 2168 | QCOMPARE(view.sectionSize(1), 50); |
| 2169 | |
| 2170 | view.hideSection(alogicalIndex: 1); |
| 2171 | model.insertRow(arow: 1); |
| 2172 | view.showSection(alogicalIndex: 2); |
| 2173 | QCOMPARE(view.sectionSize(0), 100); |
| 2174 | QCOMPARE(view.sectionSize(1), view.defaultSectionSize()); |
| 2175 | QCOMPARE(view.sectionSize(2), 50); |
| 2176 | } |
| 2177 | |
| 2178 | void tst_QHeaderView::() |
| 2179 | { |
| 2180 | #ifdef Q_OS_WINRT |
| 2181 | QSKIP("Fails on WinRT - QTBUG-68297" ); |
| 2182 | #endif |
| 2183 | int count = 6; |
| 2184 | QStandardItemModel model(1, count); |
| 2185 | QHeaderView view(Qt::Horizontal); |
| 2186 | view.setModel(&model); |
| 2187 | int height = view.height(); |
| 2188 | |
| 2189 | view.resize(w: view.defaultSectionSize() * (count / 2), h: height); // don't show all sections |
| 2190 | view.show(); |
| 2191 | view.setStretchLastSection(true); |
| 2192 | // stretch section is not visible; it should not be stretched |
| 2193 | for (int i = 0; i < count; ++i) |
| 2194 | QCOMPARE(view.sectionSize(i), view.defaultSectionSize()); |
| 2195 | |
| 2196 | view.resize(w: view.defaultSectionSize() * (count + 1), h: height); // give room to stretch |
| 2197 | |
| 2198 | // stretch section is visible; it should be stretched |
| 2199 | for (int i = 0; i < count - 1; ++i) |
| 2200 | QCOMPARE(view.sectionSize(i), view.defaultSectionSize()); |
| 2201 | QCOMPARE(view.sectionSize(count - 1), view.defaultSectionSize() * 2); |
| 2202 | } |
| 2203 | |
| 2204 | void tst_QHeaderView::() |
| 2205 | { |
| 2206 | QStandardItemModel m(4, 4); |
| 2207 | QHeaderView h(Qt::Horizontal); |
| 2208 | h.setModel(&m); |
| 2209 | h.resizeSection(logicalIndex: 1, size: -5); |
| 2210 | QVERIFY(h.sectionSize(1) >= 0); // Sections with negative sizes not well defined. |
| 2211 | } |
| 2212 | |
| 2213 | void tst_QHeaderView::() |
| 2214 | { |
| 2215 | QHeaderViewPrivate::SectionItem section; |
| 2216 | QCOMPARE(section.sectionSize(), 0); |
| 2217 | } |
| 2218 | |
| 2219 | void tst_QHeaderView::() |
| 2220 | { |
| 2221 | QTest::addColumn<IntList>(name: "hide1" ); |
| 2222 | QTest::addColumn<IntList>(name: "hide2" ); |
| 2223 | |
| 2224 | QTest::newRow(dataTag: "set 1" ) << (IntList{ 1, 3 }) |
| 2225 | << (IntList{ 1, 5 }); |
| 2226 | |
| 2227 | QTest::newRow(dataTag: "set 2" ) << (IntList{ 2, 3 }) |
| 2228 | << (IntList{ 1, 5 }); |
| 2229 | |
| 2230 | QTest::newRow(dataTag: "set 3" ) << (IntList{ 0, 2, 4 }) |
| 2231 | << (IntList{ 2, 3, 5 }); |
| 2232 | |
| 2233 | } |
| 2234 | |
| 2235 | void tst_QHeaderView::() |
| 2236 | { |
| 2237 | QFETCH(const IntList, hide1); |
| 2238 | QFETCH(const IntList, hide2); |
| 2239 | |
| 2240 | QStringListModel model({ "0" , "1" , "2" , "3" , "4" , "5" }); |
| 2241 | protected_QHeaderView view(Qt::Vertical); |
| 2242 | view.setModel(&model); |
| 2243 | view.show(); |
| 2244 | |
| 2245 | for (int i : hide1) |
| 2246 | view.hideSection(alogicalIndex: i); |
| 2247 | |
| 2248 | QCOMPARE(view.hiddenSectionCount(), hide1.count()); |
| 2249 | for (int i = 0; i < 6; i++) |
| 2250 | QCOMPARE(!view.isSectionHidden(i), !hide1.contains(i)); |
| 2251 | |
| 2252 | view.setDefaultSectionSize(2); |
| 2253 | view.scheduleDelayedItemsLayout(); |
| 2254 | view.executeDelayedItemsLayout(); //force to do a relayout |
| 2255 | |
| 2256 | QCOMPARE(view.hiddenSectionCount(), hide1.count()); |
| 2257 | for (int i = 0; i < 6; i++) { |
| 2258 | QCOMPARE(!view.isSectionHidden(i), !hide1.contains(i)); |
| 2259 | view.setSectionHidden(logicalIndex: i, hide: hide2.contains(t: i)); |
| 2260 | } |
| 2261 | |
| 2262 | QCOMPARE(view.hiddenSectionCount(), hide2.count()); |
| 2263 | for (int i = 0; i < 6; i++) |
| 2264 | QCOMPARE(!view.isSectionHidden(i), !hide2.contains(i)); |
| 2265 | } |
| 2266 | |
| 2267 | void tst_QHeaderView::() |
| 2268 | { |
| 2269 | //this is the sequence of events that make the task fail |
| 2270 | protected_QHeaderView (Qt::Vertical); |
| 2271 | QStandardItemModel model(0, 1); |
| 2272 | header.setMinimumSectionSize(0); // system default min size can be to large |
| 2273 | header.setStretchLastSection(false); |
| 2274 | header.setDefaultSectionSize(17); |
| 2275 | header.setModel(&model); |
| 2276 | header.doItemsLayout(); |
| 2277 | |
| 2278 | model.setRowCount(3); |
| 2279 | |
| 2280 | QCOMPARE(header.sectionPosition(2), 17*2); |
| 2281 | |
| 2282 | header.hideSection(alogicalIndex: 1); |
| 2283 | QCOMPARE(header.sectionPosition(2), 17); |
| 2284 | |
| 2285 | QTest::qWait(ms: 100); |
| 2286 | //the size of the section shouldn't have changed |
| 2287 | QCOMPARE(header.sectionPosition(2), 17); |
| 2288 | } |
| 2289 | |
| 2290 | |
| 2291 | //returns 0 if everything is fine. |
| 2292 | static int (const QHeaderView *view, const IntList &expected) |
| 2293 | { |
| 2294 | if (view->count() != expected.count()) |
| 2295 | return 1; |
| 2296 | |
| 2297 | for (int i = 0; i < expected.count(); i++) { |
| 2298 | if (view->logicalIndex(visualIndex: i) != expected.at(i)) |
| 2299 | return i + 10; |
| 2300 | if (view->visualIndex(logicalIndex: expected.at(i)) != i) |
| 2301 | return i + 100; |
| 2302 | } |
| 2303 | return 0; |
| 2304 | } |
| 2305 | |
| 2306 | |
| 2307 | void tst_QHeaderView::() |
| 2308 | { |
| 2309 | if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) |
| 2310 | QSKIP("Wayland: This fails. Figure out why." ); |
| 2311 | |
| 2312 | QStringListModel model1({ "0" , "1" , "2" , "3" , "4" , "5" }); |
| 2313 | QStringListModel model2({ "a" , "b" , "c" }); |
| 2314 | QSortFilterProxyModel proxy; |
| 2315 | |
| 2316 | QHeaderView view(Qt::Vertical); |
| 2317 | view.setModel(&proxy); |
| 2318 | view.show(); |
| 2319 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
| 2320 | QVERIFY(QTest::qWaitForWindowActive(&view)); |
| 2321 | |
| 2322 | proxy.setSourceModel(&model1); |
| 2323 | view.swapSections(first: 0, second: 2); |
| 2324 | view.swapSections(first: 1, second: 4); |
| 2325 | IntList expectedOrder{2, 4, 0, 3, 1, 5}; |
| 2326 | QTRY_COMPARE(checkHeaderViewOrder(&view, expectedOrder) , 0); |
| 2327 | |
| 2328 | proxy.setSourceModel(&model2); |
| 2329 | expectedOrder = {2, 0, 1}; |
| 2330 | QTRY_COMPARE(checkHeaderViewOrder(&view, expectedOrder) , 0); |
| 2331 | |
| 2332 | proxy.setSourceModel(&model1); |
| 2333 | expectedOrder = {2, 0, 1, 3, 4, 5}; |
| 2334 | QTRY_COMPARE(checkHeaderViewOrder(&view, expectedOrder) , 0); |
| 2335 | } |
| 2336 | |
| 2337 | void tst_QHeaderView::() |
| 2338 | { |
| 2339 | QTableView tv; |
| 2340 | QStandardItemModel *sim = new QStandardItemModel(&tv); |
| 2341 | QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel(&tv); |
| 2342 | proxyModel->setSourceModel(sim); |
| 2343 | proxyModel->setDynamicSortFilter(true); |
| 2344 | proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive); |
| 2345 | |
| 2346 | QList<QStandardItem *> row; |
| 2347 | for (char i = 0; i < 12; i++) |
| 2348 | row.append(t: new QStandardItem(QString(QLatin1Char('A' + i)))); |
| 2349 | sim->appendRow(items: row); |
| 2350 | row.clear(); |
| 2351 | for (char i = 12; i > 0; i--) |
| 2352 | row.append(t: new QStandardItem(QString(QLatin1Char('A' + i)))); |
| 2353 | sim->appendRow(items: row); |
| 2354 | |
| 2355 | tv.setSortingEnabled(true); |
| 2356 | tv.horizontalHeader()->setSortIndicatorShown(true); |
| 2357 | tv.horizontalHeader()->setSectionsClickable(true); |
| 2358 | tv.horizontalHeader()->setStretchLastSection(true); |
| 2359 | tv.horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive); |
| 2360 | |
| 2361 | tv.setModel(proxyModel); |
| 2362 | const int section4Size = tv.horizontalHeader()->sectionSize(logicalIndex: 4) + 1; |
| 2363 | const int section5Size = section4Size + 1; |
| 2364 | tv.horizontalHeader()->resizeSection(logicalIndex: 4, size: section4Size); |
| 2365 | tv.horizontalHeader()->resizeSection(logicalIndex: 5, size: section5Size); |
| 2366 | tv.setColumnHidden(column: 5, hide: true); |
| 2367 | tv.setColumnHidden(column: 6, hide: true); |
| 2368 | tv.horizontalHeader()->swapSections(first: 8, second: 10); |
| 2369 | tv.sortByColumn(column: 1, order: Qt::AscendingOrder); |
| 2370 | |
| 2371 | QCOMPARE(tv.isColumnHidden(5), true); |
| 2372 | QCOMPARE(tv.isColumnHidden(6), true); |
| 2373 | QCOMPARE(tv.horizontalHeader()->sectionsMoved(), true); |
| 2374 | QCOMPARE(tv.horizontalHeader()->logicalIndex(8), 10); |
| 2375 | QCOMPARE(tv.horizontalHeader()->logicalIndex(10), 8); |
| 2376 | QCOMPARE(tv.horizontalHeader()->sectionSize(4), section4Size); |
| 2377 | tv.setColumnHidden(column: 5, hide: false); // unhide, section size must be properly restored |
| 2378 | QCOMPARE(tv.horizontalHeader()->sectionSize(5), section5Size); |
| 2379 | tv.setColumnHidden(column: 5, hide: true); |
| 2380 | |
| 2381 | QSignalSpy clickedSpy(tv.horizontalHeader(), &QHeaderView::sectionClicked); |
| 2382 | QSignalSpy pressedSpy(tv.horizontalHeader(), &QHeaderView::sectionPressed); |
| 2383 | |
| 2384 | |
| 2385 | QTest::mouseClick(widget: tv.horizontalHeader()->viewport(), button: Qt::LeftButton, stateKey: Qt::NoModifier, |
| 2386 | pos: QPoint(tv.horizontalHeader()->sectionViewportPosition(logicalIndex: 11) + |
| 2387 | tv.horizontalHeader()->sectionSize(logicalIndex: 11) / 2, 5)); |
| 2388 | QCOMPARE(clickedSpy.count(), 1); |
| 2389 | QCOMPARE(pressedSpy.count(), 1); |
| 2390 | QCOMPARE(clickedSpy.at(0).at(0).toInt(), 11); |
| 2391 | QCOMPARE(pressedSpy.at(0).at(0).toInt(), 11); |
| 2392 | |
| 2393 | QTest::mouseClick(widget: tv.horizontalHeader()->viewport(), button: Qt::LeftButton, stateKey: Qt::NoModifier, |
| 2394 | pos: QPoint(tv.horizontalHeader()->sectionViewportPosition(logicalIndex: 8) + |
| 2395 | tv.horizontalHeader()->sectionSize(logicalIndex: 0) / 2, 5)); |
| 2396 | |
| 2397 | QCOMPARE(clickedSpy.count(), 2); |
| 2398 | QCOMPARE(pressedSpy.count(), 2); |
| 2399 | QCOMPARE(clickedSpy.at(1).at(0).toInt(), 8); |
| 2400 | QCOMPARE(pressedSpy.at(1).at(0).toInt(), 8); |
| 2401 | |
| 2402 | QTest::mouseClick(widget: tv.horizontalHeader()->viewport(), button: Qt::LeftButton, stateKey: Qt::NoModifier, |
| 2403 | pos: QPoint(tv.horizontalHeader()->sectionViewportPosition(logicalIndex: 0) + |
| 2404 | tv.horizontalHeader()->sectionSize(logicalIndex: 0) / 2, 5)); |
| 2405 | |
| 2406 | QCOMPARE(clickedSpy.count(), 3); |
| 2407 | QCOMPARE(pressedSpy.count(), 3); |
| 2408 | QCOMPARE(clickedSpy.at(2).at(0).toInt(), 0); |
| 2409 | QCOMPARE(pressedSpy.at(2).at(0).toInt(), 0); |
| 2410 | } |
| 2411 | |
| 2412 | void tst_QHeaderView::() |
| 2413 | { |
| 2414 | QtTestModel tm(0, 11); |
| 2415 | QTableView tv; |
| 2416 | tv.verticalHeader()->setStretchLastSection(true); |
| 2417 | tv.setModel(&tm); |
| 2418 | |
| 2419 | const int section4Size = tv.horizontalHeader()->sectionSize(logicalIndex: 4) + 1; |
| 2420 | const int section5Size = section4Size + 1; |
| 2421 | tv.horizontalHeader()->resizeSection(logicalIndex: 4, size: section4Size); |
| 2422 | tv.horizontalHeader()->resizeSection(logicalIndex: 5, size: section5Size); |
| 2423 | tv.setColumnHidden(column: 5, hide: true); |
| 2424 | tv.setColumnHidden(column: 6, hide: true); |
| 2425 | tv.horizontalHeader()->swapSections(first: 8, second: 10); |
| 2426 | |
| 2427 | tv.sortByColumn(column: 1, order: Qt::AscendingOrder); |
| 2428 | tm.emitLayoutChanged(); |
| 2429 | |
| 2430 | QCOMPARE(tv.isColumnHidden(5), true); |
| 2431 | QCOMPARE(tv.isColumnHidden(6), true); |
| 2432 | QCOMPARE(tv.horizontalHeader()->sectionsMoved(), true); |
| 2433 | QCOMPARE(tv.horizontalHeader()->logicalIndex(8), 10); |
| 2434 | QCOMPARE(tv.horizontalHeader()->logicalIndex(10), 8); |
| 2435 | QCOMPARE(tv.horizontalHeader()->sectionSize(4), section4Size); |
| 2436 | tv.setColumnHidden(column: 5, hide: false); // unhide, section size must be properly restored |
| 2437 | QCOMPARE(tv.horizontalHeader()->sectionSize(5), section5Size); |
| 2438 | tv.setColumnHidden(column: 5, hide: true); |
| 2439 | |
| 2440 | // adjust |
| 2441 | tm.rows = 3; |
| 2442 | tm.emitLayoutChanged(); |
| 2443 | |
| 2444 | // remove the row used for QPersistenModelIndexes |
| 2445 | tm.emitLayoutChangedWithRemoveFirstRow(); |
| 2446 | QCOMPARE(tv.isColumnHidden(5), true); |
| 2447 | QCOMPARE(tv.isColumnHidden(6), true); |
| 2448 | QCOMPARE(tv.horizontalHeader()->sectionsMoved(), true); |
| 2449 | QCOMPARE(tv.horizontalHeader()->logicalIndex(8), 10); |
| 2450 | QCOMPARE(tv.horizontalHeader()->logicalIndex(10), 8); |
| 2451 | QCOMPARE(tv.horizontalHeader()->sectionSize(4), section4Size); |
| 2452 | tv.setColumnHidden(column: 5, hide: false); // unhide, section size must be properly restored |
| 2453 | QCOMPARE(tv.horizontalHeader()->sectionSize(5), section5Size); |
| 2454 | tv.setColumnHidden(column: 5, hide: true); |
| 2455 | } |
| 2456 | |
| 2457 | void tst_QHeaderView::() |
| 2458 | { |
| 2459 | QStringList ; |
| 2460 | QHeaderView view(Qt::Horizontal); |
| 2461 | QStandardItemModel model(2, 2); |
| 2462 | view.setModel(&model); |
| 2463 | view.moveSection(from: 1, to: 0); |
| 2464 | view.hideSection(alogicalIndex: 0); |
| 2465 | |
| 2466 | model.insertColumn(column: 0, items: { new QStandardItem("c" ) }); |
| 2467 | } |
| 2468 | |
| 2469 | static void setModelTexts(QStandardItemModel *model) |
| 2470 | { |
| 2471 | const int columnCount = model->columnCount(); |
| 2472 | for (int i = 0, rowCount = model->rowCount(); i < rowCount; ++i) { |
| 2473 | const QString prefix = QLatin1String("item [" ) + QString::number(i) + QLatin1Char(','); |
| 2474 | for (int j = 0; j < columnCount; ++j) |
| 2475 | model->setData(index: model->index(row: i, column: j), value: prefix + QString::number(j) + QLatin1Char(']')); |
| 2476 | } |
| 2477 | } |
| 2478 | |
| 2479 | void tst_QHeaderView::() |
| 2480 | { |
| 2481 | QTableView view; // ### this test fails on QTableView &view = *m_tableview; !? + shadowing view member |
| 2482 | QStandardItemModel model(4, 3); |
| 2483 | setModelTexts(&model); |
| 2484 | view.setModel(&model); |
| 2485 | view.horizontalHeader()->setSectionsMovable(true); |
| 2486 | view.setSortingEnabled(true); |
| 2487 | view.sortByColumn(column: 1, order: Qt::AscendingOrder); |
| 2488 | view.horizontalHeader()->moveSection(from: 0,to: 2); |
| 2489 | view.setColumnHidden(column: 1, hide: true); |
| 2490 | view.show(); |
| 2491 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
| 2492 | QCOMPARE(view.horizontalHeader()->hiddenSectionCount(), 1); |
| 2493 | QTest::mouseClick(widget: view.horizontalHeader()->viewport(), button: Qt::LeftButton); |
| 2494 | QCOMPARE(view.horizontalHeader()->hiddenSectionCount(), 1); |
| 2495 | } |
| 2496 | |
| 2497 | void tst_QHeaderView::() |
| 2498 | { |
| 2499 | QTableView qtv; |
| 2500 | QStandardItemModel amodel(4, 4); |
| 2501 | qtv.setModel(&amodel); |
| 2502 | QHeaderView *hv = qtv.verticalHeader(); |
| 2503 | hv->setDefaultSectionSize(25); |
| 2504 | hv->setSectionResizeMode(QHeaderView::ResizeToContents); |
| 2505 | qtv.show(); |
| 2506 | |
| 2507 | hv->hideSection(alogicalIndex: 0); |
| 2508 | int afterlength = hv->length(); |
| 2509 | |
| 2510 | int calced_length = 0; |
| 2511 | for (int u = 0; u < hv->count(); ++u) |
| 2512 | calced_length += hv->sectionSize(logicalIndex: u); |
| 2513 | |
| 2514 | QCOMPARE(calced_length, afterlength); |
| 2515 | } |
| 2516 | |
| 2517 | void tst_QHeaderView::() |
| 2518 | { |
| 2519 | protected_QHeaderView (Qt::Horizontal); |
| 2520 | QtTestModel model(2, 3); |
| 2521 | headerView.setModel(&model); |
| 2522 | headerView.swapSections(first: 1, second: 2); |
| 2523 | headerView.hideSection(alogicalIndex: 0); |
| 2524 | headerView.testVisualRegionForSelection(); |
| 2525 | } |
| 2526 | |
| 2527 | class QTBUG53221_Model : public QAbstractItemModel |
| 2528 | { |
| 2529 | Q_OBJECT |
| 2530 | public: |
| 2531 | void insertRowAtBeginning() |
| 2532 | { |
| 2533 | Q_EMIT layoutAboutToBeChanged(); |
| 2534 | m_displayNames.insert(i: 0, QStringLiteral("Item %1" ).arg(a: m_displayNames.count())); |
| 2535 | // Rows are always inserted at the beginning, so move all others. |
| 2536 | const auto pl = persistentIndexList(); |
| 2537 | // The vertical header view will have a persistent index stored here on the second call to insertRowAtBeginning. |
| 2538 | for (const QModelIndex &persIndex : pl) |
| 2539 | changePersistentIndex(from: persIndex, to: index(row: persIndex.row() + 1, column: persIndex.column(), persIndex.parent())); |
| 2540 | Q_EMIT layoutChanged(); |
| 2541 | } |
| 2542 | |
| 2543 | QVariant data(const QModelIndex &index, int role) const override |
| 2544 | { |
| 2545 | return (role == Qt::DisplayRole) ? m_displayNames.at(i: index.row()) : QVariant(); |
| 2546 | } |
| 2547 | |
| 2548 | QModelIndex index(int row, int column, const QModelIndex &) const override { return createIndex(arow: row, acolumn: column); } |
| 2549 | QModelIndex parent(const QModelIndex &) const override { return QModelIndex(); } |
| 2550 | int rowCount(const QModelIndex &) const override { return m_displayNames.count(); } |
| 2551 | int columnCount(const QModelIndex &) const override { return 1; } |
| 2552 | |
| 2553 | private: |
| 2554 | QStringList m_displayNames; |
| 2555 | }; |
| 2556 | |
| 2557 | void tst_QHeaderView::() |
| 2558 | { |
| 2559 | QTableView tableView; |
| 2560 | QTBUG53221_Model modelTableView; |
| 2561 | tableView.setModel(&modelTableView); |
| 2562 | |
| 2563 | modelTableView.insertRowAtBeginning(); |
| 2564 | tableView.setRowHidden(row: 0, hide: true); |
| 2565 | QCOMPARE(tableView.verticalHeader()->isSectionHidden(0), true); |
| 2566 | modelTableView.insertRowAtBeginning(); |
| 2567 | QCOMPARE(tableView.verticalHeader()->isSectionHidden(0), false); |
| 2568 | QCOMPARE(tableView.verticalHeader()->isSectionHidden(1), true); |
| 2569 | modelTableView.insertRowAtBeginning(); |
| 2570 | QCOMPARE(tableView.verticalHeader()->isSectionHidden(0), false); |
| 2571 | QCOMPARE(tableView.verticalHeader()->isSectionHidden(1), false); |
| 2572 | QCOMPARE(tableView.verticalHeader()->isSectionHidden(2), true); |
| 2573 | } |
| 2574 | |
| 2575 | void tst_QHeaderView::() |
| 2576 | { |
| 2577 | QTableView tableView; |
| 2578 | QStandardItemModel model(1, 1); |
| 2579 | tableView.setModel(&model); |
| 2580 | tableView.show(); |
| 2581 | |
| 2582 | const auto = tableView.horizontalHeader(); |
| 2583 | const auto oldSizeHint = headerView->sizeHint(); |
| 2584 | QVERIFY(oldSizeHint.isValid()); |
| 2585 | |
| 2586 | tableView.setStyleSheet("QTableView QHeaderView::section { height: 100px;}" ); |
| 2587 | QCOMPARE(headerView->sizeHint().width(), oldSizeHint.width()); |
| 2588 | QCOMPARE(headerView->sizeHint().height(), 100); |
| 2589 | |
| 2590 | tableView.setStyleSheet("QTableView QHeaderView::section { width: 100px;}" ); |
| 2591 | QCOMPARE(headerView->sizeHint().height(), oldSizeHint.height()); |
| 2592 | QCOMPARE(headerView->sizeHint().width(), 100); |
| 2593 | } |
| 2594 | |
| 2595 | void protected_QHeaderView::() |
| 2596 | { |
| 2597 | QRegion r = visualRegionForSelection(selection: QItemSelection(model()->index(row: 1, column: 0), model()->index(row: 1, column: 2))); |
| 2598 | QCOMPARE(r.boundingRect().contains(QRect(1, 1, length() - 2, 1)), true); |
| 2599 | } |
| 2600 | |
| 2601 | void tst_QHeaderView::() |
| 2602 | { |
| 2603 | QTableView qtv; |
| 2604 | QStandardItemModel amodel(4, 4); |
| 2605 | qtv.setModel(&amodel); |
| 2606 | QHeaderView *hv = qtv.verticalHeader(); |
| 2607 | QCOMPARE(hv->visualIndexAt(hv->length()), -1); |
| 2608 | hv->resizeSection(logicalIndex: hv->count() - 1, size: 0); |
| 2609 | QCOMPARE(hv->visualIndexAt(hv->length()), -1); |
| 2610 | } |
| 2611 | |
| 2612 | void tst_QHeaderView::() |
| 2613 | { |
| 2614 | // Ensure that a hidden section 'far away' |
| 2615 | // does not affect setOffsetToSectionPosition .. |
| 2616 | const int sectionToHide = 513; |
| 2617 | QTableView qtv; |
| 2618 | QStandardItemModel amodel(1000, 4); |
| 2619 | qtv.setModel(&amodel); |
| 2620 | QHeaderView *hv = qtv.verticalHeader(); |
| 2621 | for (int u = 0; u < 100; u += 2) |
| 2622 | hv->resizeSection(logicalIndex: u, size: 0); |
| 2623 | hv->setOffsetToSectionPosition(150); |
| 2624 | int offset1 = hv->offset(); |
| 2625 | hv->hideSection(alogicalIndex: sectionToHide); |
| 2626 | hv->setOffsetToSectionPosition(150); |
| 2627 | int offset2 = hv->offset(); |
| 2628 | QCOMPARE(offset1, offset2); |
| 2629 | // Ensure that hidden indexes (still) is considered. |
| 2630 | hv->resizeSection(logicalIndex: sectionToHide, size: hv->sectionSize(logicalIndex: 200) * 2); |
| 2631 | hv->setOffsetToSectionPosition(800); |
| 2632 | offset1 = hv->offset(); |
| 2633 | hv->showSection(alogicalIndex: sectionToHide); |
| 2634 | hv->setOffsetToSectionPosition(800); |
| 2635 | offset2 = hv->offset(); |
| 2636 | QVERIFY(offset2 > offset1); |
| 2637 | } |
| 2638 | |
| 2639 | void tst_QHeaderView::() |
| 2640 | { |
| 2641 | QTableView qtv; |
| 2642 | QStandardItemModel amodel(1000, 4); |
| 2643 | qtv.setModel(&amodel); |
| 2644 | QHeaderView *hv = qtv.horizontalHeader(); |
| 2645 | hv->setSectionsClickable(true); |
| 2646 | hv->setFirstSectionMovable(true); |
| 2647 | hv->setSectionsMovable(false); |
| 2648 | |
| 2649 | enum { DefaultYOffset = 5, OutOfRangeYOffset = 10000 }; |
| 2650 | |
| 2651 | const auto pressOnSection = [&](int section, int yOffset = DefaultYOffset) |
| 2652 | { |
| 2653 | QTest::mousePress(widget: hv->viewport(), button: Qt::LeftButton, stateKey: Qt::NoModifier, |
| 2654 | pos: QPoint(hv->sectionViewportPosition(logicalIndex: section) + hv->sectionSize(logicalIndex: section) / 2, yOffset)); |
| 2655 | }; |
| 2656 | const auto moveOntoSection = [&](int section, int yOffset = DefaultYOffset) |
| 2657 | { |
| 2658 | QTest::mouseMove(widget: hv->viewport(), |
| 2659 | pos: QPoint(hv->sectionViewportPosition(logicalIndex: section) + hv->sectionSize(logicalIndex: section) / 2, yOffset)); |
| 2660 | }; |
| 2661 | const auto releaseOnSection = [&](int section, int yOffset = DefaultYOffset) |
| 2662 | { |
| 2663 | QTest::mouseRelease(widget: hv->viewport(), button: Qt::LeftButton, stateKey: Qt::NoModifier, |
| 2664 | pos: QPoint(hv->sectionViewportPosition(logicalIndex: section) + hv->sectionSize(logicalIndex: section) / 2, yOffset)); |
| 2665 | }; |
| 2666 | |
| 2667 | hv->setSortIndicator(logicalIndex: -1, order: Qt::AscendingOrder); |
| 2668 | QCOMPARE(hv->sortIndicatorSection(), -1); |
| 2669 | |
| 2670 | pressOnSection(0); |
| 2671 | releaseOnSection(0); |
| 2672 | // RESULT: sorting |
| 2673 | QCOMPARE(hv->sortIndicatorSection(), 0); |
| 2674 | |
| 2675 | hv->setSortIndicator(logicalIndex: -1, order: Qt::AscendingOrder); |
| 2676 | QCOMPARE(hv->sortIndicatorSection(), -1); |
| 2677 | |
| 2678 | pressOnSection(0); |
| 2679 | moveOntoSection(1); |
| 2680 | releaseOnSection(1); |
| 2681 | // RESULT: no sorting |
| 2682 | QCOMPARE(hv->sortIndicatorSection(), -1); |
| 2683 | |
| 2684 | pressOnSection(0); |
| 2685 | moveOntoSection(1); |
| 2686 | moveOntoSection(2); |
| 2687 | releaseOnSection(2); |
| 2688 | // RESULT: no sorting |
| 2689 | QCOMPARE(hv->sortIndicatorSection(), -1); |
| 2690 | |
| 2691 | pressOnSection(0); |
| 2692 | moveOntoSection(1); |
| 2693 | moveOntoSection(0); |
| 2694 | releaseOnSection(0); |
| 2695 | // RESULT: sorting by 0 |
| 2696 | QCOMPARE(hv->sortIndicatorSection(), 0); |
| 2697 | |
| 2698 | pressOnSection(0); |
| 2699 | moveOntoSection(1); |
| 2700 | releaseOnSection(1); |
| 2701 | // RESULT: no change, still sorting by 0 |
| 2702 | QCOMPARE(hv->sortIndicatorSection(), 0); |
| 2703 | |
| 2704 | auto sortOrder = hv->sortIndicatorOrder(); |
| 2705 | pressOnSection(1); |
| 2706 | moveOntoSection(0); |
| 2707 | releaseOnSection(0); |
| 2708 | // RESULT: no change, still sorting by 0 |
| 2709 | QCOMPARE(hv->sortIndicatorSection(), 0); |
| 2710 | QCOMPARE(hv->sortIndicatorOrder(), sortOrder); |
| 2711 | |
| 2712 | pressOnSection(1); |
| 2713 | moveOntoSection(0); |
| 2714 | moveOntoSection(1); |
| 2715 | releaseOnSection(1); |
| 2716 | // RESULT: sorting by 1 |
| 2717 | QCOMPARE(hv->sortIndicatorSection(), 1); |
| 2718 | |
| 2719 | pressOnSection(1); |
| 2720 | moveOntoSection(0); |
| 2721 | releaseOnSection(0); |
| 2722 | // RESULT: no change, still sorting by 1 |
| 2723 | QCOMPARE(hv->sortIndicatorSection(), 1); |
| 2724 | |
| 2725 | hv->setSortIndicator(logicalIndex: -1, order: Qt::AscendingOrder); |
| 2726 | QCOMPARE(hv->sortIndicatorSection(), -1); |
| 2727 | |
| 2728 | pressOnSection(0); |
| 2729 | releaseOnSection(0, OutOfRangeYOffset); |
| 2730 | // RESULT: no sorting |
| 2731 | QCOMPARE(hv->sortIndicatorSection(), -1); |
| 2732 | |
| 2733 | pressOnSection(0); |
| 2734 | moveOntoSection(0, OutOfRangeYOffset); |
| 2735 | releaseOnSection(0, OutOfRangeYOffset); |
| 2736 | // RESULT: no sorting |
| 2737 | QCOMPARE(hv->sortIndicatorSection(), -1); |
| 2738 | |
| 2739 | pressOnSection(0); |
| 2740 | moveOntoSection(0, OutOfRangeYOffset); |
| 2741 | moveOntoSection(0); |
| 2742 | releaseOnSection(0); |
| 2743 | // RESULT: sorting by 0 |
| 2744 | QCOMPARE(hv->sortIndicatorSection(), 0); |
| 2745 | |
| 2746 | pressOnSection(1); |
| 2747 | releaseOnSection(1, OutOfRangeYOffset); |
| 2748 | // RESULT: no change, still sorting by 0 |
| 2749 | QCOMPARE(hv->sortIndicatorSection(), 0); |
| 2750 | |
| 2751 | pressOnSection(1); |
| 2752 | moveOntoSection(1, OutOfRangeYOffset); |
| 2753 | releaseOnSection(1, OutOfRangeYOffset); |
| 2754 | // RESULT: no change, still sorting by 0 |
| 2755 | QCOMPARE(hv->sortIndicatorSection(), 0); |
| 2756 | |
| 2757 | pressOnSection(1); |
| 2758 | moveOntoSection(1, OutOfRangeYOffset); |
| 2759 | moveOntoSection(1); |
| 2760 | releaseOnSection(1); |
| 2761 | // RESULT: sorting by 1 |
| 2762 | QCOMPARE(hv->sortIndicatorSection(), 1); |
| 2763 | |
| 2764 | pressOnSection(2); |
| 2765 | moveOntoSection(1); |
| 2766 | moveOntoSection(2); |
| 2767 | moveOntoSection(2, OutOfRangeYOffset); |
| 2768 | releaseOnSection(2, OutOfRangeYOffset); |
| 2769 | // RESULT: no change, still sorting by 1 |
| 2770 | QCOMPARE(hv->sortIndicatorSection(), 1); |
| 2771 | } |
| 2772 | |
| 2773 | void tst_QHeaderView::() |
| 2774 | { |
| 2775 | QTableView view; // ### Shadowing member view (of type QHeaderView) |
| 2776 | QStandardItemModel model(4, 3); |
| 2777 | setModelTexts(&model); |
| 2778 | QStandardItem *ascendingItem = new QStandardItem(); |
| 2779 | QStandardItem *descendingItem = new QStandardItem(); |
| 2780 | ascendingItem->setData(value: Qt::AscendingOrder, role: Qt::InitialSortOrderRole); |
| 2781 | descendingItem->setData(value: Qt::DescendingOrder, role: Qt::InitialSortOrderRole); |
| 2782 | model.setHorizontalHeaderItem(column: 1, item: ascendingItem); |
| 2783 | model.setHorizontalHeaderItem(column: 2, item: descendingItem); |
| 2784 | view.setModel(&model); |
| 2785 | view.setSortingEnabled(true); |
| 2786 | view.sortByColumn(column: 0, order: Qt::AscendingOrder); |
| 2787 | view.show(); |
| 2788 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
| 2789 | |
| 2790 | const int column1Pos = view.horizontalHeader()->sectionViewportPosition(logicalIndex: 1) + 5; // +5 not to be on the handle |
| 2791 | QTest::mouseClick(widget: view.horizontalHeader()->viewport(), button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: QPoint(column1Pos, 0)); |
| 2792 | QCOMPARE(view.horizontalHeader()->sortIndicatorSection(), 1); |
| 2793 | QCOMPARE(view.horizontalHeader()->sortIndicatorOrder(), Qt::AscendingOrder); |
| 2794 | |
| 2795 | const int column2Pos = view.horizontalHeader()->sectionViewportPosition(logicalIndex: 2) + 5; // +5 not to be on the handle |
| 2796 | QTest::mouseClick(widget: view.horizontalHeader()->viewport(), button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: QPoint(column2Pos, 0)); |
| 2797 | QCOMPARE(view.horizontalHeader()->sortIndicatorSection(), 2); |
| 2798 | QCOMPARE(view.horizontalHeader()->sortIndicatorOrder(), Qt::DescendingOrder); |
| 2799 | |
| 2800 | const int column0Pos = view.horizontalHeader()->sectionViewportPosition(logicalIndex: 0) + 5; // +5 not to be on the handle |
| 2801 | QTest::mouseClick(widget: view.horizontalHeader()->viewport(), button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: QPoint(column0Pos, 0)); |
| 2802 | QCOMPARE(view.horizontalHeader()->sortIndicatorSection(), 0); |
| 2803 | QCOMPARE(view.horizontalHeader()->sortIndicatorOrder(), Qt::AscendingOrder); |
| 2804 | } |
| 2805 | |
| 2806 | const bool block_some_signals = true; // The test should also work with this set to false |
| 2807 | const int rowcount = 500; |
| 2808 | const int colcount = 10; |
| 2809 | |
| 2810 | static inline QString istr(int n, bool comma = true) |
| 2811 | { |
| 2812 | QString s; |
| 2813 | s.setNum(n); |
| 2814 | if (comma) |
| 2815 | s += ", " ; |
| 2816 | return s; |
| 2817 | } |
| 2818 | |
| 2819 | void tst_QHeaderView::calculateAndCheck(int cppline, const int precalced_comparedata[]) |
| 2820 | { |
| 2821 | qint64 endtimer = timer.elapsed(); |
| 2822 | const bool silentmode = true; |
| 2823 | if (!silentmode) |
| 2824 | qDebug().nospace() << "(Time:" << endtimer << ")" ; |
| 2825 | |
| 2826 | QString sline; |
| 2827 | sline.setNum(n: cppline - 1); |
| 2828 | |
| 2829 | const int p1 = 3133777; // just a prime (maybe not that random ;) ) |
| 2830 | const int p2 = 135928393; // just a random large prime - a bit less than signed 32-bit |
| 2831 | |
| 2832 | int sum_visual = 0; |
| 2833 | int sum_logical = 0; |
| 2834 | int sum_size = 0; |
| 2835 | int sum_hidden_size = 0; |
| 2836 | int sum_lookup_visual = 0; |
| 2837 | int sum_lookup_logical = 0; |
| 2838 | |
| 2839 | int chk_visual = 1; |
| 2840 | int chk_logical = 1; |
| 2841 | int chk_sizes = 1; |
| 2842 | int chk_hidden_size = 1; |
| 2843 | int chk_lookup_visual = 1; |
| 2844 | int chk_lookup_logical = 1; |
| 2845 | |
| 2846 | int = 0; |
| 2847 | int lastindex = view->count() - 1; |
| 2848 | |
| 2849 | // calculate information based on index |
| 2850 | for (int i = 0; i <= lastindex; ++i) { |
| 2851 | int visual = view->visualIndex(logicalIndex: i); |
| 2852 | int logical = view->logicalIndex(visualIndex: i); |
| 2853 | int ssize = view->sectionSize(logicalIndex: i); |
| 2854 | |
| 2855 | sum_visual += visual; |
| 2856 | sum_logical += logical; |
| 2857 | sum_size += ssize; |
| 2858 | |
| 2859 | if (visual >= 0) { |
| 2860 | chk_visual %= p2; |
| 2861 | chk_visual *= (visual + 1) * (i + 1) * p1; |
| 2862 | } |
| 2863 | |
| 2864 | if (logical >= 0) { |
| 2865 | chk_logical %= p2; |
| 2866 | chk_logical *= (logical + 1) * (i + 1 + (logical != i) ) * p1; |
| 2867 | } |
| 2868 | |
| 2869 | if (ssize >= 0) { |
| 2870 | chk_sizes %= p2; |
| 2871 | chk_sizes *= ( (ssize + 2) * (i + 1) * p1); |
| 2872 | } |
| 2873 | |
| 2874 | if (view->isSectionHidden(logicalIndex: i)) { |
| 2875 | view->showSection(alogicalIndex: i); |
| 2876 | int hiddensize = view->sectionSize(logicalIndex: i); |
| 2877 | sum_hidden_size += hiddensize; |
| 2878 | chk_hidden_size %= p2; |
| 2879 | chk_hidden_size += ( (hiddensize + 1) * (i + 1) * p1); |
| 2880 | // (hiddensize + 1) in the above to differ between hidden and size 0 |
| 2881 | // Though it can be changed (why isn't sections with size 0 hidden?) |
| 2882 | |
| 2883 | view->hideSection(alogicalIndex: i); |
| 2884 | } |
| 2885 | } |
| 2886 | |
| 2887 | // lookup indexes by pixel position |
| 2888 | const int max_lookup_count = 500; |
| 2889 | int lookup_to = view->height() + 1; |
| 2890 | if (lookup_to > max_lookup_count) |
| 2891 | lookup_to = max_lookup_count; // We limit this lookup - not to spend years when testing. |
| 2892 | // Notice that lookupTest also has its own extra test |
| 2893 | for (int u = 0; u < max_lookup_count; ++u) { |
| 2894 | int visu = view->visualIndexAt(position: u); |
| 2895 | int logi = view->logicalIndexAt(position: u); |
| 2896 | sum_lookup_visual += logi; |
| 2897 | sum_lookup_logical += visu; |
| 2898 | chk_lookup_visual %= p2; |
| 2899 | chk_lookup_visual *= ( (u + 1) * p1 * (visu + 2)); |
| 2900 | chk_lookup_logical %= p2; |
| 2901 | chk_lookup_logical *= ( (u + 1) * p1 * (logi + 2)); |
| 2902 | } |
| 2903 | header_lenght = view->length(); |
| 2904 | |
| 2905 | // visual and logical indexes. |
| 2906 | int sum_to_last_index = (lastindex * (lastindex + 1)) / 2; // == 0 + 1 + 2 + 3 + ... + lastindex |
| 2907 | |
| 2908 | const bool write_calced_data = false; // Do not write calculated output (unless the test fails) |
| 2909 | if (write_calced_data) { |
| 2910 | qDebug().nospace() << "(" << cppline - 1 << ")" // << " const int precalced[] = " |
| 2911 | << " {" << chk_visual << ", " << chk_logical << ", " << chk_sizes << ", " << chk_hidden_size |
| 2912 | << ", " << chk_lookup_visual << ", " << chk_lookup_logical << ", " << header_lenght << "};" ; |
| 2913 | } |
| 2914 | |
| 2915 | const bool sanity_checks = true; |
| 2916 | if (sanity_checks) { |
| 2917 | QString msg = QString("sanity problem at " ) + sline; |
| 2918 | const QScopedArrayPointer<char> holder(QTest::toString(str: msg)); |
| 2919 | const auto verifytext = holder.data(); |
| 2920 | |
| 2921 | QVERIFY2(m_tableview->model()->rowCount() == view->count() , verifytext); |
| 2922 | QVERIFY2(view->visualIndex(lastindex + 1) <= 0, verifytext); // there is no such index in model |
| 2923 | QVERIFY2(view->logicalIndex(lastindex + 1) <= 0, verifytext); // there is no such index in model. |
| 2924 | QVERIFY2(view->logicalIndex(lastindex + 1) <= 0, verifytext); // there is no such index in model. |
| 2925 | QVERIFY2(lastindex < 0 || view->visualIndex(0) >= 0, verifytext); // no rows or legal index |
| 2926 | QVERIFY2(lastindex < 0 || view->logicalIndex(0) >= 0, verifytext); // no rows or legal index |
| 2927 | QVERIFY2(lastindex < 0 || view->visualIndex(lastindex) >= 0, verifytext); // no rows or legal index |
| 2928 | QVERIFY2(lastindex < 0 || view->logicalIndex(lastindex) >= 0, verifytext); // no rows or legal index |
| 2929 | QVERIFY2(view->visualIndexAt(-1) == -1, verifytext); |
| 2930 | QVERIFY2(view->logicalIndexAt(-1) == -1, verifytext); |
| 2931 | QVERIFY2(view->visualIndexAt(view->length()) == -1, verifytext); |
| 2932 | QVERIFY2(view->logicalIndexAt(view->length()) == -1, verifytext); |
| 2933 | QVERIFY2(sum_visual == sum_logical, verifytext); |
| 2934 | QVERIFY2(sum_to_last_index == sum_logical, verifytext); |
| 2935 | } |
| 2936 | |
| 2937 | // Semantic test |
| 2938 | const bool check_semantics = true; // Otherwise there is no 'real' test |
| 2939 | if (!check_semantics) |
| 2940 | return; |
| 2941 | |
| 2942 | const int *x = precalced_comparedata; |
| 2943 | |
| 2944 | QString msg = "semantic problem at " + QString(__FILE__) + " (" + sline + ")" ; |
| 2945 | msg += "\nThe *expected* result was : {" + istr(n: x[0]) + istr(n: x[1]) + istr(n: x[2]) + istr(n: x[3]) |
| 2946 | + istr(n: x[4]) + istr(n: x[5]) + istr(n: x[6], comma: false) + QLatin1Char('}'); |
| 2947 | msg += "\nThe calculated result was : {" ; |
| 2948 | msg += istr(n: chk_visual) + istr(n: chk_logical) + istr(n: chk_sizes) + istr(n: chk_hidden_size) |
| 2949 | + istr(n: chk_lookup_visual) + istr(n: chk_lookup_logical) + istr(n: header_lenght, comma: false) + "};" ; |
| 2950 | |
| 2951 | const QScopedArrayPointer<char> holder(QTest::toString(str: msg)); |
| 2952 | const auto verifytext = holder.data(); |
| 2953 | |
| 2954 | QVERIFY2(chk_visual == x[0], verifytext); |
| 2955 | QVERIFY2(chk_logical == x[1], verifytext); |
| 2956 | QVERIFY2(chk_sizes == x[2], verifytext); |
| 2957 | QVERIFY2(chk_hidden_size == x[3], verifytext); |
| 2958 | QVERIFY2(chk_lookup_visual == x[4], verifytext); |
| 2959 | QVERIFY2(chk_lookup_logical == x[5], verifytext); |
| 2960 | QVERIFY2(header_lenght == x[6], verifytext); |
| 2961 | } |
| 2962 | |
| 2963 | void tst_QHeaderView::(bool also_use_reset_model) |
| 2964 | { |
| 2965 | QTest::addColumn<bool>(name: "updates_enabled" ); |
| 2966 | QTest::addColumn<bool>(name: "special_prepare" ); |
| 2967 | QTest::addColumn<bool>(name: "reset_model" ); |
| 2968 | |
| 2969 | if (also_use_reset_model) { |
| 2970 | QTest::newRow(dataTag: "no_updates+normal+reset" ) << false << false << true; |
| 2971 | QTest::newRow(dataTag: "hasupdates+normal+reset" ) << true << false << true; |
| 2972 | QTest::newRow(dataTag: "no_updates+special+reset" ) << false << true << true; |
| 2973 | QTest::newRow(dataTag: "hasupdates+special+reset" ) << true << true << true; |
| 2974 | } |
| 2975 | |
| 2976 | QTest::newRow(dataTag: "no_updates+normal" ) << false << false << false; |
| 2977 | QTest::newRow(dataTag: "hasupdates+normal" ) << true << false << false; |
| 2978 | QTest::newRow(dataTag: "no_updates+special" ) << false << true << false; |
| 2979 | QTest::newRow(dataTag: "hasupdates+special" ) << true << true << false; |
| 2980 | } |
| 2981 | |
| 2982 | void tst_QHeaderView::() |
| 2983 | { |
| 2984 | m_tableview->setVerticalHeader(view); |
| 2985 | |
| 2986 | QFETCH(bool, updates_enabled); |
| 2987 | QFETCH(bool, special_prepare); |
| 2988 | QFETCH(bool, reset_model); |
| 2989 | |
| 2990 | m_using_reset_model = reset_model; |
| 2991 | m_special_prepare = special_prepare; |
| 2992 | |
| 2993 | if (m_using_reset_model) { |
| 2994 | XResetModel *m = new XResetModel(); |
| 2995 | m_tableview->setModel(m); |
| 2996 | delete model; |
| 2997 | model = m; |
| 2998 | } else { |
| 2999 | m_tableview->setModel(model); |
| 3000 | } |
| 3001 | |
| 3002 | const int default_section_size = 25; |
| 3003 | view->setDefaultSectionSize(default_section_size); // Important - otherwise there will be semantic changes |
| 3004 | |
| 3005 | model->clear(); |
| 3006 | |
| 3007 | if (special_prepare) { |
| 3008 | |
| 3009 | for (int u = 0; u <= rowcount; ++u) // ensures fragmented spans in e.g Qt 4.7 |
| 3010 | model->setRowCount(u); |
| 3011 | |
| 3012 | model->setColumnCount(colcount); |
| 3013 | view->swapSections(first: 0, second: rowcount - 1); |
| 3014 | view->swapSections(first: 0, second: rowcount - 1); // No real change - setup visual and log-indexes |
| 3015 | view->hideSection(alogicalIndex: rowcount - 1); |
| 3016 | view->showSection(alogicalIndex: rowcount - 1); // No real change - (maybe init hidden vector) |
| 3017 | } else { |
| 3018 | model->setColumnCount(colcount); |
| 3019 | model->setRowCount(rowcount); |
| 3020 | } |
| 3021 | |
| 3022 | QString s; |
| 3023 | for (int i = 0; i < model->rowCount(); ++i) { |
| 3024 | model->setData(index: model->index(row: i, column: 0), value: QVariant(i)); |
| 3025 | s.setNum(n: i); |
| 3026 | s += QLatin1Char('.'); |
| 3027 | s += 'a' + (i % 25); |
| 3028 | model->setData(index: model->index(row: i, column: 1), value: QVariant(s)); |
| 3029 | } |
| 3030 | m_tableview->setUpdatesEnabled(updates_enabled); |
| 3031 | view->blockSignals(b: block_some_signals); |
| 3032 | timer.start(); |
| 3033 | } |
| 3034 | |
| 3035 | void tst_QHeaderView::() |
| 3036 | { |
| 3037 | additionalInit(); |
| 3038 | |
| 3039 | view->swapSections(first: 4, second: 9); // Make sure that visual and logical Indexes are not just the same. |
| 3040 | |
| 3041 | int check1 = 0; |
| 3042 | int check2 = 0; |
| 3043 | for (int u = 0; u < model->rowCount(); ++u) { |
| 3044 | view->resizeSection(logicalIndex: u, size: 10 + u % 30); |
| 3045 | int v = view->visualIndexAt(position: u * 29); |
| 3046 | view->visualIndexAt(position: u * 29); |
| 3047 | check1 += v; |
| 3048 | check2 += u * v; |
| 3049 | } |
| 3050 | view->resizeSection(logicalIndex: 0, size: 0); // Make sure that we have a 0 size section - before the result set |
| 3051 | view->setSectionHidden(logicalIndex: 6, hide: true); // Make sure we have a real hidden section before result set |
| 3052 | |
| 3053 | //qDebug() << "logicalIndexAtTest" << check1 << check2; |
| 3054 | const int precalced_check1 = 106327; |
| 3055 | const int precalced_check2 = 29856418; |
| 3056 | QCOMPARE(precalced_check1, check1); |
| 3057 | QCOMPARE(precalced_check2, check2); |
| 3058 | |
| 3059 | const int precalced_results[] = { 1145298384, -1710423344, -650981936, 372919464, -1544372176, -426463328, 12124 }; |
| 3060 | calculateAndCheck(__LINE__, precalced_comparedata: precalced_results); |
| 3061 | } |
| 3062 | |
| 3063 | void tst_QHeaderView::() |
| 3064 | { |
| 3065 | additionalInit(); |
| 3066 | |
| 3067 | view->swapSections(first: 4, second: 9); // Make sure that visual and logical Indexes are not just the same. |
| 3068 | int check1 = 0; |
| 3069 | int check2 = 0; |
| 3070 | |
| 3071 | for (int u = 0; u < model->rowCount(); ++u) { |
| 3072 | view->resizeSection(logicalIndex: u, size: 3 + u % 17); |
| 3073 | int v = view->visualIndexAt(position: u * 29); |
| 3074 | check1 += v; |
| 3075 | check2 += u * v; |
| 3076 | } |
| 3077 | |
| 3078 | view->resizeSection(logicalIndex: 1, size: 0); // Make sure that we have a 0 size section - before the result set |
| 3079 | view->setSectionHidden(logicalIndex: 5, hide: true); // Make sure we have a real hidden section before result set |
| 3080 | |
| 3081 | //qDebug() << "visualIndexAtTest" << check1 << check2; |
| 3082 | const int precalced_check1 = 72665; |
| 3083 | const int precalced_check2 = 14015890; |
| 3084 | QCOMPARE(precalced_check1, check1); |
| 3085 | QCOMPARE(precalced_check2, check2); |
| 3086 | |
| 3087 | const int precalced_results[] = { 1145298384, -1710423344, -1457520212, 169223959, 557466160, -324939600, 5453 }; |
| 3088 | calculateAndCheck(__LINE__, precalced_comparedata: precalced_results); |
| 3089 | } |
| 3090 | |
| 3091 | void tst_QHeaderView::() |
| 3092 | { |
| 3093 | additionalInit(); |
| 3094 | |
| 3095 | for (int u = model->rowCount(); u >= 0; --u) |
| 3096 | if (u % 8 != 0) |
| 3097 | view->hideSection(alogicalIndex: u); |
| 3098 | |
| 3099 | for (int u = model->rowCount(); u >= 0; --u) |
| 3100 | if (u % 3 == 0) |
| 3101 | view->showSection(alogicalIndex: u); |
| 3102 | |
| 3103 | view->setSectionHidden(logicalIndex: model->rowCount(), hide: true); // invalid hide (should be ignored) |
| 3104 | view->setSectionHidden(logicalIndex: -1, hide: true); // invalid hide (should be ignored) |
| 3105 | |
| 3106 | const int precalced_results[] = { -1523279360, -1523279360, -1321506816, 2105322423, 1879611280, 1879611280, 5225 }; |
| 3107 | calculateAndCheck(__LINE__, precalced_comparedata: precalced_results); |
| 3108 | } |
| 3109 | |
| 3110 | void tst_QHeaderView::() |
| 3111 | { |
| 3112 | additionalInit(); |
| 3113 | |
| 3114 | for (int u = 0; u < rowcount / 2; ++u) |
| 3115 | view->swapSections(first: u, second: rowcount - u - 1); |
| 3116 | |
| 3117 | for (int u = 0; u < rowcount; u += 2) |
| 3118 | view->swapSections(first: u, second: u + 1); |
| 3119 | |
| 3120 | view->swapSections(first: 0, second: model->rowCount()); // invalid swapsection (should be ignored) |
| 3121 | |
| 3122 | const int precalced_results[] = { -1536450048, -1774641430, -1347156568, 1, 1719705216, -240077576, 12500 }; |
| 3123 | calculateAndCheck(__LINE__, precalced_comparedata: precalced_results); |
| 3124 | } |
| 3125 | |
| 3126 | void tst_QHeaderView::() |
| 3127 | { |
| 3128 | additionalInit(); |
| 3129 | |
| 3130 | for (int u = 1; u < 5; ++u) |
| 3131 | view->moveSection(from: u, to: model->rowCount() - u); |
| 3132 | |
| 3133 | view->moveSection(from: 2, to: model->rowCount() / 2); |
| 3134 | view->moveSection(from: 0, to: 10); |
| 3135 | view->moveSection(from: 0, to: model->rowCount() - 10); |
| 3136 | |
| 3137 | view->moveSection(from: 0, to: model->rowCount()); // invalid move (should be ignored) |
| 3138 | |
| 3139 | const int precalced_results[] = { 645125952, 577086896, -1347156568, 1, 1719705216, 709383416, 12500 }; |
| 3140 | calculateAndCheck(__LINE__, precalced_comparedata: precalced_results); |
| 3141 | } |
| 3142 | |
| 3143 | void tst_QHeaderView::() |
| 3144 | { |
| 3145 | additionalInit(); |
| 3146 | |
| 3147 | view->hideSection(alogicalIndex: rowcount / 2); |
| 3148 | int restore_to = view->defaultSectionSize(); |
| 3149 | view->setDefaultSectionSize(restore_to + 5); |
| 3150 | |
| 3151 | const int precalced_results[] = { -1523279360, -1523279360, -1739688320, -1023807777, 997629696, 997629696, 14970 }; |
| 3152 | calculateAndCheck(__LINE__, precalced_comparedata: precalced_results); |
| 3153 | |
| 3154 | view->setDefaultSectionSize(restore_to); |
| 3155 | } |
| 3156 | |
| 3157 | void tst_QHeaderView::() |
| 3158 | { |
| 3159 | additionalInit(); |
| 3160 | |
| 3161 | view->swapSections(first: 0, second: 5); |
| 3162 | model->removeRows(row: 0, count: 1); // remove one row |
| 3163 | model->removeRows(row: 4, count: 10); |
| 3164 | model->setRowCount(model->rowCount() / 2 - 1); |
| 3165 | |
| 3166 | if (m_using_reset_model) { |
| 3167 | const int precalced_results[] = { 1741224292, -135269187, -569519837, 1, 1719705216, -1184395000, 6075 }; |
| 3168 | calculateAndCheck(__LINE__, precalced_comparedata: precalced_results); |
| 3169 | } else { |
| 3170 | const int precalced_results[] = { 289162397, 289162397, -569519837, 1, 1719705216, 1719705216, 6075 }; |
| 3171 | calculateAndCheck(__LINE__, precalced_comparedata: precalced_results); |
| 3172 | } |
| 3173 | } |
| 3174 | |
| 3175 | void tst_QHeaderView::() |
| 3176 | { |
| 3177 | additionalInit(); |
| 3178 | |
| 3179 | view->swapSections(first: 0, second: model->rowCount() - 1); |
| 3180 | model->insertRows(row: 0, count: 1); // insert one row |
| 3181 | model->insertRows(row: 4, count: 10); |
| 3182 | model->setRowCount(model->rowCount() * 2 - 1); |
| 3183 | |
| 3184 | if (m_using_reset_model) { |
| 3185 | const int precalced_results[] = { 2040508069, -1280266538, -150350734, 1, 1719705216, 1331312784, 25525 }; |
| 3186 | calculateAndCheck(__LINE__, precalced_comparedata: precalced_results); |
| 3187 | } else { |
| 3188 | const int precalced_results[] = { -1909447021, 339092083, -150350734, 1, 1719705216, -969712728, 25525 }; |
| 3189 | calculateAndCheck(__LINE__, precalced_comparedata: precalced_results); |
| 3190 | } |
| 3191 | } |
| 3192 | |
| 3193 | void tst_QHeaderView::() |
| 3194 | { |
| 3195 | additionalInit(); |
| 3196 | |
| 3197 | model->setRowCount(model->rowCount() + 10); |
| 3198 | |
| 3199 | for (int u = 0; u < model->rowCount(); u += 2) |
| 3200 | view->swapSections(first: u, second: u + 1); |
| 3201 | |
| 3202 | view->moveSection(from: 0, to: 5); |
| 3203 | |
| 3204 | for (int u = model->rowCount(); u >= 0; --u) { |
| 3205 | if (u % 5 != 0) { |
| 3206 | view->hideSection(alogicalIndex: u); |
| 3207 | QVERIFY(view->isSectionHidden(u)); |
| 3208 | } |
| 3209 | if (u % 3 != 0) { |
| 3210 | view->showSection(alogicalIndex: u); |
| 3211 | QVERIFY(!view->isSectionHidden(u)); |
| 3212 | } |
| 3213 | } |
| 3214 | |
| 3215 | model->insertRows(row: 3, count: 7); |
| 3216 | model->removeRows(row: 8, count: 3); |
| 3217 | model->setRowCount(model->rowCount() - 10); |
| 3218 | |
| 3219 | // the upper is not visible (when m_using_reset_model is true) |
| 3220 | // the lower 11 are modified due to insert/removeRows |
| 3221 | for (int u = model->rowCount() - 1; u >= 11; --u) { |
| 3222 | // when using reset, the hidden rows will *not* move |
| 3223 | const int calcMod = m_using_reset_model ? u : u - 4; // 7 added, 3 removed |
| 3224 | if (calcMod % 5 != 0 && calcMod % 3 == 0) { |
| 3225 | QVERIFY(view->isSectionHidden(u)); |
| 3226 | } |
| 3227 | if (calcMod % 3 != 0) { |
| 3228 | QVERIFY(!view->isSectionHidden(u)); |
| 3229 | } |
| 3230 | } |
| 3231 | if (m_using_reset_model) { |
| 3232 | const int precalced_results[] = { 898296472, 337096378, -543340640, -1964432121, -1251526424, -568618976, 9250 }; |
| 3233 | calculateAndCheck(__LINE__, precalced_comparedata: precalced_results); |
| 3234 | } else { |
| 3235 | const int precalced_results[] = { 1911338224, 1693514365, -613398968, -1912534953, 1582159424, -1851079000, 9300 }; |
| 3236 | calculateAndCheck(__LINE__, precalced_comparedata: precalced_results); |
| 3237 | } |
| 3238 | } |
| 3239 | |
| 3240 | void tst_QHeaderView::() |
| 3241 | { |
| 3242 | additionalInit(); |
| 3243 | |
| 3244 | QModelIndex idx = model->index(row: 2, column: 2); |
| 3245 | model->setData(index: idx, value: QVariant("A normal string" )); |
| 3246 | |
| 3247 | idx = model->index(row: 1, column: 3); |
| 3248 | model->setData(index: idx, value: QVariant("A normal longer string to test resize" )); |
| 3249 | |
| 3250 | QHeaderView *hh = m_tableview->horizontalHeader(); |
| 3251 | hh->resizeSections(mode: QHeaderView::ResizeToContents); |
| 3252 | QVERIFY(hh->sectionSize(3) > hh->sectionSize(2)); |
| 3253 | |
| 3254 | for (int u = 0; u < 10; ++u) |
| 3255 | view->resizeSection(logicalIndex: u, size: 1); |
| 3256 | |
| 3257 | view->resizeSections(mode: QHeaderView::ResizeToContents); |
| 3258 | QVERIFY(view->sectionSize(1) > 1); |
| 3259 | QVERIFY(view->sectionSize(2) > 1); |
| 3260 | |
| 3261 | // Check minimum section size |
| 3262 | hh->setMinimumSectionSize(150); |
| 3263 | model->setData(index: idx, value: QVariant("i" )); |
| 3264 | hh->resizeSections(mode: QHeaderView::ResizeToContents); |
| 3265 | QCOMPARE(hh->sectionSize(3), 150); |
| 3266 | hh->setMinimumSectionSize(-1); |
| 3267 | |
| 3268 | // Check maximumSection size |
| 3269 | hh->setMaximumSectionSize(200); |
| 3270 | model->setData(index: idx, value: QVariant("This is a even longer string that is expected to be more than 200 pixels" )); |
| 3271 | hh->resizeSections(mode: QHeaderView::ResizeToContents); |
| 3272 | QCOMPARE(hh->sectionSize(3), 200); |
| 3273 | hh->setMaximumSectionSize(-1); |
| 3274 | |
| 3275 | view->setDefaultSectionSize(25); // To make sure our precalced data are correct. We do not know font height etc. |
| 3276 | |
| 3277 | const int precalced_results[] = { -1523279360, -1523279360, -1347156568, 1, 1719705216, 1719705216, 12500 }; |
| 3278 | calculateAndCheck(__LINE__, precalced_comparedata: precalced_results); |
| 3279 | } |
| 3280 | |
| 3281 | void tst_QHeaderView::() |
| 3282 | { |
| 3283 | #ifndef QT_NO_DATASTREAM |
| 3284 | m_tableview->setVerticalHeader(view); |
| 3285 | m_tableview->setModel(model); |
| 3286 | view->setDefaultSectionSize(25); |
| 3287 | view->hideSection(alogicalIndex: 2); |
| 3288 | view->swapSections(first: 1, second: 2); |
| 3289 | |
| 3290 | QByteArray s = view->saveState(); |
| 3291 | view->swapSections(first: 1, second: 2); |
| 3292 | view->setDefaultSectionSize(30); // To make sure our precalced data are correct. |
| 3293 | view->restoreState(state: s); |
| 3294 | |
| 3295 | const int precalced_results[] = { -1116614432, -1528653200, -1914165644, 244434607, -1111214068, 750357900, 75}; |
| 3296 | calculateAndCheck(__LINE__, precalced_comparedata: precalced_results); |
| 3297 | #else |
| 3298 | QSKIP("Datastream required for testStreamWithHide. Skipping this test." ); |
| 3299 | #endif |
| 3300 | } |
| 3301 | |
| 3302 | void tst_QHeaderView::() |
| 3303 | { |
| 3304 | topLevel->show(); |
| 3305 | QVERIFY(QTest::qWaitForWindowExposed(topLevel)); |
| 3306 | |
| 3307 | protected_QHeaderView * = static_cast<protected_QHeaderView *>(view); |
| 3308 | |
| 3309 | TestStyle proxy; |
| 3310 | header->setStyle(&proxy); |
| 3311 | |
| 3312 | QImage image(1, 1, QImage::Format_ARGB32); |
| 3313 | QPainter p(&image); |
| 3314 | |
| 3315 | // 0, 1, 2, 3 |
| 3316 | header->paintSection(painter: &p, rect: view->rect(), logicalIndex: 0); |
| 3317 | QCOMPARE(proxy.lastPosition, QStyleOptionHeader::Beginning); |
| 3318 | header->paintSection(painter: &p, rect: view->rect(), logicalIndex: 1); |
| 3319 | QCOMPARE(proxy.lastPosition, QStyleOptionHeader::Middle); |
| 3320 | header->paintSection(painter: &p, rect: view->rect(), logicalIndex: 2); |
| 3321 | QCOMPARE(proxy.lastPosition, QStyleOptionHeader::Middle); |
| 3322 | header->paintSection(painter: &p, rect: view->rect(), logicalIndex: 3); |
| 3323 | QCOMPARE(proxy.lastPosition, QStyleOptionHeader::End); |
| 3324 | |
| 3325 | // (0),2,1,3 |
| 3326 | view->setSectionHidden(logicalIndex: 0, hide: true); |
| 3327 | view->swapSections(first: 1, second: 2); |
| 3328 | header->paintSection(painter: &p, rect: view->rect(), logicalIndex: 1); |
| 3329 | QCOMPARE(proxy.lastPosition, QStyleOptionHeader::Middle); |
| 3330 | header->paintSection(painter: &p, rect: view->rect(), logicalIndex: 2); |
| 3331 | QCOMPARE(proxy.lastPosition, QStyleOptionHeader::Beginning); |
| 3332 | header->paintSection(painter: &p, rect: view->rect(), logicalIndex: 3); |
| 3333 | QCOMPARE(proxy.lastPosition, QStyleOptionHeader::End); |
| 3334 | |
| 3335 | // (1),2,0,(3) |
| 3336 | view->setSectionHidden(logicalIndex: 3, hide: true); |
| 3337 | view->setSectionHidden(logicalIndex: 0, hide: false); |
| 3338 | view->setSectionHidden(logicalIndex: 1, hide: true); |
| 3339 | view->swapSections(first: 0, second: 1); |
| 3340 | header->paintSection(painter: &p, rect: view->rect(), logicalIndex: 0); |
| 3341 | QCOMPARE(proxy.lastPosition, QStyleOptionHeader::End); |
| 3342 | header->paintSection(painter: &p, rect: view->rect(), logicalIndex: 2); |
| 3343 | QCOMPARE(proxy.lastPosition, QStyleOptionHeader::Beginning); |
| 3344 | |
| 3345 | // (1),2,(0),(3) |
| 3346 | view->setSectionHidden(logicalIndex: 0, hide: true); |
| 3347 | header->paintSection(painter: &p, rect: view->rect(), logicalIndex: 2); |
| 3348 | QCOMPARE(proxy.lastPosition, QStyleOptionHeader::OnlyOneSection); |
| 3349 | } |
| 3350 | |
| 3351 | void tst_QHeaderView::() |
| 3352 | { |
| 3353 | QTreeView treeView; |
| 3354 | QStandardItemModel *model = new QStandardItemModel(&treeView); |
| 3355 | model->appendRow(aitem: new QStandardItem("QTBUG-48543" )); |
| 3356 | treeView.setModel(model); |
| 3357 | treeView.header()->sizeHintForColumn(column: 0); |
| 3358 | treeView.header()->sizeHintForRow(row: 0); |
| 3359 | } |
| 3360 | |
| 3361 | void tst_QHeaderView::stretchAndRestoreLastSection() |
| 3362 | { |
| 3363 | QStandardItemModel m(10, 10); |
| 3364 | QTableView tv; |
| 3365 | tv.setModel(&m); |
| 3366 | tv.showMaximized(); |
| 3367 | |
| 3368 | const int minimumSectionSize = 20; |
| 3369 | const int defaultSectionSize = 30; |
| 3370 | const int someOtherSectionSize = 40; |
| 3371 | const int biggerSizeThanAnySection = 50; |
| 3372 | |
| 3373 | QVERIFY(QTest::qWaitForWindowExposed(&tv)); |
| 3374 | |
| 3375 | QHeaderView & = *tv.horizontalHeader(); |
| 3376 | // set minimum size before resizeSections() is called |
| 3377 | // which is done inside setStretchLastSection |
| 3378 | header.setMinimumSectionSize(minimumSectionSize); |
| 3379 | header.setDefaultSectionSize(defaultSectionSize); |
| 3380 | header.resizeSection(logicalIndex: 9, size: someOtherSectionSize); |
| 3381 | header.setStretchLastSection(true); |
| 3382 | |
| 3383 | // Default last section is larger |
| 3384 | QCOMPARE(header.sectionSize(8), defaultSectionSize); |
| 3385 | QVERIFY(header.sectionSize(9) >= biggerSizeThanAnySection); |
| 3386 | |
| 3387 | // Moving last section away (restore old last section 9 - and make 8 larger) |
| 3388 | header.swapSections(first: 9, second: 8); |
| 3389 | QCOMPARE(header.sectionSize(9), someOtherSectionSize); |
| 3390 | QVERIFY(header.sectionSize(8) >= biggerSizeThanAnySection); |
| 3391 | |
| 3392 | // Make section 9 the large one again |
| 3393 | header.hideSection(alogicalIndex: 8); |
| 3394 | QVERIFY(header.sectionSize(9) >= biggerSizeThanAnySection); |
| 3395 | |
| 3396 | // Show section 8 again - and make that one the last one. |
| 3397 | header.showSection(alogicalIndex: 8); |
| 3398 | QVERIFY(header.sectionSize(8) > biggerSizeThanAnySection); |
| 3399 | QCOMPARE(header.sectionSize(9), someOtherSectionSize); |
| 3400 | |
| 3401 | // Swap the sections so the logical indexes are equal to visible indexes again. |
| 3402 | header.moveSection(from: 9, to: 8); |
| 3403 | QCOMPARE(header.sectionSize(8), defaultSectionSize); |
| 3404 | QVERIFY(header.sectionSize(9) >= biggerSizeThanAnySection); |
| 3405 | |
| 3406 | // Append sections |
| 3407 | m.setColumnCount(15); |
| 3408 | QCOMPARE(header.sectionSize(9), someOtherSectionSize); |
| 3409 | QVERIFY(header.sectionSize(14) >= biggerSizeThanAnySection); |
| 3410 | |
| 3411 | // Truncate sections (remove sections with the last section) |
| 3412 | m.setColumnCount(10); |
| 3413 | QVERIFY(header.sectionSize(9) >= biggerSizeThanAnySection); |
| 3414 | for (int u = 0; u < 9; ++u) |
| 3415 | QCOMPARE(header.sectionSize(u), defaultSectionSize); |
| 3416 | |
| 3417 | // Insert sections |
| 3418 | m.insertColumns(column: 2, count: 2); |
| 3419 | QCOMPARE(header.sectionSize(9), defaultSectionSize); |
| 3420 | QCOMPARE(header.sectionSize(10), defaultSectionSize); |
| 3421 | QVERIFY(header.sectionSize(11) >= biggerSizeThanAnySection); |
| 3422 | |
| 3423 | // Append an extra section and check restore |
| 3424 | m.setColumnCount(m.columnCount() + 1); |
| 3425 | QCOMPARE(header.sectionSize(11), someOtherSectionSize); |
| 3426 | QVERIFY(header.sectionSize(12) >= biggerSizeThanAnySection); |
| 3427 | |
| 3428 | // Remove some sections but not the last one. |
| 3429 | m.removeColumns(column: 2, count: 2); |
| 3430 | QCOMPARE(header.sectionSize(9), someOtherSectionSize); |
| 3431 | QVERIFY(header.sectionSize(10) >= biggerSizeThanAnySection); |
| 3432 | for (int u = 0; u < 9; ++u) |
| 3433 | QCOMPARE(header.sectionSize(u), defaultSectionSize); |
| 3434 | |
| 3435 | // Empty the header and start over with some more tests |
| 3436 | m.setColumnCount(0); |
| 3437 | m.setColumnCount(10); |
| 3438 | QVERIFY(header.sectionSize(9) >= biggerSizeThanAnySection); |
| 3439 | |
| 3440 | // Check resize of the last section |
| 3441 | header.resizeSection(logicalIndex: 9, size: someOtherSectionSize); |
| 3442 | QVERIFY(header.sectionSize(9) >= biggerSizeThanAnySection); // It should still be stretched |
| 3443 | header.swapSections(first: 9, second: 8); |
| 3444 | QCOMPARE(header.sectionSize(9), someOtherSectionSize); |
| 3445 | |
| 3446 | // Restore the order |
| 3447 | header.swapSections(first: 9, second: 8); |
| 3448 | QVERIFY(header.sectionSize(9) >= biggerSizeThanAnySection); |
| 3449 | |
| 3450 | // Hide the last 3 sections and test stretch last section on swap/move |
| 3451 | // when hidden sections with a larger visual index exists. |
| 3452 | header.hideSection(alogicalIndex: 7); |
| 3453 | header.hideSection(alogicalIndex: 8); |
| 3454 | header.hideSection(alogicalIndex: 9); |
| 3455 | QVERIFY(header.sectionSize(6) >= biggerSizeThanAnySection); |
| 3456 | header.moveSection(from: 2, to: 7); |
| 3457 | QVERIFY(header.sectionSize(2) >= biggerSizeThanAnySection); |
| 3458 | header.swapSections(first: 1, second: 8); |
| 3459 | QCOMPARE(header.sectionSize(2), defaultSectionSize); |
| 3460 | QVERIFY(header.sectionSize(1) >= biggerSizeThanAnySection); |
| 3461 | |
| 3462 | // Inserting sections 2 |
| 3463 | m.setColumnCount(0); |
| 3464 | m.setColumnCount(10); |
| 3465 | header.resizeSection(logicalIndex: 1, size: someOtherSectionSize); |
| 3466 | header.swapSections(first: 1, second: 9); |
| 3467 | m.insertColumns(column: 9, count: 2); |
| 3468 | header.swapSections(first: 1, second: 11); |
| 3469 | QCOMPARE(header.sectionSize(1), someOtherSectionSize); |
| 3470 | |
| 3471 | // Clear and re-add. This triggers a different code path than seColumnCount(0) |
| 3472 | m.clear(); |
| 3473 | m.setColumnCount(3); |
| 3474 | QVERIFY(header.sectionSize(2) >= biggerSizeThanAnySection); |
| 3475 | |
| 3476 | // Test import/export of the original (not stretched) sectionSize. |
| 3477 | m.setColumnCount(0); |
| 3478 | m.setColumnCount(10); |
| 3479 | header.resizeSection(logicalIndex: 9, size: someOtherSectionSize); |
| 3480 | QVERIFY(header.sectionSize(9) >= biggerSizeThanAnySection); |
| 3481 | QByteArray b = header.saveState(); |
| 3482 | m.setColumnCount(0); |
| 3483 | m.setColumnCount(10); |
| 3484 | header.restoreState(state: b); |
| 3485 | header.setStretchLastSection(false); |
| 3486 | QCOMPARE(header.sectionSize(9), someOtherSectionSize); |
| 3487 | } |
| 3488 | |
| 3489 | void tst_QHeaderView::() |
| 3490 | { |
| 3491 | QTest::addColumn<bool>(name: "stretchLastSection" ); |
| 3492 | QTest::addRow(format: "stretched" ) << true; |
| 3493 | QTest::addRow(format: "not stretched" ) << false; |
| 3494 | } |
| 3495 | |
| 3496 | void tst_QHeaderView::() |
| 3497 | { |
| 3498 | QFETCH(bool, stretchLastSection); |
| 3499 | |
| 3500 | QStandardItemModel m(5, 5); |
| 3501 | QTableView tv; |
| 3502 | tv.setModel(&m); |
| 3503 | tv.show(); |
| 3504 | |
| 3505 | const int sectionSizeMin = 20; |
| 3506 | const int sectionSizeMax = 40; |
| 3507 | const int defaultSectionSize = 30; |
| 3508 | |
| 3509 | QVERIFY(QTest::qWaitForWindowExposed(&tv)); |
| 3510 | |
| 3511 | QHeaderView & = *tv.horizontalHeader(); |
| 3512 | header.setMinimumSectionSize(sectionSizeMin); |
| 3513 | header.setMaximumSectionSize(sectionSizeMax); |
| 3514 | // check bounds for default section size |
| 3515 | header.setDefaultSectionSize(sectionSizeMin - 1); |
| 3516 | QCOMPARE(header.defaultSectionSize(), sectionSizeMin); |
| 3517 | header.setDefaultSectionSize(sectionSizeMax + 1); |
| 3518 | QCOMPARE(header.defaultSectionSize(), sectionSizeMax); |
| 3519 | |
| 3520 | header.setDefaultSectionSize(defaultSectionSize); |
| 3521 | QCOMPARE(header.defaultSectionSize(), defaultSectionSize); |
| 3522 | header.setStretchLastSection(stretchLastSection); |
| 3523 | QCOMPARE(header.stretchLastSection(), stretchLastSection); |
| 3524 | |
| 3525 | // check defaults |
| 3526 | QCOMPARE(header.sectionSize(0), defaultSectionSize); |
| 3527 | QCOMPARE(header.sectionSize(3), defaultSectionSize); |
| 3528 | |
| 3529 | // do not go above maxSectionSize |
| 3530 | header.resizeSection(logicalIndex: 0, size: sectionSizeMax + 1); |
| 3531 | QCOMPARE(header.sectionSize(0), sectionSizeMax); |
| 3532 | |
| 3533 | // do not go below minSectionSize |
| 3534 | header.resizeSection(logicalIndex: 0, size: sectionSizeMin - 1); |
| 3535 | QCOMPARE(header.sectionSize(0), sectionSizeMin); |
| 3536 | |
| 3537 | // change section size on max change |
| 3538 | header.setMinimumSectionSize(sectionSizeMin); |
| 3539 | header.setMaximumSectionSize(sectionSizeMax); |
| 3540 | header.resizeSection(logicalIndex: 0, size: sectionSizeMax); |
| 3541 | QCOMPARE(header.sectionSize(0), sectionSizeMax); |
| 3542 | header.setMaximumSectionSize(defaultSectionSize); |
| 3543 | QTRY_COMPARE(header.sectionSize(0), defaultSectionSize); |
| 3544 | |
| 3545 | // change section size on min change |
| 3546 | header.setMinimumSectionSize(sectionSizeMin); |
| 3547 | header.setMaximumSectionSize(sectionSizeMax); |
| 3548 | header.resizeSection(logicalIndex: 0, size: sectionSizeMin); |
| 3549 | QCOMPARE(header.sectionSize(0), sectionSizeMin); |
| 3550 | header.setMinimumSectionSize(defaultSectionSize); |
| 3551 | QTRY_COMPARE(header.sectionSize(0), defaultSectionSize); |
| 3552 | } |
| 3553 | |
| 3554 | void tst_QHeaderView::() |
| 3555 | { |
| 3556 | QtTestModel model(10, 10); |
| 3557 | QTableView tv; |
| 3558 | tv.setModel(&model); |
| 3559 | tv.show(); |
| 3560 | QVERIFY(QTest::qWaitForWindowExposed(&tv)); |
| 3561 | |
| 3562 | QSize s1 = tv.horizontalHeader()->sizeHint(); |
| 3563 | model.setMultiLineHeader(true); |
| 3564 | QSize s2 = tv.horizontalHeader()->sizeHint(); |
| 3565 | model.setMultiLineHeader(false); |
| 3566 | QSize s3 = tv.horizontalHeader()->sizeHint(); |
| 3567 | QCOMPARE(s1, s3); |
| 3568 | QVERIFY(s1 != s2); |
| 3569 | } |
| 3570 | |
| 3571 | |
| 3572 | class : public QHeaderView |
| 3573 | { |
| 3574 | Q_OBJECT |
| 3575 | public: |
| 3576 | using QHeaderView::QHeaderView; |
| 3577 | QString ; |
| 3578 | bool = false; |
| 3579 | protected: |
| 3580 | bool (QEvent *e) override |
| 3581 | { |
| 3582 | if (e->type() == QEvent::StatusTip) { |
| 3583 | gotStatusTipEvent = true; |
| 3584 | statusTipText = static_cast<QStatusTipEvent *>(e)->tip(); |
| 3585 | } |
| 3586 | return QHeaderView::event(e); |
| 3587 | } |
| 3588 | }; |
| 3589 | |
| 3590 | void tst_QHeaderView::() |
| 3591 | { |
| 3592 | if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) |
| 3593 | QSKIP("Wayland: This fails. Figure out why." ); |
| 3594 | |
| 3595 | StatusTipHeaderView (Qt::Horizontal); |
| 3596 | QtTestModel model(5, 5); |
| 3597 | headerView.setModel(&model); |
| 3598 | headerView.viewport()->setMouseTracking(true); |
| 3599 | headerView.setGeometry(QRect(QPoint(QApplication::desktop()->geometry().center() - QPoint(250, 250)), |
| 3600 | QSize(500, 500))); |
| 3601 | headerView.show(); |
| 3602 | QApplication::setActiveWindow(&headerView); |
| 3603 | QVERIFY(QTest::qWaitForWindowActive(&headerView)); |
| 3604 | |
| 3605 | // Ensure it is moved away first and then moved to the relevant section |
| 3606 | QTest::mouseMove(widget: QApplication::desktop(), |
| 3607 | pos: headerView.rect().bottomLeft() + QPoint(20, 20)); |
| 3608 | QPoint centerPoint = QRect(headerView.sectionPosition(logicalIndex: 0), 0, |
| 3609 | headerView.sectionSize(logicalIndex: 0), headerView.height()).center(); |
| 3610 | QTest::mouseMove(window: headerView.windowHandle(), pos: centerPoint); |
| 3611 | QTRY_VERIFY(headerView.gotStatusTipEvent); |
| 3612 | QCOMPARE(headerView.statusTipText, QLatin1String("[0,0,0] -- Header" )); |
| 3613 | |
| 3614 | headerView.gotStatusTipEvent = false; |
| 3615 | headerView.statusTipText.clear(); |
| 3616 | centerPoint = QRect(headerView.sectionPosition(logicalIndex: 1), 0, |
| 3617 | headerView.sectionSize(logicalIndex: 1), headerView.height()).center(); |
| 3618 | QTest::mouseMove(window: headerView.windowHandle(), pos: centerPoint); |
| 3619 | QTRY_VERIFY(headerView.gotStatusTipEvent); |
| 3620 | QCOMPARE(headerView.statusTipText, QLatin1String("[0,1,0] -- Header" )); |
| 3621 | } |
| 3622 | |
| 3623 | void tst_QHeaderView::testRemovingColumnsViaLayoutChanged() |
| 3624 | { |
| 3625 | const int persistentSectionSize = 101; |
| 3626 | |
| 3627 | QtTestModel model(5, 5); |
| 3628 | view->setModel(&model); |
| 3629 | for (int i = 0; i < model.cols; ++i) |
| 3630 | view->resizeSection(logicalIndex: i, size: persistentSectionSize + i); |
| 3631 | model.cleanup(); // down to 3 via layoutChanged (not columnsRemoved) |
| 3632 | for (int j = 0; j < model.cols; ++j) |
| 3633 | QCOMPARE(view->sectionSize(j), persistentSectionSize + j); |
| 3634 | // The main point of this test is that the section-size restoring code didn't go out of bounds. |
| 3635 | } |
| 3636 | |
| 3637 | void tst_QHeaderView::testModelMovingColumns() |
| 3638 | { |
| 3639 | QtTestModel model(10, 10); |
| 3640 | QHeaderView hv(Qt::Horizontal); |
| 3641 | hv.setModel(&model); |
| 3642 | hv.resizeSections(mode: QHeaderView::ResizeToContents); |
| 3643 | hv.show(); |
| 3644 | |
| 3645 | QPersistentModelIndex index3 = model.index(row: 0, column: 3); |
| 3646 | model.moveColumn(from: 3, to: 1); |
| 3647 | QCOMPARE(index3.column(), 1); |
| 3648 | } |
| 3649 | |
| 3650 | QTEST_MAIN(tst_QHeaderView) |
| 3651 | #include "tst_qheaderview.moc" |
| 3652 | |