QtBase  v6.3.1
tst_qabstractitemmodel.cpp
Go to the documentation of this file.
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 <QTest>
30 
31 #include <QtCore/QCoreApplication>
32 #include <QtCore/QSortFilterProxyModel>
33 #include <QtCore/QStringListModel>
34 #include <QtGui/QStandardItemModel>
35 
36 #include "dynamictreemodel.h"
37 
38 // for testing QModelRoleDataSpan construction
39 #include <QVarLengthArray>
40 #include <QSignalSpy>
41 #include <QMimeData>
42 
43 #include <array>
44 #include <vector>
45 #include <deque>
46 #include <list>
47 
52 {
53  Q_OBJECT
54 
55 public slots:
56  void init();
57  void cleanup();
58 
59 private slots:
60  void index();
61  void parent();
62  void hasChildren();
63  void data();
64  void headerData();
65  void itemData();
66  void itemFlags();
67  void match();
68  void dropMimeData_data();
69  void dropMimeData();
70  void canDropMimeData();
71  void changePersistentIndex();
72  void movePersistentIndex();
73 
74  void insertRows();
75  void insertColumns();
76  void removeRows();
77  void removeColumns();
78  void moveRows();
79  void moveColumns();
80 
81  void reset();
82 
83  void complexChangesWithPersistent();
84 
85  void testMoveSameParentUp_data();
86  void testMoveSameParentUp();
87 
88  void testMoveSameParentDown_data();
89  void testMoveSameParentDown();
90 
91  void testMoveToGrandParent_data();
92  void testMoveToGrandParent();
93 
94  void testMoveToSibling_data();
95  void testMoveToSibling();
96 
97  void testMoveToUncle_data();
98  void testMoveToUncle();
99 
100  void testMoveToDescendants();
101 
102  void testMoveWithinOwnRange_data();
103  void testMoveWithinOwnRange();
104 
105  void testMoveThroughProxy();
106 
107  void testReset();
108 
109  void testDataChanged();
110 
111  void testChildrenLayoutsChanged();
112 
113  void testRoleNames();
114  void testDragActions();
115  void dragActionsFallsBackToDropActions();
116 
117  void testFunctionPointerSignalConnection();
118 
119  void checkIndex();
120 
121  void modelRoleDataSpanConstruction();
122  void modelRoleDataSpan();
123 
124  void multiData();
125 private:
126  DynamicTreeModel *m_model;
127 };
128 
136 {
137 public:
138  QtTestModel(int rows, int columns, QObject *parent = nullptr);
139  QtTestModel(const QList<QList<QString> > tbl, QObject *parent = nullptr);
140  QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
141  QModelIndex parent(const QModelIndex &) const override;
142  int rowCount(const QModelIndex &parent) const override;
143  int columnCount(const QModelIndex &parent) const override;
144  bool hasChildren(const QModelIndex &) const override;
145  QVariant data(const QModelIndex &idx, int) const override;
146  bool setData(const QModelIndex &idx, const QVariant &value, int) override;
147  bool insertRows(int row, int count, const QModelIndex &parent= QModelIndex()) override;
148  bool insertColumns(int column, int count, const QModelIndex &parent= QModelIndex()) override;
149  void setPersistent(const QModelIndex &from, const QModelIndex &to);
150  bool removeRows ( int row, int count, const QModelIndex & parent = QModelIndex()) override;
151  bool removeColumns( int column, int count, const QModelIndex & parent = QModelIndex()) override;
152  bool moveRows (const QModelIndex &sourceParent, int sourceRow, int count,
153  const QModelIndex &destinationParent, int destinationChild) override;
154  bool moveColumns(const QModelIndex &sourceParent, int sourceColumn, int count,
155  const QModelIndex &destinationParent, int destinationChild) override;
156  void reset();
157 
159  int row, int column, const QModelIndex &parent) const override;
160 
162  mutable bool wrongIndex;
164 };
165 
167 
168 QtTestModel::QtTestModel(int rows, int columns, QObject *parent)
169  : QAbstractItemModel(parent), cCount(columns), rCount(rows), wrongIndex(false)
170 {
171  table.resize(rows);
172  for (int r = 0; r < rows; ++r) {
173  const QString prefix = QString::number(r) + QLatin1Char('/');
174  table[r].resize(columns);
175  for (int c = 0; c < columns; ++c)
176  table[r][c] = prefix + QString::number(c);
177  }
178 }
179 
181  : QAbstractItemModel(parent), wrongIndex(false)
182 {
183  table = tbl;
184  rCount = tbl.count();
185  cCount = tbl.at(0).count();
186 }
187 
189 {
191 }
192 
194 int QtTestModel::rowCount(const QModelIndex &parent) const { return parent.isValid() ? 0 : rCount; }
195 int QtTestModel::columnCount(const QModelIndex &parent) const { return parent.isValid() ? 0 : cCount; }
196 bool QtTestModel::hasChildren(const QModelIndex &) const { return false; }
197 
199 {
200  if (idx.row() < 0 || idx.column() < 0 || idx.column() > cCount || idx.row() > rCount) {
201  wrongIndex = true;
202  qWarning("got invalid modelIndex %d/%d", idx.row(), idx.column());
203  return QVariant();
204  }
205  return table.at(idx.row()).at(idx.column());
206 }
207 
209 {
210  table[idx.row()][idx.column()] = value.toString();
211  return true;
212 }
213 
215 {
217  int cc = columnCount(parent);
218  table.insert(row, count, QList<QString>(cc));
219  rCount = table.count();
221  return true;
222 }
223 
225 {
227  int rc = rowCount(parent);
228  for (int i = 0; i < rc; ++i)
229  table[i].insert(column, 1, "");
230  cCount = table.at(0).count();
232  return true;
233 }
234 
236 {
237  changePersistentIndex(from, to);
238 }
239 
241 {
243 
244  for (int r = row+count-1; r >= row; --r)
245  table.remove(r);
246  rCount = table.count();
247 
249  return true;
250 }
251 
253 {
255 
256  for (int c = column+count-1; c > column; --c)
257  for (int r = 0; r < rCount; ++r)
258  table[r].remove(c);
259 
260  cCount = table.at(0).count();
261 
263  return true;
264 }
265 
266 bool QtTestModel::moveRows(const QModelIndex &sourceParent, int src, int cnt,
267  const QModelIndex &destinationParent, int dst)
268 {
269  if (!QAbstractItemModel::beginMoveRows(sourceParent, src, src + cnt - 1,
270  destinationParent, dst))
271  return false;
272 
274  if (dst < src) {
275  for (int i = 0; i < cnt; ++i) {
276  buf.swap(table[src + i]);
277  table.remove(src + 1);
278  table.insert(dst, buf);
279  }
280  } else if (src < dst) {
281  for (int i = 0; i < cnt; ++i) {
282  buf.swap(table[src]);
283  table.remove(src);
284  table.insert(dst + i, buf);
285  }
286  }
287 
288  rCount = table.count();
289 
291  return true;
292 }
293 
294 bool QtTestModel::moveColumns(const QModelIndex &sourceParent, int src, int cnt,
295  const QModelIndex &destinationParent, int dst)
296 {
297  if (!QAbstractItemModel::beginMoveColumns(sourceParent, src, src + cnt - 1,
298  destinationParent, dst))
299  return false;
300 
301  for (int r = 0; r < rCount; ++r) {
302  QString buf;
303  if (dst < src) {
304  for (int i = 0; i < cnt; ++i) {
305  buf = table[r][src + i];
306  table[r].remove(src + 1);
307  table[r].insert(dst, buf);
308  }
309  } else if (src < dst) {
310  for (int i = 0; i < cnt; ++i) {
311  buf = table[r][src];
312  table[r].remove(src);
313  table[r].insert(dst + i, buf);
314  }
315  }
316  }
317 
318  cCount = table.at(0).count();
319 
321  return true;
322 }
323 
325 {
328 }
329 
331  int row, int column, const QModelIndex &parent) const
332 {
333  Q_UNUSED(data);
334  Q_UNUSED(action);
335 
336  // For testing purposes, we impose some arbitrary rules on what may be dropped.
337  if (!parent.isValid() && row < 0 && column < 0) {
338  // a drop in emtpy space in the view is allowed.
339  // For example, in a filesystem view, a file may be dropped into empty space
340  // if it represents a writable directory.
341  return true;
342  }
343 
344  // We then arbitrarily decide to only allow drops on odd rows.
345  // A filesystem view/model might be able to drop onto (writable) directories.
346  return row % 2 == 0;
347 }
348 
350 {
351  m_model = new DynamicTreeModel(this);
352 
353  ModelInsertCommand *insertCommand = new ModelInsertCommand(m_model, this);
354  insertCommand->setNumCols(4);
355  insertCommand->setStartRow(0);
356  insertCommand->setEndRow(9);
357  insertCommand->doCommand();
358 
359  insertCommand = new ModelInsertCommand(m_model, this);
360  insertCommand->setAncestorRowNumbers(QList<int>() << 5);
361  insertCommand->setNumCols(4);
362  insertCommand->setStartRow(0);
363  insertCommand->setEndRow(9);
364  insertCommand->doCommand();
365 
366  qRegisterMetaType<QAbstractItemModel::LayoutChangeHint>();
367 }
368 
370 {
371  delete m_model;
372 }
373 
374 /*
375  tests
376 */
377 
378 void tst_QAbstractItemModel::index()
379 {
380  QtTestModel model(1, 1);
382  QVERIFY(idx.isValid());
383 }
384 
385 void tst_QAbstractItemModel::parent()
386 {
387  QtTestModel model(1, 1);
389  QModelIndex par = model.parent(idx);
390  QVERIFY(!par.isValid());
391 }
392 
393 void tst_QAbstractItemModel::hasChildren()
394 {
395  QtTestModel model(1, 1);
397  QVERIFY(!model.hasChildren(idx));
398 }
399 
400 void tst_QAbstractItemModel::data()
401 {
402  QtTestModel model(1, 1);
404  QVERIFY(idx.isValid());
406 
407  // Default does nothing
409 }
410 
411 void tst_QAbstractItemModel::headerData()
412 {
413  QtTestModel model(1, 1);
415  QString("1"));
416 
417  // Default text alignment for header must be invalid
419 }
420 
421 void tst_QAbstractItemModel::itemData()
422 {
423  QtTestModel model(1, 1);
425  QVERIFY(idx.isValid());
427  QCOMPARE(dat.count(Qt::DisplayRole), 1);
428  QCOMPARE(dat.value(Qt::DisplayRole).toString(), QString("0/0"));
429 }
430 
431 void tst_QAbstractItemModel::itemFlags()
432 {
433  QtTestModel model(1, 1);
435  QVERIFY(idx.isValid());
436  Qt::ItemFlags flags = model.flags(idx);
438 }
439 
440 void tst_QAbstractItemModel::match()
441 {
442  QtTestModel model(4, 1);
444  QVERIFY(start.isValid());
446  QCOMPARE(res.count(), 1);
448  bool areEqual = (idx == res.first());
449  QVERIFY(areEqual);
450 
454  model.setData(model.index(3, 0, QModelIndex()), "boar", Qt::DisplayRole);
455 
457  QCOMPARE(res.count(), 1);
459  QCOMPARE(res.count(), 3);
461  QCOMPARE(res.count(), 2);
463  QCOMPARE(res.count(), 2);
465  QCOMPARE(res.count(), 3);
467  QCOMPARE(res.count(), 2);
469  QCOMPARE(res.count(), 0);
471  QCOMPARE(res.count(), 1);
472  res = model.match(start, Qt::DisplayRole, QVariant("bat"), -1,
474  QCOMPARE(res.count(), 1);
475 
476  res = model.match(start, Qt::DisplayRole, QVariant(".*O.*"), -1,
478  QCOMPARE(res.count(), 2);
479  res = model.match(start, Qt::DisplayRole, QVariant(".*O.*"), -1,
481  QCOMPARE(res.count(), 0);
482 
485  QCOMPARE(res.count(), 0);
486  res = model.match(start,
490  -1,
492  QCOMPARE(res.count(), 2);
493 
494  // Ensure that the case sensitivity is properly ignored when passing a
495  // QRegularExpression object.
496  res = model.match(start,
500  -1,
502  QCOMPARE(res.count(), 2);
503 }
504 
509 
510 static StringTableRow qStringTableRow(const QString &s1, const QString &s2, const QString &s3)
511 {
513  row << s1 << s2 << s3;
514  return row;
515 }
516 
517 #ifdef Q_CC_MSVC
518 # define STRINGTABLE (StringTable())
519 #else
520 # define STRINGTABLE StringTable()
521 #endif
522 
523 void tst_QAbstractItemModel::dropMimeData_data()
524 {
525  QTest::addColumn<StringTable>("src_table"); // drag source
526  QTest::addColumn<StringTable>("dst_table"); // drop target
527  QTest::addColumn<Selection>("selection"); // dragged items
528  QTest::addColumn<Position>("dst_position"); // drop position
529  QTest::addColumn<StringTable>("res_table"); // expected result
530 
531  {
532  QTest::newRow("2x2 dropped at [0, 0]")
533  << (STRINGTABLE // source table
534  << (qStringTableRow("A", "B", "C"))
535  << (qStringTableRow("D", "E", "F")))
536  << (STRINGTABLE // destination table
537  << (qStringTableRow("0", "1", "2"))
538  << (qStringTableRow("3", "4", "5")))
539  << (Selection() // selection
540  << Position(0, 0) << Position(0, 1)
541  << Position(1, 0) << Position(1, 1))
542  << Position(0, 0) // drop position
543  << (STRINGTABLE // resulting table
544  << (qStringTableRow("A", "B", "" ))
545  << (qStringTableRow("D", "E", "" ))
546  << (qStringTableRow("0", "1", "2"))
547  << (qStringTableRow("3", "4", "5")));
548  }
549 
550  {
551  QTest::newRow("2x2 dropped at [1, 0]")
552  << (STRINGTABLE // source table
553  << (qStringTableRow("A", "B", "C"))
554  << (qStringTableRow("D", "E", "F")))
555  << (STRINGTABLE // destination table
556  << (qStringTableRow("0", "1", "2"))
557  << (qStringTableRow("3", "4", "5")))
558  << (Selection() // selection
559  << Position(0, 0) << Position(0, 1)
560  << Position(1, 0) << Position(1, 1))
561  << Position(1, 0) // drop position
562  << (STRINGTABLE // resulting table
563  << (qStringTableRow("0", "1", "2"))
564  << (qStringTableRow("A", "B", "" ))
565  << (qStringTableRow("D", "E", "" ))
566  << (qStringTableRow("3", "4", "5")));
567  }
568 
569  {
570  QTest::newRow("2x2 dropped at [3, 0]")
571  << (STRINGTABLE // source table
572  << (qStringTableRow("A", "B", "C"))
573  << (qStringTableRow("D", "E", "F")))
574  << (STRINGTABLE // destination table
575  << (qStringTableRow("0", "1", "2"))
576  << (qStringTableRow("3", "4", "5")))
577  << (Selection() // selection
578  << Position(0, 0) << Position(0, 1)
579  << Position(1, 0) << Position(1, 1))
580  << Position(3, 0) // drop position
581  << (STRINGTABLE // resulting table
582  << (qStringTableRow("0", "1", "2"))
583  << (qStringTableRow("3", "4", "5"))
584  << (qStringTableRow("A", "B", "" ))
585  << (qStringTableRow("D", "E", "" )));
586  }
587 
588  {
589  QTest::newRow("2x2 dropped at [0, 1]")
590  << (STRINGTABLE // source table
591  << (qStringTableRow("A", "B", "C"))
592  << (qStringTableRow("D", "E", "F")))
593  << (STRINGTABLE // destination table
594  << (qStringTableRow("0", "1", "2"))
595  << (qStringTableRow("3", "4", "5")))
596  << (Selection() // selection
597  << Position(0, 0) << Position(0, 1)
598  << Position(1, 0) << Position(1, 1))
599  << Position(0, 1) // drop position
600  << (STRINGTABLE // resulting table
601  << (qStringTableRow("" , "A", "B"))
602  << (qStringTableRow("" , "D", "E"))
603  << (qStringTableRow("0", "1", "2"))
604  << (qStringTableRow("3", "4", "5")));
605  }
606 
607  {
608  QTest::newRow("2x2 dropped at [0, 2] (line break)")
609  << (STRINGTABLE // source table
610  << (qStringTableRow("A", "B", "C"))
611  << (qStringTableRow("D", "E", "F")))
612  << (STRINGTABLE // destination table
613  << (qStringTableRow("0", "1", "2"))
614  << (qStringTableRow("3", "4", "5")))
615  << (Selection() // selection
616  << Position(0, 0) << Position(0, 1)
617  << Position(1, 0) << Position(1, 1))
618  << Position(0, 2) // drop position
619  << (STRINGTABLE // resulting table
620  << (qStringTableRow("" , "" , "A"))
621  << (qStringTableRow("" , "" , "D"))
622  << (qStringTableRow("" , "" , "B"))
623  << (qStringTableRow("" , "" , "E"))
624  << (qStringTableRow("0", "1", "2"))
625  << (qStringTableRow("3", "4", "5")));
626  }
627 
628  {
629  QTest::newRow("2x2 dropped at [3, 2] (line break)")
630  << (STRINGTABLE // source table
631  << (qStringTableRow("A", "B", "C"))
632  << (qStringTableRow("D", "E", "F")))
633  << (STRINGTABLE // destination table
634  << (qStringTableRow("0", "1", "2"))
635  << (qStringTableRow("3", "4", "5")))
636  << (Selection() // selection
637  << Position(0, 0) << Position(0, 1)
638  << Position(1, 0) << Position(1, 1))
639  << Position(3, 2) // drop position
640  << (STRINGTABLE // resulting table
641  << (qStringTableRow("0", "1", "2"))
642  << (qStringTableRow("3", "4", "5"))
643  << (qStringTableRow("" , "" , "A"))
644  << (qStringTableRow("" , "" , "D"))
645  << (qStringTableRow("" , "" , "B"))
646  << (qStringTableRow("" , "" , "E")));
647  }
648 
649  {
650  QTest::newRow("non-square dropped at [0, 0]")
651  << (STRINGTABLE // source table
652  << (qStringTableRow("A", "B", "C"))
653  << (qStringTableRow("D", "E", "F")))
654  << (STRINGTABLE // destination table
655  << (qStringTableRow("0", "1", "2"))
656  << (qStringTableRow("3", "4", "5")))
657  << (Selection() // selection
658  << Position(0, 0) << Position(0, 1)
659  << Position(1, 0))
660  << Position(0, 0) // drop position
661  << (STRINGTABLE // resulting table
662  << (qStringTableRow("A", "B", "" ))
663  << (qStringTableRow("D", "" , "" ))
664  << (qStringTableRow("0", "1", "2"))
665  << (qStringTableRow("3", "4", "5")));
666  }
667 
668  {
669  QTest::newRow("non-square dropped at [0, 2]")
670  << (STRINGTABLE // source table
671  << (qStringTableRow("A", "B", "C"))
672  << (qStringTableRow("D", "E", "F")))
673  << (STRINGTABLE // destination table
674  << (qStringTableRow("0", "1", "2"))
675  << (qStringTableRow("3", "4", "5")))
676  << (Selection() // selection
677  << Position(0, 0) << Position(0, 1)
678  << Position(1, 0))
679  << Position(0, 2) // drop position
680  << (STRINGTABLE // resulting table
681  << (qStringTableRow("" , "" , "A"))
682  << (qStringTableRow("" , "" , "D"))
683  << (qStringTableRow("" , "" , "B"))
684  << (qStringTableRow("0", "1", "2"))
685  << (qStringTableRow("3", "4", "5")));
686  }
687 
688  {
689  QTest::newRow("2x 1x2 dropped at [0, 0] (duplicates)")
690  << (STRINGTABLE // source table
691  << (qStringTableRow("A", "B", "C"))
692  << (qStringTableRow("D", "E", "F")))
693  << (STRINGTABLE // destination table
694  << (qStringTableRow("0", "1", "2"))
695  << (qStringTableRow("3", "4", "5")))
696  << (Selection() // selection; 2x the same row (to simulate selections in hierarchy)
697  << Position(0, 0) << Position(0, 1)
698  << Position(0, 0) << Position(0, 1))
699  << Position(0, 0) // drop position
700  << (STRINGTABLE // resulting table
701  << (qStringTableRow("A", "B", "" ))
702  << (qStringTableRow("A", "" , "" ))
703  << (qStringTableRow("" , "B", "" )) // ### FIXME: strange behavior, but rare case
704  << (qStringTableRow("0", "1", "2"))
705  << (qStringTableRow("3", "4", "5")));
706  }
707 
708  {
709  QTest::newRow("2x 1x2 dropped at [3, 2] (duplicates)")
710  << (STRINGTABLE // source table
711  << (qStringTableRow("A", "B", "C"))
712  << (qStringTableRow("D", "E", "F")))
713  << (STRINGTABLE // destination table
714  << (qStringTableRow("0", "1", "2"))
715  << (qStringTableRow("3", "4", "5")))
716  << (Selection() // selection; 2x the same row (to simulate selections in hierarchy)
717  << Position(0, 0) << Position(0, 1)
718  << Position(0, 0) << Position(0, 1))
719  << Position(3, 2) // drop position
720  << (STRINGTABLE // resulting table
721  << (qStringTableRow("0", "1", "2"))
722  << (qStringTableRow("3", "4", "5"))
723  << (qStringTableRow("" , "" , "A"))
724  << (qStringTableRow("" , "" , "B"))
725  << (qStringTableRow("" , "" , "A"))
726  << (qStringTableRow("" , "" , "B")));
727  }
728  {
729  QTest::newRow("2x 1x2 dropped at [3, 2] (different rows)")
730  << (STRINGTABLE // source table
731  << (qStringTableRow("A", "B", "C"))
732  << (qStringTableRow("D", "E", "F"))
733  << (qStringTableRow("G", "H", "I")))
734  << (STRINGTABLE // destination table
735  << (qStringTableRow("0", "1", "2"))
736  << (qStringTableRow("3", "4", "5")))
737  << (Selection() // selection; 2x the same row (to simulate selections in hierarchy)
738  << Position(0, 0) << Position(0, 1)
739  << Position(2, 0) << Position(2, 1))
740  << Position(2, 1) // drop position
741  << (STRINGTABLE // resulting table
742  << (qStringTableRow("0", "1", "2"))
743  << (qStringTableRow("3", "4", "5"))
744  << (qStringTableRow("" , "A" , "B"))
745  << (qStringTableRow("" , "G" , "H")));
746  }
747 
748  {
749  QTest::newRow("2x 1x2 dropped at [3, 2] (different rows, over the edge)")
750  << (STRINGTABLE // source table
751  << (qStringTableRow("A", "B", "C"))
752  << (qStringTableRow("D", "E", "F"))
753  << (qStringTableRow("G", "H", "I")))
754  << (STRINGTABLE // destination table
755  << (qStringTableRow("0", "1", "2"))
756  << (qStringTableRow("3", "4", "5")))
757  << (Selection() // selection; 2x the same row (to simulate selections in hierarchy)
758  << Position(0, 0) << Position(0, 1)
759  << Position(2, 0) << Position(2, 1))
760  << Position(3, 2) // drop position
761  << (STRINGTABLE // resulting table
762  << (qStringTableRow("0", "1", "2"))
763  << (qStringTableRow("3", "4", "5"))
764  << (qStringTableRow("" , "" , "A"))
765  << (qStringTableRow("" , "" , "G"))
766  << (qStringTableRow("" , "" , "B"))
767  << (qStringTableRow("" , "" , "H")));
768  }
769 }
770 
771 void tst_QAbstractItemModel::dropMimeData()
772 {
773  QFETCH(StringTable, src_table);
774  QFETCH(StringTable, dst_table);
776  QFETCH(Position, dst_position);
777  QFETCH(StringTable, res_table);
778 
779  QtTestModel src(src_table);
780  QtTestModel dst(dst_table);
781  QtTestModel res(res_table);
782 
783  // get the mimeData from the "selected" indexes
784  QModelIndexList selectedIndexes;
785  for (int i = 0; i < selection.count(); ++i)
786  selectedIndexes << src.index(selection.at(i).first, selection.at(i).second, QModelIndex());
787  QMimeData *md = src.mimeData(selectedIndexes);
788  // do the drop
789  dst.dropMimeData(md, Qt::CopyAction, dst_position.first, dst_position.second, QModelIndex());
790  delete md;
791 
792  // compare to the expected results
793  QCOMPARE(dst.rowCount(QModelIndex()), res.rowCount(QModelIndex()));
794  QCOMPARE(dst.columnCount(QModelIndex()), res.columnCount(QModelIndex()));
795  for (int r = 0; r < dst.rowCount(QModelIndex()); ++r) {
796  for (int c = 0; c < dst.columnCount(QModelIndex()); ++c) {
797  QModelIndex dst_idx = dst.index(r, c, QModelIndex());
798  QModelIndex res_idx = res.index(r, c, QModelIndex());
799  QMap<int, QVariant> dst_data = dst.itemData(dst_idx);
800  QMap<int, QVariant> res_data = res.itemData(res_idx);
801  QCOMPARE(dst_data , res_data);
802  }
803  }
804 }
805 
806 void tst_QAbstractItemModel::canDropMimeData()
807 {
808  QtTestModel model(3, 3);
809 
813 }
814 
815 void tst_QAbstractItemModel::changePersistentIndex()
816 {
817  QtTestModel model(3, 3);
818  QModelIndex a = model.index(1, 2, QModelIndex());
819  QModelIndex b = model.index(2, 1, QModelIndex());
821  QVERIFY(p == a);
822  model.setPersistent(a, b);
823  QVERIFY(p == b);
824 }
825 
826 void tst_QAbstractItemModel::movePersistentIndex()
827 {
828  QtTestModel model(3, 3);
829 
831  QVERIFY(a.isValid());
832  QCOMPARE(a.row(), 1);
833  QCOMPARE(a.column(), 1);
834 
835  model.insertRow(0);
836  QCOMPARE(a.row(), 2);
837 
838  model.insertRow(1);
839  QCOMPARE(a.row(), 3);
840 
841  model.insertColumn(0);
842  QCOMPARE(a.column(), 2);
843 }
844 
845 void tst_QAbstractItemModel::removeRows()
846 {
847  QtTestModel model(10, 10);
848 
849  QSignalSpy rowsAboutToBeRemovedSpy(&model, &QtTestModel::rowsAboutToBeRemoved);
850  QSignalSpy rowsRemovedSpy(&model, &QtTestModel::rowsRemoved);
851 
852  QVERIFY(rowsAboutToBeRemovedSpy.isValid());
853  QVERIFY(rowsRemovedSpy.isValid());
854 
855  QCOMPARE(model.removeRows(6, 4), true);
856  QCOMPARE(rowsAboutToBeRemovedSpy.count(), 1);
857  QCOMPARE(rowsRemovedSpy.count(), 1);
858 }
859 
860 void tst_QAbstractItemModel::removeColumns()
861 {
862  QtTestModel model(10, 10);
863 
864  QSignalSpy columnsAboutToBeRemovedSpy(&model, &QtTestModel::columnsAboutToBeRemoved);
865  QSignalSpy columnsRemovedSpy(&model, &QtTestModel::columnsRemoved);
866 
867  QVERIFY(columnsAboutToBeRemovedSpy.isValid());
868  QVERIFY(columnsRemovedSpy.isValid());
869 
870  QCOMPARE(model.removeColumns(6, 4), true);
871  QCOMPARE(columnsAboutToBeRemovedSpy.count(), 1);
872  QCOMPARE(columnsRemovedSpy.count(), 1);
873 }
874 
875 void tst_QAbstractItemModel::insertRows()
876 {
877  QtTestModel model(10, 10);
878 
879  QSignalSpy rowsAboutToBeInsertedSpy(&model, &QtTestModel::rowsAboutToBeInserted);
880  QSignalSpy rowsInsertedSpy(&model, &QtTestModel::rowsInserted);
881 
882  QVERIFY(rowsAboutToBeInsertedSpy.isValid());
883  QVERIFY(rowsInsertedSpy.isValid());
884 
885  QCOMPARE(model.insertRows(6, 4), true);
886  QCOMPARE(rowsAboutToBeInsertedSpy.count(), 1);
887  QCOMPARE(rowsInsertedSpy.count(), 1);
888 }
889 
890 void tst_QAbstractItemModel::insertColumns()
891 {
892  QtTestModel model(10, 10);
893 
894  QSignalSpy columnsAboutToBeInsertedSpy(&model, &QtTestModel::columnsAboutToBeInserted);
895  QSignalSpy columnsInsertedSpy(&model, &QtTestModel::columnsInserted);
896 
897  QVERIFY(columnsAboutToBeInsertedSpy.isValid());
898  QVERIFY(columnsInsertedSpy.isValid());
899 
900  QCOMPARE(model.insertColumns(6, 4), true);
901  QCOMPARE(columnsAboutToBeInsertedSpy.count(), 1);
902  QCOMPARE(columnsInsertedSpy.count(), 1);
903 }
904 
905 void tst_QAbstractItemModel::moveRows()
906 {
907  QtTestModel model(10, 10);
908 
909  QSignalSpy rowsAboutToBeMovedSpy(&model, &QtTestModel::rowsAboutToBeMoved);
910  QSignalSpy rowsMovedSpy(&model, &QtTestModel::rowsMoved);
911 
912  QVERIFY(rowsAboutToBeMovedSpy.isValid());
913  QVERIFY(rowsMovedSpy.isValid());
914 
915  QCOMPARE(model.moveRows(QModelIndex(), 6, 4, QModelIndex(), 1), true);
916  QCOMPARE(rowsAboutToBeMovedSpy.count(), 1);
917  QCOMPARE(rowsMovedSpy.count(), 1);
918 }
919 
920 void tst_QAbstractItemModel::moveColumns()
921 {
922  QtTestModel model(10, 10);
923 
924  QSignalSpy columnsAboutToBeMovedSpy(&model, &QtTestModel::columnsAboutToBeMoved);
925  QSignalSpy columnsMovedSpy(&model, &QtTestModel::columnsMoved);
926 
927  QVERIFY(columnsAboutToBeMovedSpy.isValid());
928  QVERIFY(columnsMovedSpy.isValid());
929 
930  QCOMPARE(model.moveColumns(QModelIndex(), 6, 4, QModelIndex(), 1), true);
931  QCOMPARE(columnsAboutToBeMovedSpy.count(), 1);
932  QCOMPARE(columnsMovedSpy.count(), 1);
933 
934  QCOMPARE(model.moveColumn(QModelIndex(), 4, QModelIndex(), 1), true);
935  QCOMPARE(columnsAboutToBeMovedSpy.count(), 2);
936  QCOMPARE(columnsMovedSpy.count(), 2);
937 }
938 
939 void tst_QAbstractItemModel::reset()
940 {
941  QtTestModel model(10, 10);
942 
944  QVERIFY(resetSpy.isValid());
945  model.reset();
946  QCOMPARE(resetSpy.count(), 1);
947 }
948 
949 void tst_QAbstractItemModel::complexChangesWithPersistent()
950 {
951  QtTestModel model(10, 10);
957  for (int i=0; i <10 ; i++) {
958  e[i] = model.index(2, i , QModelIndex());
959  }
960 
961  QVERIFY(a == model.index(1, 1, QModelIndex()));
962  QVERIFY(b == model.index(9, 7, QModelIndex()));
963  QVERIFY(c == model.index(5, 6, QModelIndex()));
964  QVERIFY(d == model.index(3, 9, QModelIndex()));
965  for (int i=0; i <8 ; i++)
966  QVERIFY(e[i] == model.index(2, i , QModelIndex()));
967 
968  //remove a bunch of columns
969  model.removeColumns(2, 4);
970 
971  QVERIFY(a == model.index(1, 1, QModelIndex()));
972  QVERIFY(b == model.index(9, 3, QModelIndex()));
973  QVERIFY(c == model.index(5, 2, QModelIndex()));
974  QVERIFY(d == model.index(3, 5, QModelIndex()));
975  for (int i=0; i <2 ; i++)
976  QVERIFY(e[i] == model.index(2, i , QModelIndex()));
977  for (int i=2; i <6 ; i++)
978  QVERIFY(!e[i].isValid());
979  for (int i=6; i <10 ; i++)
980  QVERIFY(e[i] == model.index(2, i-4 , QModelIndex()));
981 
982  //move some indexes around
983  model.setPersistent(model.index(1, 1 , QModelIndex()), model.index(9, 3 , QModelIndex()));
984  model.setPersistent(model.index(9, 3 , QModelIndex()), model.index(8, 4 , QModelIndex()));
985 
986  QVERIFY(a == model.index(9, 3, QModelIndex()));
987  QVERIFY(b == model.index(8, 4, QModelIndex()));
988  QVERIFY(c == model.index(5, 2, QModelIndex()));
989  QVERIFY(d == model.index(3, 5, QModelIndex()));
990  for (int i=0; i <2 ; i++)
991  QVERIFY(e[i] == model.index(2, i , QModelIndex()));
992  for (int i=2; i <6 ; i++)
993  QVERIFY(!e[i].isValid());
994  for (int i=6; i <10 ; i++)
995  QVERIFY(e[i] == model.index(2, i-4 , QModelIndex()));
996 
997  //inserting a bunch of columns
998  model.insertColumns(2, 2);
999  QVERIFY(a == model.index(9, 5, QModelIndex()));
1000  QVERIFY(b == model.index(8, 6, QModelIndex()));
1001  QVERIFY(c == model.index(5, 4, QModelIndex()));
1002  QVERIFY(d == model.index(3, 7, QModelIndex()));
1003  for (int i=0; i <2 ; i++)
1004  QVERIFY(e[i] == model.index(2, i , QModelIndex()));
1005  for (int i=2; i <6 ; i++)
1006  QVERIFY(!e[i].isValid());
1007  for (int i=6; i <10 ; i++)
1008  QVERIFY(e[i] == model.index(2, i-2 , QModelIndex()));
1009 }
1010 
1011 void tst_QAbstractItemModel::testMoveSameParentDown_data()
1012 {
1013  QTest::addColumn<int>("startRow");
1014  QTest::addColumn<int>("endRow");
1015  QTest::addColumn<int>("destRow");
1016  // We can't put the actual parent index for the move in here because m_model is not defined until init() is run.
1017  QTest::addColumn<bool>("topLevel");
1018 
1019  // Move from the start to the middle
1020  QTest::newRow("move01") << 0 << 2 << 8 << true;
1021  // Move from the start to the end
1022  QTest::newRow("move02") << 0 << 2 << 10 << true;
1023  // Move from the middle to the middle
1024  QTest::newRow("move03") << 3 << 5 << 8 << true;
1025  // Move from the middle to the end
1026  QTest::newRow("move04") << 3 << 5 << 10 << true;
1027 
1028  QTest::newRow("move05") << 0 << 2 << 8 << false;
1029  QTest::newRow("move06") << 0 << 2 << 10 << false;
1030  QTest::newRow("move07") << 3 << 5 << 8 << false;
1031  QTest::newRow("move08") << 3 << 5 << 10 << false;
1032 }
1033 
1034 void tst_QAbstractItemModel::testMoveSameParentDown()
1035 {
1036  QFETCH(int, startRow);
1037  QFETCH(int, endRow);
1038  QFETCH(int, destRow);
1039  QFETCH(bool, topLevel);
1040 
1041  QModelIndex moveParent = topLevel ? QModelIndex() : m_model->index(5, 0);
1042 
1043  QList<QPersistentModelIndex> persistentList;
1044  QModelIndexList indexList;
1045 
1046  for (int column = 0; column < m_model->columnCount(); ++column) {
1047  for (int row = 0; row < m_model->rowCount(); ++row) {
1048  QModelIndex idx = m_model->index(row, column);
1049  QVERIFY(idx.isValid());
1050  indexList << idx;
1051  persistentList << QPersistentModelIndex(idx);
1052  }
1053  }
1054 
1055  QModelIndex parent = m_model->index(5, 0);
1056  for (int column = 0; column < m_model->columnCount(); ++column) {
1057  for (int row = 0; row < m_model->rowCount(parent); ++row) {
1058  QModelIndex idx = m_model->index(row, column, parent);
1059  QVERIFY(idx.isValid());
1060  indexList << idx;
1061  persistentList << QPersistentModelIndex(idx);
1062  }
1063  }
1064 
1065  QSignalSpy beforeSpy(m_model, &DynamicTreeModel::rowsAboutToBeMoved);
1066  QSignalSpy afterSpy(m_model, &DynamicTreeModel::rowsMoved);
1067 
1068  QVERIFY(beforeSpy.isValid());
1069  QVERIFY(afterSpy.isValid());
1070 
1071  ModelMoveCommand *moveCommand = new ModelMoveCommand(m_model, this);
1072  moveCommand->setNumCols(4);
1073  if (!topLevel)
1074  moveCommand->setAncestorRowNumbers(QList<int>() << 5);
1075  moveCommand->setStartRow(startRow);
1076  moveCommand->setEndRow(endRow);
1077  moveCommand->setDestRow(destRow);
1078  if (!topLevel)
1079  moveCommand->setDestAncestors(QList<int>() << 5);
1080  moveCommand->doCommand();
1081 
1082  QVariantList beforeSignal = beforeSpy.takeAt(0);
1083  QVariantList afterSignal = afterSpy.takeAt(0);
1084 
1085  QCOMPARE(beforeSignal.size(), 5);
1086  QCOMPARE(beforeSignal.at(0).value<QModelIndex>(), moveParent);
1087  QCOMPARE(beforeSignal.at(1).toInt(), startRow);
1088  QCOMPARE(beforeSignal.at(2).toInt(), endRow);
1089  QCOMPARE(beforeSignal.at(3).value<QModelIndex>(), moveParent);
1090  QCOMPARE(beforeSignal.at(4).toInt(), destRow);
1091 
1092  QCOMPARE(afterSignal.size(), 5);
1093  QCOMPARE(afterSignal.at(0).value<QModelIndex>(), moveParent);
1094  QCOMPARE(afterSignal.at(1).toInt(), startRow);
1095  QCOMPARE(afterSignal.at(2).toInt(), endRow);
1096  QCOMPARE(afterSignal.at(3).value<QModelIndex>(), moveParent);
1097  QCOMPARE(afterSignal.at(4).toInt(), destRow);
1098 
1099  for (int i = 0; i < indexList.size(); i++) {
1100  QModelIndex idx = indexList.at(i);
1101  QModelIndex persistentIndex = persistentList.at(i);
1102  if (idx.parent() == moveParent) {
1103  int row = idx.row();
1104  if ( row >= startRow) {
1105  if (row <= endRow) {
1106  QCOMPARE(row + destRow - endRow - 1, persistentIndex.row());
1107  QCOMPARE(idx.column(), persistentIndex.column());
1108  QCOMPARE(idx.parent(), persistentIndex.parent());
1109  QCOMPARE(idx.model(), persistentIndex.model());
1110  } else if (row < destRow) {
1111  QCOMPARE(row - (endRow - startRow + 1), persistentIndex.row());
1112  QCOMPARE(idx.column(), persistentIndex.column());
1113  QCOMPARE(idx.parent(), persistentIndex.parent());
1114  QCOMPARE(idx.model(), persistentIndex.model());
1115  } else {
1116  QCOMPARE(idx, persistentIndex);
1117  }
1118  } else {
1119  QCOMPARE(idx, persistentIndex);
1120  }
1121  } else {
1122  QCOMPARE(idx, persistentIndex);
1123  }
1124  }
1125 }
1126 
1127 void tst_QAbstractItemModel::testMoveSameParentUp_data()
1128 {
1129  QTest::addColumn<int>("startRow");
1130  QTest::addColumn<int>("endRow");
1131  QTest::addColumn<int>("destRow");
1132  QTest::addColumn<bool>("topLevel");
1133 
1134  // Move from the middle to the start
1135  QTest::newRow("move01") << 5 << 7 << 0 << true;
1136  // Move from the end to the start
1137  QTest::newRow("move02") << 8 << 9 << 0 << true;
1138  // Move from the middle to the middle
1139  QTest::newRow("move03") << 5 << 7 << 2 << true;
1140  // Move from the end to the middle
1141  QTest::newRow("move04") << 8 << 9 << 5 << true;
1142 
1143  QTest::newRow("move05") << 5 << 7 << 0 << false;
1144  QTest::newRow("move06") << 8 << 9 << 0 << false;
1145  QTest::newRow("move07") << 5 << 7 << 2 << false;
1146  QTest::newRow("move08") << 8 << 9 << 5 << false;
1147 }
1148 
1149 void tst_QAbstractItemModel::testMoveSameParentUp()
1150 {
1151  QFETCH(int, startRow);
1152  QFETCH(int, endRow);
1153  QFETCH(int, destRow);
1154  QFETCH(bool, topLevel);
1155 
1156  QModelIndex moveParent = topLevel ? QModelIndex() : m_model->index(5, 0);
1157 
1158  QList<QPersistentModelIndex> persistentList;
1159  QModelIndexList indexList;
1160 
1161  for (int column = 0; column < m_model->columnCount(); ++column) {
1162  for (int row = 0; row < m_model->rowCount(); ++row) {
1163  QModelIndex idx = m_model->index(row, column);
1164  QVERIFY(idx.isValid());
1165  indexList << idx;
1166  persistentList << QPersistentModelIndex(idx);
1167  }
1168  }
1169 
1170  QModelIndex parent = m_model->index(2, 0);
1171  for (int column = 0; column < m_model->columnCount(); ++column) {
1172  for (int row = 0; row < m_model->rowCount(parent); ++row) {
1173  QModelIndex idx = m_model->index(row, column, parent);
1174  QVERIFY(idx.isValid());
1175  indexList << idx;
1176  persistentList << QPersistentModelIndex(idx);
1177  }
1178  }
1179 
1180  QSignalSpy beforeSpy(m_model, &DynamicTreeModel::rowsAboutToBeMoved);
1181  QSignalSpy afterSpy(m_model, &DynamicTreeModel::rowsMoved);
1182 
1183  QVERIFY(beforeSpy.isValid());
1184  QVERIFY(afterSpy.isValid());
1185 
1186  ModelMoveCommand *moveCommand = new ModelMoveCommand(m_model, this);
1187  moveCommand->setNumCols(4);
1188  if (!topLevel)
1189  moveCommand->setAncestorRowNumbers(QList<int>() << 5);
1190  moveCommand->setStartRow(startRow);
1191  moveCommand->setEndRow(endRow);
1192  moveCommand->setDestRow(destRow);
1193  if (!topLevel)
1194  moveCommand->setDestAncestors(QList<int>() << 5);
1195  moveCommand->doCommand();
1196 
1197  QVariantList beforeSignal = beforeSpy.takeAt(0);
1198  QVariantList afterSignal = afterSpy.takeAt(0);
1199 
1200  QCOMPARE(beforeSignal.size(), 5);
1201  QCOMPARE(beforeSignal.at(0).value<QModelIndex>(), moveParent);
1202  QCOMPARE(beforeSignal.at(1).toInt(), startRow);
1203  QCOMPARE(beforeSignal.at(2).toInt(), endRow);
1204  QCOMPARE(beforeSignal.at(3).value<QModelIndex>(), moveParent);
1205  QCOMPARE(beforeSignal.at(4).toInt(), destRow);
1206 
1207  QCOMPARE(afterSignal.size(), 5);
1208  QCOMPARE(afterSignal.at(0).value<QModelIndex>(), moveParent);
1209  QCOMPARE(afterSignal.at(1).toInt(), startRow);
1210  QCOMPARE(afterSignal.at(2).toInt(), endRow);
1211  QCOMPARE(afterSignal.at(3).value<QModelIndex>(), moveParent);
1212  QCOMPARE(afterSignal.at(4).toInt(), destRow);
1213 
1214  for (int i = 0; i < indexList.size(); i++) {
1215  QModelIndex idx = indexList.at(i);
1216  QModelIndex persistentIndex = persistentList.at(i);
1217  if (idx.parent() == moveParent) {
1218  int row = idx.row();
1219  if ( row >= destRow) {
1220  if (row < startRow) {
1221  QCOMPARE(row + endRow - startRow + 1, persistentIndex.row());
1222  QCOMPARE(idx.column(), persistentIndex.column());
1223  QCOMPARE(idx.parent(), persistentIndex.parent());
1224  QCOMPARE(idx.model(), persistentIndex.model());
1225  } else if (row <= endRow) {
1226  QCOMPARE(row + destRow - startRow, persistentIndex.row());
1227  QCOMPARE(idx.column(), persistentIndex.column());
1228  QCOMPARE(idx.parent(), persistentIndex.parent());
1229  QCOMPARE(idx.model(), persistentIndex.model());
1230  } else {
1231  QCOMPARE(idx, persistentIndex);
1232  }
1233  } else {
1234  QCOMPARE(idx, persistentIndex);
1235  }
1236  } else {
1237  QCOMPARE(idx, persistentIndex);
1238  }
1239  }
1240 }
1241 
1242 void tst_QAbstractItemModel::testMoveThroughProxy()
1243 {
1245  proxy->setSourceModel(m_model);
1246 
1247  QList<QPersistentModelIndex> persistentList;
1248 
1249  persistentList.append(proxy->index(0, 0));
1250  persistentList.append(proxy->index(0, 0, proxy->mapFromSource(m_model->index(5, 0))));
1251 
1252  ModelMoveCommand *moveCommand = new ModelMoveCommand(m_model, this);
1253  moveCommand->setNumCols(4);
1254  moveCommand->setAncestorRowNumbers(QList<int>() << 5);
1255  moveCommand->setStartRow(0);
1256  moveCommand->setEndRow(0);
1257  moveCommand->setDestRow(0);
1258  moveCommand->doCommand();
1259 }
1260 
1261 void tst_QAbstractItemModel::testMoveToGrandParent_data()
1262 {
1263  QTest::addColumn<int>("startRow");
1264  QTest::addColumn<int>("endRow");
1265  QTest::addColumn<int>("destRow");
1266 
1267  // Move from the start to the middle
1268  QTest::newRow("move01") << 0 << 2 << 8;
1269  // Move from the start to the end
1270  QTest::newRow("move02") << 0 << 2 << 10;
1271  // Move from the middle to the middle
1272  QTest::newRow("move03") << 3 << 5 << 8;
1273  // Move from the middle to the end
1274  QTest::newRow("move04") << 3 << 5 << 10;
1275 
1276  // Move from the middle to the start
1277  QTest::newRow("move05") << 5 << 7 << 0;
1278  // Move from the end to the start
1279  QTest::newRow("move06") << 8 << 9 << 0;
1280  // Move from the middle to the middle
1281  QTest::newRow("move07") << 5 << 7 << 2;
1282  // Move from the end to the middle
1283  QTest::newRow("move08") << 8 << 9 << 5;
1284 
1285  // Moving to the same row in a different parent doesn't confuse things.
1286  QTest::newRow("move09") << 8 << 8 << 8;
1287 
1288  // Moving to the row of my parent and its neighbours doesn't confuse things
1289  QTest::newRow("move10") << 8 << 8 << 4;
1290  QTest::newRow("move11") << 8 << 8 << 5;
1291  QTest::newRow("move12") << 8 << 8 << 6;
1292 
1293  // Moving everything from one parent to another
1294  QTest::newRow("move13") << 0 << 9 << 10;
1295  QTest::newRow("move14") << 0 << 9 << 0;
1296 }
1297 
1298 void tst_QAbstractItemModel::testMoveToGrandParent()
1299 {
1300  QFETCH(int, startRow);
1301  QFETCH(int, endRow);
1302  QFETCH(int, destRow);
1303 
1304  QList<QPersistentModelIndex> persistentList;
1305  QModelIndexList indexList;
1306  QModelIndexList parentsList;
1307 
1308  for (int column = 0; column < m_model->columnCount(); ++column) {
1309  for (int row = 0; row < m_model->rowCount(); ++row) {
1310  QModelIndex idx = m_model->index(row, column);
1311  QVERIFY(idx.isValid());
1312  indexList << idx;
1313  parentsList << idx.parent();
1314  persistentList << QPersistentModelIndex(idx);
1315  }
1316  }
1317 
1318  QModelIndex sourceIndex = m_model->index(5, 0);
1319  for (int column = 0; column < m_model->columnCount(); ++column) {
1320  for (int row = 0; row < m_model->rowCount(sourceIndex); ++row) {
1321  QModelIndex idx = m_model->index(row, column, sourceIndex);
1322  QVERIFY(idx.isValid());
1323  indexList << idx;
1324  parentsList << idx.parent();
1325  persistentList << QPersistentModelIndex(idx);
1326  }
1327  }
1328 
1329  QSignalSpy beforeSpy(m_model, &DynamicTreeModel::rowsAboutToBeMoved);
1330  QSignalSpy afterSpy(m_model, &DynamicTreeModel::rowsMoved);
1331 
1332  QVERIFY(beforeSpy.isValid());
1333  QVERIFY(afterSpy.isValid());
1334 
1335  QPersistentModelIndex persistentSource = sourceIndex;
1336 
1337  ModelMoveCommand *moveCommand = new ModelMoveCommand(m_model, this);
1338  moveCommand->setAncestorRowNumbers(QList<int>() << 5);
1339  moveCommand->setNumCols(4);
1340  moveCommand->setStartRow(startRow);
1341  moveCommand->setEndRow(endRow);
1342  moveCommand->setDestRow(destRow);
1343  moveCommand->doCommand();
1344 
1345  QVariantList beforeSignal = beforeSpy.takeAt(0);
1346  QVariantList afterSignal = afterSpy.takeAt(0);
1347 
1348  QCOMPARE(beforeSignal.size(), 5);
1349  QCOMPARE(beforeSignal.at(0).value<QModelIndex>(), sourceIndex);
1350  QCOMPARE(beforeSignal.at(1).toInt(), startRow);
1351  QCOMPARE(beforeSignal.at(2).toInt(), endRow);
1352  QCOMPARE(beforeSignal.at(3).value<QModelIndex>(), QModelIndex());
1353  QCOMPARE(beforeSignal.at(4).toInt(), destRow);
1354 
1355  QCOMPARE(afterSignal.size(), 5);
1356  QCOMPARE(afterSignal.at(0).value<QModelIndex>(), static_cast<QModelIndex>(persistentSource));
1357  QCOMPARE(afterSignal.at(1).toInt(), startRow);
1358  QCOMPARE(afterSignal.at(2).toInt(), endRow);
1359  QCOMPARE(afterSignal.at(3).value<QModelIndex>(), QModelIndex());
1360  QCOMPARE(afterSignal.at(4).toInt(), destRow);
1361 
1362  for (int i = 0; i < indexList.size(); i++) {
1363  QModelIndex idx = indexList.at(i);
1364  QModelIndex idxParent = parentsList.at(i);
1365  QModelIndex persistentIndex = persistentList.at(i);
1366  int row = idx.row();
1367  if (idxParent == QModelIndex()) {
1368  if (row >= destRow) {
1369  QCOMPARE(row + endRow - startRow + 1, persistentIndex.row());
1370  QCOMPARE(idx.column(), persistentIndex.column());
1371  QCOMPARE(idxParent, persistentIndex.parent());
1372  QCOMPARE(idx.model(), persistentIndex.model());
1373  } else {
1374  QCOMPARE(idx, persistentIndex);
1375  }
1376  } else {
1377  if (row < startRow) {
1378  QCOMPARE(idx, persistentIndex);
1379  } else if (row <= endRow) {
1380  QCOMPARE(row + destRow - startRow, persistentIndex.row());
1381  QCOMPARE(idx.column(), persistentIndex.column());
1382  QCOMPARE(QModelIndex(), persistentIndex.parent());
1383  QCOMPARE(idx.model(), persistentIndex.model());
1384  } else {
1385  QCOMPARE(row - (endRow - startRow + 1), persistentIndex.row());
1386  QCOMPARE(idx.column(), persistentIndex.column());
1387 
1388  if (idxParent.row() >= destRow) {
1389  QModelIndex adjustedParent;
1390  adjustedParent = idxParent.sibling(idxParent.row() + endRow - startRow + 1, idxParent.column());
1391  QCOMPARE(adjustedParent, persistentIndex.parent());
1392  } else {
1393  QCOMPARE(idxParent, persistentIndex.parent());
1394  }
1395  QCOMPARE(idx.model(), persistentIndex.model());
1396  }
1397  }
1398  }
1399 }
1400 
1401 void tst_QAbstractItemModel::testMoveToSibling_data()
1402 {
1403  QTest::addColumn<int>("startRow");
1404  QTest::addColumn<int>("endRow");
1405  QTest::addColumn<int>("destRow");
1406 
1407  // Move from the start to the middle
1408  QTest::newRow("move01") << 0 << 2 << 8;
1409  // Move from the start to the end
1410  QTest::newRow("move02") << 0 << 2 << 10;
1411  // Move from the middle to the middle
1412  QTest::newRow("move03") << 2 << 4 << 8;
1413  // Move from the middle to the end
1414  QTest::newRow("move04") << 2 << 4 << 10;
1415 
1416  // Move from the middle to the start
1417  QTest::newRow("move05") << 8 << 8 << 0;
1418  // Move from the end to the start
1419  QTest::newRow("move06") << 8 << 9 << 0;
1420  // Move from the middle to the middle
1421  QTest::newRow("move07") << 6 << 8 << 2;
1422  // Move from the end to the middle
1423  QTest::newRow("move08") << 8 << 9 << 5;
1424 
1425  // Moving to the same row in a different parent doesn't confuse things.
1426  QTest::newRow("move09") << 8 << 8 << 8;
1427 
1428  // Moving to the row of my target and its neighbours doesn't confuse things
1429  QTest::newRow("move10") << 8 << 8 << 4;
1430  QTest::newRow("move11") << 8 << 8 << 5;
1431  QTest::newRow("move12") << 8 << 8 << 6;
1432 
1433  // Move such that the destination parent no longer valid after the move.
1434  // The destination parent is always QMI(5, 0), but after this move the
1435  // row count is 5, so (5, 0) (used internally in QAIM) no longer refers to a valid index.
1436  QTest::newRow("move13") << 0 << 4 << 0;
1437 }
1438 
1439 void tst_QAbstractItemModel::testMoveToSibling()
1440 {
1441  QFETCH(int, startRow);
1442  QFETCH(int, endRow);
1443  QFETCH(int, destRow);
1444 
1445  QList<QPersistentModelIndex> persistentList;
1446  QModelIndexList indexList;
1447  QModelIndexList parentsList;
1448 
1449  const int column = 0;
1450 
1451  for (int i = 0; i < m_model->rowCount(); ++i) {
1452  QModelIndex idx = m_model->index(i, column);
1453  QVERIFY(idx.isValid());
1454  indexList << idx;
1455  parentsList << idx.parent();
1456  persistentList << QPersistentModelIndex(idx);
1457  }
1458 
1459  QModelIndex destIndex = m_model->index(5, 0);
1460  QModelIndex sourceIndex;
1461  for (int i = 0; i < m_model->rowCount(destIndex); ++i) {
1462  QModelIndex idx = m_model->index(i, column, destIndex);
1463  QVERIFY(idx.isValid());
1464  indexList << idx;
1465  parentsList << idx.parent();
1466  persistentList << QPersistentModelIndex(idx);
1467  }
1468 
1469  QSignalSpy beforeSpy(m_model, &DynamicTreeModel::rowsAboutToBeMoved);
1470  QSignalSpy afterSpy(m_model, &DynamicTreeModel::rowsMoved);
1471 
1472  QVERIFY(beforeSpy.isValid());
1473  QVERIFY(afterSpy.isValid());
1474 
1475  QPersistentModelIndex persistentDest = destIndex;
1476 
1477  ModelMoveCommand *moveCommand = new ModelMoveCommand(m_model, this);
1478  moveCommand->setNumCols(4);
1479  moveCommand->setStartRow(startRow);
1480  moveCommand->setEndRow(endRow);
1481  moveCommand->setDestAncestors(QList<int>() << 5);
1482  moveCommand->setDestRow(destRow);
1483  moveCommand->doCommand();
1484 
1485  QVariantList beforeSignal = beforeSpy.takeAt(0);
1486  QVariantList afterSignal = afterSpy.takeAt(0);
1487 
1488  QCOMPARE(beforeSignal.size(), 5);
1489  QCOMPARE(beforeSignal.at(0).value<QModelIndex>(), sourceIndex);
1490  QCOMPARE(beforeSignal.at(1).toInt(), startRow);
1491  QCOMPARE(beforeSignal.at(2).toInt(), endRow);
1492  QCOMPARE(beforeSignal.at(3).value<QModelIndex>(), destIndex);
1493  QCOMPARE(beforeSignal.at(4).toInt(), destRow);
1494 
1495  QCOMPARE(afterSignal.size(), 5);
1496  QCOMPARE(afterSignal.at(0).value<QModelIndex>(), sourceIndex);
1497  QCOMPARE(afterSignal.at(1).toInt(), startRow);
1498  QCOMPARE(afterSignal.at(2).toInt(), endRow);
1499  QCOMPARE(afterSignal.at(3).value<QModelIndex>(), static_cast<QModelIndex>(persistentDest));
1500  QCOMPARE(afterSignal.at(4).toInt(), destRow);
1501 
1502  for (int i = 0; i < indexList.size(); i++) {
1503  QModelIndex idx = indexList.at(i);
1504  QModelIndex idxParent = parentsList.at(i);
1505  QModelIndex persistentIndex = persistentList.at(i);
1506 
1507  QModelIndex adjustedDestination = destIndex.sibling(destIndex.row() - (endRow - startRow + 1), destIndex.column());
1508  int row = idx.row();
1509  if (idxParent == destIndex) {
1510  if (row >= destRow) {
1511  QCOMPARE(row + endRow - startRow + 1, persistentIndex.row());
1512  QCOMPARE(idx.column(), persistentIndex.column());
1513  if (idxParent.row() > startRow) {
1514  QCOMPARE(adjustedDestination, persistentIndex.parent());
1515  } else {
1516  QCOMPARE(destIndex, persistentIndex.parent());
1517  }
1518  QCOMPARE(idx.model(), persistentIndex.model());
1519  } else {
1520  QCOMPARE(idx, persistentIndex);
1521  }
1522  } else {
1523  if (row < startRow) {
1524  QCOMPARE(idx, persistentIndex);
1525  } else if (row <= endRow) {
1526  QCOMPARE(row + destRow - startRow, persistentIndex.row());
1527  QCOMPARE(idx.column(), persistentIndex.column());
1528  if (destIndex.row() > startRow) {
1529  QCOMPARE(adjustedDestination, persistentIndex.parent());
1530  } else {
1531  QCOMPARE(destIndex, persistentIndex.parent());
1532  }
1533 
1534  QCOMPARE(idx.model(), persistentIndex.model());
1535  } else {
1536  QCOMPARE(row - (endRow - startRow + 1), persistentIndex.row());
1537  QCOMPARE(idx.column(), persistentIndex.column());
1538  QCOMPARE(idxParent, persistentIndex.parent());
1539  QCOMPARE(idx.model(), persistentIndex.model());
1540  }
1541  }
1542  }
1543 }
1544 
1545 void tst_QAbstractItemModel::testMoveToUncle_data()
1546 {
1547  QTest::addColumn<int>("startRow");
1548  QTest::addColumn<int>("endRow");
1549  QTest::addColumn<int>("destRow");
1550 
1551  // Move from the start to the middle
1552  QTest::newRow("move01") << 0 << 2 << 8;
1553  // Move from the start to the end
1554  QTest::newRow("move02") << 0 << 2 << 10;
1555  // Move from the middle to the middle
1556  QTest::newRow("move03") << 3 << 5 << 8;
1557  // Move from the middle to the end
1558  QTest::newRow("move04") << 3 << 5 << 10;
1559 
1560  // Move from the middle to the start
1561  QTest::newRow("move05") << 5 << 7 << 0;
1562  // Move from the end to the start
1563  QTest::newRow("move06") << 8 << 9 << 0;
1564  // Move from the middle to the middle
1565  QTest::newRow("move07") << 5 << 7 << 2;
1566  // Move from the end to the middle
1567  QTest::newRow("move08") << 8 << 9 << 5;
1568 
1569  // Moving to the same row in a different parent doesn't confuse things.
1570  QTest::newRow("move09") << 8 << 8 << 8;
1571 
1572  // Moving to the row of my parent and its neighbours doesn't confuse things
1573  QTest::newRow("move10") << 8 << 8 << 4;
1574  QTest::newRow("move11") << 8 << 8 << 5;
1575  QTest::newRow("move12") << 8 << 8 << 6;
1576 
1577  // Moving everything from one parent to another
1578  QTest::newRow("move13") << 0 << 9 << 10;
1579 }
1580 
1581 void tst_QAbstractItemModel::testMoveToUncle()
1582 {
1583  // Need to have some extra rows available.
1584  ModelInsertCommand *insertCommand = new ModelInsertCommand(m_model, this);
1585  insertCommand->setAncestorRowNumbers(QList<int>() << 9);
1586  insertCommand->setNumCols(4);
1587  insertCommand->setStartRow(0);
1588  insertCommand->setEndRow(9);
1589  insertCommand->doCommand();
1590 
1591  QFETCH(int, startRow);
1592  QFETCH(int, endRow);
1593  QFETCH(int, destRow);
1594 
1595  QList<QPersistentModelIndex> persistentList;
1596  QModelIndexList indexList;
1597  QModelIndexList parentsList;
1598 
1599  const int column = 0;
1600 
1601  QModelIndex sourceIndex = m_model->index(9, 0);
1602  for (int i = 0; i < m_model->rowCount(sourceIndex); ++i) {
1603  QModelIndex idx = m_model->index(i, column, sourceIndex);
1604  QVERIFY(idx.isValid());
1605  indexList << idx;
1606  parentsList << idx.parent();
1607  persistentList << QPersistentModelIndex(idx);
1608  }
1609 
1610  QModelIndex destIndex = m_model->index(5, 0);
1611  for (int i = 0; i < m_model->rowCount(destIndex); ++i) {
1612  QModelIndex idx = m_model->index(i, column, destIndex);
1613  QVERIFY(idx.isValid());
1614  indexList << idx;
1615  parentsList << idx.parent();
1616  persistentList << QPersistentModelIndex(idx);
1617  }
1618 
1619  QSignalSpy beforeSpy(m_model, &DynamicTreeModel::rowsAboutToBeMoved);
1620  QSignalSpy afterSpy(m_model, &DynamicTreeModel::rowsMoved);
1621 
1622  QVERIFY(beforeSpy.isValid());
1623  QVERIFY(afterSpy.isValid());
1624 
1625  ModelMoveCommand *moveCommand = new ModelMoveCommand(m_model, this);
1626  moveCommand->setAncestorRowNumbers(QList<int>() << 9);
1627  moveCommand->setNumCols(4);
1628  moveCommand->setStartRow(startRow);
1629  moveCommand->setEndRow(endRow);
1630  moveCommand->setDestAncestors(QList<int>() << 5);
1631  moveCommand->setDestRow(destRow);
1632  moveCommand->doCommand();
1633 
1634  QVariantList beforeSignal = beforeSpy.takeAt(0);
1635  QVariantList afterSignal = afterSpy.takeAt(0);
1636 
1637  QCOMPARE(beforeSignal.size(), 5);
1638  QCOMPARE(beforeSignal.at(0).value<QModelIndex>(), sourceIndex);
1639  QCOMPARE(beforeSignal.at(1).toInt(), startRow);
1640  QCOMPARE(beforeSignal.at(2).toInt(), endRow);
1641  QCOMPARE(beforeSignal.at(3).value<QModelIndex>(), destIndex);
1642  QCOMPARE(beforeSignal.at(4).toInt(), destRow);
1643 
1644  QCOMPARE(afterSignal.size(), 5);
1645  QCOMPARE(afterSignal.at(0).value<QModelIndex>(), sourceIndex);
1646  QCOMPARE(afterSignal.at(1).toInt(), startRow);
1647  QCOMPARE(afterSignal.at(2).toInt(), endRow);
1648  QCOMPARE(afterSignal.at(3).value<QModelIndex>(), destIndex);
1649  QCOMPARE(afterSignal.at(4).toInt(), destRow);
1650 
1651  for (int i = 0; i < indexList.size(); i++) {
1652  QModelIndex idx = indexList.at(i);
1653  QModelIndex idxParent = parentsList.at(i);
1654  QModelIndex persistentIndex = persistentList.at(i);
1655 
1656  int row = idx.row();
1657  if (idxParent == destIndex) {
1658  if (row >= destRow) {
1659  QCOMPARE(row + endRow - startRow + 1, persistentIndex.row());
1660  QCOMPARE(idx.column(), persistentIndex.column());
1661  QCOMPARE(destIndex, persistentIndex.parent());
1662  QCOMPARE(idx.model(), persistentIndex.model());
1663  } else {
1664  QCOMPARE(idx, persistentIndex);
1665  }
1666  } else {
1667  if (row < startRow) {
1668  QCOMPARE(idx, persistentIndex);
1669  } else if (row <= endRow) {
1670  QCOMPARE(row + destRow - startRow, persistentIndex.row());
1671  QCOMPARE(idx.column(), persistentIndex.column());
1672  QCOMPARE(destIndex, persistentIndex.parent());
1673  QCOMPARE(idx.model(), persistentIndex.model());
1674  } else {
1675  QCOMPARE(row - (endRow - startRow + 1), persistentIndex.row());
1676  QCOMPARE(idx.column(), persistentIndex.column());
1677  QCOMPARE(idxParent, persistentIndex.parent());
1678  QCOMPARE(idx.model(), persistentIndex.model());
1679  }
1680  }
1681  }
1682 }
1683 
1684 void tst_QAbstractItemModel::testMoveToDescendants()
1685 {
1686  // Attempt to move a row to its ancestors depth rows deep.
1687  const int depth = 6;
1688 
1689  // Need to have some extra rows available in a tree.
1690  QList<int> rows;
1691  ModelInsertCommand *insertCommand;
1692  for (int i = 0; i < depth; i++) {
1693  insertCommand = new ModelInsertCommand(m_model, this);
1694  insertCommand->setAncestorRowNumbers(rows);
1695  insertCommand->setNumCols(4);
1696  insertCommand->setStartRow(0);
1697  insertCommand->setEndRow(9);
1698  insertCommand->doCommand();
1699  rows << 9;
1700  }
1701 
1702  QList<QPersistentModelIndex> persistentList;
1703  QModelIndexList indexList;
1704  QModelIndexList parentsList;
1705 
1706  const int column = 0;
1707 
1708  QModelIndex sourceIndex = m_model->index(9, 0);
1709  for (int i = 0; i < m_model->rowCount(sourceIndex); ++i) {
1710  QModelIndex idx = m_model->index(i, column, sourceIndex);
1711  QVERIFY(idx.isValid());
1712  indexList << idx;
1713  parentsList << idx.parent();
1714  persistentList << QPersistentModelIndex(idx);
1715  }
1716 
1717  QModelIndex destIndex = m_model->index(5, 0);
1718  for (int i = 0; i < m_model->rowCount(destIndex); ++i) {
1719  QModelIndex idx = m_model->index(i, column, destIndex);
1720  QVERIFY(idx.isValid());
1721  indexList << idx;
1722  parentsList << idx.parent();
1723  persistentList << QPersistentModelIndex(idx);
1724  }
1725 
1726  QSignalSpy beforeSpy(m_model, &DynamicTreeModel::rowsAboutToBeMoved);
1727  QSignalSpy afterSpy(m_model, &DynamicTreeModel::rowsMoved);
1728 
1729  QVERIFY(beforeSpy.isValid());
1730  QVERIFY(afterSpy.isValid());
1731 
1732  ModelMoveCommand *moveCommand;
1733  QList<int> ancestors;
1734  while (ancestors.size() < depth) {
1735  ancestors << 9;
1736  for (int row = 0; row <= 9; row++) {
1737  moveCommand = new ModelMoveCommand(m_model, this);
1738  moveCommand->setNumCols(4);
1739  moveCommand->setStartRow(9);
1740  moveCommand->setEndRow(9);
1741  moveCommand->setDestAncestors(ancestors);
1742  moveCommand->setDestRow(row);
1743  moveCommand->doCommand();
1744 
1745  QCOMPARE(beforeSpy.size(), 0);
1746  QCOMPARE(afterSpy.size(), 0);
1747  }
1748  }
1749 }
1750 
1751 void tst_QAbstractItemModel::testMoveWithinOwnRange_data()
1752 {
1753  QTest::addColumn<int>("startRow");
1754  QTest::addColumn<int>("endRow");
1755  QTest::addColumn<int>("destRow");
1756 
1757  QTest::newRow("move01") << 0 << 0 << 0;
1758  QTest::newRow("move02") << 0 << 0 << 1;
1759  QTest::newRow("move03") << 0 << 5 << 0;
1760  QTest::newRow("move04") << 0 << 5 << 1;
1761  QTest::newRow("move05") << 0 << 5 << 2;
1762  QTest::newRow("move06") << 0 << 5 << 3;
1763  QTest::newRow("move07") << 0 << 5 << 4;
1764  QTest::newRow("move08") << 0 << 5 << 5;
1765  QTest::newRow("move09") << 0 << 5 << 6;
1766  QTest::newRow("move10") << 3 << 5 << 5;
1767  QTest::newRow("move11") << 3 << 5 << 6;
1768  QTest::newRow("move12") << 4 << 5 << 5;
1769  QTest::newRow("move13") << 4 << 5 << 6;
1770  QTest::newRow("move14") << 5 << 5 << 5;
1771  QTest::newRow("move15") << 5 << 5 << 6;
1772  QTest::newRow("move16") << 5 << 9 << 9;
1773  QTest::newRow("move17") << 5 << 9 << 10;
1774  QTest::newRow("move18") << 6 << 9 << 9;
1775  QTest::newRow("move19") << 6 << 9 << 10;
1776  QTest::newRow("move20") << 7 << 9 << 9;
1777  QTest::newRow("move21") << 7 << 9 << 10;
1778  QTest::newRow("move22") << 8 << 9 << 9;
1779  QTest::newRow("move23") << 8 << 9 << 10;
1780  QTest::newRow("move24") << 9 << 9 << 9;
1781  QTest::newRow("move25") << 0 << 9 << 10;
1782 }
1783 
1784 void tst_QAbstractItemModel::testMoveWithinOwnRange()
1785 {
1786  QFETCH(int, startRow);
1787  QFETCH(int, endRow);
1788  QFETCH(int, destRow);
1789 
1790  QSignalSpy beforeSpy(m_model, &DynamicTreeModel::rowsAboutToBeMoved);
1791  QSignalSpy afterSpy(m_model, &DynamicTreeModel::rowsMoved);
1792 
1793  QVERIFY(beforeSpy.isValid());
1794  QVERIFY(afterSpy.isValid());
1795 
1796  ModelMoveCommand *moveCommand = new ModelMoveCommand(m_model, this);
1797  moveCommand->setNumCols(4);
1798  moveCommand->setStartRow(startRow);
1799  moveCommand->setEndRow(endRow);
1800  moveCommand->setDestRow(destRow);
1801  moveCommand->doCommand();
1802 
1803  QCOMPARE(beforeSpy.size(), 0);
1804  QCOMPARE(afterSpy.size(), 0);
1805 }
1806 
1807 class ListenerObject : public QObject
1808 {
1809  Q_OBJECT
1810 public:
1812 
1813 protected:
1814  void fillIndexStores(const QModelIndex &parent);
1815 
1816 public slots:
1817  void slotAboutToBeReset();
1818  void slotReset();
1819 
1820 private:
1821  QAbstractProxyModel *m_model;
1822  QList<QPersistentModelIndex> m_persistentIndexes;
1823  QModelIndexList m_nonPersistentIndexes;
1824 };
1825 
1826 
1828 {
1829  Q_OBJECT
1830 public:
1832 
1834  {
1835  return {{Qt::UserRole + 1, QByteArrayLiteral("custom")}};
1836  }
1837 };
1838 
1840  : QObject(parent), m_model(parent)
1841 {
1842  connect(m_model, SIGNAL(modelAboutToBeReset()), SLOT(slotAboutToBeReset()));
1843  connect(m_model, SIGNAL(modelReset()), SLOT(slotReset()));
1844 
1846 }
1847 
1849 {
1850  const int column = 0;
1851  int row = 0;
1852  QModelIndex idx = m_model->index(row, column, parent);
1853  while (idx.isValid()) {
1854  m_persistentIndexes << QPersistentModelIndex(idx);
1855  m_nonPersistentIndexes << idx;
1856  if (m_model->hasChildren(idx))
1858  ++row;
1859  idx = m_model->index(row, column, parent);
1860  }
1861 }
1862 
1864 {
1865  // Nothing has been changed yet. All indexes should be the same.
1866  for (int i = 0; i < m_persistentIndexes.size(); ++i) {
1867  QModelIndex idx = m_persistentIndexes.at(i);
1868  QCOMPARE(idx, m_nonPersistentIndexes.at(i));
1869  QVERIFY(m_model->mapToSource(idx).isValid());
1870  }
1871 }
1872 
1874 {
1875  for (const auto &idx : qAsConst(m_persistentIndexes)) {
1876  QVERIFY(!idx.isValid());
1877  }
1878 }
1879 
1880 void tst_QAbstractItemModel::testReset()
1881 {
1882  QSignalSpy beforeResetSpy(m_model, &DynamicTreeModel::modelAboutToBeReset);
1883  QSignalSpy afterResetSpy(m_model, &DynamicTreeModel::modelReset);
1884 
1885  QVERIFY(beforeResetSpy.isValid());
1886  QVERIFY(afterResetSpy.isValid());
1887 
1888  QSortFilterProxyModel *nullProxy = new QSortFilterProxyModel(this);
1889  nullProxy->setSourceModel(m_model);
1890 
1891  // Makes sure the model and proxy are in a consistent state. before and after reset.
1892  ListenerObject *listener = new ListenerObject(nullProxy);
1893 
1894  ModelResetCommandFixed *resetCommand = new ModelResetCommandFixed(m_model, this);
1895 
1896  resetCommand->setNumCols(4);
1897  resetCommand->setStartRow(0);
1898  resetCommand->setEndRow(0);
1899  resetCommand->setDestRow(0);
1900  resetCommand->setDestAncestors(QList<int>() << 5);
1901  resetCommand->doCommand();
1902 
1903  // Verify that the correct signals were emitted
1904  QCOMPARE(beforeResetSpy.size(), 1);
1905  QCOMPARE(afterResetSpy.size(), 1);
1906 
1907  // Verify that the move actually happened.
1908  QCOMPARE(m_model->rowCount(), 9);
1909  QModelIndex destIndex = m_model->index(4, 0);
1910  QCOMPARE(m_model->rowCount(destIndex), 11);
1911 
1912  // Delete it because its slots test things which are not true after this point.
1913  delete listener;
1914 
1915  QSignalSpy proxyBeforeResetSpy(nullProxy, &QSortFilterProxyModel::modelAboutToBeReset);
1916  QSignalSpy proxyAfterResetSpy(nullProxy, &QSortFilterProxyModel::modelReset);
1917 
1918  // Before setting it, it does not have custom roles.
1919  QCOMPARE(nullProxy->roleNames().value(Qt::UserRole + 1), QByteArray());
1920 
1921  nullProxy->setSourceModel(new ModelWithCustomRole(this));
1922  QCOMPARE(proxyBeforeResetSpy.size(), 1);
1923  QCOMPARE(proxyAfterResetSpy.size(), 1);
1924 
1925  QCOMPARE(nullProxy->roleNames().value(Qt::UserRole + 1), QByteArray("custom"));
1926 
1927  nullProxy->setSourceModel(m_model);
1928  QCOMPARE(proxyBeforeResetSpy.size(), 2);
1929  QCOMPARE(proxyAfterResetSpy.size(), 2);
1930 
1931  // After being reset the proxy must be queried again.
1932  QCOMPARE(nullProxy->roleNames().value(Qt::UserRole + 1), QByteArray());
1933 }
1934 
1936 {
1937  Q_OBJECT
1938  Q_ENUMS(Roles)
1939 public:
1940  enum Roles {
1943  UserRole
1944  };
1945 
1947  : QStringListModel(QStringList() << "a" << "b" << "c", parent)
1948  {
1949  }
1950 
1952  {
1953  const QModelIndex top = index(0, 0);
1954  const QModelIndex bottom = index(2, 0);
1955 
1959  }
1960 };
1961 
1962 void tst_QAbstractItemModel::testDataChanged()
1963 {
1965 
1968 
1969  QVERIFY(withRoles.isValid());
1970  QVERIFY(withoutRoles.isValid());
1971 
1972  model.emitSignals();
1973 
1974  QCOMPARE(withRoles.size(), withoutRoles.size());
1975  QCOMPARE(withRoles.size(), 3);
1976 
1977  const QVariantList secondEmission = withRoles.at(1);
1978  const QVariantList thirdEmission = withRoles.at(2);
1979 
1980  const QList<int> secondRoles = secondEmission.at(2).value<QList<int> >();
1981  const QList<int> thirdRoles = thirdEmission.at(2).value<QList<int> >();
1982 
1983  QCOMPARE(secondRoles.size(), 1);
1984  QVERIFY(secondRoles.contains(Qt::ToolTipRole));
1985 
1986  QCOMPARE(thirdRoles.size(), 2);
1987  QVERIFY(thirdRoles.contains(Qt::ToolTipRole));
1989 }
1990 
1992 
1994 {
1995  Q_OBJECT
1996 public:
1998  : QObject(parent), m_p1(p1), m_p2(p2), m_p1Persistent(p1), m_p2Persistent(p2)
1999  {
2000  connect(p1.model(), SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>)), SLOT(layoutAboutToBeChanged(QList<QPersistentModelIndex>)));
2001  connect(p1.model(), SIGNAL(layoutChanged(QList<QPersistentModelIndex>)), SLOT(layoutChanged(QList<QPersistentModelIndex>)));
2002  }
2003 
2004 private slots:
2005  void layoutAboutToBeChanged(const QList<QPersistentModelIndex> &parents)
2006  {
2007  QCOMPARE(parents.size(), 2);
2008  QVERIFY(parents.first() != parents.at(1));
2009  QVERIFY(parents.contains(m_p1));
2010  QVERIFY(parents.contains(m_p2));
2011  }
2012 
2013  void layoutChanged(const QList<QPersistentModelIndex> &parents)
2014  {
2015  QCOMPARE(parents.size(), 2);
2016  QVERIFY(parents.first() != parents.at(1));
2017  QVERIFY(parents.contains(m_p1Persistent));
2018  QVERIFY(parents.contains(m_p2Persistent));
2019  QVERIFY(!parents.contains(m_p2)); // Has changed
2020  }
2021 
2022 private:
2023  QModelIndex m_p1;
2024  QModelIndex m_p2;
2025  QPersistentModelIndex m_p1Persistent;
2026  QPersistentModelIndex m_p2Persistent;
2027 };
2028 
2029 void tst_QAbstractItemModel::testChildrenLayoutsChanged()
2030 {
2032 
2033  ModelInsertCommand *insertCommand = new ModelInsertCommand(&model, this);
2034  insertCommand->setStartRow(0);
2035  insertCommand->setEndRow(9);
2036  insertCommand->doCommand();
2037 
2038  insertCommand = new ModelInsertCommand(&model, this);
2039  insertCommand->setAncestorRowNumbers(QList<int>() << 2);
2040  insertCommand->setStartRow(0);
2041  insertCommand->setEndRow(9);
2042  insertCommand->doCommand();
2043 
2044  insertCommand = new ModelInsertCommand(&model, this);
2045  insertCommand->setAncestorRowNumbers(QList<int>() << 5);
2046  insertCommand->setStartRow(0);
2047  insertCommand->setEndRow(9);
2048  insertCommand->doCommand();
2049 
2050  qRegisterMetaType<QList<QPersistentModelIndex> >();
2051 
2052  {
2053  const QModelIndex p1 = model.index(2, 0);
2054  const QModelIndex p2 = model.index(5, 0);
2055 
2056  const QPersistentModelIndex p1FirstPersistent = model.index(0, 0, p1);
2057  const QPersistentModelIndex p1LastPersistent = model.index(9, 0, p1);
2058  const QPersistentModelIndex p2FirstPersistent = model.index(0, 0, p2);
2059  const QPersistentModelIndex p2LastPersistent = model.index(9, 0, p2);
2060 
2061  QVERIFY(p1.isValid());
2062  QVERIFY(p2.isValid());
2063 
2064  QCOMPARE(model.rowCount(), 10);
2065  QCOMPARE(model.rowCount(p1), 10);
2066  QCOMPARE(model.rowCount(p2), 10);
2067 
2070 
2071  QVERIFY(beforeSpy.isValid());
2072  QVERIFY(afterSpy.isValid());
2073 
2075  changeCommand->setAncestorRowNumbers(QList<int>() << 2);
2076  changeCommand->setSecondAncestorRowNumbers(QList<int>() << 5);
2077  changeCommand->doCommand();
2078 
2079  QCOMPARE(beforeSpy.size(), 1);
2080  QCOMPARE(afterSpy.size(), 1);
2081 
2082  const QVariantList beforeSignal = beforeSpy.first();
2083  const QVariantList afterSignal = afterSpy.first();
2084  QCOMPARE(beforeSignal.size(), 2);
2085  QCOMPARE(afterSignal.size(), 2);
2086 
2087  const QList<QPersistentModelIndex> beforeParents = beforeSignal.first().value<QList<QPersistentModelIndex> >();
2088  QCOMPARE(beforeParents.size(), 2);
2089  QVERIFY(beforeParents.first() != beforeParents.at(1));
2090  QVERIFY(beforeParents.contains(p1));
2091  QVERIFY(beforeParents.contains(p2));
2092 
2093  const QList<QPersistentModelIndex> afterParents = afterSignal.first().value<QList<QPersistentModelIndex> >();
2094  QCOMPARE(afterParents.size(), 2);
2095  QVERIFY(afterParents.first() != afterParents.at(1));
2096  QVERIFY(afterParents.contains(p1));
2097  QVERIFY(afterParents.contains(p2));
2098 
2099  // The first will be the last, and the lest will be the first.
2100  QCOMPARE(p1FirstPersistent.row(), 1);
2101  QCOMPARE(p1LastPersistent.row(), 0);
2102  QCOMPARE(p2FirstPersistent.row(), 9);
2103  QCOMPARE(p2LastPersistent.row(), 8);
2104  }
2105 
2106  insertCommand = new ModelInsertCommand(&model, this);
2107  insertCommand->setAncestorRowNumbers(QList<int>() << 5 << 4);
2108  insertCommand->setStartRow(0);
2109  insertCommand->setEndRow(9);
2110  insertCommand->doCommand();
2111 
2112  delete insertCommand;
2113 
2114  // Even when p2 itself is moved around, signal emission remains correct for its children.
2115  {
2116  const QModelIndex p1 = model.index(5, 0);
2117  const QModelIndex p2 = model.index(4, 0, p1);
2118 
2119  QVERIFY(p1.isValid());
2120  QVERIFY(p2.isValid());
2121 
2122  QCOMPARE(model.rowCount(), 10);
2123  QCOMPARE(model.rowCount(p1), 10);
2124  QCOMPARE(model.rowCount(p2), 10);
2125 
2126  const QPersistentModelIndex p1Persistent = p1;
2127  const QPersistentModelIndex p2Persistent = p2;
2128 
2129  const QPersistentModelIndex p1FirstPersistent = model.index(0, 0, p1);
2130  const QPersistentModelIndex p1LastPersistent = model.index(9, 0, p1);
2131  const QPersistentModelIndex p2FirstPersistent = model.index(0, 0, p2);
2132  const QPersistentModelIndex p2LastPersistent = model.index(9, 0, p2);
2133 
2136 
2137  QVERIFY(beforeSpy.isValid());
2138  QVERIFY(afterSpy.isValid());
2139 
2140  // Because the arguments in the signal are persistent, we need to check them for the aboutToBe
2141  // case at emission time - before they get updated.
2142  SignalArgumentChecker checker(p1, p2);
2143 
2145  changeCommand->setAncestorRowNumbers(QList<int>() << 5);
2146  changeCommand->setSecondAncestorRowNumbers(QList<int>() << 5 << 4);
2147  changeCommand->doCommand();
2148 
2149  // p2 has been moved.
2150  QCOMPARE(p2Persistent.row(), p2.row() + 1);
2151 
2152  QCOMPARE(beforeSpy.size(), 1);
2153  QCOMPARE(afterSpy.size(), 1);
2154 
2155  const QVariantList beforeSignal = beforeSpy.first();
2156  const QVariantList afterSignal = afterSpy.first();
2157  QCOMPARE(beforeSignal.size(), 2);
2158  QCOMPARE(afterSignal.size(), 2);
2159 
2160  QCOMPARE(p1FirstPersistent.row(), 1);
2161  QCOMPARE(p1LastPersistent.row(), 0);
2162  QCOMPARE(p2FirstPersistent.row(), 9);
2163  QCOMPARE(p2LastPersistent.row(), 8);
2164  }
2165 }
2166 
2168 {
2169  Q_OBJECT
2170 public:
2173  {
2174 
2175  }
2176 
2178  {
2180  roles.insert(Qt::UserRole + 2, "custom");
2181  return roles;
2182  }
2183 
2184  Qt::DropActions supportedDragActions() const override
2185  {
2187  }
2188 };
2189 
2190 void tst_QAbstractItemModel::testRoleNames()
2191 {
2194  QVERIFY(roles.contains(Qt::UserRole + 2));
2195  QVERIFY(roles.value(Qt::UserRole + 2) == "custom");
2196 }
2197 
2198 void tst_QAbstractItemModel::testDragActions()
2199 {
2201  const Qt::DropActions actions = model->supportedDragActions();
2202  QVERIFY(actions & Qt::CopyAction); // Present by default
2203  QVERIFY(actions & Qt::MoveAction);
2204 }
2205 
2207 {
2208  Q_OBJECT
2209 public:
2212  {
2213  }
2214  Qt::DropActions supportedDropActions() const override
2215  {
2216  return Qt::MoveAction;
2217  }
2218 };
2219 
2220 void tst_QAbstractItemModel::dragActionsFallsBackToDropActions()
2221 {
2225 }
2226 
2228 {
2229  Q_OBJECT
2230 public:
2233  {
2234 
2235  }
2236 
2237 public Q_SLOTS:
2238  void testSlot()
2239  {
2240  testPassed = true;
2241  }
2243  {
2244  testPassed = !idx.isValid();
2245  }
2247  {
2248  testPassed = !idx.isValid() && start == 0;
2249  }
2251  {
2252  testPassed = !idx.isValid() && start == 0 && end == 1;
2253  }
2254 
2255 public:
2257 };
2258 
2259 void tst_QAbstractItemModel::testFunctionPointerSignalConnection()
2260 {
2262  {
2263  SignalConnectionTester tester;
2265 
2266  QVERIFY(!tester.testPassed);
2267 
2268  model.insertRows(0, 2);
2269 
2270  QVERIFY(tester.testPassed);
2271  tester.testPassed = false;
2272  QMetaObject::invokeMethod(&model, "rowsInserted", Q_ARG(QModelIndex, QModelIndex()), Q_ARG(int, 0), Q_ARG(int, 1));
2273  QVERIFY(tester.testPassed);
2274  }
2275  {
2276  SignalConnectionTester tester;
2278 
2279  QVERIFY(!tester.testPassed);
2280 
2281  model.insertRows(0, 2);
2282 
2283  QVERIFY(tester.testPassed);
2284  tester.testPassed = false;
2285  QMetaObject::invokeMethod(&model, "rowsInserted", Q_ARG(QModelIndex, QModelIndex()), Q_ARG(int, 0), Q_ARG(int, 1));
2286  QVERIFY(tester.testPassed);
2287  }
2288  {
2289  SignalConnectionTester tester;
2291 
2292  QVERIFY(!tester.testPassed);
2293 
2294  model.insertRows(0, 2);
2295 
2296  QVERIFY(tester.testPassed);
2297  tester.testPassed = false;
2298  QMetaObject::invokeMethod(&model, "rowsInserted", Q_ARG(QModelIndex, QModelIndex()), Q_ARG(int, 0), Q_ARG(int, 1));
2299  QVERIFY(tester.testPassed);
2300  }
2301  {
2302  SignalConnectionTester tester;
2304 
2305  QVERIFY(!tester.testPassed);
2306 
2307  model.insertRows(0, 2);
2308 
2309  QVERIFY(tester.testPassed);
2310  tester.testPassed = false;
2311  QMetaObject::invokeMethod(&model, "rowsInserted", Q_ARG(QModelIndex, QModelIndex()), Q_ARG(int, 0), Q_ARG(int, 1));
2312  QVERIFY(tester.testPassed);
2313  }
2314  {
2315  SignalConnectionTester tester;
2316  QObject::connect(&model, SIGNAL(rowsInserted(QModelIndex,int,int)), &tester, SLOT(testSlot()));
2317 
2318  QVERIFY(!tester.testPassed);
2319 
2320  model.insertRows(0, 2);
2321 
2322  QVERIFY(tester.testPassed);
2323  tester.testPassed = false;
2324  QMetaObject::invokeMethod(&model, "rowsInserted", Q_ARG(QModelIndex, QModelIndex()), Q_ARG(int, 0), Q_ARG(int, 1));
2325  QVERIFY(tester.testPassed);
2326  }
2327  // Intentionally does not compile.
2328 // model.rowsInserted(QModelIndex(), 0, 0);
2329 }
2330 
2331 void tst_QAbstractItemModel::checkIndex()
2332 {
2333  const QRegularExpression ignorePattern("^Index QModelIndex");
2334 
2335  // checkIndex is QAbstractItemModel API; using QStandardItem as an easy
2336  // way to build a tree model
2338  QStandardItem *topLevel = new QStandardItem("topLevel");
2339  model.appendRow(topLevel);
2340 
2341  topLevel->appendRow(new QStandardItem("child1"));
2342  topLevel->appendRow(new QStandardItem("child2"));
2343 
2347  QTest::ignoreMessage(QtWarningMsg, ignorePattern);
2349 
2350  QModelIndex topLevelIndex = model.index(0, 0);
2351  QVERIFY(topLevelIndex.isValid());
2352  QVERIFY(model.checkIndex(topLevelIndex));
2356 
2357  QModelIndex childIndex = model.index(0, 0, topLevelIndex);
2358  QVERIFY(childIndex.isValid());
2359  QVERIFY(model.checkIndex(childIndex));
2361  QTest::ignoreMessage(QtWarningMsg, ignorePattern);
2364 
2365  childIndex = model.index(1, 0, topLevelIndex);
2366  QVERIFY(childIndex.isValid());
2367  QVERIFY(model.checkIndex(childIndex));
2369  QTest::ignoreMessage(QtWarningMsg, ignorePattern);
2372 
2373  topLevel->removeRow(1);
2374  QTest::ignoreMessage(QtWarningMsg, ignorePattern);
2375  QVERIFY(!model.checkIndex(childIndex));
2377  QTest::ignoreMessage(QtWarningMsg, ignorePattern);
2379  QTest::ignoreMessage(QtWarningMsg, ignorePattern);
2381 
2382  QStandardItemModel model2;
2383  model2.appendRow(new QStandardItem("otherTopLevel"));
2384  topLevelIndex = model2.index(0, 0);
2385  QVERIFY(topLevelIndex.isValid());
2386  QVERIFY(model2.checkIndex(topLevelIndex));
2390 
2391  QTest::ignoreMessage(QtWarningMsg, ignorePattern);
2392  QVERIFY(!model.checkIndex(topLevelIndex));
2393  QTest::ignoreMessage(QtWarningMsg, ignorePattern);
2395  QTest::ignoreMessage(QtWarningMsg, ignorePattern);
2397  QTest::ignoreMessage(QtWarningMsg, ignorePattern);
2399 }
2400 
2401 template <typename T>
2402 inline constexpr bool CanConvertToSpan = std::is_convertible_v<T, QModelRoleDataSpan>;
2403 
2404 void tst_QAbstractItemModel::modelRoleDataSpanConstruction()
2405 {
2406  // Compile time test
2407  static_assert(CanConvertToSpan<QModelRoleData &>);
2408  static_assert(CanConvertToSpan<QModelRoleData (&)[123]>);
2409  static_assert(CanConvertToSpan<QVector<QModelRoleData> &>);
2411  static_assert(CanConvertToSpan<std::vector<QModelRoleData> &>);
2412  static_assert(CanConvertToSpan<std::array<QModelRoleData, 123> &>);
2413 
2414  static_assert(!CanConvertToSpan<QModelRoleData>);
2415  static_assert(!CanConvertToSpan<QVector<QModelRoleData>>);
2416  static_assert(!CanConvertToSpan<const QVector<QModelRoleData> &>);
2417  static_assert(!CanConvertToSpan<std::vector<QModelRoleData>>);
2418  static_assert(!CanConvertToSpan<std::deque<QModelRoleData>>);
2419  static_assert(!CanConvertToSpan<std::deque<QModelRoleData> &>);
2420  static_assert(!CanConvertToSpan<std::list<QModelRoleData> &>);
2421  static_assert(!CanConvertToSpan<std::list<QModelRoleData>>);
2422 }
2423 
2424 void tst_QAbstractItemModel::modelRoleDataSpan()
2425 {
2426  QModelRoleData data[3] = {
2430  };
2431  QModelRoleData *dataPtr = data;
2432 
2434 
2435  QCOMPARE(span.size(), 3);
2436  QCOMPARE(span.length(), 3);
2437  QCOMPARE(span.data(), dataPtr);
2438  QCOMPARE(span.begin(), dataPtr);
2439  QCOMPARE(span.end(), dataPtr + 3);
2440  for (int i = 0; i < 3; ++i)
2441  QCOMPARE(span[i].role(), data[i].role());
2442 
2443  data[0].setData(42);
2444  data[1].setData(QStringLiteral("a string"));
2445  data[2].setData(123.5);
2446 
2447  QCOMPARE(span.dataForRole(Qt::DisplayRole)->toInt(), 42);
2448  QCOMPARE(span.dataForRole(Qt::DecorationRole)->toString(), "a string");
2449  QCOMPARE(span.dataForRole(Qt::EditRole)->toDouble(), 123.5);
2450 }
2451 
2452 // model implementing data(), but not multiData(); check that the
2453 // default implementation of multiData() does the right thing
2455 {
2456  Q_OBJECT
2457 
2458 public:
2459  int rowCount(const QModelIndex &) const override
2460  {
2461  return 1000;
2462  }
2463 
2464  // We handle roles <= 10. All such roles return a QVariant(int) containing
2465  // the same value as the role, except for 10 which returns a string.
2466  QVariant data(const QModelIndex &index, int role) const override
2467  {
2469 
2470  if (role < 10)
2471  return QVariant::fromValue(role);
2472  else if (role == 10)
2473  return QVariant::fromValue(QStringLiteral("Hello!"));
2474 
2475  return QVariant();
2476  }
2477 };
2478 
2479 void tst_QAbstractItemModel::multiData()
2480 {
2481  QModelRoleData data[] = {
2482  QModelRoleData(1),
2483  QModelRoleData(42),
2484  QModelRoleData(5),
2485  QModelRoleData(2),
2486  QModelRoleData(12),
2487  QModelRoleData(2),
2488  QModelRoleData(10),
2489  QModelRoleData(-123)
2490  };
2491 
2493 
2494  for (const auto &roledata : span)
2495  QVERIFY(roledata.data().isNull());
2496 
2498  const QModelIndex index = model.index(0, 0);
2499  QVERIFY(index.isValid());
2500 
2501  const auto check = [&]() {
2502  for (auto &roledata : span) {
2503  const auto role = roledata.role();
2504  if (role < 10) {
2505  QVERIFY(!roledata.data().isNull());
2506  QVERIFY(roledata.data().userType() == qMetaTypeId<int>());
2507  QCOMPARE(roledata.data().toInt(), role);
2508  } else if (role == 10) {
2509  QVERIFY(!roledata.data().isNull());
2510  QVERIFY(roledata.data().userType() == qMetaTypeId<QString>());
2511  QCOMPARE(roledata.data().toString(), QStringLiteral("Hello!"));
2512  } else {
2513  QVERIFY(roledata.data().isNull());
2514  }
2515  }
2516  };
2517 
2519  check();
2520 
2522  check();
2523 
2524  for (auto &roledata : span)
2525  roledata.clearData();
2526 
2528  check();
2529 }
2530 
2532 #include "tst_qabstractitemmodel.moc"
small capitals from c petite p scientific i
[1]
Definition: afcover.h:80
FT_UInt idx
Definition: cffcmap.c:135
CustomRoleModel(QObject *parent=nullptr)
int rowCount(const QModelIndex &index=QModelIndex()) const override
int columnCount(const QModelIndex &index=QModelIndex()) const override
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
ListenerObject(QAbstractProxyModel *parent)
void fillIndexStores(const QModelIndex &parent)
void setSecondAncestorRowNumbers(QList< int > rows)
void setNumCols(int cols)
void setStartRow(int row)
void setEndRow(int row)
void setAncestorRowNumbers(QList< int > rowNumbers)
virtual void doCommand() override
virtual void doCommand() override
void setDestRow(int row)
void setDestAncestors(QList< int > rows)
QHash< int, QByteArray > roleNames() const override
QVariant data(const QModelIndex &index, int role) const override
int rowCount(const QModelIndex &) const override
OverrideDropActions(QObject *parent=nullptr)
Qt::DropActions supportedDropActions() const override
OverrideRoleNamesAndDragActions(QObject *parent=nullptr)
Qt::DropActions supportedDragActions() const override
QHash< int, QByteArray > roleNames() const override
The QAbstractItemModel class provides the abstract interface for item model classes.
void rowsMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row, QPrivateSignal)
virtual Qt::DropActions supportedDropActions() const
void modelAboutToBeReset(QPrivateSignal)
virtual bool canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const
bool beginMoveRows(const QModelIndex &sourceParent, int sourceFirst, int sourceLast, const QModelIndex &destinationParent, int destinationRow)
virtual Q_INVOKABLE QModelIndexList match(const QModelIndex &start, int role, const QVariant &value, int hits=1, Qt::MatchFlags flags=Qt::MatchFlags(Qt::MatchStartsWith|Qt::MatchWrap)) const
void columnsRemoved(const QModelIndex &parent, int first, int last, QPrivateSignal)
void rowsAboutToBeInserted(const QModelIndex &parent, int first, int last, QPrivateSignal)
void columnsAboutToBeInserted(const QModelIndex &parent, int first, int last, QPrivateSignal)
Q_INVOKABLE bool hasIndex(int row, int column, const QModelIndex &parent=QModelIndex()) const
void modelReset(QPrivateSignal)
void beginRemoveColumns(const QModelIndex &parent, int first, int last)
void changePersistentIndex(const QModelIndex &from, const QModelIndex &to)
void layoutAboutToBeChanged(const QList< QPersistentModelIndex > &parents=QList< QPersistentModelIndex >(), QAbstractItemModel::LayoutChangeHint hint=QAbstractItemModel::NoLayoutChangeHint)
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList< int > &roles=QList< int >())
QObject * parent() const
Definition: qobject.h:409
bool insertRow(int row, const QModelIndex &parent=QModelIndex())
void columnsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationColumn, QPrivateSignal)
bool moveColumn(const QModelIndex &sourceParent, int sourceColumn, const QModelIndex &destinationParent, int destinationChild)
virtual bool moveColumns(const QModelIndex &sourceParent, int sourceColumn, int count, const QModelIndex &destinationParent, int destinationChild)
virtual bool removeRows(int row, int count, const QModelIndex &parent=QModelIndex())
void columnsAboutToBeRemoved(const QModelIndex &parent, int first, int last, QPrivateSignal)
void layoutChanged(const QList< QPersistentModelIndex > &parents=QList< QPersistentModelIndex >(), QAbstractItemModel::LayoutChangeHint hint=QAbstractItemModel::NoLayoutChangeHint)
bool insertColumn(int column, const QModelIndex &parent=QModelIndex())
bool checkIndex(const QModelIndex &index, CheckIndexOptions options=CheckIndexOption::NoOption) const
void columnsMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int column, QPrivateSignal)
virtual Q_INVOKABLE bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole)
void rowsAboutToBeRemoved(const QModelIndex &parent, int first, int last, QPrivateSignal)
bool beginMoveColumns(const QModelIndex &sourceParent, int sourceFirst, int sourceLast, const QModelIndex &destinationParent, int destinationColumn)
virtual QHash< int, QByteArray > roleNames() const
void beginInsertColumns(const QModelIndex &parent, int first, int last)
virtual QMap< int, QVariant > itemData(const QModelIndex &index) const
virtual bool insertRows(int row, int count, const QModelIndex &parent=QModelIndex())
virtual bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild)
virtual Qt::DropActions supportedDragActions() const
void rowsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow, QPrivateSignal)
void rowsInserted(const QModelIndex &parent, int first, int last, QPrivateSignal)
QModelIndex createIndex(int row, int column, const void *data=nullptr) const
void columnsInserted(const QModelIndex &parent, int first, int last, QPrivateSignal)
virtual void multiData(const QModelIndex &index, QModelRoleDataSpan roleDataSpan) const
void beginRemoveRows(const QModelIndex &parent, int first, int last)
virtual Q_INVOKABLE QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const =0
void beginInsertRows(const QModelIndex &parent, int first, int last)
void rowsRemoved(const QModelIndex &parent, int first, int last, QPrivateSignal)
The QAbstractListModel class provides an abstract model that can be subclassed to create one-dimensio...
QModelIndex index(int row, int column=0, const QModelIndex &parent=QModelIndex()) const override
QObject * parent() const
Definition: qobject.h:409
The QAbstractProxyModel class provides a base class for proxy item models that can do sorting,...
QHash< int, QByteArray > roleNames() const override
virtual Q_INVOKABLE QModelIndex mapToSource(const QModelIndex &proxyIndex) const =0
bool hasChildren(const QModelIndex &parent=QModelIndex()) const override
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
QObject * parent() const
Definition: qobject.h:409
Qt::ItemFlags flags(const QModelIndex &index) const override
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:85
bool contains(const Key &key) const noexcept
Definition: qhash.h:944
T value(const Key &key) const noexcept
Definition: qhash.h:997
iterator insert(const Key &key, const T &value)
Definition: qhash.h:1228
Definition: qlist.h:108
qsizetype size() const noexcept
Definition: qlist.h:414
T takeAt(qsizetype i)
Definition: qlist.h:607
const_reference at(qsizetype i) const noexcept
Definition: qlist.h:457
qsizetype count() const noexcept
Definition: qlist.h:415
T & first()
Definition: qlist.h:643
void append(parameter_type t)
Definition: qlist.h:469
Definition: qmap.h:222
T value(const Key &key, const T &defaultValue=T()) const
Definition: qmap.h:392
size_type count(const Key &key) const
Definition: qmap.h:439
The QMimeData class provides a container for data that records information about its MIME type.
Definition: qmimedata.h:52
The QModelIndex class is used to locate data in a data model.
constexpr int row() const noexcept
QModelIndex parent() const
constexpr const QAbstractItemModel * model() const noexcept
constexpr int column() const noexcept
constexpr bool isValid() const noexcept
QModelIndex sibling(int row, int column) const
The QModelRoleData class holds a role and the data associated to that role.
The QModelRoleDataSpan class provides a span over QModelRoleData objects.
The QObject class is the base class of all Qt objects.
Definition: qobject.h:125
QObject * parent() const
Definition: qobject.h:409
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
Definition: qobject.cpp:2772
The QPersistentModelIndex class is used to locate data in a data model.
The QRegularExpression class provides pattern matching using regular expressions.
The QSortFilterProxyModel class provides support for sorting and filtering data passed between anothe...
void setSourceModel(QAbstractItemModel *sourceModel) override
QVariant data(const QModelIndex &item, int role=Qt::DisplayRole) const override
int rowCount(const QModelIndex &parent=QModelIndex()) const override
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role=Qt::EditRole) override
QHash< int, QByteArray > roleNames() const override
bool insertColumns(int column, int count, const QModelIndex &parent=QModelIndex()) override
bool removeColumns(int column, int count, const QModelIndex &parent=QModelIndex()) override
The QStandardItem class provides an item for use with the QStandardItemModel class.
void removeRow(int row)
void appendRow(const QList< QStandardItem * > &items)
The QStandardItemModel class provides a generic model for storing custom data.\inmodule QtGui.
void appendRow(const QList< QStandardItem * > &items)
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
The QString class provides a Unicode character string.
Definition: qstring.h:388
static QString number(int, int base=10)
Definition: qstring.cpp:7538
The QStringList class provides a list of strings.
The QStringListModel class provides a model that supplies strings to views.
QStringListModel(QObject *parent=nullptr)
The QVariant class acts like a union for the most common Qt data types.
Definition: qvariant.h:95
static auto fromValue(const T &value) -> std::enable_if_t< std::is_copy_constructible_v< T >, QVariant >
Definition: qvariant.h:391
bool isValid() const
Definition: qvariant.h:582
int toInt(bool *ok=nullptr) const
Definition: qvariant.cpp:1833
QString toString() const
Definition: qvariant.cpp:1416
T value() const
Definition: qvariant.h:378
bool hasChildren(const QModelIndex &) const override
bool removeRows(int row, int count, const QModelIndex &parent=QModelIndex()) override
bool insertColumns(int column, int count, const QModelIndex &parent=QModelIndex()) override
bool canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const override
bool moveColumns(const QModelIndex &sourceParent, int sourceColumn, int count, const QModelIndex &destinationParent, int destinationChild) override
bool insertRows(int row, int count, const QModelIndex &parent=QModelIndex()) override
QList< QList< QString > > table
void setPersistent(const QModelIndex &from, const QModelIndex &to)
bool removeColumns(int column, int count, const QModelIndex &parent=QModelIndex()) override
int columnCount(const QModelIndex &parent) const override
QVariant data(const QModelIndex &idx, int) const override
bool setData(const QModelIndex &idx, const QVariant &value, int) override
QtTestModel(int rows, int columns, QObject *parent=nullptr)
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
int rowCount(const QModelIndex &parent) const override
bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild) override
SignalArgumentChecker(const QModelIndex &p1, const QModelIndex &p2, QObject *parent=nullptr)
void testSlotWithParam_3(const QModelIndex &idx, int start, int end)
SignalConnectionTester(QObject *parent=nullptr)
void testSlotWithParam_1(const QModelIndex &idx)
void testSlotWithParam_2(const QModelIndex &idx, int start)
map insert("Paris", "France")
QPixmap p2
QPixmap p1
[0]
double e
QCOMPARE(spy.count(), 1)
Q_TESTLIB_EXPORT QTestData & newRow(const char *dataTag)
Definition: qtestcase.cpp:2658
Q_TESTLIB_EXPORT void ignoreMessage(QtMsgType type, const char *message)
Definition: qtestcase.cpp:2292
@ Horizontal
Definition: qnamespace.h:124
@ TextAlignmentRole
Definition: qnamespace.h:1510
@ UserRole
Definition: qnamespace.h:1527
@ DecorationRole
Definition: qnamespace.h:1503
@ EditRole
Definition: qnamespace.h:1504
@ ToolTipRole
Definition: qnamespace.h:1505
@ DisplayRole
Definition: qnamespace.h:1502
DropAction
Definition: qnamespace.h:1484
@ CopyAction
Definition: qnamespace.h:1485
@ MoveAction
Definition: qnamespace.h:1486
@ ItemIsSelectable
Definition: qnamespace.h:1532
@ ItemIsEnabled
Definition: qnamespace.h:1537
@ MatchWildcard
Definition: qnamespace.h:1551
@ MatchCaseSensitive
Definition: qnamespace.h:1554
@ MatchExactly
Definition: qnamespace.h:1546
@ MatchFixedString
Definition: qnamespace.h:1552
@ MatchRegularExpression
Definition: qnamespace.h:1550
@ MatchEndsWith
Definition: qnamespace.h:1549
@ MatchContains
Definition: qnamespace.h:1547
@ MatchStartsWith
Definition: qnamespace.h:1548
action
Definition: devices.py:78
#define QByteArrayLiteral(str)
Definition: qbytearray.h:80
std::pair< T1, T2 > QPair
Definition: qcontainerfwd.h:56
EGLOutputLayerEXT EGLint EGLAttrib value
@ QtWarningMsg
Definition: qlogging.h:62
#define qWarning
Definition: qlogging.h:179
#define SLOT(a)
Definition: qobjectdefs.h:87
#define Q_ARG(type, data)
Definition: qobjectdefs.h:98
#define SIGNAL(a)
Definition: qobjectdefs.h:88
GLboolean GLboolean GLboolean b
GLint GLenum GLsizei GLsizei GLsizei depth
GLboolean r
[2]
GLboolean GLboolean GLboolean GLboolean a
[7]
GLuint index
[2]
GLuint GLuint end
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat s1
GLdouble GLdouble GLdouble GLdouble top
GLenum GLenum GLsizei count
GLenum src
GLenum GLenum dst
GLint GLint bottom
GLenum GLuint GLenum GLsizei const GLchar * buf
GLbitfield flags
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLuint start
GLenum GLenum GLsizei void GLsizei void * column
Definition: qopenglext.h:2747
GLboolean reset
Definition: qopenglext.h:2748
GLuint res
Definition: qopenglext.h:8867
const GLubyte * c
Definition: qopenglext.h:12701
GLenum GLenum GLsizei void * row
Definition: qopenglext.h:2747
GLenum GLenum GLsizei void GLsizei void void * span
Definition: qopenglext.h:2747
GLfloat GLfloat p
[1]
Definition: qopenglext.h:12698
GLenum GLenum GLsizei void * table
Definition: qopenglext.h:2745
#define Q_ASSERT(cond)
Definition: qrandom.cpp:84
#define QStringLiteral(str)
#define s3
#define s2
#define QTEST_MAIN(TestObject)
Definition: qtest.h:664
#define QFETCH(Type, name)
Definition: qtestcase.h:230
#define QVERIFY(statement)
Definition: qtestcase.h:64
#define Q_OBJECT
Definition: qtmetamacros.h:158
#define Q_SLOTS
Definition: qtmetamacros.h:80
#define slots
Definition: qtmetamacros.h:76
#define Q_ENUMS(x)
Definition: qtmetamacros.h:99
#define emit
Definition: qtmetamacros.h:85
QSqlQueryModel * model
[16]
Q_UNUSED(salary)
[21]
settings remove("monkey")
connect(quitButton, &QPushButton::clicked, &app, &QCoreApplication::quit, Qt::QueuedConnection)
QItemSelection * selection
[0]
QNetworkProxy proxy
[0]
The QLatin1Char class provides an 8-bit ASCII/Latin-1 character.
Definition: qchar.h:53
bool contains(const AT &t) const noexcept
Definition: qlist.h:78
static bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType, QGenericReturnArgument ret, QGenericArgument val0=QGenericArgument(nullptr), QGenericArgument val1=QGenericArgument(), QGenericArgument val2=QGenericArgument(), QGenericArgument val3=QGenericArgument(), QGenericArgument val4=QGenericArgument(), QGenericArgument val5=QGenericArgument(), QGenericArgument val6=QGenericArgument(), QGenericArgument val7=QGenericArgument(), QGenericArgument val8=QGenericArgument(), QGenericArgument val9=QGenericArgument())
Q_DECLARE_METATYPE(QAbstractItemModel::LayoutChangeHint)
QList< QList< QString > > StringTable
constexpr bool CanConvertToSpan
QList< QString > StringTableRow
QPair< int, int > Position
#define STRINGTABLE
QList< QPair< int, int > > Selection
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent