1/****************************************************************************
2**
3** Copyright (C) 2018 Luca Beldi <v.ronin@yahoo.it>
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtCore module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
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 Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include <QTest>
41#include <QSignalSpy>
42#include <QStandardItemModel>
43#include <QStringListModel>
44#include <QAbstractItemModelTester>
45#include <random>
46
47#include <qtransposeproxymodel.h>
48
49class tst_QTransposeProxyModel : public QObject
50{
51 Q_OBJECT
52private Q_SLOTS:
53 void initTestCase();
54 void index();
55 void data();
56 void setData_data();
57 void setData();
58 void parent();
59 void mapToSource();
60 void mapFromSource();
61 void basicTest_data();
62 void basicTest();
63 void sort();
64 void insertRowBase_data();
65 void insertRowBase();
66 void insertColumnBase_data();
67 void insertColumnBase();
68 void insertColumnProxy_data();
69 void insertColumnProxy();
70 void insertRowProxy_data();
71 void insertRowProxy();
72 void removeRowBase_data();
73 void removeRowBase();
74 void removeColumnBase_data();
75 void removeColumnBase();
76 void removeColumnProxy_data();
77 void removeColumnProxy();
78 void removeRowProxy_data();
79 void removeRowProxy();
80 void headerData();
81 void setHeaderData();
82 void span();
83 void itemData();
84 void setItemData();
85 void moveRowsBase();
86 void moveColumnsProxy();
87private:
88 void testTransposed(
89 const QAbstractItemModel *const baseModel,
90 const QAbstractItemModel *const transposed,
91 const QModelIndex &baseParent = QModelIndex(),
92 const QModelIndex &transposedParent = QModelIndex()
93 );
94 QAbstractItemModel *createListModel(QObject *parent);
95 QAbstractItemModel *createTableModel(QObject *parent);
96 QAbstractItemModel *createTreeModel(QObject *parent);
97};
98
99QAbstractItemModel *tst_QTransposeProxyModel::createListModel(QObject *parent)
100{
101 QStringList sequence;
102 sequence.reserve(alloc: 10);
103 for (int i = 0; i < 10; ++i)
104 sequence.append(t: QString::number(i));
105 return new QStringListModel(sequence, parent);
106}
107
108QAbstractItemModel *tst_QTransposeProxyModel::createTableModel(QObject *parent)
109{
110 QAbstractItemModel *model = new QStandardItemModel(parent);
111 model->insertRows(row: 0, count: 5);
112 model->insertColumns(column: 0, count: 4);
113 for (int i = 0; i < model->rowCount(); ++i) {
114 for (int j = 0; j < model->columnCount(); ++j) {
115 model->setData(index: model->index(row: i, column: j), QStringLiteral("%1,%2").arg(a: i).arg(a: j), role: Qt::EditRole);
116 model->setData(index: model->index(row: i, column: j), value: i, role: Qt::UserRole);
117 model->setData(index: model->index(row: i, column: j), value: j, role: Qt::UserRole + 1);
118 }
119 }
120 return model;
121}
122
123QAbstractItemModel *tst_QTransposeProxyModel::createTreeModel(QObject *parent)
124{
125 QAbstractItemModel *model = new QStandardItemModel(parent);
126 model->insertRows(row: 0, count: 5);
127 model->insertColumns(column: 0, count: 4);
128 for (int i = 0; i < model->rowCount(); ++i) {
129 for (int j = 0; j < model->columnCount(); ++j) {
130 const QModelIndex parIdx = model->index(row: i, column: j);
131 model->setData(index: parIdx, QStringLiteral("%1,%2").arg(a: i).arg(a: j), role: Qt::EditRole);
132 model->setData(index: parIdx, value: i, role: Qt::UserRole);
133 model->setData(index: parIdx, value: j, role: Qt::UserRole + 1);
134 model->insertRows(row: 0, count: 3, parent: parIdx);
135 model->insertColumns(column: 0, count: 2, parent: parIdx);
136 for (int h = 0; h < model->rowCount(parent: parIdx); ++h) {
137 for (int k = 0; k < model->columnCount(parent: parIdx); ++k) {
138 const QModelIndex childIdx = model->index(row: h, column: k, parent: parIdx);
139 model->setData(index: childIdx, QStringLiteral("%1,%2,%3,%4").arg(a: i).arg(a: j).arg(a: h).arg(a: k), role: Qt::EditRole);
140 model->setData(index: childIdx, value: i, role: Qt::UserRole);
141 model->setData(index: childIdx, value: j, role: Qt::UserRole + 1);
142 model->setData(index: childIdx, value: h, role: Qt::UserRole + 2);
143 model->setData(index: childIdx, value: k, role: Qt::UserRole + 3);
144 }
145 }
146 }
147 }
148 return model;
149}
150
151void tst_QTransposeProxyModel::testTransposed(
152 const QAbstractItemModel *const baseModel,
153 const QAbstractItemModel *const transposed,
154 const QModelIndex &baseParent,
155 const QModelIndex &transposedParent
156)
157{
158 QCOMPARE(transposed->hasChildren(transposedParent), baseModel->hasChildren(baseParent));
159 QCOMPARE(transposed->columnCount(transposedParent), baseModel->rowCount(baseParent));
160 QCOMPARE(transposed->rowCount(transposedParent), baseModel->columnCount(baseParent));
161 for (int i = 0, maxRow = baseModel->rowCount(parent: baseParent); i < maxRow; ++i) {
162 for (int j = 0, maxCol = baseModel->columnCount(parent: baseParent); j < maxCol; ++j) {
163 const QModelIndex baseIdx = baseModel->index(row: i, column: j, parent: baseParent);
164 const QModelIndex transIdx = transposed->index(row: j, column: i, parent: transposedParent);
165 QCOMPARE(transIdx.data(), baseIdx.data());
166 QCOMPARE(transIdx.data(Qt::UserRole), baseIdx.data(Qt::UserRole));
167 QCOMPARE(transIdx.data(Qt::UserRole + 1), baseIdx.data(Qt::UserRole + 1));
168 QCOMPARE(transIdx.data(Qt::UserRole + 2), baseIdx.data(Qt::UserRole + 2));
169 QCOMPARE(transIdx.data(Qt::UserRole + 3), baseIdx.data(Qt::UserRole + 3));
170 if (baseModel->hasChildren(parent: baseIdx)) {
171 testTransposed(baseModel, transposed, baseParent: baseIdx, transposedParent: transIdx);
172 }
173 }
174 }
175}
176
177void tst_QTransposeProxyModel::initTestCase()
178{
179 qRegisterMetaType<QList<QPersistentModelIndex> >();
180 qRegisterMetaType<QAbstractItemModel::LayoutChangeHint>();
181}
182
183void tst_QTransposeProxyModel::index()
184{
185 QAbstractItemModel *model = createTreeModel(parent: this);
186 QTransposeProxyModel proxy;
187 new QAbstractItemModelTester(&proxy, &proxy);
188 proxy.setSourceModel(model);
189 QVERIFY(!proxy.index(0, -1).isValid());
190 QVERIFY(!proxy.index(0, -1).isValid());
191 QVERIFY(!proxy.index(-1, -1).isValid());
192 QVERIFY(!proxy.index(0, proxy.columnCount()).isValid());
193 QVERIFY(!proxy.index(proxy.rowCount(), 0).isValid());
194 QVERIFY(!proxy.index(proxy.rowCount(), proxy.columnCount()).isValid());
195 QModelIndex tempIdx = proxy.index(row: 0, column: 1);
196 QVERIFY(tempIdx.isValid());
197 QCOMPARE(tempIdx.row(), 0);
198 QCOMPARE(tempIdx.column(), 1);
199 tempIdx = proxy.index(row: 0, column: 1, parent: tempIdx);
200 QVERIFY(tempIdx.isValid());
201 QCOMPARE(tempIdx.row(), 0);
202 QCOMPARE(tempIdx.column(), 1);
203 delete model;
204}
205
206void tst_QTransposeProxyModel::data()
207{
208 QStringListModel model{QStringList{"A", "B"}};
209 QTransposeProxyModel proxy;
210 new QAbstractItemModelTester(&proxy, &proxy);
211 proxy.setSourceModel(&model);
212 QCOMPARE(proxy.index(0, 1).data().toString(), QStringLiteral("B"));
213}
214
215void tst_QTransposeProxyModel::parent()
216{
217 QAbstractItemModel *model = createTreeModel(parent: this);
218 QTransposeProxyModel proxy;
219 new QAbstractItemModelTester(&proxy, &proxy);
220 proxy.setSourceModel(model);
221 const QModelIndex parentIdx = proxy.index(row: 0, column: 0);
222 const QModelIndex childIdx = proxy.index(row: 0, column: 0, parent: parentIdx);
223 QVERIFY(parentIdx.isValid());
224 QVERIFY(childIdx.isValid());
225 QCOMPARE(childIdx.parent(), parentIdx);
226 delete model;
227}
228
229void tst_QTransposeProxyModel::mapToSource()
230{
231 QAbstractItemModel *model = createTreeModel(parent: this);
232 QTransposeProxyModel proxy;
233 new QAbstractItemModelTester(&proxy, &proxy);
234 proxy.setSourceModel(model);
235 QVERIFY(!proxy.mapToSource(QModelIndex()).isValid());
236 QCOMPARE(proxy.mapToSource(proxy.index(0, 0)), model->index(0, 0));
237 QCOMPARE(proxy.mapToSource(proxy.index(1, 0)), model->index(0, 1));
238 QCOMPARE(proxy.mapToSource(proxy.index(0, 1)), model->index(1, 0));
239 const QModelIndex proxyParent = proxy.index(row: 1, column: 0);
240 const QModelIndex sourceParent = model->index(row: 0, column: 1);
241 QCOMPARE(proxy.mapToSource(proxy.index(0, 0, proxyParent)), model->index(0, 0, sourceParent));
242 QCOMPARE(proxy.mapToSource(proxy.index(1, 0, proxyParent)), model->index(0, 1, sourceParent));
243 QCOMPARE(proxy.mapToSource(proxy.index(0, 1, proxyParent)), model->index(1, 0, sourceParent));
244 delete model;
245}
246
247void tst_QTransposeProxyModel::mapFromSource()
248{
249 QAbstractItemModel *model = createTreeModel(parent: this);
250 QTransposeProxyModel proxy;
251 new QAbstractItemModelTester(&proxy, &proxy);
252 proxy.setSourceModel(model);
253 QVERIFY(!proxy.mapFromSource(QModelIndex()).isValid());
254 QCOMPARE(proxy.mapFromSource(model->index(0, 0)), proxy.index(0, 0));
255 QCOMPARE(proxy.mapFromSource(model->index(0, 1)), proxy.index(1, 0));
256 QCOMPARE(proxy.mapFromSource(model->index(1, 0)), proxy.index(0, 1));
257 const QModelIndex proxyParent = proxy.index(row: 1, column: 0);
258 const QModelIndex sourceParent = model->index(row: 0, column: 1);
259 QCOMPARE(proxy.mapToSource(proxy.index(0, 0, proxyParent)), model->index(0, 0, sourceParent));
260 QCOMPARE(proxy.mapFromSource(model->index(1, 0, sourceParent)), proxy.index(0, 1, proxyParent));
261 QCOMPARE(proxy.mapFromSource(model->index(0, 1, sourceParent)), proxy.index(1, 0, proxyParent));
262 delete model;
263}
264
265void tst_QTransposeProxyModel::basicTest_data()
266{
267 QTest::addColumn<QAbstractItemModel *>(name: "model");
268 QTest::newRow(dataTag: "List") << createListModel(parent: this);
269 QTest::newRow(dataTag: "Table") << createTableModel(parent: this);
270 QTest::newRow(dataTag: "Tree") << createTreeModel(parent: this);
271}
272
273void tst_QTransposeProxyModel::basicTest()
274{
275 QFETCH(QAbstractItemModel *, model);
276 QTransposeProxyModel proxy;
277 new QAbstractItemModelTester(&proxy, &proxy);
278 proxy.setSourceModel(model);
279 testTransposed(baseModel: model, transposed: &proxy);
280 delete model;
281}
282
283void tst_QTransposeProxyModel::sort()
284{
285 QStringList sequence;
286 sequence.reserve(alloc: 100);
287 for (int i = 0; i < 100; ++i)
288 sequence.append(QStringLiteral("%1").arg(a: i, fieldWidth: 3, base: 10, fillChar: QLatin1Char('0')));
289 std::shuffle(first: sequence.begin(), last: sequence.end(), g: std::mt19937(88));
290 const QString firstItemBeforeSort = sequence.first();
291 QStringListModel baseModel(sequence);
292 QTransposeProxyModel proxyModel;
293 new QAbstractItemModelTester(&proxyModel, &proxyModel);
294 proxyModel.setSourceModel(&baseModel);
295 QSignalSpy layoutChangedSpy(&proxyModel, &QAbstractItemModel::layoutChanged);
296 QVERIFY(layoutChangedSpy.isValid());
297 QSignalSpy layoutAboutToBeChangedSpy(&proxyModel, &QAbstractItemModel::layoutAboutToBeChanged);
298 QVERIFY(layoutAboutToBeChangedSpy.isValid());
299 QPersistentModelIndex firstIndexBeforeSort = proxyModel.index(row: 0, column: 0);
300 baseModel.sort(column: 0, order: Qt::AscendingOrder);
301 QCOMPARE(layoutChangedSpy.count(), 1);
302 QCOMPARE(layoutAboutToBeChangedSpy.count(), 1);
303 QCOMPARE(layoutChangedSpy.takeFirst().at(1).toInt(), int(QAbstractItemModel::HorizontalSortHint));
304 QCOMPARE(firstIndexBeforeSort.data().toString(), firstItemBeforeSort);
305 for (int i = 0; i < 100; ++i)
306 QCOMPARE(proxyModel.index(0, i).data().toInt(), i);
307}
308
309void tst_QTransposeProxyModel::removeColumnBase_data()
310{
311 QTest::addColumn<QAbstractItemModel *>(name: "model");
312 QTest::addColumn<QModelIndex>(name: "parent");
313 QTest::newRow(dataTag: "Table") << createTableModel(parent: this) << QModelIndex();
314 QTest::newRow(dataTag: "Tree_Root_Item") << createTreeModel(parent: this) << QModelIndex();
315 QAbstractItemModel *model = createTreeModel(parent: this);
316 QTest::newRow(dataTag: "Tree_Child_Item") << model << model->index(row: 0, column: 0);
317}
318
319void tst_QTransposeProxyModel::removeColumnBase()
320{
321 QFETCH(QAbstractItemModel * const, model);
322 QFETCH(const QModelIndex, parent);
323 QTransposeProxyModel proxy;
324 QSignalSpy rowRemoveSpy(&proxy, &QAbstractItemModel::rowsRemoved);
325 QVERIFY(rowRemoveSpy.isValid());
326 QSignalSpy rowAboutToBeRemoveSpy(&proxy, &QAbstractItemModel::rowsAboutToBeRemoved);
327 QVERIFY(rowAboutToBeRemoveSpy.isValid());
328 new QAbstractItemModelTester(&proxy, &proxy);
329 proxy.setSourceModel(model);
330 const int oldRowCount = proxy.rowCount(parent: proxy.mapFromSource(sourceIndex: parent));
331 const QVariant expectedNewVal = model->index(row: 0, column: 2, parent).data();
332 QVERIFY(model->removeColumn(1, parent));
333 QCOMPARE(proxy.rowCount(proxy.mapFromSource(parent)), oldRowCount - 1);
334 QCOMPARE(proxy.index(1, 0, proxy.mapFromSource(parent)).data(), expectedNewVal);
335 QCOMPARE(rowRemoveSpy.count(), 1);
336 QCOMPARE(rowAboutToBeRemoveSpy.count(), 1);
337 for (const auto &spyArgs : {rowRemoveSpy.takeFirst(),
338 rowAboutToBeRemoveSpy.takeFirst()}) {
339 QCOMPARE(spyArgs.at(0).value<QModelIndex>(), proxy.mapFromSource(parent));
340 QCOMPARE(spyArgs.at(1).toInt(), 1);
341 QCOMPARE(spyArgs.at(2).toInt(), 1);
342 }
343 delete model;
344}
345
346void tst_QTransposeProxyModel::insertColumnBase_data()
347{
348 QTest::addColumn<QAbstractItemModel *>(name: "model");
349 QTest::addColumn<QModelIndex>(name: "parent");
350 QTest::newRow(dataTag: "Table") << createTableModel(parent: this) << QModelIndex();
351 QTest::newRow(dataTag: "Tree_Root_Item") << createTreeModel(parent: this) << QModelIndex();
352 QAbstractItemModel *model = createTreeModel(parent: this);
353 QTest::newRow(dataTag: "Tree_Child_Item") << model << model->index(row: 0, column: 0);
354}
355
356void tst_QTransposeProxyModel::insertColumnBase()
357{
358 QFETCH(QAbstractItemModel * const, model);
359 QFETCH(const QModelIndex, parent);
360 QTransposeProxyModel proxy;
361 QSignalSpy rowInsertSpy(&proxy, &QAbstractItemModel::rowsInserted);
362 QVERIFY(rowInsertSpy.isValid());
363 QSignalSpy rowAboutToBeInsertSpy(&proxy, &QAbstractItemModel::rowsAboutToBeInserted);
364 QVERIFY(rowAboutToBeInsertSpy.isValid());
365 new QAbstractItemModelTester(&proxy, &proxy);
366 proxy.setSourceModel(model);
367 const int oldRowCount = proxy.rowCount(parent: proxy.mapFromSource(sourceIndex: parent));
368 QVERIFY(model->insertColumn(1, parent));
369 QCOMPARE(proxy.rowCount(proxy.mapFromSource(parent)), oldRowCount + 1);
370 QVERIFY(!proxy.index(1, 0, proxy.mapFromSource(parent)).data().isValid());
371 QCOMPARE(rowInsertSpy.count(), 1);
372 QCOMPARE(rowAboutToBeInsertSpy.count(), 1);
373 for (const auto &spyArgs : {rowInsertSpy.takeFirst(),
374 rowAboutToBeInsertSpy.takeFirst()}) {
375 QCOMPARE(spyArgs.at(0).value<QModelIndex>(), proxy.mapFromSource(parent));
376 QCOMPARE(spyArgs.at(1).toInt(), 1);
377 QCOMPARE(spyArgs.at(2).toInt(), 1);
378 }
379 delete model;
380}
381
382void tst_QTransposeProxyModel::removeRowBase_data()
383{
384 QTest::addColumn<QAbstractItemModel *>(name: "model");
385 QTest::addColumn<QModelIndex>(name: "parent");
386 QTest::newRow(dataTag: "List") << createListModel(parent: this) << QModelIndex();
387 QTest::newRow(dataTag: "Table") << createTableModel(parent: this) << QModelIndex();
388 QTest::newRow(dataTag: "Tree_Root_Item") << createTreeModel(parent: this) << QModelIndex();
389 QAbstractItemModel *model = createTreeModel(parent: this);
390 QTest::newRow(dataTag: "Tree_Child_Item") << model << model->index(row: 0, column: 0);
391}
392
393void tst_QTransposeProxyModel::removeRowBase()
394{
395 QFETCH(QAbstractItemModel * const, model);
396 QFETCH(const QModelIndex, parent);
397 QTransposeProxyModel proxy;
398 QSignalSpy columnsRemoveSpy(&proxy, &QAbstractItemModel::columnsRemoved);
399 QVERIFY(columnsRemoveSpy.isValid());
400 QSignalSpy columnsAboutToBeRemoveSpy(&proxy, &QAbstractItemModel::columnsAboutToBeRemoved);
401 QVERIFY(columnsAboutToBeRemoveSpy.isValid());
402 new QAbstractItemModelTester(&proxy, &proxy);
403 proxy.setSourceModel(model);
404 const int oldColCount = proxy.columnCount(parent: proxy.mapFromSource(sourceIndex: parent));
405 const QVariant expectedNewVal = model->index(row: 2, column: 0, parent).data();
406 QVERIFY(model->removeRow(1, parent));
407 QCOMPARE(proxy.columnCount(proxy.mapFromSource(parent)), oldColCount - 1);
408 QCOMPARE(proxy.index(0, 1, proxy.mapFromSource(parent)).data(), expectedNewVal);
409 QCOMPARE(columnsRemoveSpy.count(), 1);
410 QCOMPARE(columnsAboutToBeRemoveSpy.count(), 1);
411 for (const auto &spyArgs : {columnsRemoveSpy.takeFirst(),
412 columnsAboutToBeRemoveSpy.takeFirst()}) {
413 QCOMPARE(spyArgs.at(0).value<QModelIndex>(), proxy.mapFromSource(parent));
414 QCOMPARE(spyArgs.at(1).toInt(), 1);
415 QCOMPARE(spyArgs.at(2).toInt(), 1);
416 }
417 delete model;
418}
419
420void tst_QTransposeProxyModel::insertRowBase_data()
421{
422 QTest::addColumn<QAbstractItemModel *>(name: "model");
423 QTest::addColumn<QModelIndex>(name: "parent");
424 QTest::newRow(dataTag: "List") << createListModel(parent: this) << QModelIndex();
425 QTest::newRow(dataTag: "Table") << createTableModel(parent: this) << QModelIndex();
426 QTest::newRow(dataTag: "Tree_Root_Item") << createTreeModel(parent: this) << QModelIndex();
427 QAbstractItemModel *model = createTreeModel(parent: this);
428 QTest::newRow(dataTag: "Tree_Child_Item") << model << model->index(row: 0, column: 0);
429}
430
431void tst_QTransposeProxyModel::insertRowBase()
432{
433 QFETCH(QAbstractItemModel * const, model);
434 QFETCH(const QModelIndex, parent);
435 QTransposeProxyModel proxy;
436 QSignalSpy columnsInsertSpy(&proxy, &QAbstractItemModel::columnsInserted);
437 QVERIFY(columnsInsertSpy.isValid());
438 QSignalSpy columnsAboutToBeInsertSpy(&proxy, &QAbstractItemModel::columnsAboutToBeInserted);
439 QVERIFY(columnsAboutToBeInsertSpy.isValid());
440 new QAbstractItemModelTester(&proxy, &proxy);
441 proxy.setSourceModel(model);
442 const int oldColCount = proxy.columnCount(parent: proxy.mapFromSource(sourceIndex: parent));
443 QVERIFY(model->insertRow(1, parent));
444 QCOMPARE(proxy.columnCount(proxy.mapFromSource(parent)), oldColCount + 1);
445 QVERIFY(proxy.index(0, 1, proxy.mapFromSource(parent)).data().isNull());
446 QCOMPARE(columnsInsertSpy.count(), 1);
447 QCOMPARE(columnsAboutToBeInsertSpy.count(), 1);
448 for (const auto &spyArgs : {columnsInsertSpy.takeFirst(),
449 columnsAboutToBeInsertSpy.takeFirst()}) {
450 QCOMPARE(spyArgs.at(0).value<QModelIndex>(), proxy.mapFromSource(parent));
451 QCOMPARE(spyArgs.at(1).toInt(), 1);
452 QCOMPARE(spyArgs.at(2).toInt(), 1);
453 }
454 delete model;
455}
456
457void tst_QTransposeProxyModel::removeColumnProxy_data()
458{
459 QTest::addColumn<QAbstractItemModel *>(name: "model");
460 QTest::addColumn<bool>(name: "rootItem");
461 QTest::newRow(dataTag: "List") << createListModel(parent: this) << true;
462 QTest::newRow(dataTag: "Table") << createTableModel(parent: this) << true;
463 QTest::newRow(dataTag: "Tree_Root_Item") << createTreeModel(parent: this) << true;
464 QTest::newRow(dataTag: "Tree_Child_Item") << createTreeModel(parent: this) << false;
465}
466
467void tst_QTransposeProxyModel::removeColumnProxy()
468{
469 QFETCH(QAbstractItemModel *, model);
470 QFETCH(bool, rootItem);
471 QTransposeProxyModel proxy;
472 new QAbstractItemModelTester(&proxy, &proxy);
473 QSignalSpy columnsRemoveSpy(&proxy, &QAbstractItemModel::columnsRemoved);
474 QVERIFY(columnsRemoveSpy.isValid());
475 QSignalSpy columnsAboutToBeRemoveSpy(&proxy, &QAbstractItemModel::columnsAboutToBeRemoved);
476 QVERIFY(columnsAboutToBeRemoveSpy.isValid());
477 QSignalSpy rowsRemoveSpy(model, &QAbstractItemModel::rowsRemoved);
478 QVERIFY(rowsRemoveSpy.isValid());
479 QSignalSpy rowsAboutToBeRemoveSpy(model, &QAbstractItemModel::rowsAboutToBeRemoved);
480 QVERIFY(rowsAboutToBeRemoveSpy.isValid());
481 proxy.setSourceModel(model);
482 const QModelIndex proxyParent = rootItem ? QModelIndex() : proxy.index(row: 0, column: 1);
483 const QModelIndex sourceParent = proxy.mapToSource(proxyIndex: proxyParent);
484 const int oldColCount = proxy.columnCount(parent: proxyParent);
485 const int oldRowCount = model->rowCount(parent: sourceParent);
486 const QVariant expectedNewVal = proxy.index(row: 0, column: 2, parent: proxyParent).data();
487 QVERIFY(proxy.removeColumn(1, proxyParent));
488 QCOMPARE(proxy.columnCount(proxyParent), oldColCount - 1);
489 QCOMPARE(model->rowCount(sourceParent), oldRowCount - 1);
490 QCOMPARE(proxy.index(0, 1, proxyParent).data(), expectedNewVal);
491 QCOMPARE(model->index(1, 0, sourceParent).data(), expectedNewVal);
492 QCOMPARE(columnsRemoveSpy.count(), 1);
493 QCOMPARE(columnsAboutToBeRemoveSpy.count(), 1);
494 QCOMPARE(rowsRemoveSpy.count(), 1);
495 QCOMPARE(rowsAboutToBeRemoveSpy.count(), 1);
496 for (const auto &spyArgs : {columnsRemoveSpy.takeFirst(),
497 columnsAboutToBeRemoveSpy.takeFirst()}) {
498 QCOMPARE(spyArgs.at(0).value<QModelIndex>(), proxyParent);
499 QCOMPARE(spyArgs.at(1).toInt(), 1);
500 QCOMPARE(spyArgs.at(2).toInt(), 1);
501 }
502 for (const auto &spyArgs : {rowsRemoveSpy.takeFirst(),
503 rowsAboutToBeRemoveSpy.takeFirst()}) {
504 QCOMPARE(spyArgs.at(0).value<QModelIndex>(), sourceParent);
505 QCOMPARE(spyArgs.at(1).toInt(), 1);
506 QCOMPARE(spyArgs.at(2).toInt(), 1);
507 }
508 delete model;
509}
510
511void tst_QTransposeProxyModel::insertColumnProxy_data()
512{
513 QTest::addColumn<QAbstractItemModel *>(name: "model");
514 QTest::addColumn<bool>(name: "rootItem");
515 QTest::newRow(dataTag: "List") << createListModel(parent: this) << true;
516 QTest::newRow(dataTag: "Table") << createTableModel(parent: this) << true;
517 QTest::newRow(dataTag: "Tree_Root_Item") << createTreeModel(parent: this) << true;
518 QTest::newRow(dataTag: "Tree_Child_Item") << createTreeModel(parent: this) << false;
519}
520
521void tst_QTransposeProxyModel::insertColumnProxy()
522{
523 QFETCH(QAbstractItemModel *, model);
524 QFETCH(bool, rootItem);
525 QTransposeProxyModel proxy;
526 new QAbstractItemModelTester(&proxy, &proxy);
527 QSignalSpy columnsInsertSpy(&proxy, &QAbstractItemModel::columnsInserted);
528 QVERIFY(columnsInsertSpy.isValid());
529 QSignalSpy columnsAboutToBeInsertSpy(&proxy, &QAbstractItemModel::columnsAboutToBeInserted);
530 QVERIFY(columnsAboutToBeInsertSpy.isValid());
531 QSignalSpy rowsInsertSpy(model, &QAbstractItemModel::rowsInserted);
532 QVERIFY(rowsInsertSpy.isValid());
533 QSignalSpy rowsAboutToBeInsertSpy(model, &QAbstractItemModel::rowsAboutToBeInserted);
534 QVERIFY(rowsAboutToBeInsertSpy.isValid());
535 proxy.setSourceModel(model);
536 const QModelIndex proxyParent = rootItem ? QModelIndex() : proxy.index(row: 0, column: 1);
537 const QModelIndex sourceParent = proxy.mapToSource(proxyIndex: proxyParent);
538 const int oldColCount = proxy.columnCount(parent: proxyParent);
539 const int oldRowCount = model->rowCount(parent: sourceParent);
540 QVERIFY(proxy.insertColumn(1, proxyParent));
541 QCOMPARE(proxy.columnCount(proxyParent), oldColCount + 1);
542 QCOMPARE(model->rowCount(sourceParent), oldRowCount + 1);
543 QVERIFY(proxy.index(0, 1, proxyParent).data().isNull());
544 QVERIFY(model->index(1, 0, sourceParent).data().isNull());
545 QCOMPARE(columnsInsertSpy.count(), 1);
546 QCOMPARE(columnsAboutToBeInsertSpy.count(), 1);
547 QCOMPARE(rowsInsertSpy.count(), 1);
548 QCOMPARE(rowsAboutToBeInsertSpy.count(), 1);
549 for (const auto &spyArgs : {columnsInsertSpy.takeFirst(),
550 columnsAboutToBeInsertSpy.takeFirst()}) {
551 QCOMPARE(spyArgs.at(0).value<QModelIndex>(), proxyParent);
552 QCOMPARE(spyArgs.at(1).toInt(), 1);
553 QCOMPARE(spyArgs.at(2).toInt(), 1);
554 }
555 for (const auto &spyArgs : {rowsInsertSpy.takeFirst(),
556 rowsAboutToBeInsertSpy.takeFirst()}) {
557 QCOMPARE(spyArgs.at(0).value<QModelIndex>(), sourceParent);
558 QCOMPARE(spyArgs.at(1).toInt(), 1);
559 QCOMPARE(spyArgs.at(2).toInt(), 1);
560 }
561 delete model;
562}
563
564void tst_QTransposeProxyModel::removeRowProxy_data()
565{
566 QTest::addColumn<QAbstractItemModel *>(name: "model");
567 QTest::addColumn<bool>(name: "rootItem");
568 QTest::newRow(dataTag: "Table") << createTableModel(parent: this) << true;
569 QTest::newRow(dataTag: "Tree_Root_Item") << createTreeModel(parent: this) << true;
570 QTest::newRow(dataTag: "Tree_Child_Item") << createTreeModel(parent: this) << false;
571}
572
573void tst_QTransposeProxyModel::removeRowProxy()
574{
575 QFETCH(QAbstractItemModel *, model);
576 QFETCH(bool, rootItem);
577 QTransposeProxyModel proxy;
578 new QAbstractItemModelTester(&proxy, &proxy);
579 QSignalSpy rowsRemoveSpy(&proxy, &QAbstractItemModel::rowsRemoved);
580 QVERIFY(rowsRemoveSpy.isValid());
581 QSignalSpy rowsAboutToBeRemoveSpy(&proxy, &QAbstractItemModel::rowsAboutToBeRemoved);
582 QVERIFY(rowsAboutToBeRemoveSpy.isValid());
583 QSignalSpy columnsRemoveSpy(model, &QAbstractItemModel::columnsRemoved);
584 QVERIFY(columnsRemoveSpy.isValid());
585 QSignalSpy columnsAboutToBeRemoveSpy(model, &QAbstractItemModel::columnsAboutToBeRemoved);
586 QVERIFY(columnsAboutToBeRemoveSpy.isValid());
587 proxy.setSourceModel(model);
588 const QModelIndex proxyParent = rootItem ? QModelIndex() : proxy.index(row: 0, column: 1);
589 const QModelIndex sourceParent = proxy.mapToSource(proxyIndex: proxyParent);
590 const int oldRowCount = proxy.rowCount(parent: proxyParent);
591 const int oldColCount = model->columnCount(parent: sourceParent);
592 const QVariant expectedNewVal = proxy.index(row: 2, column: 0, parent: proxyParent).data();
593 QVERIFY(proxy.removeRow(1, proxyParent));
594 QCOMPARE(proxy.rowCount(proxyParent), oldRowCount - 1);
595 QCOMPARE(model->columnCount(sourceParent), oldColCount - 1);
596 QCOMPARE(proxy.index(1, 0, proxyParent).data(), expectedNewVal);
597 QCOMPARE(model->index(0, 1, sourceParent).data(), expectedNewVal);
598 QCOMPARE(columnsRemoveSpy.count(), 1);
599 QCOMPARE(columnsAboutToBeRemoveSpy.count(), 1);
600 QCOMPARE(rowsRemoveSpy.count(), 1);
601 QCOMPARE(rowsAboutToBeRemoveSpy.count(), 1);
602 for (const auto &spyArgs : {columnsRemoveSpy.takeFirst(),
603 columnsAboutToBeRemoveSpy.takeFirst()}) {
604 QCOMPARE(spyArgs.at(0).value<QModelIndex>(), sourceParent);
605 QCOMPARE(spyArgs.at(1).toInt(), 1);
606 QCOMPARE(spyArgs.at(2).toInt(), 1);
607 }
608 for (const auto &spyArgs : {rowsRemoveSpy.takeFirst(),
609 rowsAboutToBeRemoveSpy.takeFirst()}) {
610 QCOMPARE(spyArgs.at(0).value<QModelIndex>(), proxyParent);
611 QCOMPARE(spyArgs.at(1).toInt(), 1);
612 QCOMPARE(spyArgs.at(2).toInt(), 1);
613 }
614 delete model;
615}
616
617void tst_QTransposeProxyModel::insertRowProxy_data()
618{
619 QTest::addColumn<QAbstractItemModel *>(name: "model");
620 QTest::addColumn<bool>(name: "rootItem");
621 QTest::newRow(dataTag: "Table") << createTableModel(parent: this) << true;
622 QTest::newRow(dataTag: "Tree_Root_Item") << createTreeModel(parent: this) << true;
623 QTest::newRow(dataTag: "Tree_Child_Item") << createTreeModel(parent: this) << false;
624}
625
626void tst_QTransposeProxyModel::insertRowProxy()
627{
628 QFETCH(QAbstractItemModel *, model);
629 QFETCH(bool, rootItem);
630 QTransposeProxyModel proxy;
631 new QAbstractItemModelTester(&proxy, &proxy);
632 QSignalSpy rowsInsertSpy(&proxy, &QAbstractItemModel::rowsInserted);
633 QVERIFY(rowsInsertSpy.isValid());
634 QSignalSpy rowsAboutToBeInsertSpy(&proxy, &QAbstractItemModel::rowsAboutToBeInserted);
635 QVERIFY(rowsAboutToBeInsertSpy.isValid());
636 QSignalSpy columnsInsertSpy(model, &QAbstractItemModel::columnsInserted);
637 QVERIFY(columnsInsertSpy.isValid());
638 QSignalSpy columnsAboutToBeInsertSpy(model, &QAbstractItemModel::columnsAboutToBeInserted);
639 QVERIFY(columnsAboutToBeInsertSpy.isValid());
640 proxy.setSourceModel(model);
641 const QModelIndex proxyParent = rootItem ? QModelIndex() : proxy.index(row: 0, column: 1);
642 const QModelIndex sourceParent = proxy.mapToSource(proxyIndex: proxyParent);
643 const int oldRowCount = proxy.rowCount(parent: proxyParent);
644 const int oldColCount = model->columnCount(parent: sourceParent);
645 QVERIFY(proxy.insertRow(1, proxyParent));
646 QCOMPARE(proxy.rowCount(proxyParent), oldRowCount + 1);
647 QCOMPARE(model->columnCount(sourceParent), oldColCount + 1);
648 QVERIFY(proxy.index(1, 0, proxyParent).data().isNull());
649 QVERIFY(model->index(0, 1, sourceParent).data().isNull());
650 QCOMPARE(columnsInsertSpy.count(), 1);
651 QCOMPARE(columnsAboutToBeInsertSpy.count(), 1);
652 QCOMPARE(rowsInsertSpy.count(), 1);
653 QCOMPARE(rowsAboutToBeInsertSpy.count(), 1);
654 for (const auto &spyArgs : {columnsInsertSpy.takeFirst(),
655 columnsAboutToBeInsertSpy.takeFirst()}) {
656 QCOMPARE(spyArgs.at(0).value<QModelIndex>(), sourceParent);
657 QCOMPARE(spyArgs.at(1).toInt(), 1);
658 QCOMPARE(spyArgs.at(2).toInt(), 1);
659 }
660 for (const auto &spyArgs : {rowsInsertSpy.takeFirst(),
661 rowsAboutToBeInsertSpy.takeFirst()}) {
662 QCOMPARE(spyArgs.at(0).value<QModelIndex>(), proxyParent);
663 QCOMPARE(spyArgs.at(1).toInt(), 1);
664 QCOMPARE(spyArgs.at(2).toInt(), 1);
665 }
666 delete model;
667}
668
669void tst_QTransposeProxyModel::headerData()
670{
671 QStandardItemModel model;
672 model.insertRows(row: 0, count: 3);
673 model.insertColumns(column: 0, count: 5);
674 for (int i = 0; i < model.rowCount(); ++i)
675 model.setHeaderData(section: i, orientation: Qt::Horizontal, value: QChar('A' + i));
676 for (int i = 1; i <= model.columnCount(); ++i)
677 model.setHeaderData(section: i, orientation: Qt::Vertical, value: i);
678 QTransposeProxyModel proxy;
679 new QAbstractItemModelTester(&proxy, &proxy);
680 proxy.setSourceModel(&model);
681 for (int i = 0; i < model.rowCount(); ++i)
682 QCOMPARE(model.headerData(i, Qt::Horizontal), proxy.headerData(i, Qt::Vertical));
683 for (int i = 0; i < model.columnCount(); ++i)
684 QCOMPARE(model.headerData(i, Qt::Vertical), proxy.headerData(i, Qt::Horizontal));
685}
686
687void tst_QTransposeProxyModel::setHeaderData()
688{
689 QStandardItemModel model;
690 model.insertRows(row: 0, count: 3);
691 model.insertColumns(column: 0, count: 5);
692 for (int i = 0; i < model.rowCount(); ++i)
693 model.setHeaderData(section: i, orientation: Qt::Horizontal, value: QChar('A' + i));
694 for (int i = 1; i <= model.columnCount(); ++i)
695 model.setHeaderData(section: i, orientation: Qt::Vertical, value: i);
696 QTransposeProxyModel proxy;
697 new QAbstractItemModelTester(&proxy, &proxy);
698 proxy.setSourceModel(&model);
699 QVERIFY(proxy.setHeaderData(1, Qt::Horizontal, 99));
700 QCOMPARE(model.headerData(1, Qt::Vertical).toInt(), 99);
701 QVERIFY(proxy.setHeaderData(1, Qt::Vertical, QChar('Z')));
702 QCOMPARE(model.headerData(1, Qt::Horizontal).toChar(), QChar('Z'));
703}
704
705void tst_QTransposeProxyModel::span()
706{
707 class SpanModel : public QStandardItemModel
708 {
709 Q_DISABLE_COPY(SpanModel)
710 public:
711 SpanModel(int rows, int columns, QObject *parent = nullptr)
712 : QStandardItemModel(rows, columns, parent)
713 {}
714 QSize span(const QModelIndex &index) const override
715 {
716 Q_UNUSED(index)
717 return QSize(2, 1);
718 }
719 };
720 SpanModel model(3, 5);
721 QTransposeProxyModel proxy;
722 new QAbstractItemModelTester(&proxy, &proxy);
723 proxy.setSourceModel(&model);
724 QCOMPARE(proxy.span(proxy.index(0, 0)), QSize(1, 2));
725}
726
727void tst_QTransposeProxyModel::itemData()
728{
729 QAbstractItemModel *model = createTreeModel(parent: this);
730 QTransposeProxyModel proxy;
731 new QAbstractItemModelTester(&proxy, &proxy);
732 proxy.setSourceModel(model);
733 QMap<int, QVariant> itmData = proxy.itemData(index: proxy.index(row: 0, column: 1));
734 QCOMPARE(itmData.value(Qt::DisplayRole).toString(), QStringLiteral("1,0"));
735 QCOMPARE(itmData.value(Qt::UserRole).toInt(), 1);
736 QCOMPARE(itmData.value(Qt::UserRole + 1).toInt(), 0);
737 itmData = proxy.itemData(index: proxy.index(row: 1, column: 2, parent: proxy.index(row: 0, column: 1)));
738 QCOMPARE(itmData.value(Qt::DisplayRole).toString(), QStringLiteral("1,0,2,1"));
739 QCOMPARE(itmData.value(Qt::UserRole).toInt(), 1);
740 QCOMPARE(itmData.value(Qt::UserRole + 1).toInt(), 0);
741 QCOMPARE(itmData.value(Qt::UserRole + 2).toInt(), 2);
742 QCOMPARE(itmData.value(Qt::UserRole + 3).toInt(), 1);
743 QVERIFY(proxy.itemData(QModelIndex()).isEmpty());
744 delete model;
745}
746
747void tst_QTransposeProxyModel::setItemData()
748{
749 QAbstractItemModel *model = createTreeModel(parent: this);
750 QTransposeProxyModel proxy;
751 new QAbstractItemModelTester(&proxy, &proxy);
752 proxy.setSourceModel(model);
753 QSignalSpy sourceDataChangeSpy(model, &QAbstractItemModel::dataChanged);
754 QVERIFY(sourceDataChangeSpy.isValid());
755 QSignalSpy proxyDataChangeSpy(&proxy, &QAbstractItemModel::dataChanged);
756 QVERIFY(proxyDataChangeSpy.isValid());
757 const QMap<int, QVariant> itmData = {
758 std::make_pair<int, QVariant>(x: Qt::DisplayRole, QStringLiteral("Test")),
759 std::make_pair<int, QVariant>(x: Qt::UserRole, y: 88),
760 std::make_pair<int, QVariant>(x: Qt::UserRole + 1, y: 99),
761 };
762 QModelIndex idx = proxy.index(row: 0, column: 1);
763 QVERIFY(proxy.setItemData(idx, itmData));
764 QCOMPARE(idx.data(Qt::DisplayRole).toString(), QStringLiteral("Test"));
765 QCOMPARE(idx.data(Qt::UserRole).toInt(), 88);
766 QCOMPARE(idx.data(Qt::UserRole + 1).toInt(), 99);
767 QCOMPARE(sourceDataChangeSpy.size(), 1);
768 QCOMPARE(proxyDataChangeSpy.size(), 1);
769 auto signalData = proxyDataChangeSpy.takeFirst();
770 QCOMPARE(signalData.at(0).value<QModelIndex>(), idx);
771 QCOMPARE(signalData.at(1).value<QModelIndex>(), idx);
772 const QVector<int> expectedRoles{Qt::DisplayRole, Qt::UserRole, Qt::EditRole, Qt::UserRole + 1};
773 QVector<int> receivedRoles = signalData.at(i: 2).value<QVector<int> >();
774 QCOMPARE(receivedRoles.size(), expectedRoles.size());
775 for (int role : expectedRoles)
776 QVERIFY(receivedRoles.contains(role));
777 signalData = sourceDataChangeSpy.takeFirst();
778 QCOMPARE(signalData.at(0).value<QModelIndex>(), proxy.mapToSource(idx));
779 QCOMPARE(signalData.at(1).value<QModelIndex>(), proxy.mapToSource(idx));
780 receivedRoles = signalData.at(i: 2).value<QVector<int> >();
781 QCOMPARE(receivedRoles.size(), expectedRoles.size());
782 for (int role : expectedRoles)
783 QVERIFY(receivedRoles.contains(role));
784 idx = proxy.index(row: 1, column: 2, parent: proxy.index(row: 0, column: 1));
785 QVERIFY(proxy.setItemData(idx, itmData));
786 QCOMPARE(idx.data(Qt::DisplayRole).toString(), QStringLiteral("Test"));
787 QCOMPARE(idx.data(Qt::UserRole).toInt(), 88);
788 QCOMPARE(idx.data(Qt::UserRole + 1).toInt(), 99);
789 QCOMPARE(idx.data(Qt::UserRole + 2).toInt(), 2);
790 QCOMPARE(idx.data(Qt::UserRole + 3).toInt(), 1);
791 QCOMPARE(sourceDataChangeSpy.size(), 1);
792 QCOMPARE(proxyDataChangeSpy.size(), 1);
793 signalData = proxyDataChangeSpy.takeFirst();
794 QCOMPARE(signalData.at(0).value<QModelIndex>(), idx);
795 QCOMPARE(signalData.at(1).value<QModelIndex>(), idx);
796 receivedRoles = signalData.at(i: 2).value<QVector<int> >();
797 QCOMPARE(receivedRoles.size(), expectedRoles.size());
798 for (int role : expectedRoles)
799 QVERIFY(receivedRoles.contains(role));
800 signalData = sourceDataChangeSpy.takeFirst();
801 QCOMPARE(signalData.at(0).value<QModelIndex>(), proxy.mapToSource(idx));
802 QCOMPARE(signalData.at(1).value<QModelIndex>(), proxy.mapToSource(idx));
803 receivedRoles = signalData.at(i: 2).value<QVector<int> >();
804 QCOMPARE(receivedRoles.size(), expectedRoles.size());
805 for (int role : expectedRoles)
806 QVERIFY(receivedRoles.contains(role));
807 QVERIFY(!proxy.setItemData(QModelIndex(), itmData));
808 delete model;
809}
810
811void tst_QTransposeProxyModel::moveRowsBase()
812{
813 QStringListModel model{QStringList{"A", "B", "C", "D"}};
814 QTransposeProxyModel proxy;
815 QSignalSpy columnsMoveSpy(&proxy, &QAbstractItemModel::columnsMoved);
816 QVERIFY(columnsMoveSpy.isValid());
817 QSignalSpy columnsAboutToBeMoveSpy(&proxy, &QAbstractItemModel::columnsAboutToBeMoved);
818 QVERIFY(columnsAboutToBeMoveSpy.isValid());
819 new QAbstractItemModelTester(&proxy, &proxy);
820 proxy.setSourceModel(&model);
821 const QStringList expectedNewVal = {"B", "A", "C", "D"};
822 QVERIFY(model.moveRows(QModelIndex(), 0, 1, QModelIndex(), 2));
823 for (int i = 0; i < expectedNewVal.size(); ++i)
824 QCOMPARE(proxy.index(0, i).data(), expectedNewVal.at(i));
825 QCOMPARE(columnsMoveSpy.count(), 1);
826 QCOMPARE(columnsAboutToBeMoveSpy.count(), 1);
827 for (const auto &spyArgs : {columnsMoveSpy.takeFirst(),
828 columnsAboutToBeMoveSpy.takeFirst()}) {
829 QVERIFY(!spyArgs.at(0).value<QModelIndex>().isValid());
830 QCOMPARE(spyArgs.at(1).toInt(), 0);
831 QCOMPARE(spyArgs.at(2).toInt(), 0);
832 QVERIFY(!spyArgs.at(3).value<QModelIndex>().isValid());
833 QCOMPARE(spyArgs.at(4).toInt(), 2);
834 }
835}
836
837void tst_QTransposeProxyModel::moveColumnsProxy()
838{
839 QStringListModel model{QStringList{"A", "B", "C", "D"}};
840 QTransposeProxyModel proxy;
841 new QAbstractItemModelTester(&proxy, &proxy);
842 QSignalSpy columnsMoveSpy(&proxy, &QAbstractItemModel::columnsMoved);
843 QVERIFY(columnsMoveSpy.isValid());
844 QSignalSpy columnsAboutToBeMoveSpy(&proxy, &QAbstractItemModel::columnsAboutToBeMoved);
845 QVERIFY(columnsAboutToBeMoveSpy.isValid());
846 QSignalSpy rowsMoveSpy(&model, &QAbstractItemModel::rowsMoved);
847 QVERIFY(rowsMoveSpy.isValid());
848 QSignalSpy rowsAboutToBeMoveSpy(&model, &QAbstractItemModel::rowsAboutToBeMoved);
849 QVERIFY(rowsAboutToBeMoveSpy.isValid());
850 proxy.setSourceModel(&model);
851 const QStringList expectedNewVal = {"B", "A", "C", "D"};
852 QVERIFY(proxy.moveColumns(QModelIndex(), 0, 1, QModelIndex(), 2));
853 for (int i = 0; i < expectedNewVal.size(); ++i)
854 QCOMPARE(proxy.index(0, i).data(), expectedNewVal.at(i));
855 for (int i = 0; i < expectedNewVal.size(); ++i)
856 QCOMPARE(model.index(i, 0).data(), expectedNewVal.at(i));
857 QCOMPARE(columnsMoveSpy.count(), 1);
858 QCOMPARE(columnsAboutToBeMoveSpy.count(), 1);
859 QCOMPARE(rowsMoveSpy.count(), 1);
860 QCOMPARE(rowsAboutToBeMoveSpy.count(), 1);
861 for (const auto &spyArgs : {columnsMoveSpy.takeFirst(),
862 columnsAboutToBeMoveSpy.takeFirst(),
863 rowsMoveSpy.takeFirst(),rowsAboutToBeMoveSpy.takeFirst()}) {
864 QVERIFY(!spyArgs.at(0).value<QModelIndex>().isValid());
865 QCOMPARE(spyArgs.at(1).toInt(), 0);
866 QCOMPARE(spyArgs.at(2).toInt(), 0);
867 QVERIFY(!spyArgs.at(3).value<QModelIndex>().isValid());
868 }
869}
870
871void tst_QTransposeProxyModel::setData_data()
872{
873 QTest::addColumn<QAbstractItemModel *>(name: "model");
874 QTest::addColumn<bool>(name: "rootItem");
875 QTest::addColumn<bool>(name: "viaProxy");
876 QTest::newRow(dataTag: "List_via_Base") << createListModel(parent: this) << true << false;
877 QTest::newRow(dataTag: "Table_via_Base") << createTableModel(parent: this) << true << false;
878 QTest::newRow(dataTag: "Tree_via_Base_Root_Item") << createTreeModel(parent: this) << true << false;
879 QTest::newRow(dataTag: "Tree_via_Base_Child_Item") << createTreeModel(parent: this) << false << false;
880 QTest::newRow(dataTag: "List_via_Proxy") << createListModel(parent: this) << true << true;
881 QTest::newRow(dataTag: "Table_via_Proxy") << createTableModel(parent: this) << true << true;
882 QTest::newRow(dataTag: "Tree_via_Proxy_Root_Item") << createTreeModel(parent: this) << true << true;
883 QTest::newRow(dataTag: "Tree_via_Proxy_Child_Item") << createTreeModel(parent: this) << false << true;
884}
885
886void tst_QTransposeProxyModel::setData()
887{
888 QFETCH(QAbstractItemModel *, model);
889 QFETCH(bool, rootItem);
890 QFETCH(bool, viaProxy);
891 QTransposeProxyModel proxy;
892 new QAbstractItemModelTester(&proxy, &proxy);
893 proxy.setSourceModel(model);
894 QSignalSpy sourceDataChangeSpy(model, &QAbstractItemModel::dataChanged);
895 QVERIFY(sourceDataChangeSpy.isValid());
896 QSignalSpy proxyDataChangeSpy(&proxy, &QAbstractItemModel::dataChanged);
897 QVERIFY(proxyDataChangeSpy.isValid());
898 const QString testData = QStringLiteral("TestingSetData");
899 if (viaProxy) {
900 const QModelIndex parIdx = rootItem ? QModelIndex() : proxy.index(row: 0, column: 1);
901 QVERIFY(proxy.setData(proxy.index(0, 1, parIdx), testData));
902 QCOMPARE(model->index(1, 0, proxy.mapToSource(parIdx)).data().toString(), testData);
903 } else {
904 const QModelIndex parIdx = rootItem ? QModelIndex() : model->index(row: 1, column: 0);
905 QVERIFY(model->setData(model->index(1, 0, parIdx), testData));
906 QCOMPARE(proxy.index(0, 1, proxy.mapFromSource(parIdx)).data().toString(), testData);
907 }
908 QCOMPARE(sourceDataChangeSpy.size(), 1);
909 QCOMPARE(proxyDataChangeSpy.size(), 1);
910 delete model;
911}
912
913QTEST_GUILESS_MAIN(tst_QTransposeProxyModel)
914
915#include "tst_qtransposeproxymodel.moc"
916

source code of qtbase/tests/auto/corelib/itemmodels/qtransposeproxymodel/tst_qtransposeproxymodel.cpp