| 1 | /**************************************************************************** | 
| 2 | ** | 
| 3 | ** Copyright (C) 2016 The Qt Company Ltd. | 
| 4 | ** Contact: https://www.qt.io/licensing/ | 
| 5 | ** | 
| 6 | ** This file is part of the test suite of the Qt Toolkit. | 
| 7 | ** | 
| 8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ | 
| 9 | ** Commercial License Usage | 
| 10 | ** Licensees holding valid commercial Qt licenses may use this file in | 
| 11 | ** accordance with the commercial license agreement provided with the | 
| 12 | ** Software or, alternatively, in accordance with the terms contained in | 
| 13 | ** a written agreement between you and The Qt Company. For licensing terms | 
| 14 | ** and conditions see https://www.qt.io/terms-conditions. For further | 
| 15 | ** information use the contact form at https://www.qt.io/contact-us. | 
| 16 | ** | 
| 17 | ** GNU General Public License Usage | 
| 18 | ** Alternatively, this file may be used under the terms of the GNU | 
| 19 | ** General Public License version 3 as published by the Free Software | 
| 20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT | 
| 21 | ** included in the packaging of this file. Please review the following | 
| 22 | ** information to ensure the GNU General Public License requirements will | 
| 23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. | 
| 24 | ** | 
| 25 | ** $QT_END_LICENSE$ | 
| 26 | ** | 
| 27 | ****************************************************************************/ | 
| 28 |  | 
| 29 | #include <QCompleter> | 
| 30 | #include <QHBoxLayout> | 
| 31 | #include <QLineEdit> | 
| 32 | #include <QListWidget> | 
| 33 | #include <QSignalSpy> | 
| 34 | #include <QStyledItemDelegate> | 
| 35 | #include <QTest> | 
| 36 | #include <private/qlistwidget_p.h> | 
| 37 |  | 
| 38 | using IntList = QVector<int>; | 
| 39 |  | 
| 40 | class tst_QListWidget : public QObject | 
| 41 | { | 
| 42 |     Q_OBJECT | 
| 43 |  | 
| 44 | public: | 
| 45 |     tst_QListWidget() = default; | 
| 46 |  | 
| 47 |     enum ModelChanged { | 
| 48 |         RowsAboutToBeInserted, | 
| 49 |         RowsInserted, | 
| 50 |         RowsAboutToBeRemoved, | 
| 51 |         RowsRemoved, | 
| 52 |         ColumnsAboutToBeInserted, | 
| 53 |         ColumnsInserted, | 
| 54 |         ColumnsAboutToBeRemoved, | 
| 55 |         ColumnsRemoved | 
| 56 |     }; | 
| 57 |  | 
| 58 | private slots: | 
| 59 |     void initTestCase(); | 
| 60 |     void cleanupTestCase(); | 
| 61 |     void init(); | 
| 62 |     void addItem(); | 
| 63 |     void addItem2(); | 
| 64 |     void addItems(); | 
| 65 |     void openPersistentEditor(); | 
| 66 |     void closePersistentEditor(); | 
| 67 |     void count(); | 
| 68 |     void currentItem(); | 
| 69 |     void setCurrentItem_data(); | 
| 70 |     void setCurrentItem(); | 
| 71 |     void currentRow(); | 
| 72 |     void setCurrentRow_data(); | 
| 73 |     void setCurrentRow(); | 
| 74 |     void editItem_data(); | 
| 75 |     void editItem(); | 
| 76 |     void findItems(); | 
| 77 |     void insertItem_data(); | 
| 78 |     void insertItem(); | 
| 79 |     void insertItems_data(); | 
| 80 |     void insertItems(); | 
| 81 |     void moveItemsPriv_data(); | 
| 82 |     void moveItemsPriv(); | 
| 83 |  | 
| 84 |     void itemAssignment(); | 
| 85 |     void item_data(); | 
| 86 |     void item(); | 
| 87 |     void takeItem_data(); | 
| 88 |     void takeItem(); | 
| 89 |     void setItemHidden(); | 
| 90 |     void selectedItems_data(); | 
| 91 |     void selectedItems(); | 
| 92 |     void removeItems_data(); | 
| 93 |     void removeItems(); | 
| 94 |     void itemStreaming_data(); | 
| 95 |     void itemStreaming(); | 
| 96 |     void sortItems_data(); | 
| 97 |     void sortItems(); | 
| 98 |     void sortHiddenItems(); | 
| 99 |     void sortHiddenItems_data(); | 
| 100 |     void closeEditor(); | 
| 101 |     void setData_data(); | 
| 102 |     void setData(); | 
| 103 |     void insertItemsWithSorting_data(); | 
| 104 |     void insertItemsWithSorting(); | 
| 105 |     void changeDataWithSorting_data(); | 
| 106 |     void changeDataWithSorting(); | 
| 107 |     void itemData(); | 
| 108 |     void itemWidget(); | 
| 109 | #ifndef Q_OS_MAC | 
| 110 |     void fastScroll(); | 
| 111 | #endif | 
| 112 |     void insertUnchanged(); | 
| 113 |     void setSortingEnabled(); | 
| 114 |     void task199503_crashWhenCleared(); | 
| 115 |     void task217070_scrollbarsAdjusted(); | 
| 116 |     void task258949_keypressHangup(); | 
| 117 |     void QTBUG8086_currentItemChangedOnClick(); | 
| 118 |     void QTBUG14363_completerWithAnyKeyPressedEditTriggers(); | 
| 119 |     void mimeData(); | 
| 120 |     void QTBUG50891_ensureSelectionModelSignalConnectionsAreSet(); | 
| 121 | #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) | 
| 122 |     void clearItemData(); | 
| 123 | #endif | 
| 124 |  | 
| 125 |     void moveRows_data(); | 
| 126 |     void moveRows(); | 
| 127 |     void moveRowsInvalid_data(); | 
| 128 |     void moveRowsInvalid(); | 
| 129 |  | 
| 130 | protected slots: | 
| 131 |     void rowsAboutToBeInserted(const QModelIndex &parent, int first, int last) | 
| 132 |         { modelChanged(change: RowsAboutToBeInserted, parent, first, last); } | 
| 133 |     void rowsInserted(const QModelIndex &parent, int first, int last) | 
| 134 |         { modelChanged(change: RowsInserted, parent, first, last); } | 
| 135 |     void rowsAboutToBeRemoved(const QModelIndex &parent, int first, int last) | 
| 136 |         { modelChanged(change: RowsAboutToBeRemoved, parent, first, last); } | 
| 137 |     void rowsRemoved(const QModelIndex &parent, int first, int last) | 
| 138 |         { modelChanged(change: RowsRemoved, parent, first, last); } | 
| 139 |     void columnsAboutToBeInserted(const QModelIndex &parent, int first, int last) | 
| 140 |         { modelChanged(change: ColumnsAboutToBeInserted, parent, first, last); } | 
| 141 |     void columnsInserted(const QModelIndex &parent, int first, int last) | 
| 142 |         { modelChanged(change: ColumnsInserted, parent, first, last); } | 
| 143 |     void columnsAboutToBeRemoved(const QModelIndex &parent, int first, int last) | 
| 144 |         { modelChanged(change: ColumnsAboutToBeRemoved, parent, first, last); } | 
| 145 |     void columnsRemoved(const QModelIndex &parent, int first, int last) | 
| 146 |         { modelChanged(change: ColumnsRemoved, parent, first, last); } | 
| 147 |  | 
| 148 |     void modelChanged(ModelChanged change, const QModelIndex &parent, int first, int last) | 
| 149 |     { | 
| 150 |         rcParent[change] = parent; | 
| 151 |         rcFirst[change] = first; | 
| 152 |         rcLast[change] = last; | 
| 153 |     } | 
| 154 |  | 
| 155 | private: | 
| 156 |     QListWidget *testWidget = nullptr; | 
| 157 |     QVector<QModelIndex> rcParent{8}; | 
| 158 |     QVector<int> rcFirst = QVector<int>(8, 0); | 
| 159 |     QVector<int> rcLast = QVector<int>(8, 0); | 
| 160 |  | 
| 161 |     void populate(); | 
| 162 |     void checkDefaultValues(); | 
| 163 | }; | 
| 164 |  | 
| 165 |  | 
| 166 | void tst_QListWidget::moveRowsInvalid_data() | 
| 167 | { | 
| 168 |     QTest::addColumn<QListWidget*>(name: "baseWidget" ); | 
| 169 |     QTest::addColumn<QModelIndex>(name: "startParent" ); | 
| 170 |     QTest::addColumn<int>(name: "startRow" ); | 
| 171 |     QTest::addColumn<int>(name: "count" ); | 
| 172 |     QTest::addColumn<QModelIndex>(name: "destinationParent" ); | 
| 173 |     QTest::addColumn<int>(name: "destination" ); | 
| 174 |  | 
| 175 |     const auto createWidget = []() -> QListWidget* { | 
| 176 |         QListWidget* result = new QListWidget; | 
| 177 |         result->addItems(labels: {"A" , "B" , "C" , "D" , "E" , "F" }); | 
| 178 |         return result; | 
| 179 |     }; | 
| 180 |     constexpr int rowCount = 6; | 
| 181 |  | 
| 182 |     QTest::addRow(format: "destination_equal_source" ) << createWidget() << QModelIndex() << 0 << 1 << QModelIndex() << 0; | 
| 183 |     QTest::addRow(format: "count_equal_0" ) << createWidget() << QModelIndex() << 0 << 0 << QModelIndex() << 2; | 
| 184 |     QListWidget* tempWidget = createWidget(); | 
| 185 |     QTest::addRow(format: "move_child" ) << tempWidget << tempWidget->model()->index(row: 0, column: 0) << 0 << 1 << QModelIndex() << 2; | 
| 186 |     tempWidget = createWidget(); | 
| 187 |     QTest::addRow(format: "move_to_child" ) << tempWidget << QModelIndex() << 0 << 1 << tempWidget->model()->index(row: 0, column: 0) << 2; | 
| 188 |     QTest::addRow(format: "negative_count" ) << createWidget() << QModelIndex() << 0 << -1 << QModelIndex() << 2; | 
| 189 |     QTest::addRow(format: "negative_source_row" ) << createWidget() << QModelIndex() << -1 << 1 << QModelIndex() << 2; | 
| 190 |     QTest::addRow(format: "negative_destination_row" ) << createWidget() << QModelIndex() << 0 << 1 << QModelIndex() << -1; | 
| 191 |     QTest::addRow(format: "source_row_equal_rowCount" ) << createWidget() << QModelIndex() << rowCount << 1 << QModelIndex() << 1; | 
| 192 |     QTest::addRow(format: "source_row_equal_destination_row" ) << createWidget() << QModelIndex() << 2 << 1 << QModelIndex() << 2; | 
| 193 |     QTest::addRow(format: "source_row_equal_destination_row_plus1" ) << createWidget() << QModelIndex() << 2 << 1 << QModelIndex() << 3; | 
| 194 |     QTest::addRow(format: "destination_row_greater_rowCount" ) << createWidget() << QModelIndex() << 0 << 1 << QModelIndex() << rowCount + 1; | 
| 195 |     QTest::addRow(format: "move_row_within_source_range" ) << createWidget() << QModelIndex() << 0 << 3 << QModelIndex() << 2; | 
| 196 | } | 
| 197 |  | 
| 198 | void tst_QListWidget::moveRowsInvalid() | 
| 199 | { | 
| 200 |     QFETCH(QListWidget* const, baseWidget); | 
| 201 |     QFETCH(const QModelIndex, startParent); | 
| 202 |     QFETCH(const int, startRow); | 
| 203 |     QFETCH(const int, count); | 
| 204 |     QFETCH(const QModelIndex, destinationParent); | 
| 205 |     QFETCH(const int, destination); | 
| 206 |     QAbstractItemModel *baseModel = baseWidget->model(); | 
| 207 |     QSignalSpy rowMovedSpy(baseModel, &QAbstractItemModel::rowsMoved); | 
| 208 |     QSignalSpy rowAboutMovedSpy(baseModel, &QAbstractItemModel::rowsAboutToBeMoved); | 
| 209 |     QVERIFY(rowMovedSpy.isValid()); | 
| 210 |     QVERIFY(rowAboutMovedSpy.isValid()); | 
| 211 |     QVERIFY(!baseModel->moveRows(startParent, startRow, count, destinationParent, destination)); | 
| 212 |     QCOMPARE(rowMovedSpy.size(), 0); | 
| 213 |     QCOMPARE(rowAboutMovedSpy.size(), 0); | 
| 214 |     delete baseWidget; | 
| 215 | } | 
| 216 |  | 
| 217 | void tst_QListWidget::moveRows_data() | 
| 218 | { | 
| 219 |     QTest::addColumn<int>(name: "startRow" ); | 
| 220 |     QTest::addColumn<int>(name: "count" ); | 
| 221 |     QTest::addColumn<int>(name: "destination" ); | 
| 222 |     QTest::addColumn<QStringList>(name: "expected" ); | 
| 223 |  | 
| 224 |     QTest::newRow(dataTag: "1_Item_from_top_to_middle" ) << 0 << 1 << 3 << QStringList{"B" , "C" , "A" , "D" , "E" , "F" }; | 
| 225 |     QTest::newRow(dataTag: "1_Item_from_top_to_bottom" ) << 0 << 1 << 6 << QStringList{"B" , "C" , "D" , "E" , "F" , "A" }; | 
| 226 |     QTest::newRow(dataTag: "1_Item_from_middle_to_top" ) << 2 << 1 << 0 << QStringList{"C" , "A" , "B" , "D" , "E" , "F" }; | 
| 227 |     QTest::newRow(dataTag: "1_Item_from_bottom_to_middle" ) << 5 << 1 << 2 << QStringList{"A" , "B" , "F" , "C" , "D" , "E" }; | 
| 228 |     QTest::newRow(dataTag: "1_Item_from_bottom to_top" ) << 5 << 1 << 0 << QStringList{"F" , "A" , "B" , "C" , "D" , "E" }; | 
| 229 |     QTest::newRow(dataTag: "1_Item_from_middle_to_bottom" ) << 2 << 1 << 6 << QStringList{"A" , "B" , "D" , "E" , "F" , "C" }; | 
| 230 |     QTest::newRow(dataTag: "1_Item_from_middle_to_middle_before" ) << 2 << 1 << 1 << QStringList{"A" , "C" , "B" , "D" , "E" , "F" }; | 
| 231 |     QTest::newRow(dataTag: "1_Item_from_middle_to_middle_after" ) << 2 << 1 << 4 << QStringList{"A" , "B" , "D" , "C" , "E" , "F" }; | 
| 232 |  | 
| 233 |     QTest::newRow(dataTag: "2_Items_from_top_to_middle" ) << 0 << 2 << 3 << QStringList{"C" , "A" , "B" , "D" , "E" , "F" }; | 
| 234 |     QTest::newRow(dataTag: "2_Items_from_top_to_bottom" ) << 0 << 2 << 6 << QStringList{"C" , "D" , "E" , "F" , "A" , "B" }; | 
| 235 |     QTest::newRow(dataTag: "2_Items_from_middle_to_top" ) << 2 << 2 << 0 << QStringList{"C" , "D" , "A" , "B" , "E" , "F" }; | 
| 236 |     QTest::newRow(dataTag: "2_Items_from_bottom_to_middle" ) << 4 << 2 << 2 << QStringList{"A" , "B" , "E" , "F" , "C" , "D" }; | 
| 237 |     QTest::newRow(dataTag: "2_Items_from_bottom_to_top" ) << 4 << 2 << 0 << QStringList{"E" , "F" , "A" , "B" , "C" , "D" }; | 
| 238 |     QTest::newRow(dataTag: "2_Items_from_middle_to_bottom" ) << 2 << 2 << 6 << QStringList{"A" , "B" , "E" , "F" , "C" , "D" }; | 
| 239 |     QTest::newRow(dataTag: "2_Items_from_middle_to_middle_before" ) << 3 << 2 << 1 << QStringList{"A" , "D" , "E" , "B" , "C" , "F" }; | 
| 240 |     QTest::newRow(dataTag: "2_Items_from_middle_to_middle_after" ) << 1 << 2 << 5 << QStringList{"A" , "D" , "E" , "B" , "C" , "F" }; | 
| 241 | } | 
| 242 |  | 
| 243 | void tst_QListWidget::moveRows() | 
| 244 | { | 
| 245 |     QFETCH(const int, startRow); | 
| 246 |     QFETCH(const int, count); | 
| 247 |     QFETCH(const int, destination); | 
| 248 |     QFETCH(const QStringList, expected); | 
| 249 |     QListWidget baseWidget; | 
| 250 |     baseWidget.addItems(labels: QStringList{"A" , "B" , "C" , "D" , "E" , "F" }); | 
| 251 |     QAbstractItemModel *baseModel = baseWidget.model(); | 
| 252 |     QSignalSpy rowMovedSpy(baseModel, &QAbstractItemModel::rowsMoved); | 
| 253 |     QSignalSpy rowAboutMovedSpy(baseModel, &QAbstractItemModel::rowsAboutToBeMoved); | 
| 254 |     QVERIFY(baseModel->moveRows(QModelIndex(), startRow, count, QModelIndex(), destination)); | 
| 255 |     QCOMPARE(baseModel->rowCount(), expected.size()); | 
| 256 |     for (int i = 0; i < expected.size(); ++i) | 
| 257 |         QCOMPARE(baseModel->index(i, 0).data().toString(), expected.at(i)); | 
| 258 |     QCOMPARE(rowMovedSpy.size(), 1); | 
| 259 |     QCOMPARE(rowAboutMovedSpy.size(), 1); | 
| 260 |     for (const QList<QVariant> &signalArgs : {rowMovedSpy.first(), rowAboutMovedSpy.first()}){ | 
| 261 |         QVERIFY(!signalArgs.at(0).value<QModelIndex>().isValid()); | 
| 262 |         QCOMPARE(signalArgs.at(1).toInt(), startRow); | 
| 263 |         QCOMPARE(signalArgs.at(2).toInt(), startRow + count - 1); | 
| 264 |         QVERIFY(!signalArgs.at(3).value<QModelIndex>().isValid()); | 
| 265 |         QCOMPARE(signalArgs.at(4).toInt(), destination); | 
| 266 |     } | 
| 267 | } | 
| 268 |  | 
| 269 |  | 
| 270 | void tst_QListWidget::initTestCase() | 
| 271 | { | 
| 272 |     qRegisterMetaType<QListWidgetItem*>(typeName: "QListWidgetItem*" ); | 
| 273 |     qRegisterMetaType<QList<QPersistentModelIndex>>(typeName: "QList<QPersistentModelIndex>" ); | 
| 274 |     qRegisterMetaType<QAbstractItemModel::LayoutChangeHint>(typeName: "QAbstractItemModel::LayoutChangeHint" ); | 
| 275 |  | 
| 276 |     testWidget = new QListWidget; | 
| 277 |     testWidget->show(); | 
| 278 |  | 
| 279 |     connect(sender: testWidget->model(), signal: &QAbstractItemModel::rowsAboutToBeInserted, | 
| 280 |             receiver: this, slot: &tst_QListWidget::rowsAboutToBeInserted); | 
| 281 |     connect(sender: testWidget->model(), signal: &QAbstractItemModel::rowsInserted, | 
| 282 |             receiver: this, slot: &tst_QListWidget::rowsInserted); | 
| 283 |     connect(sender: testWidget->model(), signal: &QAbstractItemModel::rowsAboutToBeRemoved, | 
| 284 |             receiver: this, slot: &tst_QListWidget::rowsAboutToBeRemoved); | 
| 285 |     connect(sender: testWidget->model(), signal: &QAbstractItemModel::rowsRemoved, | 
| 286 |             receiver: this, slot: &tst_QListWidget::rowsRemoved); | 
| 287 |  | 
| 288 |     connect(sender: testWidget->model(), signal: &QAbstractItemModel::columnsAboutToBeInserted, | 
| 289 |             receiver: this, slot: &tst_QListWidget::columnsAboutToBeInserted); | 
| 290 |     connect(sender: testWidget->model(), signal: &QAbstractItemModel::columnsInserted, | 
| 291 |             receiver: this, slot: &tst_QListWidget::columnsInserted); | 
| 292 |     connect(sender: testWidget->model(), signal: &QAbstractItemModel::columnsAboutToBeRemoved, | 
| 293 |             receiver: this, slot: &tst_QListWidget::columnsAboutToBeRemoved); | 
| 294 |     connect(sender: testWidget->model(), signal: &QAbstractItemModel::columnsRemoved, | 
| 295 |             receiver: this, slot: &tst_QListWidget::columnsRemoved); | 
| 296 |  | 
| 297 |     checkDefaultValues(); | 
| 298 | } | 
| 299 |  | 
| 300 | void tst_QListWidget::cleanupTestCase() | 
| 301 | { | 
| 302 |     delete testWidget; | 
| 303 | } | 
| 304 |  | 
| 305 | void tst_QListWidget::init() | 
| 306 | { | 
| 307 |     testWidget->clear(); | 
| 308 |     QCoreApplication::sendPostedEvents(receiver: nullptr, event_type: QEvent::DeferredDelete); | 
| 309 | } | 
| 310 |  | 
| 311 | void tst_QListWidget::checkDefaultValues() | 
| 312 | { | 
| 313 |     QCOMPARE(testWidget->currentItem(), nullptr); | 
| 314 |     QCOMPARE(testWidget->currentRow(), -1); | 
| 315 |     QCOMPARE(testWidget->count(), 0); | 
| 316 | } | 
| 317 |  | 
| 318 | void tst_QListWidget::populate() | 
| 319 | { | 
| 320 |     addItem(); | 
| 321 |     addItem2(); | 
| 322 |     addItems(); | 
| 323 |     setItemHidden(); | 
| 324 |  | 
| 325 |     testWidget->setCurrentIndex(testWidget->model()->index(row: 0, column: 0)); | 
| 326 |  | 
| 327 |     // setCurrentItem(); | 
| 328 |     // setCurrentRow(); | 
| 329 | } | 
| 330 |  | 
| 331 | void tst_QListWidget::addItem() | 
| 332 | { | 
| 333 |     int count = testWidget->count(); | 
| 334 |     const QString label = QString::number(count); | 
| 335 |     testWidget->addItem(label); | 
| 336 |     QCOMPARE(testWidget->count(), ++count); | 
| 337 |     QCOMPARE(testWidget->item(testWidget->count() - 1)->text(), label); | 
| 338 | } | 
| 339 |  | 
| 340 | void tst_QListWidget::addItem2() | 
| 341 | { | 
| 342 |     int count = testWidget->count(); | 
| 343 |  | 
| 344 |     // Boundary Checking | 
| 345 |     testWidget->addItem(aitem: nullptr); | 
| 346 |     QCOMPARE(testWidget->count(), count); | 
| 347 |  | 
| 348 |     QListWidgetItem *item = new QListWidgetItem(QString::number(count)); | 
| 349 |     item->setFlags(item->flags() | Qt::ItemIsEditable); | 
| 350 |     testWidget->addItem(aitem: item); | 
| 351 |     QCOMPARE(testWidget->count(), ++count); | 
| 352 |     QCOMPARE(testWidget->item(testWidget->count()-1), item); | 
| 353 |     QCOMPARE(item->isHidden(), false); | 
| 354 | } | 
| 355 |  | 
| 356 | void tst_QListWidget::addItems() | 
| 357 | { | 
| 358 |     int count = testWidget->count(); | 
| 359 |  | 
| 360 |     // Boundary Checking | 
| 361 |     testWidget->addItems(labels: QStringList()); | 
| 362 |     QCOMPARE(testWidget->count(), count); | 
| 363 |  | 
| 364 |     QString label = QString::number(count); | 
| 365 |     const QStringList stringList{QString::number(testWidget->count() + 1), | 
| 366 |                                  QString::number(testWidget->count() + 2), | 
| 367 |                                  QString::number(testWidget->count() + 3), | 
| 368 |                                  label}; | 
| 369 |     testWidget->addItems(labels: stringList); | 
| 370 |     QCOMPARE(testWidget->count(), count + stringList.count()); | 
| 371 |     QCOMPARE(testWidget->item(testWidget->count()-1)->text(), label); | 
| 372 | } | 
| 373 |  | 
| 374 |  | 
| 375 | void tst_QListWidget::openPersistentEditor() | 
| 376 | { | 
| 377 |     // Boundary checking | 
| 378 |     testWidget->openPersistentEditor(item: nullptr); | 
| 379 |     QListWidgetItem *item = new QListWidgetItem(QString::number(testWidget->count())); | 
| 380 |     testWidget->openPersistentEditor(item); | 
| 381 |  | 
| 382 |     int childCount = testWidget->viewport()->children().count(); | 
| 383 |     testWidget->addItem(aitem: item); | 
| 384 |     testWidget->openPersistentEditor(item); | 
| 385 |     QCOMPARE(childCount + 1, testWidget->viewport()->children().count()); | 
| 386 | } | 
| 387 |  | 
| 388 | void tst_QListWidget::closePersistentEditor() | 
| 389 | { | 
| 390 |     // Boundary checking | 
| 391 |     int childCount = testWidget->viewport()->children().count(); | 
| 392 |     testWidget->closePersistentEditor(item: nullptr); | 
| 393 |     QListWidgetItem *item = new QListWidgetItem(QString::number(testWidget->count())); | 
| 394 |     testWidget->closePersistentEditor(item); | 
| 395 |     QCOMPARE(childCount, testWidget->viewport()->children().count()); | 
| 396 |  | 
| 397 |     // Create something | 
| 398 |     testWidget->addItem(aitem: item); | 
| 399 |     testWidget->openPersistentEditor(item); | 
| 400 |  | 
| 401 |     // actual test | 
| 402 |     childCount = testWidget->viewport()->children().count(); | 
| 403 |     testWidget->closePersistentEditor(item); | 
| 404 |     QCoreApplication::sendPostedEvents(receiver: nullptr, event_type: QEvent::DeferredDelete); | 
| 405 |     QCOMPARE(testWidget->viewport()->children().count(), childCount - 1); | 
| 406 | } | 
| 407 |  | 
| 408 | void tst_QListWidget::setItemHidden() | 
| 409 | { | 
| 410 | #if QT_DEPRECATED_SINCE(5, 13) | 
| 411 | QT_WARNING_PUSH | 
| 412 | QT_WARNING_DISABLE_DEPRECATED | 
| 413 |     // Boundary checking | 
| 414 |     testWidget->setItemHidden(item: nullptr, hide: true); | 
| 415 |     testWidget->setItemHidden(item: nullptr, hide: false); | 
| 416 | QT_WARNING_POP | 
| 417 | #endif | 
| 418 |  | 
| 419 |     auto countHidden = [](QListWidget *testWidget) | 
| 420 |     { | 
| 421 |         int totalHidden = 0; | 
| 422 |         for (int i = 0; i < testWidget->model()->rowCount(); ++i) { | 
| 423 |             if (testWidget->item(row: i)->isHidden()) | 
| 424 |                 totalHidden++; | 
| 425 |         } | 
| 426 |         return totalHidden; | 
| 427 |     }; | 
| 428 |     const int totalHidden = countHidden(testWidget); | 
| 429 |     QListWidgetItem *item = new QListWidgetItem(QString::number(testWidget->count())); | 
| 430 |     testWidget->addItem(aitem: item); | 
| 431 |  | 
| 432 |     // Check that nothing else changed | 
| 433 |     QCOMPARE(countHidden(testWidget), totalHidden); | 
| 434 |  | 
| 435 |     item->setHidden(true); | 
| 436 |     QCOMPARE(item->isHidden(), true); | 
| 437 |  | 
| 438 |     // Check that nothing else changed | 
| 439 |     QCOMPARE(countHidden(testWidget), totalHidden + 1); | 
| 440 |  | 
| 441 |     item->setHidden(false); | 
| 442 |     QCOMPARE(item->isHidden(), false); | 
| 443 |  | 
| 444 |     // Check that nothing else changed | 
| 445 |     QCOMPARE(countHidden(testWidget), totalHidden); | 
| 446 |  | 
| 447 |     item->setHidden(true); | 
| 448 | } | 
| 449 |  | 
| 450 | void tst_QListWidget::setCurrentItem_data() | 
| 451 | { | 
| 452 |     QTest::addColumn<int>(name: "fill" ); | 
| 453 |     QTest::newRow(dataTag: "HasItems: 0" ) << 0; | 
| 454 |     QTest::newRow(dataTag: "HasItems: 1" ) << 1; | 
| 455 |     QTest::newRow(dataTag: "HasItems: 2" ) << 2; | 
| 456 |     QTest::newRow(dataTag: "HasItems: 3" ) << 3; | 
| 457 | } | 
| 458 |  | 
| 459 | void tst_QListWidget::setCurrentItem() | 
| 460 | { | 
| 461 |     QFETCH(int, fill); | 
| 462 |     for (int i = 0; i < fill; ++i) | 
| 463 |         testWidget->addItem(label: QString::number(i)); | 
| 464 |  | 
| 465 |     // Boundary checking | 
| 466 |     testWidget->setCurrentItem(nullptr); | 
| 467 |     QVERIFY(!testWidget->currentItem()); | 
| 468 |     QListWidgetItem item; | 
| 469 |     testWidget->setCurrentItem(&item); | 
| 470 |     QVERIFY(!testWidget->currentItem()); | 
| 471 |  | 
| 472 |     // Make sure that currentItem changes to what is passed into setCurrentItem | 
| 473 |     for (int i = 0; i < testWidget->count(); ++i) { | 
| 474 |         testWidget->setCurrentItem(testWidget->item(row: i)); | 
| 475 |         for (int j = 0; j < testWidget->count(); ++j) { | 
| 476 |             testWidget->setCurrentItem(testWidget->item(row: j)); | 
| 477 |             QCOMPARE(testWidget->item(j), testWidget->currentItem()); | 
| 478 |         } | 
| 479 |     } | 
| 480 | } | 
| 481 |  | 
| 482 | void tst_QListWidget::setCurrentRow_data() | 
| 483 | { | 
| 484 |     QTest::addColumn<int>(name: "fill" ); | 
| 485 |     QTest::newRow(dataTag: "HasItems: 0" ) << 0; | 
| 486 |     QTest::newRow(dataTag: "HasItems: 1" ) << 1; | 
| 487 |     QTest::newRow(dataTag: "HasItems: 2" ) << 2; | 
| 488 |     QTest::newRow(dataTag: "HasItems: 3" ) << 3; | 
| 489 | } | 
| 490 |  | 
| 491 | void tst_QListWidget::setCurrentRow() | 
| 492 | { | 
| 493 |     QFETCH(int, fill); | 
| 494 |     for (int i = 0; i < fill; ++i) | 
| 495 |         testWidget->addItem(label: QString::number(i)); | 
| 496 |  | 
| 497 |     // Boundary checking | 
| 498 |     testWidget->setCurrentRow(-1); | 
| 499 |     QCOMPARE(-1, testWidget->currentRow()); | 
| 500 |     testWidget->setCurrentRow(testWidget->count()); | 
| 501 |     QCOMPARE(-1, testWidget->currentRow()); | 
| 502 |  | 
| 503 |     // Make sure that currentRow changes to what is passed into setCurrentRow | 
| 504 |     for (int i = 0; i < testWidget->count(); ++i) { | 
| 505 |         testWidget->setCurrentRow(i); | 
| 506 |         for (int j = 0; j < testWidget->count(); ++j) { | 
| 507 |             testWidget->setCurrentRow(j); | 
| 508 |             QCOMPARE(j, testWidget->currentRow()); | 
| 509 |         } | 
| 510 |     } | 
| 511 | } | 
| 512 |  | 
| 513 | void tst_QListWidget::count() | 
| 514 | { | 
| 515 |     populate(); | 
| 516 |  | 
| 517 |     // actual test | 
| 518 |     QCOMPARE(testWidget->model()->rowCount(), testWidget->count()); | 
| 519 | } | 
| 520 |  | 
| 521 | void tst_QListWidget::currentItem() | 
| 522 | { | 
| 523 |     populate(); | 
| 524 |  | 
| 525 |     // actual test | 
| 526 |     QModelIndex currentIndex = testWidget->selectionModel()->currentIndex(); | 
| 527 |     if (currentIndex.isValid()) | 
| 528 |         QCOMPARE(testWidget->currentItem(), testWidget->item(currentIndex.row())); | 
| 529 |     else | 
| 530 |         QCOMPARE(testWidget->currentItem(), nullptr); | 
| 531 | } | 
| 532 |  | 
| 533 | void tst_QListWidget::currentRow() | 
| 534 | { | 
| 535 |     populate(); | 
| 536 |  | 
| 537 |     // actual test | 
| 538 |     QModelIndex currentIndex = testWidget->selectionModel()->currentIndex(); | 
| 539 |     if (currentIndex.isValid()) | 
| 540 |         QCOMPARE(testWidget->currentRow(), currentIndex.row()); | 
| 541 |     else | 
| 542 |         QCOMPARE(testWidget->currentRow(), -1); | 
| 543 | } | 
| 544 |  | 
| 545 | void tst_QListWidget::editItem_data() | 
| 546 | { | 
| 547 |     QTest::addColumn<bool>(name: "editable" ); | 
| 548 |     QTest::newRow(dataTag: "editable" ) << true; | 
| 549 |     QTest::newRow(dataTag: "not editable" ) << false; | 
| 550 | } | 
| 551 |  | 
| 552 | void tst_QListWidget::editItem() | 
| 553 | { | 
| 554 |     // Boundary checking | 
| 555 |     testWidget->editItem(item: nullptr); | 
| 556 |     QListWidgetItem *item = new QListWidgetItem(QString::number(testWidget->count())); | 
| 557 |     testWidget->editItem(item); | 
| 558 |  | 
| 559 |     QFETCH(bool, editable); | 
| 560 |     if (editable) | 
| 561 |         item->setFlags(item->flags() | Qt::ItemIsEditable); | 
| 562 |     testWidget->addItem(aitem: item); | 
| 563 |  | 
| 564 |     int childCount = testWidget->viewport()->children().count(); | 
| 565 |     QWidget *existsAlready = testWidget->indexWidget(index: testWidget->model()->index(row: testWidget->row(item), column: 0)); | 
| 566 |     testWidget->editItem(item); | 
| 567 |     Qt::ItemFlags flags = item->flags(); | 
| 568 |  | 
| 569 |     // There doesn't seem to be a way to detect if the item has already been edited... | 
| 570 |     if (!existsAlready && flags & Qt::ItemIsEditable && flags & Qt::ItemIsEnabled) { | 
| 571 |         QList<QObject *> children = testWidget->viewport()->children(); | 
| 572 |         QVERIFY(children.count() > childCount); | 
| 573 |         bool found = false; | 
| 574 |         for (int i = 0; i < children.size(); ++i) { | 
| 575 |             if (children.at(i)->inherits(classname: "QExpandingLineEdit" )) | 
| 576 |                 found = true; | 
| 577 |         } | 
| 578 |         QVERIFY(found); | 
| 579 |     } else { | 
| 580 |         QCOMPARE(testWidget->viewport()->children().count(), childCount); | 
| 581 |     } | 
| 582 | } | 
| 583 |  | 
| 584 | void tst_QListWidget::findItems() | 
| 585 | { | 
| 586 |     // This really just tests that the items that are returned are converted from index's to items correctly. | 
| 587 |  | 
| 588 |     // Boundary checking | 
| 589 |     QCOMPARE(testWidget->findItems("GirlsCanWearJeansAndCutTheirHairShort" , Qt::MatchExactly).count(), 0); | 
| 590 |  | 
| 591 |     populate(); | 
| 592 |  | 
| 593 |     for (int i = 0; i < testWidget->count(); ++i) | 
| 594 |         QCOMPARE(testWidget->findItems(testWidget->item(i)->text(), Qt::MatchExactly).count(), 1); | 
| 595 | } | 
| 596 |  | 
| 597 |  | 
| 598 | void tst_QListWidget::insertItem_data() | 
| 599 | { | 
| 600 |     QTest::addColumn<QStringList>(name: "initialItems" ); | 
| 601 |     QTest::addColumn<int>(name: "insertIndex" ); | 
| 602 |     QTest::addColumn<QString>(name: "itemLabel" ); | 
| 603 |     QTest::addColumn<int>(name: "expectedIndex" ); | 
| 604 |  | 
| 605 |     const QStringList initialItems{"foo" , "bar" }; | 
| 606 |  | 
| 607 |     QTest::newRow(dataTag: "Insert less then 0" ) << initialItems << -1 << "inserted"  << 0; | 
| 608 |     QTest::newRow(dataTag: "Insert at 0" ) << initialItems << 0 << "inserted"  << 0; | 
| 609 |     QTest::newRow(dataTag: "Insert beyond count" ) << initialItems << initialItems.count()+1 << "inserted"  << initialItems.count(); | 
| 610 |     QTest::newRow(dataTag: "Insert at count" ) << initialItems << initialItems.count() << "inserted"  << initialItems.count(); | 
| 611 |     QTest::newRow(dataTag: "Insert in the middle" ) << initialItems << 1 << "inserted"  << 1; | 
| 612 | } | 
| 613 |  | 
| 614 | void tst_QListWidget::insertItem() | 
| 615 | { | 
| 616 |     QFETCH(QStringList, initialItems); | 
| 617 |     QFETCH(int, insertIndex); | 
| 618 |     QFETCH(QString, itemLabel); | 
| 619 |     QFETCH(int, expectedIndex); | 
| 620 |  | 
| 621 |     testWidget->insertItems(row: 0, labels: initialItems); | 
| 622 |     QCOMPARE(testWidget->count(), initialItems.count()); | 
| 623 |  | 
| 624 |     testWidget->insertItem(row: insertIndex, label: itemLabel); | 
| 625 |  | 
| 626 |     QCOMPARE(rcFirst[RowsAboutToBeInserted], expectedIndex); | 
| 627 |     QCOMPARE(rcLast[RowsAboutToBeInserted], expectedIndex); | 
| 628 |     QCOMPARE(rcFirst[RowsInserted], expectedIndex); | 
| 629 |     QCOMPARE(rcLast[RowsInserted], expectedIndex); | 
| 630 |  | 
| 631 |     QCOMPARE(testWidget->count(), initialItems.count() + 1); | 
| 632 |     QCOMPARE(testWidget->item(expectedIndex)->text(), itemLabel); | 
| 633 | } | 
| 634 |  | 
| 635 | void tst_QListWidget::insertItems_data() | 
| 636 | { | 
| 637 |     QTest::addColumn<int>(name: "rowCount" ); | 
| 638 |     QTest::addColumn<int>(name: "insertType" ); | 
| 639 |  | 
| 640 |     QTest::newRow(dataTag: "Insert 1 item using constructor" ) << 1 << 0; | 
| 641 |     QTest::newRow(dataTag: "Insert 10 items using constructor" ) << 10 << 0; | 
| 642 |     QTest::newRow(dataTag: "Insert 100 items using constructor" ) << 100 << 0; | 
| 643 |  | 
| 644 |     QTest::newRow(dataTag: "Insert 1 item with insertItem" ) << 1 << 1; | 
| 645 |     QTest::newRow(dataTag: "Insert 10 items with insertItem" ) << 10 << 1; | 
| 646 |     QTest::newRow(dataTag: "Insert 100 items with insertItem" ) << 100 << 1; | 
| 647 |  | 
| 648 |     QTest::newRow(dataTag: "Insert/Create 1 item using insertItem" ) << 1 << 2; | 
| 649 |     QTest::newRow(dataTag: "Insert/Create 10 items using insertItem" ) << 10 << 2; | 
| 650 |     QTest::newRow(dataTag: "Insert/Create 100 items using insertItem" ) << 100 << 2; | 
| 651 |  | 
| 652 |     QTest::newRow(dataTag: "Insert 0 items with insertItems" ) << 0 << 3; | 
| 653 |     QTest::newRow(dataTag: "Insert 1 item with insertItems" ) << 1 << 3; | 
| 654 |     QTest::newRow(dataTag: "Insert 10 items with insertItems" ) << 10 << 3; | 
| 655 |     QTest::newRow(dataTag: "Insert 100 items with insertItems" ) << 100 << 3; | 
| 656 | } | 
| 657 |  | 
| 658 | void tst_QListWidget::insertItems() | 
| 659 | { | 
| 660 |     QFETCH(int, rowCount); | 
| 661 |     QFETCH(int, insertType); | 
| 662 |  | 
| 663 |     QSignalSpy itemChangedSpy(testWidget, &QListWidget::itemChanged); | 
| 664 |     QSignalSpy dataChangedSpy(testWidget->model(), &QAbstractItemModel::dataChanged); | 
| 665 |  | 
| 666 |     if (insertType == 3) { | 
| 667 |         QStringList strings; | 
| 668 |         for (int i = 0; i < rowCount; ++i) | 
| 669 |             strings << QString::number(i); | 
| 670 |         testWidget->insertItems(row: 0, labels: strings); | 
| 671 |     } else { | 
| 672 |         for (int r = 0; r < rowCount; ++r) { | 
| 673 |             if (insertType == 0) { | 
| 674 |                 // insert with QListWidgetItem constructor | 
| 675 |                 new QListWidgetItem(QString::number(r), testWidget); | 
| 676 |             } else if (insertType == 1) { | 
| 677 |                 // insert actual item | 
| 678 |                 testWidget->insertItem(row: r, item: new QListWidgetItem(QString::number(r))); | 
| 679 |             } else if (insertType == 2) { | 
| 680 |                 // insert/creating with string | 
| 681 |                 testWidget->insertItem(row: r, label: QString::number(r)); | 
| 682 |             } else if (insertType == 3) { | 
| 683 |                 QStringList strings; | 
| 684 |                 for (int i = 0; i < rowCount; ++i) | 
| 685 |                     strings << QString::number(i); | 
| 686 |                 testWidget->insertItems(row: 0, labels: strings); | 
| 687 |                 break; | 
| 688 |             } else { | 
| 689 |                 QVERIFY(0); | 
| 690 |             } | 
| 691 |         } | 
| 692 |     } | 
| 693 |     // compare the results | 
| 694 |     QCOMPARE(testWidget->count(), rowCount); | 
| 695 |  | 
| 696 |     // check if the text | 
| 697 |     for (int r = 0; r < rowCount; ++r) | 
| 698 |         QCOMPARE(testWidget->item(r)->text(), QString::number(r)); | 
| 699 |  | 
| 700 |     // make sure all items have view set correctly | 
| 701 |     for (int i = 0; i < testWidget->count(); ++i) | 
| 702 |         QCOMPARE(testWidget->item(i)->listWidget(), testWidget); | 
| 703 |  | 
| 704 |     QCOMPARE(itemChangedSpy.count(), 0); | 
| 705 |     QCOMPARE(dataChangedSpy.count(), 0); | 
| 706 | } | 
| 707 |  | 
| 708 | void tst_QListWidget::itemAssignment() | 
| 709 | { | 
| 710 |     QListWidgetItem itemInWidget("inWidget" , testWidget); | 
| 711 |     itemInWidget.setFlags(itemInWidget.flags() | Qt::ItemIsUserTristate); | 
| 712 |     QListWidgetItem itemOutsideWidget("outsideWidget" ); | 
| 713 |  | 
| 714 |     QVERIFY(itemInWidget.listWidget()); | 
| 715 |     QCOMPARE(itemInWidget.text(), QString("inWidget" )); | 
| 716 |     QVERIFY(itemInWidget.flags() & Qt::ItemIsUserTristate); | 
| 717 |  | 
| 718 |     QVERIFY(!itemOutsideWidget.listWidget()); | 
| 719 |     QCOMPARE(itemOutsideWidget.text(), QString("outsideWidget" )); | 
| 720 |     QVERIFY(!(itemOutsideWidget.flags() & Qt::ItemIsUserTristate)); | 
| 721 |  | 
| 722 |     itemOutsideWidget = itemInWidget; | 
| 723 |     QVERIFY(!itemOutsideWidget.listWidget()); | 
| 724 |     QCOMPARE(itemOutsideWidget.text(), QString("inWidget" )); | 
| 725 |     QVERIFY(itemOutsideWidget.flags() & Qt::ItemIsUserTristate); | 
| 726 | } | 
| 727 |  | 
| 728 | void tst_QListWidget::item_data() | 
| 729 | { | 
| 730 |     QTest::addColumn<int>(name: "row" ); | 
| 731 |     QTest::addColumn<bool>(name: "outOfBounds" ); | 
| 732 |  | 
| 733 |     QTest::newRow(dataTag: "First item, row: 0" ) << 0 << false; | 
| 734 |     QTest::newRow(dataTag: "Middle item, row: 1" ) << 1 << false; | 
| 735 |     QTest::newRow(dataTag: "Last item, row: 2" ) << 2 << false; | 
| 736 |     QTest::newRow(dataTag: "Out of bounds, row: -1" ) << -1 << true; | 
| 737 |     QTest::newRow(dataTag: "Out of bounds, row: 3" ) << 3 << true; | 
| 738 | } | 
| 739 |  | 
| 740 | void tst_QListWidget::item() | 
| 741 | { | 
| 742 |     QFETCH(int, row); | 
| 743 |     QFETCH(bool, outOfBounds); | 
| 744 |  | 
| 745 |     (new QListWidgetItem(testWidget))->setText("item0" ); | 
| 746 |     (new QListWidgetItem(testWidget))->setText("item1" ); | 
| 747 |     (new QListWidgetItem(testWidget))->setText("item2" ); | 
| 748 |  | 
| 749 |     QCOMPARE(testWidget->count(), 3); | 
| 750 |  | 
| 751 |     QListWidgetItem *item = testWidget->item(row); | 
| 752 |     if (outOfBounds) { | 
| 753 |         QCOMPARE(item, nullptr); | 
| 754 |         QCOMPARE(testWidget->count(), 3); | 
| 755 |     } else { | 
| 756 |         QCOMPARE(item->text(), QStringLiteral("item" ) + QString::number(row)); | 
| 757 |         QCOMPARE(testWidget->count(), 3); | 
| 758 |     } | 
| 759 | } | 
| 760 |  | 
| 761 | void tst_QListWidget::takeItem_data() | 
| 762 | { | 
| 763 |     QTest::addColumn<int>(name: "row" ); | 
| 764 |     QTest::addColumn<bool>(name: "outOfBounds" ); | 
| 765 |  | 
| 766 |     QTest::newRow(dataTag: "First item, row: 0" ) << 0 << false; | 
| 767 |     QTest::newRow(dataTag: "Middle item, row: 1" ) << 1 << false; | 
| 768 |     QTest::newRow(dataTag: "Last item, row: 2" ) << 2 << false; | 
| 769 |     QTest::newRow(dataTag: "Out of bounds, row: -1" ) << -1 << true; | 
| 770 |     QTest::newRow(dataTag: "Out of bounds, row: 3" ) << 3 << true; | 
| 771 | } | 
| 772 |  | 
| 773 | void tst_QListWidget::takeItem() | 
| 774 | { | 
| 775 |     QFETCH(int, row); | 
| 776 |     QFETCH(bool, outOfBounds); | 
| 777 |  | 
| 778 |     (new QListWidgetItem(testWidget))->setText("item0" ); | 
| 779 |     (new QListWidgetItem(testWidget))->setText("item1" ); | 
| 780 |     (new QListWidgetItem(testWidget))->setText("item2" ); | 
| 781 |  | 
| 782 |     QCOMPARE(testWidget->count(), 3); | 
| 783 |  | 
| 784 |     QListWidgetItem *item = testWidget->takeItem(row); | 
| 785 |     if (outOfBounds) { | 
| 786 |         QCOMPARE(item, nullptr); | 
| 787 |         QCOMPARE(testWidget->count(), 3); | 
| 788 |     } else { | 
| 789 |         QCOMPARE(item->text(), QStringLiteral("item" ) + QString::number(row)); | 
| 790 |         QCOMPARE(testWidget->count(), 2); | 
| 791 |     } | 
| 792 |  | 
| 793 |     delete item; | 
| 794 | } | 
| 795 |  | 
| 796 | void tst_QListWidget::selectedItems_data() | 
| 797 | { | 
| 798 |     QTest::addColumn<int>(name: "itemCount" ); | 
| 799 |     QTest::addColumn<IntList>(name: "hiddenRows" ); | 
| 800 |     QTest::addColumn<IntList>(name: "selectedRows" ); | 
| 801 |     QTest::addColumn<IntList>(name: "expectedRows" ); | 
| 802 |  | 
| 803 |  | 
| 804 |     QTest::newRow(dataTag: "none hidden, none selected" ) | 
| 805 |         << 3 | 
| 806 |         << IntList() | 
| 807 |         << IntList() | 
| 808 |         << IntList(); | 
| 809 |  | 
| 810 |     QTest::newRow(dataTag: "none hidden, all selected" ) | 
| 811 |         << 3 | 
| 812 |         << IntList() | 
| 813 |         << (IntList() << 0 << 1 << 2) | 
| 814 |         << (IntList() << 0 << 1 << 2); | 
| 815 |  | 
| 816 |     QTest::newRow(dataTag: "first hidden, all selected" ) | 
| 817 |         << 3 | 
| 818 |         << (IntList() << 0) | 
| 819 |         << (IntList() << 0 << 1 << 2) | 
| 820 |         << (IntList() << 0 << 1 << 2); | 
| 821 |  | 
| 822 |     QTest::newRow(dataTag: "last hidden, all selected" ) | 
| 823 |         << 3 | 
| 824 |         << (IntList() << 2) | 
| 825 |         << (IntList() << 0 << 1 << 2) | 
| 826 |         << (IntList() << 0 << 1 << 2); | 
| 827 |  | 
| 828 |     QTest::newRow(dataTag: "middle hidden, all selected" ) | 
| 829 |         << 3 | 
| 830 |         << (IntList() << 1) | 
| 831 |         << (IntList() << 0 << 1 << 2) | 
| 832 |         << (IntList() << 0 << 1 << 2); | 
| 833 |  | 
| 834 |     QTest::newRow(dataTag: "all hidden, all selected" ) | 
| 835 |         << 3 | 
| 836 |         << (IntList() << 0 << 1 << 2) | 
| 837 |         << (IntList() << 0 << 1 << 2) | 
| 838 |         << (IntList() << 0 << 1 << 2); | 
| 839 | } | 
| 840 |  | 
| 841 | void tst_QListWidget::selectedItems() | 
| 842 | { | 
| 843 |     QFETCH(int, itemCount); | 
| 844 |     QFETCH(const IntList, hiddenRows); | 
| 845 |     QFETCH(const IntList, selectedRows); | 
| 846 |     QFETCH(const IntList, expectedRows); | 
| 847 |  | 
| 848 |     QCOMPARE(testWidget->count(), 0); | 
| 849 |  | 
| 850 |     //insert items | 
| 851 |     for (int i = 0; i < itemCount; ++i) | 
| 852 |         new QListWidgetItem(QStringLiteral("Item" ) + QString::number(i), testWidget); | 
| 853 |  | 
| 854 |     //test the selection | 
| 855 |     testWidget->setSelectionMode(QListWidget::SingleSelection); | 
| 856 |     for (int i = 0; i < itemCount; ++i) { | 
| 857 |         QListWidgetItem *item = testWidget->item(row: i); | 
| 858 |         item->setSelected(true); | 
| 859 |         QVERIFY(item->isSelected()); | 
| 860 |         QCOMPARE(testWidget->selectedItems().count(), 1); | 
| 861 |     } | 
| 862 |     //let's clear the selection | 
| 863 |     testWidget->clearSelection(); | 
| 864 |     //... and set the selection mode to allow more than 1 item to be selected | 
| 865 |     testWidget->setSelectionMode(QAbstractItemView::MultiSelection); | 
| 866 |  | 
| 867 |     //verify items are inserted | 
| 868 |     QCOMPARE(testWidget->count(), itemCount); | 
| 869 |     // hide items | 
| 870 |     for (int row : hiddenRows) | 
| 871 |         testWidget->item(row)->setHidden(true); | 
| 872 |     // select items | 
| 873 |     for (int row : selectedRows) | 
| 874 |         testWidget->item(row)->setSelected(true); | 
| 875 |  | 
| 876 |     // check that the correct number of items and the expected items are there | 
| 877 |     QList<QListWidgetItem *> selectedItems = testWidget->selectedItems(); | 
| 878 |     QCOMPARE(selectedItems.count(), expectedRows.count()); | 
| 879 |     for (int row : expectedRows) | 
| 880 |         QVERIFY(selectedItems.contains(testWidget->item(row))); | 
| 881 |  | 
| 882 |     //check that isSelected agrees with selectedItems | 
| 883 |     for (int i = 0; i < itemCount; ++i) { | 
| 884 |         QListWidgetItem *item = testWidget->item(row: i); | 
| 885 |         if (item->isSelected()) | 
| 886 |             QVERIFY(selectedItems.contains(item)); | 
| 887 |     } | 
| 888 | } | 
| 889 |  | 
| 890 | void tst_QListWidget::removeItems_data() | 
| 891 | { | 
| 892 |     QTest::addColumn<int>(name: "rowCount" ); | 
| 893 |     QTest::addColumn<int>(name: "removeRows" ); | 
| 894 |     QTest::addColumn<int>(name: "row" ); | 
| 895 |     QTest::addColumn<int>(name: "expectedRowCount" ); | 
| 896 |  | 
| 897 |     QTest::newRow(dataTag: "Empty" ) << 0 << 1 << 0 << 0; | 
| 898 |     QTest::newRow(dataTag: "1:1" ) << 1 << 1 << 0 << 0; | 
| 899 |     QTest::newRow(dataTag: "3:1" ) << 3 << 1 << 0 << 2; | 
| 900 |     QTest::newRow(dataTag: "3:2" ) << 3 << 2 << 0 << 1; | 
| 901 |     QTest::newRow(dataTag: "100:10" ) << 100 << 10 << 0 << 90; | 
| 902 | } | 
| 903 |  | 
| 904 | void tst_QListWidget::removeItems() | 
| 905 | { | 
| 906 |     QFETCH(int, rowCount); | 
| 907 |     QFETCH(int, removeRows); | 
| 908 |     QFETCH(int, row); | 
| 909 |     QFETCH(int, expectedRowCount); | 
| 910 |  | 
| 911 |     //insert items | 
| 912 |     for (int r = 0; r < rowCount; ++r) | 
| 913 |         new QListWidgetItem(QString::number(r), testWidget); | 
| 914 |  | 
| 915 |     // remove and compare the results | 
| 916 |     for (int r = 0; r < removeRows; ++r) | 
| 917 |         delete testWidget->item(row); | 
| 918 |     QCOMPARE(testWidget->count(), expectedRowCount); | 
| 919 |  | 
| 920 |     // check if the correct items were removed | 
| 921 |     for (int r = 0; r < expectedRowCount; ++r) | 
| 922 |         if (r < row) | 
| 923 |             QCOMPARE(testWidget->item(r)->text(), QString::number(r)); | 
| 924 |         else | 
| 925 |             QCOMPARE(testWidget->item(r)->text(), QString::number(r + removeRows)); | 
| 926 | } | 
| 927 |  | 
| 928 | void tst_QListWidget::moveItemsPriv_data() | 
| 929 | { | 
| 930 |     QTest::addColumn<int>(name: "rowCount" ); | 
| 931 |     QTest::addColumn<int>(name: "srcRow" ); | 
| 932 |     QTest::addColumn<int>(name: "dstRow" ); | 
| 933 |     QTest::addColumn<bool>(name: "shouldHaveSignaled" ); | 
| 934 |  | 
| 935 |     QTest::newRow(dataTag: "Empty" ) << 0 << 0 << 0 << false; | 
| 936 |     QTest::newRow(dataTag: "Overflow src" ) << 5 << 5 << 2 << false; | 
| 937 |     QTest::newRow(dataTag: "Underflow src" ) << 5 << -1 << 2 << false; | 
| 938 |     QTest::newRow(dataTag: "Overflow dst" ) << 5 << 2 << 6 << false; | 
| 939 |     QTest::newRow(dataTag: "Underflow dst" ) << 5 << 2 << -1 << false; | 
| 940 |     QTest::newRow(dataTag: "Same place" ) << 5 << 2 << 2 << false; | 
| 941 |     QTest::newRow(dataTag: "Up" ) << 5 << 4 << 2 << true; | 
| 942 |     QTest::newRow(dataTag: "Down" ) << 5 << 2 << 4 << true; | 
| 943 |     QTest::newRow(dataTag: "QTBUG-6532 assert" ) << 5 << 0 << 1 << false; | 
| 944 |     QTest::newRow(dataTag: "QTBUG-6565 to the end" ) << 5 << 3 << 5 << true; | 
| 945 |     QTest::newRow(dataTag: "Same place 2" ) << 2 << 0 << 1 << false; | 
| 946 |     QTest::newRow(dataTag: "swap" ) << 2 << 0 << 2 << true; | 
| 947 |     QTest::newRow(dataTag: "swap2" ) << 4 << 1 << 3 << true; | 
| 948 |     QTest::newRow(dataTag: "swap3" ) << 4 << 3 << 2 << true; | 
| 949 |     QTest::newRow(dataTag: "swap4" ) << 2 << 1 << 0 << true; | 
| 950 | } | 
| 951 |  | 
| 952 | void tst_QListWidget::moveItemsPriv() | 
| 953 | { | 
| 954 |     QFETCH(int, rowCount); | 
| 955 |     QFETCH(int, srcRow); | 
| 956 |     QFETCH(int, dstRow); | 
| 957 |     QFETCH(bool, shouldHaveSignaled); | 
| 958 |  | 
| 959 |     for (int r = 0; r < rowCount; ++r) | 
| 960 |         new QListWidgetItem(QString::number(r), testWidget); | 
| 961 |  | 
| 962 |     QListModel *model = qobject_cast<QListModel *>(object: testWidget->model()); | 
| 963 |     QVERIFY(model); | 
| 964 |     QSignalSpy beginMoveSpy(model, &QAbstractItemModel::rowsAboutToBeMoved); | 
| 965 |     QSignalSpy movedSpy(model, &QAbstractItemModel::rowsMoved); | 
| 966 |     model->move(srcRow, dstRow); | 
| 967 |  | 
| 968 |     if (shouldHaveSignaled) { | 
| 969 |         if (srcRow < dstRow) | 
| 970 |             QCOMPARE(testWidget->item(dstRow - 1)->text(), QString::number(srcRow)); | 
| 971 |         else | 
| 972 |             QCOMPARE(testWidget->item(dstRow)->text(), QString::number(srcRow)); | 
| 973 |  | 
| 974 |         QCOMPARE(beginMoveSpy.count(), 1); | 
| 975 |         const QList<QVariant> &beginMoveArgs = beginMoveSpy.takeFirst(); | 
| 976 |         QCOMPARE(beginMoveArgs.at(1).toInt(), srcRow); | 
| 977 |         QCOMPARE(beginMoveArgs.at(2).toInt(), srcRow); | 
| 978 |         QCOMPARE(beginMoveArgs.at(4).toInt(), dstRow); | 
| 979 |  | 
| 980 |         QCOMPARE(movedSpy.count(), 1); | 
| 981 |         const QList<QVariant> &movedArgs = movedSpy.takeFirst(); | 
| 982 |         QCOMPARE(movedArgs.at(1).toInt(), srcRow); | 
| 983 |         QCOMPARE(movedArgs.at(2).toInt(), srcRow); | 
| 984 |         QCOMPARE(movedArgs.at(4).toInt(), dstRow); | 
| 985 |     } else { | 
| 986 |         QCOMPARE(beginMoveSpy.count(), 0); | 
| 987 |         QCOMPARE(movedSpy.count(), 0); | 
| 988 |     } | 
| 989 | } | 
| 990 |  | 
| 991 | void tst_QListWidget::itemStreaming_data() | 
| 992 | { | 
| 993 |     QTest::addColumn<QString>(name: "text" ); | 
| 994 |     QTest::addColumn<QString>(name: "toolTip" ); | 
| 995 |  | 
| 996 |     QTest::newRow(dataTag: "Data" ) << "item text"  << "tool tip text" ; | 
| 997 | } | 
| 998 |  | 
| 999 | void tst_QListWidget::itemStreaming() | 
| 1000 | { | 
| 1001 |     QFETCH(QString, text); | 
| 1002 |     QFETCH(QString, toolTip); | 
| 1003 |  | 
| 1004 |     QListWidgetItem item; | 
| 1005 |     QCOMPARE(item.text(), QString()); | 
| 1006 |     QCOMPARE(item.toolTip(), QString()); | 
| 1007 |  | 
| 1008 |     item.setText(text); | 
| 1009 |     item.setToolTip(toolTip); | 
| 1010 |     QCOMPARE(item.text(), text); | 
| 1011 |     QCOMPARE(item.toolTip(), toolTip); | 
| 1012 |  | 
| 1013 |     QByteArray buffer; | 
| 1014 |     QDataStream out(&buffer, QIODevice::WriteOnly); | 
| 1015 |     out << item; | 
| 1016 |  | 
| 1017 |     QListWidgetItem item2; | 
| 1018 |     QCOMPARE(item2.text(), QString()); | 
| 1019 |     QCOMPARE(item2.toolTip(), QString()); | 
| 1020 |  | 
| 1021 |     QVERIFY(!buffer.isEmpty()); | 
| 1022 |  | 
| 1023 |     QDataStream in(&buffer, QIODevice::ReadOnly); | 
| 1024 |     in >> item2; | 
| 1025 |     QCOMPARE(item2.text(), text); | 
| 1026 |     QCOMPARE(item2.toolTip(), toolTip); | 
| 1027 | } | 
| 1028 |  | 
| 1029 | void tst_QListWidget::sortItems_data() | 
| 1030 | { | 
| 1031 |     QTest::addColumn<Qt::SortOrder>(name: "order" ); | 
| 1032 |     QTest::addColumn<QVariantList>(name: "initialList" ); | 
| 1033 |     QTest::addColumn<QVariantList>(name: "expectedList" ); | 
| 1034 |     QTest::addColumn<IntList>(name: "expectedRows" ); | 
| 1035 |  | 
| 1036 |     QTest::newRow(dataTag: "ascending strings" ) | 
| 1037 |         << Qt::AscendingOrder | 
| 1038 |         << (QVariantList() << QString("c" ) << QString("d" ) << QString("a" ) << QString("b" )) | 
| 1039 |         << (QVariantList() << QString("a" ) << QString("b" ) << QString("c" ) << QString("d" )) | 
| 1040 |         << (IntList() << 2 << 3 << 0 << 1); | 
| 1041 |  | 
| 1042 |     QTest::newRow(dataTag: "descending strings" ) | 
| 1043 |         << Qt::DescendingOrder | 
| 1044 |         << (QVariantList() << QString("c" ) << QString("d" ) << QString("a" ) << QString("b" )) | 
| 1045 |         << (QVariantList() << QString("d" ) << QString("c" ) << QString("b" ) << QString("a" )) | 
| 1046 |         << (IntList() << 1 << 0 << 3 << 2); | 
| 1047 |  | 
| 1048 |     QTest::newRow(dataTag: "ascending numbers" ) | 
| 1049 |         << Qt::AscendingOrder | 
| 1050 |         << (QVariantList() << 1 << 11 << 2 << 22) | 
| 1051 |         << (QVariantList() << 1 << 2 << 11 << 22) | 
| 1052 |         << (IntList() << 0 << 2 << 1 << 3); | 
| 1053 |  | 
| 1054 |     QTest::newRow(dataTag: "descending numbers" ) | 
| 1055 |         << Qt::DescendingOrder | 
| 1056 |         << (QVariantList() << 1 << 11 << 2 << 22) | 
| 1057 |         << (QVariantList() << 22 << 11 << 2 << 1) | 
| 1058 |         << (IntList() << 3 << 1 << 2 << 0); | 
| 1059 | } | 
| 1060 |  | 
| 1061 | void tst_QListWidget::sortItems() | 
| 1062 | { | 
| 1063 |     QFETCH(Qt::SortOrder, order); | 
| 1064 |     QFETCH(const QVariantList, initialList); | 
| 1065 |     QFETCH(const QVariantList, expectedList); | 
| 1066 |     QFETCH(const IntList, expectedRows); | 
| 1067 |  | 
| 1068 |     for (const QVariant &data : initialList) { | 
| 1069 |         QListWidgetItem *item = new QListWidgetItem(testWidget); | 
| 1070 |         item->setData(role: Qt::DisplayRole, value: data); | 
| 1071 |     } | 
| 1072 |  | 
| 1073 |     QAbstractItemModel *model = testWidget->model(); | 
| 1074 |     QVector<QPersistentModelIndex> persistent; | 
| 1075 |     for (int j = 0; j < model->rowCount(parent: QModelIndex()); ++j) | 
| 1076 |         persistent << model->index(row: j, column: 0, parent: QModelIndex()); | 
| 1077 |  | 
| 1078 |     testWidget->sortItems(order); | 
| 1079 |  | 
| 1080 |     QCOMPARE(testWidget->count(), expectedList.count()); | 
| 1081 |     for (int i = 0; i < testWidget->count(); ++i) | 
| 1082 |         QCOMPARE(testWidget->item(i)->text(), expectedList.at(i).toString()); | 
| 1083 |  | 
| 1084 |     for (int k = 0; k < testWidget->count(); ++k) | 
| 1085 |         QCOMPARE(persistent.at(k).row(), expectedRows.at(k)); | 
| 1086 | } | 
| 1087 |  | 
| 1088 | void tst_QListWidget::sortHiddenItems_data() | 
| 1089 | { | 
| 1090 |     QTest::addColumn<Qt::SortOrder>(name: "order" ); | 
| 1091 |     QTest::addColumn<QStringList>(name: "initialList" ); | 
| 1092 |     QTest::addColumn<QStringList>(name: "expectedList" ); | 
| 1093 |     QTest::addColumn<IntList>(name: "expectedRows" ); | 
| 1094 |     QTest::addColumn<IntList>(name: "expectedVisibility" ); | 
| 1095 |  | 
| 1096 |     QStringList initial, expected; | 
| 1097 |     IntList rowOrder; | 
| 1098 |     IntList visible; | 
| 1099 |     for (int i = 0; i < 20; ++i) { | 
| 1100 |         initial << QString(QChar(0x41 + i)); | 
| 1101 |         expected << QString(QChar(0x54 - i)); | 
| 1102 |         rowOrder << 19 - i; | 
| 1103 |         visible << (i % 2); | 
| 1104 |  | 
| 1105 |     } | 
| 1106 |     QTest::newRow(dataTag: "descending order, 20 items" ) | 
| 1107 |         << Qt::DescendingOrder | 
| 1108 |         << initial | 
| 1109 |         << expected | 
| 1110 |         << rowOrder | 
| 1111 |         << visible; | 
| 1112 |  | 
| 1113 |     QTest::newRow(dataTag: "ascending order" ) | 
| 1114 |         << Qt::AscendingOrder | 
| 1115 |         << (QStringList() << "c"  << "d"  << "a"  << "b" ) | 
| 1116 |         << (QStringList() << "a"  << "b"  << "c"  << "d" ) | 
| 1117 |         << (IntList() << 2 << 3 << 0 << 1) | 
| 1118 |         << (IntList() << 1 << 0 << 1 << 0); | 
| 1119 |  | 
| 1120 |     QTest::newRow(dataTag: "descending order" ) | 
| 1121 |         << Qt::DescendingOrder | 
| 1122 |         << (QStringList() << "c"  << "d"  << "a"  << "b" ) | 
| 1123 |         << (QStringList() << "d"  << "c"  << "b"  << "a" ) | 
| 1124 |         << (IntList() << 1 << 0 << 3 << 2) | 
| 1125 |         << (IntList() << 0 << 1 << 0 << 1); | 
| 1126 | } | 
| 1127 |  | 
| 1128 | void tst_QListWidget::sortHiddenItems() | 
| 1129 | { | 
| 1130 |     QFETCH(Qt::SortOrder, order); | 
| 1131 |     QFETCH(QStringList, initialList); | 
| 1132 |     QFETCH(QStringList, expectedList); | 
| 1133 |     QFETCH(IntList, expectedRows); | 
| 1134 |     QFETCH(IntList, expectedVisibility); | 
| 1135 |  | 
| 1136 |     // init() won't clear hidden items... | 
| 1137 |     QListWidget *tw = new QListWidget(); | 
| 1138 |     tw->addItems(labels: initialList); | 
| 1139 |  | 
| 1140 |     QAbstractItemModel *model = tw->model(); | 
| 1141 |     QVector<QPersistentModelIndex> persistent; | 
| 1142 |     for (int j = 0; j < model->rowCount(parent: QModelIndex()); ++j) { | 
| 1143 |         persistent << model->index(row: j, column: 0, parent: QModelIndex()); | 
| 1144 |         tw->setRowHidden(row: j, hide: j & 1); // every odd is hidden | 
| 1145 |     } | 
| 1146 |  | 
| 1147 |     tw->setSortingEnabled(true); | 
| 1148 |     tw->sortItems(order); | 
| 1149 |  | 
| 1150 |     QCOMPARE(tw->count(), expectedList.count()); | 
| 1151 |     for (int i = 0; i < tw->count(); ++i) { | 
| 1152 |         QCOMPARE(tw->item(i)->text(), expectedList.at(i)); | 
| 1153 |         QCOMPARE(tw->item(i)->isHidden(), !expectedVisibility.at(i)); | 
| 1154 |     } | 
| 1155 |  | 
| 1156 |     for (int k = 0; k < tw->count(); ++k) | 
| 1157 |         QCOMPARE(persistent.at(k).row(), expectedRows.at(k)); | 
| 1158 |  | 
| 1159 |     delete tw; | 
| 1160 | } | 
| 1161 |  | 
| 1162 | class TestListWidget : public QListWidget | 
| 1163 | { | 
| 1164 |     Q_OBJECT | 
| 1165 | public: | 
| 1166 |     using QListWidget::QListWidget; | 
| 1167 |     using QListWidget::state; | 
| 1168 |     using QListWidget::closeEditor; | 
| 1169 |     using QListWidget::mimeData; | 
| 1170 |     using QListWidget::indexFromItem; | 
| 1171 |  | 
| 1172 |     bool isEditingState() const { | 
| 1173 |         return QListWidget::state() == QListWidget::EditingState; | 
| 1174 |     } | 
| 1175 | }; | 
| 1176 |  | 
| 1177 | void tst_QListWidget::closeEditor() | 
| 1178 | { | 
| 1179 |     TestListWidget w; | 
| 1180 |     w.addItems(labels: {"a" , "b" , "c" , "d" }); | 
| 1181 |     QListWidgetItem *item = w.item(row: 0); | 
| 1182 |     item->setFlags(item->flags() | Qt::ItemIsEditable); | 
| 1183 |     QVERIFY(item); | 
| 1184 |     w.editItem(item); | 
| 1185 |  | 
| 1186 |     QVERIFY(w.isEditingState()); | 
| 1187 |  | 
| 1188 |     w.reset(); | 
| 1189 |  | 
| 1190 |     QVERIFY(!w.isEditingState()); | 
| 1191 | } | 
| 1192 |  | 
| 1193 | void tst_QListWidget::setData_data() | 
| 1194 | { | 
| 1195 |     QTest::addColumn<QStringList>(name: "initialItems" ); | 
| 1196 |     QTest::addColumn<int>(name: "itemIndex" ); | 
| 1197 |     QTest::addColumn<IntList>(name: "roles" ); | 
| 1198 |     QTest::addColumn<QVariantList>(name: "values" ); | 
| 1199 |     QTest::addColumn<int>(name: "expectedSignalCount" ); | 
| 1200 |  | 
| 1201 |     QStringList initialItems; | 
| 1202 |     IntList roles; | 
| 1203 |     QVariantList values; | 
| 1204 |  | 
| 1205 |     { | 
| 1206 |         initialItems.clear(); roles.clear(); values.clear(); | 
| 1207 |         initialItems << "foo" ; | 
| 1208 |         roles << Qt::DisplayRole; | 
| 1209 |         values << "xxx" ; | 
| 1210 |         QTest::newRow(dataTag: "changing a role should emit" ) | 
| 1211 |             << initialItems << 0 << roles << values << 1; | 
| 1212 |     } | 
| 1213 |     { | 
| 1214 |         initialItems.clear(); roles.clear(); values.clear(); | 
| 1215 |         initialItems << "foo" ; | 
| 1216 |         roles << Qt::DisplayRole; | 
| 1217 |         values << "foo" ; | 
| 1218 |         QTest::newRow(dataTag: "setting the same value should not emit" ) | 
| 1219 |             << initialItems << 0 << roles << values << 0; | 
| 1220 |     } | 
| 1221 |     { | 
| 1222 |         initialItems.clear(); roles.clear(); values.clear(); | 
| 1223 |         initialItems << "foo" ; | 
| 1224 |         roles << Qt::DisplayRole << Qt::DisplayRole; | 
| 1225 |         values << "bar"  << "bar" ; | 
| 1226 |         QTest::newRow(dataTag: "setting the same value twice should only emit once" ) | 
| 1227 |             << initialItems << 0 << roles << values << 1; | 
| 1228 |     } | 
| 1229 |     { | 
| 1230 |         initialItems.clear(); roles.clear(); values.clear(); | 
| 1231 |         initialItems << "foo" ; | 
| 1232 |         roles << Qt::DisplayRole << Qt::ToolTipRole << Qt::WhatsThisRole; | 
| 1233 |         values << "bar"  << "bartooltip"  << "barwhatsthis" ; | 
| 1234 |         QTest::newRow(dataTag: "changing three roles should emit three times" ) | 
| 1235 |             << initialItems << 0 << roles << values << 3; | 
| 1236 |     } | 
| 1237 | } | 
| 1238 |  | 
| 1239 | void tst_QListWidget::setData() | 
| 1240 | { | 
| 1241 |     QFETCH(QStringList, initialItems); | 
| 1242 |     QFETCH(int, itemIndex); | 
| 1243 |     QFETCH(IntList, roles); | 
| 1244 |     QFETCH(QVariantList, values); | 
| 1245 |     QFETCH(int, expectedSignalCount); | 
| 1246 |  | 
| 1247 |     QCOMPARE(roles.count(), values.count()); | 
| 1248 |  | 
| 1249 |     for (int manipulateModel = 0; manipulateModel < 2; ++manipulateModel) { | 
| 1250 |         testWidget->clear(); | 
| 1251 |         testWidget->insertItems(row: 0, labels: initialItems); | 
| 1252 |         QCOMPARE(testWidget->count(), initialItems.count()); | 
| 1253 |  | 
| 1254 |         QSignalSpy itemChanged(testWidget, &QListWidget::itemChanged); | 
| 1255 |         QSignalSpy dataChanged(testWidget->model(), &QAbstractItemModel::dataChanged); | 
| 1256 |  | 
| 1257 |         for (int i = 0; i < roles.count(); ++i) { | 
| 1258 |             if (manipulateModel) | 
| 1259 |                 testWidget->model()->setData( | 
| 1260 |                     index: testWidget->model()->index(row: itemIndex, column: 0, parent: testWidget->rootIndex()), | 
| 1261 |                     value: values.at(i), | 
| 1262 |                     role: roles.at(i)); | 
| 1263 |             else | 
| 1264 |                 testWidget->item(row: itemIndex)->setData(role: roles.at(i), value: values.at(i)); | 
| 1265 |         } | 
| 1266 |  | 
| 1267 |         // make sure the data is actually set | 
| 1268 |         for (int i = 0; i < roles.count(); ++i) | 
| 1269 |             QCOMPARE(testWidget->item(itemIndex)->data(roles.at(i)), values.at(i)); | 
| 1270 |  | 
| 1271 |         // make sure we get the right number of emits | 
| 1272 |         QCOMPARE(itemChanged.count(), expectedSignalCount); | 
| 1273 |         QCOMPARE(dataChanged.count(), expectedSignalCount); | 
| 1274 |     } | 
| 1275 | } | 
| 1276 |  | 
| 1277 | void tst_QListWidget::insertItemsWithSorting_data() | 
| 1278 | { | 
| 1279 |     QTest::addColumn<Qt::SortOrder>(name: "sortOrder" ); | 
| 1280 |     QTest::addColumn<QStringList>(name: "initialItems" ); | 
| 1281 |     QTest::addColumn<QStringList>(name: "insertItems" ); | 
| 1282 |     QTest::addColumn<QStringList>(name: "expectedItems" ); | 
| 1283 |     QTest::addColumn<IntList>(name: "expectedRows" ); | 
| 1284 |  | 
| 1285 |     QTest::newRow(dataTag: "() + (a) = (a)" ) | 
| 1286 |         << Qt::AscendingOrder | 
| 1287 |         << QStringList() | 
| 1288 |         << (QStringList() << "a" ) | 
| 1289 |         << (QStringList() << "a" ) | 
| 1290 |         << IntList(); | 
| 1291 |     QTest::newRow(dataTag: "() + (c, b, a) = (a, b, c)" ) | 
| 1292 |         << Qt::AscendingOrder | 
| 1293 |         << QStringList() | 
| 1294 |         << (QStringList() << "c"  << "b"  << "a" ) | 
| 1295 |         << (QStringList() << "a"  << "b"  << "c" ) | 
| 1296 |         << IntList(); | 
| 1297 |     QTest::newRow(dataTag: "() + (a, b, c) = (c, b, a)" ) | 
| 1298 |         << Qt::DescendingOrder | 
| 1299 |         << QStringList() | 
| 1300 |         << (QStringList() << "a"  << "b"  << "c" ) | 
| 1301 |         << (QStringList() << "c"  << "b"  << "a" ) | 
| 1302 |         << IntList(); | 
| 1303 |     QTest::newRow(dataTag: "(a) + (b) = (a, b)" ) | 
| 1304 |         << Qt::AscendingOrder | 
| 1305 |         << QStringList("a" ) | 
| 1306 |         << (QStringList() << "b" ) | 
| 1307 |         << (QStringList() << "a"  << "b" ) | 
| 1308 |         << (IntList() << 0); | 
| 1309 |     QTest::newRow(dataTag: "(a) + (b) = (b, a)" ) | 
| 1310 |         << Qt::DescendingOrder | 
| 1311 |         << QStringList("a" ) | 
| 1312 |         << (QStringList() << "b" ) | 
| 1313 |         << (QStringList() << "b"  << "a" ) | 
| 1314 |         << (IntList() << 1); | 
| 1315 |     QTest::newRow(dataTag: "(a, c, b) + (d) = (a, b, c, d)" ) | 
| 1316 |         << Qt::AscendingOrder | 
| 1317 |         << (QStringList() << "a"  << "c"  << "b" ) | 
| 1318 |         << (QStringList() << "d" ) | 
| 1319 |         << (QStringList() << "a"  << "b"  << "c"  << "d" ) | 
| 1320 |         << (IntList() << 0 << 1 << 2); | 
| 1321 |     QTest::newRow(dataTag: "(b, c, a) + (d) = (d, c, b, a)" ) | 
| 1322 |         << Qt::DescendingOrder | 
| 1323 |         << (QStringList() << "b"  << "c"  << "a" ) | 
| 1324 |         << (QStringList() << "d" ) | 
| 1325 |         << (QStringList() << "d"  << "c"  << "b"  << "a" ) | 
| 1326 |         << (IntList() << 1 << 2 << 3); | 
| 1327 |     { | 
| 1328 |         IntList ascendingRows; | 
| 1329 |         IntList reverseRows; | 
| 1330 |         QStringList ascendingItems; | 
| 1331 |         QStringList reverseItems; | 
| 1332 |         for (char i = 'a'; i <= 'z'; ++i) { | 
| 1333 |             ascendingItems << QString(1, QLatin1Char(i)); | 
| 1334 |             reverseItems << QString(1, QLatin1Char('z' - i + 'a')); | 
| 1335 |             ascendingRows << i - 'a'; | 
| 1336 |             reverseRows << 'z' - i + 'a'; | 
| 1337 |         } | 
| 1338 |         QTest::newRow(dataTag: "() + (sorted items) = (sorted items)" ) | 
| 1339 |             << Qt::AscendingOrder | 
| 1340 |             << QStringList() | 
| 1341 |             << ascendingItems | 
| 1342 |             << ascendingItems | 
| 1343 |             << IntList(); | 
| 1344 |         QTest::newRow(dataTag: "(sorted items) + () = (sorted items)" ) | 
| 1345 |             << Qt::AscendingOrder | 
| 1346 |             << ascendingItems | 
| 1347 |             << QStringList() | 
| 1348 |             << ascendingItems | 
| 1349 |             << ascendingRows; | 
| 1350 |         QTest::newRow(dataTag: "() + (ascending items) = (reverse items)" ) | 
| 1351 |             << Qt::DescendingOrder | 
| 1352 |             << QStringList() | 
| 1353 |             << ascendingItems | 
| 1354 |             << reverseItems | 
| 1355 |             << IntList(); | 
| 1356 |         QTest::newRow(dataTag: "(reverse items) + () = (ascending items)" ) | 
| 1357 |             << Qt::AscendingOrder | 
| 1358 |             << reverseItems | 
| 1359 |             << QStringList() | 
| 1360 |             << ascendingItems | 
| 1361 |             << ascendingRows; | 
| 1362 |         QTest::newRow(dataTag: "(reverse items) + () = (reverse items)" ) | 
| 1363 |             << Qt::DescendingOrder | 
| 1364 |             << reverseItems | 
| 1365 |             << QStringList() | 
| 1366 |             << reverseItems | 
| 1367 |             << ascendingRows; | 
| 1368 |     } | 
| 1369 | } | 
| 1370 |  | 
| 1371 | void tst_QListWidget::insertItemsWithSorting() | 
| 1372 | { | 
| 1373 |     QFETCH(Qt::SortOrder, sortOrder); | 
| 1374 |     QFETCH(const QStringList, initialItems); | 
| 1375 |     QFETCH(const QStringList, insertItems); | 
| 1376 |     QFETCH(const QStringList, expectedItems); | 
| 1377 |     QFETCH(const IntList, expectedRows); | 
| 1378 |  | 
| 1379 |     for (int method = 0; method < 5; ++method) { | 
| 1380 |         QListWidget w; | 
| 1381 |         w.setSortingEnabled(true); | 
| 1382 |         w.sortItems(order: sortOrder); | 
| 1383 |         w.addItems(labels: initialItems); | 
| 1384 |  | 
| 1385 |         QAbstractItemModel *model = w.model(); | 
| 1386 |         QList<QPersistentModelIndex> persistent; | 
| 1387 |         for (int j = 0; j < model->rowCount(parent: QModelIndex()); ++j) | 
| 1388 |             persistent << model->index(row: j, column: 0, parent: QModelIndex()); | 
| 1389 |  | 
| 1390 |         switch (method) { | 
| 1391 |             case 0: | 
| 1392 |                 // insert using item constructor | 
| 1393 |                 for (const QString &str : insertItems) | 
| 1394 |                     new QListWidgetItem(str, &w); | 
| 1395 |                 break; | 
| 1396 |             case 1: | 
| 1397 |                 // insert using insertItems() | 
| 1398 |                 w.insertItems(row: 0, labels: insertItems); | 
| 1399 |                 break; | 
| 1400 |             case 2: | 
| 1401 |                 // insert using insertItem() | 
| 1402 |                 for (const QString &str : insertItems) | 
| 1403 |                     w.insertItem(row: 0, label: str); | 
| 1404 |                 break; | 
| 1405 |             case 3: | 
| 1406 |                 // insert using addItems() | 
| 1407 |                 w.addItems(labels: insertItems); | 
| 1408 |                 break; | 
| 1409 |             case 4: | 
| 1410 |                 // insert using addItem() | 
| 1411 |                 for (const QString &str : insertItems) | 
| 1412 |                     w.addItem(label: str); | 
| 1413 |                 break; | 
| 1414 |         } | 
| 1415 |         QCOMPARE(w.count(), expectedItems.count()); | 
| 1416 |         for (int i = 0; i < w.count(); ++i) | 
| 1417 |             QCOMPARE(w.item(i)->text(), expectedItems.at(i)); | 
| 1418 |  | 
| 1419 |         for (int k = 0; k < persistent.count(); ++k) | 
| 1420 |             QCOMPARE(persistent.at(k).row(), expectedRows.at(k)); | 
| 1421 |     } | 
| 1422 | } | 
| 1423 |  | 
| 1424 | void tst_QListWidget::changeDataWithSorting_data() | 
| 1425 | { | 
| 1426 |     QTest::addColumn<Qt::SortOrder>(name: "sortOrder" ); | 
| 1427 |     QTest::addColumn<QStringList>(name: "initialItems" ); | 
| 1428 |     QTest::addColumn<int>(name: "itemIndex" ); | 
| 1429 |     QTest::addColumn<QString>(name: "newValue" ); | 
| 1430 |     QTest::addColumn<QStringList>(name: "expectedItems" ); | 
| 1431 |     QTest::addColumn<IntList>(name: "expectedRows" ); | 
| 1432 |     QTest::addColumn<bool>(name: "reorderingExpected" ); | 
| 1433 |  | 
| 1434 |     QTest::newRow(dataTag: "change a to b in (a)" ) | 
| 1435 |         << Qt::AscendingOrder | 
| 1436 |         << (QStringList() << "a" ) | 
| 1437 |         << 0 << "b"  | 
| 1438 |         << (QStringList() << "b" ) | 
| 1439 |         << (IntList() << 0) | 
| 1440 |         << false; | 
| 1441 |     QTest::newRow(dataTag: "change a to b in (a, c)" ) | 
| 1442 |         << Qt::AscendingOrder | 
| 1443 |         << (QStringList() << "a"  << "c" ) | 
| 1444 |         << 0 << "b"  | 
| 1445 |         << (QStringList() << "b"  << "c" ) | 
| 1446 |         << (IntList() << 0 << 1) | 
| 1447 |         << false; | 
| 1448 |     QTest::newRow(dataTag: "change a to c in (a, b)" ) | 
| 1449 |         << Qt::AscendingOrder | 
| 1450 |         << (QStringList() << "a"  << "b" ) | 
| 1451 |         << 0 << "c"  | 
| 1452 |         << (QStringList() << "b"  << "c" ) | 
| 1453 |         << (IntList() << 1 << 0) | 
| 1454 |         << true; | 
| 1455 |     QTest::newRow(dataTag: "change c to a in (c, b)" ) | 
| 1456 |         << Qt::DescendingOrder | 
| 1457 |         << (QStringList() << "c"  << "b" ) | 
| 1458 |         << 0 << "a"  | 
| 1459 |         << (QStringList() << "b"  << "a" ) | 
| 1460 |         << (IntList() << 1 << 0) | 
| 1461 |         << true; | 
| 1462 |     QTest::newRow(dataTag: "change e to i in (a, c, e, g)" ) | 
| 1463 |         << Qt::AscendingOrder | 
| 1464 |         << (QStringList() << "a"  << "c"  << "e"  << "g" ) | 
| 1465 |         << 2 << "i"  | 
| 1466 |         << (QStringList() << "a"  << "c"  << "g"  << "i" ) | 
| 1467 |         << (IntList() << 0 << 1 << 3 << 2) | 
| 1468 |         << true; | 
| 1469 |     QTest::newRow(dataTag: "change e to a in (c, e, g, i)" ) | 
| 1470 |         << Qt::AscendingOrder | 
| 1471 |         << (QStringList() << "c"  << "e"  << "g"  << "i" ) | 
| 1472 |         << 1 << "a"  | 
| 1473 |         << (QStringList() << "a"  << "c"  << "g"  << "i" ) | 
| 1474 |         << (IntList() << 1 << 0 << 2 << 3) | 
| 1475 |         << true; | 
| 1476 |     QTest::newRow(dataTag: "change e to f in (c, e, g, i)" ) | 
| 1477 |         << Qt::AscendingOrder | 
| 1478 |         << (QStringList() << "c"  << "e"  << "g"  << "i" ) | 
| 1479 |         << 1 << "f"  | 
| 1480 |         << (QStringList() << "c"  << "f"  << "g"  << "i" ) | 
| 1481 |         << (IntList() << 0 << 1 << 2 << 3) | 
| 1482 |         << false; | 
| 1483 | } | 
| 1484 |  | 
| 1485 | class QListWidgetDataChanged : public QListWidget | 
| 1486 | { | 
| 1487 |     Q_OBJECT | 
| 1488 | public: | 
| 1489 |     using QListWidget::QListWidget; | 
| 1490 |  | 
| 1491 |     void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles) override | 
| 1492 |     { | 
| 1493 |         QListWidget::dataChanged(topLeft, bottomRight, roles); | 
| 1494 |         currentRoles = roles; | 
| 1495 |     } | 
| 1496 |     QVector<int> currentRoles; | 
| 1497 | }; | 
| 1498 |  | 
| 1499 | void tst_QListWidget::itemData() | 
| 1500 | { | 
| 1501 |     QListWidgetDataChanged widget; | 
| 1502 |     QListWidgetItem item(&widget); | 
| 1503 |     item.setFlags(item.flags() | Qt::ItemIsEditable); | 
| 1504 |     item.setData(role: Qt::DisplayRole,  value: QString("0" )); | 
| 1505 |     QCOMPARE(widget.currentRoles, QVector<int>({Qt::DisplayRole, Qt::EditRole})); | 
| 1506 |     item.setData(role: Qt::CheckStateRole, value: Qt::PartiallyChecked); | 
| 1507 |     QCOMPARE(widget.currentRoles, QVector<int>{Qt::CheckStateRole}); | 
| 1508 |     for (int i = 0; i < 4; ++i) | 
| 1509 |     { | 
| 1510 |         item.setData(role: Qt::UserRole + i, value: QString::number(i + 1)); | 
| 1511 |         QCOMPARE(widget.currentRoles, QVector<int>{Qt::UserRole + i}); | 
| 1512 |     } | 
| 1513 |     QMap<int, QVariant> flags = widget.model()->itemData(index: widget.model()->index(row: 0, column: 0)); | 
| 1514 |     QCOMPARE(flags.count(), 6); | 
| 1515 |     for (int i = 0; i < 4; ++i) | 
| 1516 |         QCOMPARE(flags[Qt::UserRole + i].toString(), QString::number(i + 1)); | 
| 1517 |  | 
| 1518 |     item.setBackground(QBrush(Qt::red)); | 
| 1519 |     item.setForeground(QBrush(Qt::red)); | 
| 1520 |     item.setSizeHint(QSize(10, 10)); | 
| 1521 |     QCOMPARE(item.data(Qt::BackgroundRole), QVariant(QBrush(Qt::red))); | 
| 1522 |     QCOMPARE(item.data(Qt::ForegroundRole), QVariant(QBrush(Qt::red))); | 
| 1523 |     QCOMPARE(item.data(Qt::SizeHintRole), QVariant(QSize(10, 10))); | 
| 1524 |     // an empty brush should result in a QVariant() | 
| 1525 |     item.setBackground(QBrush()); | 
| 1526 |     item.setForeground(QBrush()); | 
| 1527 |     item.setSizeHint(QSize()); | 
| 1528 |     QCOMPARE(item.data(Qt::BackgroundRole), QVariant()); | 
| 1529 |     QCOMPARE(item.data(Qt::ForegroundRole), QVariant()); | 
| 1530 |     QCOMPARE(item.data(Qt::SizeHintRole), QVariant()); | 
| 1531 | } | 
| 1532 |  | 
| 1533 | void tst_QListWidget::changeDataWithSorting() | 
| 1534 | { | 
| 1535 |     QFETCH(Qt::SortOrder, sortOrder); | 
| 1536 |     QFETCH(QStringList, initialItems); | 
| 1537 |     QFETCH(int, itemIndex); | 
| 1538 |     QFETCH(QString, newValue); | 
| 1539 |     QFETCH(QStringList, expectedItems); | 
| 1540 |     QFETCH(IntList, expectedRows); | 
| 1541 |     QFETCH(bool, reorderingExpected); | 
| 1542 |  | 
| 1543 |     QListWidget w; | 
| 1544 |     w.setSortingEnabled(true); | 
| 1545 |     w.sortItems(order: sortOrder); | 
| 1546 |     w.addItems(labels: initialItems); | 
| 1547 |  | 
| 1548 |     QAbstractItemModel *model = w.model(); | 
| 1549 |     QVector<QPersistentModelIndex> persistent; | 
| 1550 |     for (int j = 0; j < model->rowCount(parent: QModelIndex()); ++j) | 
| 1551 |         persistent << model->index(row: j, column: 0, parent: QModelIndex()); | 
| 1552 |  | 
| 1553 |     QSignalSpy dataChangedSpy(model, &QAbstractItemModel::dataChanged); | 
| 1554 |     QSignalSpy layoutChangedSpy(model, &QAbstractItemModel::layoutChanged); | 
| 1555 |  | 
| 1556 |     QListWidgetItem *item = w.item(row: itemIndex); | 
| 1557 |     item->setText(newValue); | 
| 1558 |     for (int i = 0; i < expectedItems.count(); ++i) { | 
| 1559 |         QCOMPARE(w.item(i)->text(), expectedItems.at(i)); | 
| 1560 |         for (int j = 0; j < persistent.count(); ++j) { | 
| 1561 |             if (persistent.at(i: j).row() == i) // the same toplevel row | 
| 1562 |                 QCOMPARE(persistent.at(j).internalPointer(), static_cast<void *>(w.item(i))); | 
| 1563 |         } | 
| 1564 |     } | 
| 1565 |  | 
| 1566 |     for (int k = 0; k < persistent.count(); ++k) | 
| 1567 |         QCOMPARE(persistent.at(k).row(), expectedRows.at(k)); | 
| 1568 |  | 
| 1569 |     QCOMPARE(dataChangedSpy.count(), 1); | 
| 1570 |     QCOMPARE(layoutChangedSpy.count(), reorderingExpected ? 1 : 0); | 
| 1571 | } | 
| 1572 |  | 
| 1573 | void tst_QListWidget::itemWidget() | 
| 1574 | { | 
| 1575 |     QListWidget list; | 
| 1576 |     QWidget widget; | 
| 1577 |  | 
| 1578 |     QListWidgetItem *item = new QListWidgetItem(&list); | 
| 1579 |  | 
| 1580 |  | 
| 1581 |     QCOMPARE(list.itemWidget(item), nullptr); | 
| 1582 |     list.setItemWidget(item, widget: &widget); | 
| 1583 |     QCOMPARE(list.itemWidget(item), &widget); | 
| 1584 |     list.removeItemWidget(aItem: item); | 
| 1585 |     QCOMPARE(list.itemWidget(item), nullptr); | 
| 1586 | } | 
| 1587 |  | 
| 1588 | #ifndef Q_OS_MAC | 
| 1589 | class MyListWidget : public QListWidget | 
| 1590 | { | 
| 1591 |     Q_OBJECT | 
| 1592 | public: | 
| 1593 |     using QListWidget::QListWidget; | 
| 1594 |  | 
| 1595 |     void paintEvent(QPaintEvent *e) override | 
| 1596 |     { | 
| 1597 |         painted += e->region(); | 
| 1598 |         QListWidget::paintEvent(e); | 
| 1599 |     } | 
| 1600 |  | 
| 1601 |     QRegion painted; | 
| 1602 | }; | 
| 1603 |  | 
| 1604 | void tst_QListWidget::fastScroll() | 
| 1605 | { | 
| 1606 |     if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) | 
| 1607 |         QSKIP("Wayland: This fails. Figure out why." ); | 
| 1608 |  | 
| 1609 |     QWidget topLevel; | 
| 1610 |     MyListWidget widget(&topLevel); | 
| 1611 |     for (int i = 0; i < 50; ++i) | 
| 1612 |         widget.addItem(QStringLiteral("Item " ) + QString::number(i)); | 
| 1613 |  | 
| 1614 |     topLevel.resize(w: 300, h: 300); // toplevel needs to be wide enough for the item | 
| 1615 |     topLevel.show(); | 
| 1616 |  | 
| 1617 |     // Force the mouse cursor off the widget as it causes item it is over to highlight, | 
| 1618 |     // which causes unexpected paint region. | 
| 1619 |     QTest::mouseMove(widget: &widget, pos: QPoint(-10, -10)); | 
| 1620 |  | 
| 1621 |     // Make sure the widget gets the first full repaint. On | 
| 1622 |     // some WMs, we'll get two (first inactive exposure, then | 
| 1623 |     // active exposure. | 
| 1624 |     QVERIFY(QTest::qWaitForWindowActive(&topLevel)); | 
| 1625 |  | 
| 1626 |     QSize itemSize = widget.visualItemRect(item: widget.item(row: 0)).size(); | 
| 1627 |     QVERIFY(!itemSize.isEmpty()); | 
| 1628 |  | 
| 1629 |     QScrollBar *sbar = widget.verticalScrollBar(); | 
| 1630 |     widget.setVerticalScrollMode(QAbstractItemView::ScrollPerItem); | 
| 1631 |     widget.painted = QRegion(); | 
| 1632 |     sbar->setValue(sbar->value() + sbar->singleStep()); | 
| 1633 |     QApplication::processEvents(); | 
| 1634 |  | 
| 1635 |     const QSize actualItemSize = widget.painted.boundingRect().size(); | 
| 1636 |     if (actualItemSize != itemSize) | 
| 1637 |         QEXPECT_FAIL("" , "QTBUG-21098" , Continue); | 
| 1638 |  | 
| 1639 |     // only one item should be repainted, the rest should be scrolled in memory | 
| 1640 |     QCOMPARE(actualItemSize, itemSize); | 
| 1641 | } | 
| 1642 | #endif // Q_OS_MAC | 
| 1643 |  | 
| 1644 | void tst_QListWidget::insertUnchanged() | 
| 1645 | { | 
| 1646 |     QListWidget w; | 
| 1647 |     QSignalSpy itemChangedSpy(&w, &QListWidget::itemChanged); | 
| 1648 |     QListWidgetItem item("foo" , &w); | 
| 1649 |     QCOMPARE(itemChangedSpy.count(), 0); | 
| 1650 | } | 
| 1651 |  | 
| 1652 | void tst_QListWidget::setSortingEnabled() | 
| 1653 | { | 
| 1654 |     QListWidget w; | 
| 1655 |     QListWidgetItem *item1 = new QListWidgetItem(&w); | 
| 1656 |     QListWidgetItem *item2 = new QListWidgetItem(&w); | 
| 1657 |  | 
| 1658 |     w.setSortingEnabled(true); | 
| 1659 |     QCOMPARE(w.isSortingEnabled(), true); | 
| 1660 |     QCOMPARE(w.item(0), item1); | 
| 1661 |     QCOMPARE(w.item(1), item2); | 
| 1662 | } | 
| 1663 |  | 
| 1664 | void tst_QListWidget::task199503_crashWhenCleared() | 
| 1665 | { | 
| 1666 |     //we test here for a crash that would occur if you clear the items in the currentItemChanged signal | 
| 1667 |     QListWidget w; | 
| 1668 |     w.addItems(labels: {"item1" , "item2" , "item3" }); | 
| 1669 |     w.setCurrentRow(0); | 
| 1670 |     w.connect(sender: &w, signal: &QListWidget::currentItemChanged, receiver: &w, slot: &QListWidget::clear); | 
| 1671 |     w.setCurrentRow(1); | 
| 1672 | } | 
| 1673 |  | 
| 1674 | void tst_QListWidget::task217070_scrollbarsAdjusted() | 
| 1675 | { | 
| 1676 |     if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) | 
| 1677 |         QSKIP("Wayland: This fails. Figure out why." ); | 
| 1678 |  | 
| 1679 |     //This task was mailing for style using SH_ScrollView_FrameOnlyAroundContents such as QMotifStyle | 
| 1680 |     QListWidget v; | 
| 1681 |     for (int i = 0; i < 200;i++) | 
| 1682 |         v.addItem(label: QString::number(i)); | 
| 1683 |     v.show(); | 
| 1684 |     v.setViewMode(QListView::IconMode); | 
| 1685 |     v.setResizeMode(QListView::Adjust); | 
| 1686 |     v.setUniformItemSizes(true); | 
| 1687 |     v.resize(w: 160, h: 100); | 
| 1688 |     QVERIFY(QTest::qWaitForWindowActive(&v)); | 
| 1689 |     QScrollBar *hbar = v.horizontalScrollBar(); | 
| 1690 |     QScrollBar *vbar = v.verticalScrollBar(); | 
| 1691 |     QVERIFY(hbar && vbar); | 
| 1692 |     const auto style = vbar->style(); | 
| 1693 |     for (int f = 150; f > 90 ; f--) { | 
| 1694 |         v.resize(w: f, h: 100); | 
| 1695 |         QTRY_VERIFY(style->styleHint(QStyle::SH_ScrollBar_Transient, nullptr, vbar) || | 
| 1696 |                     vbar->isVisible()); | 
| 1697 |         //the horizontal scrollbar must not be visible. | 
| 1698 |         QVERIFY(!hbar->isVisible()); | 
| 1699 |     } | 
| 1700 | } | 
| 1701 |  | 
| 1702 | void tst_QListWidget::task258949_keypressHangup() | 
| 1703 | { | 
| 1704 |     QListWidget lw; | 
| 1705 |     for (int y = 0; y < 5; y++) { | 
| 1706 |         QListWidgetItem *lwi = new QListWidgetItem(&lw); | 
| 1707 |         lwi->setText(y ? "1"  : "0" ); | 
| 1708 |         if (y) | 
| 1709 |             lwi->setFlags(Qt::ItemIsSelectable); | 
| 1710 |     } | 
| 1711 |  | 
| 1712 |     lw.show(); | 
| 1713 |     lw.setCurrentIndex(lw.model()->index(row: 0, column: 0)); | 
| 1714 |     QCOMPARE(lw.currentIndex(), lw.model()->index(0, 0)); | 
| 1715 |     QTest::qWait(ms: 30); | 
| 1716 |     QTest::keyPress(widget: &lw, key: '1'); //this used to freeze | 
| 1717 |     QTRY_COMPARE(lw.currentIndex(), lw.model()->index(0, 0)); | 
| 1718 | } | 
| 1719 |  | 
| 1720 | void tst_QListWidget::QTBUG8086_currentItemChangedOnClick() | 
| 1721 | { | 
| 1722 |     QWidget win; | 
| 1723 |     QHBoxLayout layout(&win); | 
| 1724 |     QListWidget list; | 
| 1725 |     for (int i = 0 ; i < 4; ++i) | 
| 1726 |         new QListWidgetItem(QString::number(i), &list); | 
| 1727 |  | 
| 1728 |     layout.addWidget(&list); | 
| 1729 |  | 
| 1730 |     QLineEdit edit; | 
| 1731 |     layout.addWidget(&edit); | 
| 1732 |  | 
| 1733 |     edit.setFocus(); | 
| 1734 |     win.show(); | 
| 1735 |  | 
| 1736 |     QSignalSpy spy(&list, &QListWidget::currentItemChanged); | 
| 1737 |  | 
| 1738 |     QVERIFY(QTest::qWaitForWindowExposed(&win)); | 
| 1739 |  | 
| 1740 |     QCOMPARE(spy.count(), 0); | 
| 1741 |  | 
| 1742 |     QTest::mouseClick(widget: list.viewport(), button: Qt::LeftButton, stateKey: {}, | 
| 1743 |                       pos: list.visualItemRect(item: list.item(row: 2)).center()); | 
| 1744 |  | 
| 1745 |     QCOMPARE(spy.count(), 1); | 
| 1746 | } | 
| 1747 |  | 
| 1748 |  | 
| 1749 | class ItemDelegate : public QStyledItemDelegate | 
| 1750 | { | 
| 1751 |     Q_OBJECT | 
| 1752 | public: | 
| 1753 |     using QStyledItemDelegate::QStyledItemDelegate; | 
| 1754 |     QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &, | 
| 1755 |                           const QModelIndex &) const override | 
| 1756 |     { | 
| 1757 |         QLineEdit *lineEdit = new QLineEdit(parent); | 
| 1758 |         lineEdit->setFrame(false); | 
| 1759 |         QCompleter *completer = new QCompleter(QStringList() << "completer" , lineEdit); | 
| 1760 |         completer->setCompletionMode(QCompleter::InlineCompletion); | 
| 1761 |         lineEdit->setCompleter(completer); | 
| 1762 |         return lineEdit; | 
| 1763 |     } | 
| 1764 | }; | 
| 1765 |  | 
| 1766 | void tst_QListWidget::QTBUG14363_completerWithAnyKeyPressedEditTriggers() | 
| 1767 | { | 
| 1768 |     if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) | 
| 1769 |         QSKIP("Wayland: This fails. Figure out why." ); | 
| 1770 |  | 
| 1771 |     QListWidget listWidget; | 
| 1772 |     listWidget.setEditTriggers(QAbstractItemView::AnyKeyPressed); | 
| 1773 |     listWidget.setItemDelegate(new ItemDelegate(&listWidget)); | 
| 1774 |     QListWidgetItem *item = new QListWidgetItem(QLatin1String("select an item (don't start editing)" ), &listWidget); | 
| 1775 |     item->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable|Qt::ItemIsEditable); | 
| 1776 |     new QListWidgetItem(QLatin1String("try to type the letter 'c'" ), &listWidget); | 
| 1777 |     new QListWidgetItem(QLatin1String("completer" ), &listWidget); | 
| 1778 |     listWidget.show(); | 
| 1779 |     listWidget.setCurrentItem(item); | 
| 1780 |     QApplication::setActiveWindow(&listWidget); | 
| 1781 |     QVERIFY(QTest::qWaitForWindowActive(&listWidget)); | 
| 1782 |     listWidget.setFocus(); | 
| 1783 |     QCOMPARE(QApplication::focusWidget(), &listWidget); | 
| 1784 |  | 
| 1785 |     QTest::keyClick(widget: listWidget.viewport(), key: Qt::Key_C); | 
| 1786 |  | 
| 1787 |     QLineEdit *le = qobject_cast<QLineEdit*>(object: listWidget.itemWidget(item)); | 
| 1788 |     QVERIFY(le); | 
| 1789 |     QCOMPARE(le->text(), QString("completer" )); | 
| 1790 |     QCOMPARE(le->completer()->currentCompletion(), QString("completer" )); | 
| 1791 | } | 
| 1792 |  | 
| 1793 | void tst_QListWidget::mimeData() | 
| 1794 | { | 
| 1795 |     TestListWidget list; | 
| 1796 |  | 
| 1797 |     for (int x = 0; x < 10; ++x) | 
| 1798 |         list.addItem(aitem: new QListWidgetItem(QStringLiteral("123" ))); | 
| 1799 |  | 
| 1800 |     const QList<QListWidgetItem *> tableWidgetItemList{list.item(row: 1)}; | 
| 1801 |     const QModelIndexList modelIndexList{list.indexFromItem(item: list.item(row: 1))}; | 
| 1802 |  | 
| 1803 |     // do these checks more than once to ensure that the "cached indexes" work as expected | 
| 1804 |     QMimeData *data; | 
| 1805 |     for (int i = 0; i < 2; ++i) { | 
| 1806 |       QVERIFY(!list.mimeData({})); | 
| 1807 |       QVERIFY(!list.model()->mimeData({})); | 
| 1808 |  | 
| 1809 |       QVERIFY((data = list.mimeData(tableWidgetItemList))); | 
| 1810 |       delete data; | 
| 1811 |  | 
| 1812 |       QVERIFY((data = list.model()->mimeData(modelIndexList))); | 
| 1813 |       delete data; | 
| 1814 |     } | 
| 1815 |  | 
| 1816 |     // check the saved data is actually the same | 
| 1817 |     QMimeData *data2; | 
| 1818 |     data = list.mimeData(items: tableWidgetItemList); | 
| 1819 |     data2 = list.model()->mimeData(indexes: modelIndexList); | 
| 1820 |  | 
| 1821 |     const QString format = QStringLiteral("application/x-qabstractitemmodeldatalist" ); | 
| 1822 |  | 
| 1823 |     QVERIFY(data->hasFormat(format)); | 
| 1824 |     QVERIFY(data2->hasFormat(format)); | 
| 1825 |     QCOMPARE(data->data(format), data2->data(format)); | 
| 1826 |  | 
| 1827 |     delete data; | 
| 1828 |     delete data2; | 
| 1829 | } | 
| 1830 |  | 
| 1831 | void tst_QListWidget::QTBUG50891_ensureSelectionModelSignalConnectionsAreSet() | 
| 1832 | { | 
| 1833 |     QListWidget list; | 
| 1834 |     for (int i = 0 ; i < 4; ++i) | 
| 1835 |         new QListWidgetItem(QString::number(i), &list); | 
| 1836 |  | 
| 1837 |     list.setSelectionModel(new QItemSelectionModel(list.model())); | 
| 1838 |     list.show(); | 
| 1839 |     QVERIFY(QTest::qWaitForWindowExposed(&list)); | 
| 1840 |  | 
| 1841 |     QSignalSpy currentItemChangedSpy(&list, &QListWidget::currentItemChanged); | 
| 1842 |     QSignalSpy itemSelectionChangedSpy(&list, &QListWidget::itemSelectionChanged); | 
| 1843 |  | 
| 1844 |     QCOMPARE(currentItemChangedSpy.count(), 0); | 
| 1845 |     QCOMPARE(itemSelectionChangedSpy.count(), 0); | 
| 1846 |  | 
| 1847 |     QTest::mouseClick(widget: list.viewport(), button: Qt::LeftButton, stateKey: {}, | 
| 1848 |                       pos: list.visualItemRect(item: list.item(row: 2)).center()); | 
| 1849 |  | 
| 1850 |     QCOMPARE(currentItemChangedSpy.count(), 1); | 
| 1851 |     QCOMPARE(itemSelectionChangedSpy.count(), 1); | 
| 1852 |  | 
| 1853 | } | 
| 1854 |  | 
| 1855 | #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) | 
| 1856 | void tst_QListWidget::clearItemData() | 
| 1857 | { | 
| 1858 |     QListWidget list; | 
| 1859 |     for (int i = 0 ; i < 4; ++i) | 
| 1860 |         new QListWidgetItem(QString::number(i), &list); | 
| 1861 |     QSignalSpy dataChangeSpy(list.model(), &QAbstractItemModel::dataChanged); | 
| 1862 |     QVERIFY(dataChangeSpy.isValid()); | 
| 1863 |     QVERIFY(!list.model()->clearItemData(QModelIndex())); | 
| 1864 |     QCOMPARE(dataChangeSpy.size(), 0); | 
| 1865 |     QVERIFY(list.model()->clearItemData(list.model()->index(0, 0))); | 
| 1866 |     QVERIFY(!list.model()->index(0, 0).data().isValid()); | 
| 1867 |     QCOMPARE(dataChangeSpy.size(), 1); | 
| 1868 |     const QList<QVariant> dataChangeArgs = dataChangeSpy.takeFirst(); | 
| 1869 |     QCOMPARE(dataChangeArgs.at(0).value<QModelIndex>(), list.model()->index(0, 0)); | 
| 1870 |     QCOMPARE(dataChangeArgs.at(1).value<QModelIndex>(), list.model()->index(0, 0)); | 
| 1871 |     QVERIFY(dataChangeArgs.at(2).value<QVector<int>>().isEmpty()); | 
| 1872 |     QVERIFY(list.model()->clearItemData(list.model()->index(0, 0))); | 
| 1873 |     QCOMPARE(dataChangeSpy.size(), 0); | 
| 1874 | } | 
| 1875 | #endif | 
| 1876 |  | 
| 1877 | QTEST_MAIN(tst_QListWidget) | 
| 1878 | #include "tst_qlistwidget.moc" | 
| 1879 |  |