1
/****************************************************************************
2
**
3
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4
** All rights reserved.
5
** Contact: Nokia Corporation (qt-info@nokia.com)
6
**
7
** This file is part of the test suite of the Qt Toolkit.
8
**
9
** $QT_BEGIN_LICENSE:LGPL$
10
** GNU Lesser General Public License Usage
11
** This file may be used under the terms of the GNU Lesser General Public
12
** License version 2.1 as published by the Free Software Foundation and
13
** appearing in the file LICENSE.LGPL included in the packaging of this
14
** file. Please review the following information to ensure the GNU Lesser
15
** General Public License version 2.1 requirements will be met:
16
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17
**
18
** In addition, as a special exception, Nokia gives you certain additional
19
** rights. These rights are described in the Nokia Qt LGPL Exception
20
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21
**
22
** GNU General Public License Usage
23
** Alternatively, this file may be used under the terms of the GNU General
24
** Public License version 3.0 as published by the Free Software Foundation
25
** and appearing in the file LICENSE.GPL included in the packaging of this
26
** file. Please review the following information to ensure the GNU General
27
** Public License version 3.0 requirements will be met:
28
** http://www.gnu.org/copyleft/gpl.html.
29
**
30
** Other Usage
31
** Alternatively, this file may be used in accordance with the terms and
32
** conditions contained in a signed written agreement between you and Nokia.
33
**
34
**
35
**
36
**
37
**
38
** $QT_END_LICENSE$
39
**
40
****************************************************************************/
41
42
43
#include <QtTest/QtTest>
44
#include <QtCore/QtCore>
45
46
#include <QtGui/QSortFilterProxyModel>
47
48
//TESTED_CLASS=QAbstractListModel QAbstractTableModel
49
//TESTED_FILES=
50
51
#include "dynamictreemodel.h"
52
53
Q_DECLARE_METATYPE(QModelIndex)
54
55
/*!
56
    Note that this doesn't test models, but any functionality that QAbstractItemModel shoudl provide
57
 */
58
class tst_QAbstractItemModel : public QObject
59
{
60
    Q_OBJECT
61
62
public:
63
    tst_QAbstractItemModel();
64
    virtual ~tst_QAbstractItemModel();
65
66
public slots:
67
    void initTestCase();
68
    void cleanupTestCase();
69
    void init();
70
    void cleanup();
71
72
private slots:
73
    void index();
74
    void parent();
75
    void hasChildren();
76
    void _data();
77
    void headerData();
78
    void itemData();
79
    void itemFlags();
80
    void match();
81
    void dropMimeData_data();
82
    void dropMimeData();
83
    void changePersistentIndex();
84
    void movePersistentIndex();
85
86
    void insertRows();
87
    void insertColumns();
88
    void removeRows();
89
    void removeColumns();
90
91
    void reset();
92
93
    void complexChangesWithPersistent();
94
95
    void testMoveSameParentUp_data();
96
    void testMoveSameParentUp();
97
98
    void testMoveSameParentDown_data();
99
    void testMoveSameParentDown();
100
101
    void testMoveToGrandParent_data();
102
    void testMoveToGrandParent();
103
104
    void testMoveToSibling_data();
105
    void testMoveToSibling();
106
107
    void testMoveToUncle_data();
108
    void testMoveToUncle();
109
110
    void testMoveToDescendants();
111
112
    void testMoveWithinOwnRange_data();
113
    void testMoveWithinOwnRange();
114
115
    void testMoveThroughProxy();
116
117
    void testReset();
118
119
120
private:
121
    DynamicTreeModel *m_model;
122
123
};
124
125
/*!
126
    Test model that impliments the pure vitual functions and anything else that is
127
    needed.
128
129
    It is a table implimented as a vector of vectors of strings.
130
 */
131
class QtTestModel: public QAbstractItemModel
132
{
133
public:
134
    QtTestModel(int rows, int columns, QObject *parent = 0);
135
    QtTestModel(const QVector<QVector<QString> > tbl, QObject *parent = 0);
136
    QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
137
    QModelIndex parent(const QModelIndex &) const;
138
    int rowCount(const QModelIndex &parent) const;
139
    int columnCount(const QModelIndex &parent) const;
140
    bool hasChildren(const QModelIndex &) const;
141
    QVariant data(const QModelIndex &idx, int) const;
142
    bool setData(const QModelIndex &idx, const QVariant &value, int);
143
    bool insertRows(int row, int count, const QModelIndex &parent= QModelIndex());
144
    bool insertColumns(int column, int count, const QModelIndex &parent= QModelIndex());
145
    void setPersistent(const QModelIndex &from, const QModelIndex &to);
146
    bool removeRows ( int row, int count, const QModelIndex & parent = QModelIndex() );
147
    bool removeColumns( int column, int count, const QModelIndex & parent = QModelIndex());
148
    void reset();
149
150
    int cCount, rCount;
151
    mutable bool wrongIndex;
152
    QVector<QVector<QString> > table;
153
};
154
155
QtTestModel::QtTestModel(int rows, int columns, QObject *parent)
156
    : QAbstractItemModel(parent), cCount(columns), rCount(rows), wrongIndex(false) {
157
158
    table.resize(rows);
159
    for (int r = 0; r < rows; ++r) {
160
        table[r].resize(columns);
161
        for (int c = 0; c < columns; ++c)
162
            table[r][c] = QString("%1/%2").arg(r).arg(c);
163
    }
164
}
165
166
QtTestModel::QtTestModel(const QVector<QVector<QString> > tbl, QObject *parent)
167
    : QAbstractItemModel(parent), wrongIndex(false) {
168
    table = tbl;
169
    rCount = tbl.count();
170
    cCount = tbl.at(0).count();
171
}
172
173
QModelIndex QtTestModel::index(int row, int column, const QModelIndex &parent) const
174
        { return hasIndex(row, column, parent) ? createIndex(row, column, 0) : QModelIndex(); }
175
176
QModelIndex QtTestModel::parent(const QModelIndex &) const { return QModelIndex(); }
177
int QtTestModel::rowCount(const QModelIndex &parent) const { return parent.isValid() ? 0 : rCount; }
178
int QtTestModel::columnCount(const QModelIndex &parent) const { return parent.isValid() ? 0 : cCount; }
179
bool QtTestModel::hasChildren(const QModelIndex &) const { return false; }
180
181
QVariant QtTestModel::data(const QModelIndex &idx, int) const
182
{
183
    if (idx.row() < 0 || idx.column() < 0 || idx.column() > cCount || idx.row() > rCount) {
184
        wrongIndex = true;
185
        qWarning("got invalid modelIndex %d/%d", idx.row(), idx.column());
186
        return QVariant();
187
    }
188
    return table.at(idx.row()).at(idx.column());
189
}
190
191
bool QtTestModel::setData(const QModelIndex &idx, const QVariant &value, int)
192
{
193
    table[idx.row()][idx.column()] = value.toString();
194
    return true;
195
}
196
197
bool QtTestModel::insertRows(int row, int count, const QModelIndex &parent)
198
{
199
    QAbstractItemModel::beginInsertRows(parent, row, row + count - 1);
200
    int cc = columnCount(parent);
201
    table.insert(row, count, QVector<QString>(cc));
202
    rCount = table.count();
203
    QAbstractItemModel::endInsertRows();
204
    return true;
205
}
206
207
bool QtTestModel::insertColumns(int column, int count, const QModelIndex &parent)
208
{
209
    QAbstractItemModel::beginInsertColumns(parent, column, column + count - 1);
210
    int rc = rowCount(parent);
211
    for (int i = 0; i < rc; ++i)
212
        table[i].insert(column, 1, "");
213
    cCount = table.at(0).count();
214
    QAbstractItemModel::endInsertColumns();
215
    return true;
216
}
217
218
void QtTestModel::setPersistent(const QModelIndex &from, const QModelIndex &to)
219
{
220
    changePersistentIndex(from, to);
221
}
222
223
bool QtTestModel::removeRows( int row, int count, const QModelIndex & parent)
224
{
225
    QAbstractItemModel::beginRemoveRows(parent, row, row + count - 1);
226
227
    for (int r = row+count-1; r >= row; --r)
228
        table.remove(r);
229
    rCount = table.count();
230
231
    QAbstractItemModel::endRemoveRows();
232
    return true;
233
}
234
235
bool QtTestModel::removeColumns(int column, int count, const QModelIndex & parent)
236
{
237
    QAbstractItemModel::beginRemoveColumns(parent, column, column + count - 1);
238
239
    for (int c = column+count-1; c > column; --c)
240
        for (int r = 0; r < rCount; ++r)
241
            table[r].remove(c);
242
243
    cCount = table.at(0).count();
244
245
    QAbstractItemModel::endRemoveColumns();
246
    return true;
247
}
248
249
void QtTestModel::reset()
250
{
251
    QAbstractItemModel::reset();
252
}
253
254
tst_QAbstractItemModel::tst_QAbstractItemModel()
255
{
256
}
257
258
tst_QAbstractItemModel::~tst_QAbstractItemModel()
259
{
260
}
261
262
/**
263
 * The source Model *must* be initialized before the _data function, since the _data function uses QModelIndexes to reference the items in the tables.
264
 * Therefore, we must initialize it globally.
265
 */
266
267
void tst_QAbstractItemModel::initTestCase()
268
{
269
    qRegisterMetaType<QModelIndex>("QModelIndex");
270
}
271
272
void tst_QAbstractItemModel::cleanupTestCase()
273
{
274
275
}
276
277
void tst_QAbstractItemModel::init()
278
{
279
    m_model = new DynamicTreeModel(this);
280
281
    ModelInsertCommand *insertCommand = new ModelInsertCommand(m_model, this);
282
    insertCommand->setNumCols(4);
283
    insertCommand->setStartRow(0);
284
    insertCommand->setEndRow(9);
285
    insertCommand->doCommand();
286
287
    insertCommand = new ModelInsertCommand(m_model, this);
288
    insertCommand->setAncestorRowNumbers(QList<int>() << 5);
289
    insertCommand->setNumCols(4);
290
    insertCommand->setStartRow(0);
291
    insertCommand->setEndRow(9);
292
    insertCommand->doCommand();
293
}
294
295
void tst_QAbstractItemModel::cleanup()
296
{
297
298
}
299
300
/*
301
  tests
302
*/
303
304
void tst_QAbstractItemModel::index()
305
{
306
    QtTestModel model(1, 1);
307
    QModelIndex idx = model.index(0, 0, QModelIndex());
308
    QVERIFY(idx.isValid());
309
}
310
311
void tst_QAbstractItemModel::parent()
312
{
313
    QtTestModel model(1, 1);
314
    QModelIndex idx = model.index(0, 0, QModelIndex());
315
    QModelIndex par = model.parent(idx);
316
    QVERIFY(!par.isValid());
317
}
318
319
void tst_QAbstractItemModel::hasChildren()
320
{
321
    QtTestModel model(1, 1);
322
    QModelIndex idx = model.index(0, 0, QModelIndex());
323
    QVERIFY(model.hasChildren(idx) == false);
324
}
325
326
void tst_QAbstractItemModel::_data()
327
{
328
    QtTestModel model(1, 1);
329
    QModelIndex idx = model.index(0, 0, QModelIndex());
330
    QVERIFY(idx.isValid());
331
    QCOMPARE(model.data(idx, Qt::DisplayRole).toString(), QString("0/0"));
332
333
    // Default does nothing
334
    QCOMPARE(model.setHeaderData(0, Qt::Horizontal, QVariant(0), 0), false);
335
}
336
337
void tst_QAbstractItemModel::headerData()
338
{
339
    QtTestModel model(1, 1);
340
    QCOMPARE(model.headerData(0, Qt::Horizontal, Qt::DisplayRole).toString(),
341
            QString("1"));
342
343
    // Default text alignment for header must be invalid
344
    QVERIFY( !model.headerData(0, Qt::Horizontal, Qt::TextAlignmentRole).isValid() );
345
}
346
347
void tst_QAbstractItemModel::itemData()
348
{
349
    QtTestModel model(1, 1);
350
    QModelIndex idx = model.index(0, 0, QModelIndex());
351
    QVERIFY(idx.isValid());
352
    QMap<int, QVariant> dat = model.itemData(idx);
353
    QCOMPARE(dat.count(Qt::DisplayRole), 1);
354
    QCOMPARE(dat.value(Qt::DisplayRole).toString(), QString("0/0"));
355
}
356
357
void tst_QAbstractItemModel::itemFlags()
358
{
359
    QtTestModel model(1, 1);
360
    QModelIndex idx = model.index(0, 0, QModelIndex());
361
    QVERIFY(idx.isValid());
362
    Qt::ItemFlags flags = model.flags(idx);
363
    QCOMPARE(Qt::ItemIsSelectable|Qt::ItemIsEnabled, flags);
364
}
365
366
void tst_QAbstractItemModel::match()
367
{
368
    QtTestModel model(4, 1);
369
    QModelIndex start = model.index(0, 0, QModelIndex());
370
    QVERIFY(start.isValid());
371
    QModelIndexList res = model.match(start, Qt::DisplayRole, QVariant("1"), 3);
372
    QCOMPARE(res.count(), 1);
373
    QModelIndex idx = model.index(1, 0, QModelIndex());
374
    bool areEqual = (idx == res.first());
375
    QVERIFY(areEqual);
376
377
    model.setData(model.index(0, 0, QModelIndex()), "bat", Qt::DisplayRole);
378
    model.setData(model.index(1, 0, QModelIndex()), "cat", Qt::DisplayRole);
379
    model.setData(model.index(2, 0, QModelIndex()), "dog", Qt::DisplayRole);
380
    model.setData(model.index(3, 0, QModelIndex()), "boar", Qt::DisplayRole);
381
382
    res = model.match(start, Qt::DisplayRole, QVariant("dog"), -1, Qt::MatchExactly);
383
    QCOMPARE(res.count(), 1);
384
    res = model.match(start, Qt::DisplayRole, QVariant("a"), -1, Qt::MatchContains);
385
    QCOMPARE(res.count(), 3);
386
    res = model.match(start, Qt::DisplayRole, QVariant("b"), -1, Qt::MatchStartsWith);
387
    QCOMPARE(res.count(), 2);
388
    res = model.match(start, Qt::DisplayRole, QVariant("t"), -1, Qt::MatchEndsWith);
389
    QCOMPARE(res.count(), 2);
390
    res = model.match(start, Qt::DisplayRole, QVariant("*a*"), -1, Qt::MatchWildcard);
391
    QCOMPARE(res.count(), 3);
392
    res = model.match(start, Qt::DisplayRole, QVariant(".*O.*"), -1, Qt::MatchRegExp);
393
    QCOMPARE(res.count(), 2);
394
    res = model.match(start, Qt::DisplayRole, QVariant(".*O.*"), -1, Qt::MatchRegExp | Qt::MatchCaseSensitive);
395
    QCOMPARE(res.count(), 0);
396
    res = model.match(start, Qt::DisplayRole, QVariant("BOAR"), -1, Qt::MatchFixedString);
397
    QCOMPARE(res.count(), 1);
398
    res = model.match(start, Qt::DisplayRole, QVariant("bat"), -1,
399
                      Qt::MatchFixedString | Qt::MatchCaseSensitive);
400
    QCOMPARE(res.count(), 1);
401
}
402
403
typedef QPair<int, int> Position;
404
typedef QVector<QPair<int, int> > Selection;
405
typedef QVector<QVector<QString> > StringTable;
406
typedef QVector<QString> StringTableRow;
407
Q_DECLARE_METATYPE(Position)
408
Q_DECLARE_METATYPE(Selection)
409
Q_DECLARE_METATYPE(StringTable)
410
411
static StringTableRow qStringTableRow(const QString &s1, const QString &s2, const QString &s3)
412
{
413
    StringTableRow row;
414
    row << s1 << s2 << s3;
415
    return row;
416
}
417
418
#ifdef Q_CC_MSVC
419
# define STRINGTABLE (StringTable())
420
#else
421
# define STRINGTABLE StringTable()
422
#endif
423
424
void tst_QAbstractItemModel::dropMimeData_data()
425
{
426
    QTest::addColumn<StringTable>("src_table"); // drag source
427
    QTest::addColumn<StringTable>("dst_table"); // drop target
428
    QTest::addColumn<Selection>("selection"); // dragged items
429
    QTest::addColumn<Position>("dst_position"); // drop position
430
    QTest::addColumn<StringTable>("res_table"); // expected result
431
432
    {
433
        QTest::newRow("2x2 dropped at [0, 0]")
434
            << (STRINGTABLE // source table
435
                << (qStringTableRow("A", "B", "C"))
436
                << (qStringTableRow("D", "E", "F")))
437
            << (STRINGTABLE // destination table
438
                << (qStringTableRow("0", "1", "2"))
439
                << (qStringTableRow("3", "4", "5")))
440
            << (Selection() // selection
441
                << Position(0, 0) << Position(0, 1)
442
                << Position(1, 0) << Position(1, 1))
443
            << Position(0, 0) // drop position
444
            << (STRINGTABLE // resulting table
445
                << (qStringTableRow("A", "B", "" ))
446
                << (qStringTableRow("D", "E", "" ))
447
                << (qStringTableRow("0", "1", "2"))
448
                << (qStringTableRow("3", "4", "5")));
449
    }
450
451
    {
452
        QTest::newRow("2x2 dropped at [1, 0]")
453
            << (STRINGTABLE // source table
454
                << (qStringTableRow("A", "B", "C"))
455
                << (qStringTableRow("D", "E", "F")))
456
            << (STRINGTABLE // destination table
457
                << (qStringTableRow("0", "1", "2"))
458
                << (qStringTableRow("3", "4", "5")))
459
            << (Selection() // selection
460
                << Position(0, 0) << Position(0, 1)
461
                << Position(1, 0) << Position(1, 1))
462
            << Position(1, 0) // drop position
463
            << (STRINGTABLE // resulting table
464
                << (qStringTableRow("0", "1", "2"))
465
                << (qStringTableRow("A", "B", "" ))
466
                << (qStringTableRow("D", "E", "" ))
467
                << (qStringTableRow("3", "4", "5")));
468
    }
469
470
    {
471
        QTest::newRow("2x2 dropped at [3, 0]")
472
            << (STRINGTABLE // source table
473
                << (qStringTableRow("A", "B", "C"))
474
                << (qStringTableRow("D", "E", "F")))
475
            << (STRINGTABLE // destination table
476
                << (qStringTableRow("0", "1", "2"))
477
                << (qStringTableRow("3", "4", "5")))
478
            << (Selection() // selection
479
                << Position(0, 0) << Position(0, 1)
480
                << Position(1, 0) << Position(1, 1))
481
            << Position(3, 0) // drop position
482
            << (STRINGTABLE // resulting table
483
                << (qStringTableRow("0", "1", "2"))
484
                << (qStringTableRow("3", "4", "5"))
485
                << (qStringTableRow("A", "B", "" ))
486
                << (qStringTableRow("D", "E", "" )));
487
    }
488
489
    {
490
        QTest::newRow("2x2 dropped at [0, 1]")
491
            << (STRINGTABLE // source table
492
                << (qStringTableRow("A", "B", "C"))
493
                << (qStringTableRow("D", "E", "F")))
494
            << (STRINGTABLE // destination table
495
                << (qStringTableRow("0", "1", "2"))
496
                << (qStringTableRow("3", "4", "5")))
497
            << (Selection() // selection
498
                << Position(0, 0) << Position(0, 1)
499
                << Position(1, 0) << Position(1, 1))
500
            << Position(0, 1) // drop position
501
            << (STRINGTABLE // resulting table
502
                << (qStringTableRow("" , "A", "B"))
503
                << (qStringTableRow("" , "D", "E"))
504
                << (qStringTableRow("0", "1", "2"))
505
                << (qStringTableRow("3", "4", "5")));
506
    }
507
508
    {
509
        QTest::newRow("2x2 dropped at [0, 2] (line break)")
510
            << (STRINGTABLE // source table
511
                << (qStringTableRow("A", "B", "C"))
512
                << (qStringTableRow("D", "E", "F")))
513
            << (STRINGTABLE // destination table
514
                << (qStringTableRow("0", "1", "2"))
515
                << (qStringTableRow("3", "4", "5")))
516
            << (Selection() // selection
517
                << Position(0, 0) << Position(0, 1)
518
                << Position(1, 0) << Position(1, 1))
519
            << Position(0, 2) // drop position
520
            << (STRINGTABLE // resulting table
521
                << (qStringTableRow("" , "" , "A"))
522
                << (qStringTableRow("" , "" , "D"))
523
                << (qStringTableRow("" , "" , "B"))
524
                << (qStringTableRow("" , "" , "E"))
525
                << (qStringTableRow("0", "1", "2"))
526
                << (qStringTableRow("3", "4", "5")));
527
    }
528
529
    {
530
        QTest::newRow("2x2 dropped at [3, 2] (line break)")
531
            << (STRINGTABLE // source table
532
                << (qStringTableRow("A", "B", "C"))
533
                << (qStringTableRow("D", "E", "F")))
534
            << (STRINGTABLE // destination table
535
                << (qStringTableRow("0", "1", "2"))
536
                << (qStringTableRow("3", "4", "5")))
537
            << (Selection() // selection
538
                << Position(0, 0) << Position(0, 1)
539
                << Position(1, 0) << Position(1, 1))
540
            << Position(3, 2) // drop position
541
            << (STRINGTABLE // resulting table
542
                << (qStringTableRow("0", "1", "2"))
543
                << (qStringTableRow("3", "4", "5"))
544
                << (qStringTableRow("" , "" , "A"))
545
                << (qStringTableRow("" , "" , "D"))
546
                << (qStringTableRow("" , "" , "B"))
547
                << (qStringTableRow("" , "" , "E")));
548
    }
549
550
    {
551
        QTest::newRow("non-square dropped at [0, 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))
561
            << Position(0, 0) // drop position
562
            << (STRINGTABLE // resulting table
563
                << (qStringTableRow("A", "B", "" ))
564
                << (qStringTableRow("D", "" , "" ))
565
                << (qStringTableRow("0", "1", "2"))
566
                << (qStringTableRow("3", "4", "5")));
567
    }
568
569
    {
570
        QTest::newRow("non-square dropped at [0, 2]")
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))
580
            << Position(0, 2) // drop position
581
            << (STRINGTABLE // resulting table
582
                << (qStringTableRow("" , "" , "A"))
583
                << (qStringTableRow("" , "" , "D"))
584
                << (qStringTableRow("" , "" , "B"))
585
                << (qStringTableRow("0", "1", "2"))
586
                << (qStringTableRow("3", "4", "5")));
587
    }
588
589
    {
590
        QTest::newRow("2x 1x2 dropped at [0, 0] (duplicates)")
591
            << (STRINGTABLE // source table
592
                << (qStringTableRow("A", "B", "C"))
593
                << (qStringTableRow("D", "E", "F")))
594
            << (STRINGTABLE // destination table
595
                << (qStringTableRow("0", "1", "2"))
596
                << (qStringTableRow("3", "4", "5")))
597
            << (Selection() // selection; 2x the same row (to simulate selections in hierarchy)
598
                << Position(0, 0) << Position(0, 1)
599
                << Position(0, 0) << Position(0, 1))
600
            << Position(0, 0) // drop position
601
            << (STRINGTABLE // resulting table
602
                << (qStringTableRow("A", "B", "" ))
603
                << (qStringTableRow("A", "" , "" ))
604
                << (qStringTableRow("" , "B", "" )) // ### FIXME: strange behavior, but rare case
605
                << (qStringTableRow("0", "1", "2"))
606
                << (qStringTableRow("3", "4", "5")));
607
    }
608
609
    {
610
        QTest::newRow("2x 1x2 dropped at [3, 2] (duplicates)")
611
            << (STRINGTABLE // source table
612
                << (qStringTableRow("A", "B", "C"))
613
                << (qStringTableRow("D", "E", "F")))
614
            << (STRINGTABLE // destination table
615
                << (qStringTableRow("0", "1", "2"))
616
                << (qStringTableRow("3", "4", "5")))
617
            << (Selection() // selection; 2x the same row (to simulate selections in hierarchy)
618
                << Position(0, 0) << Position(0, 1)
619
                << Position(0, 0) << Position(0, 1))
620
            << Position(3, 2) // drop position
621
            << (STRINGTABLE // resulting table
622
                << (qStringTableRow("0", "1", "2"))
623
                << (qStringTableRow("3", "4", "5"))
624
                << (qStringTableRow("" , "" , "A"))
625
                << (qStringTableRow("" , "" , "B"))
626
                << (qStringTableRow("" , "" , "A"))
627
                << (qStringTableRow("" , "" , "B")));
628
    }
629
    {
630
        QTest::newRow("2x 1x2 dropped at [3, 2] (different rows)")
631
            << (STRINGTABLE // source table
632
                << (qStringTableRow("A", "B", "C"))
633
                << (qStringTableRow("D", "E", "F"))
634
                << (qStringTableRow("G", "H", "I")))
635
            << (STRINGTABLE // destination table
636
                << (qStringTableRow("0", "1", "2"))
637
                << (qStringTableRow("3", "4", "5")))
638
            << (Selection() // selection; 2x the same row (to simulate selections in hierarchy)
639
                << Position(0, 0) << Position(0, 1)
640
                << Position(2, 0) << Position(2, 1))
641
            << Position(2, 1) // drop position
642
            << (STRINGTABLE // resulting table
643
                << (qStringTableRow("0", "1", "2"))
644
                << (qStringTableRow("3", "4", "5"))
645
                << (qStringTableRow("" , "A" , "B"))
646
                << (qStringTableRow("" , "G" , "H")));
647
    }
648
649
    {
650
        QTest::newRow("2x 1x2 dropped at [3, 2] (different rows, over the edge)")
651
            << (STRINGTABLE // source table
652
                << (qStringTableRow("A", "B", "C"))
653
                << (qStringTableRow("D", "E", "F"))
654
                << (qStringTableRow("G", "H", "I")))
655
            << (STRINGTABLE // destination table
656
                << (qStringTableRow("0", "1", "2"))
657
                << (qStringTableRow("3", "4", "5")))
658
            << (Selection() // selection; 2x the same row (to simulate selections in hierarchy)
659
                << Position(0, 0) << Position(0, 1)
660
                << Position(2, 0) << Position(2, 1))
661
            << Position(3, 2) // drop position
662
            << (STRINGTABLE // resulting table
663
                << (qStringTableRow("0", "1", "2"))
664
                << (qStringTableRow("3", "4", "5"))
665
                << (qStringTableRow("" , "" , "A"))
666
                << (qStringTableRow("" , "" , "G"))
667
                << (qStringTableRow("" , "" , "B"))
668
                << (qStringTableRow("" , "" , "H")));
669
    }
670
}
671
672
void tst_QAbstractItemModel::dropMimeData()
673
{
674
    QFETCH(StringTable, src_table);
675
    QFETCH(StringTable, dst_table);
676
    QFETCH(Selection, selection);
677
    QFETCH(Position, dst_position);
678
    QFETCH(StringTable, res_table);
679
680
    QtTestModel src(src_table);
681
    QtTestModel dst(dst_table);
682
    QtTestModel res(res_table);
683
684
//     qDebug() << "src" << src.rowCount(QModelIndex()) << src.columnCount(QModelIndex());
685
//     qDebug() << "dst" << dst.rowCount(QModelIndex()) << dst.columnCount(QModelIndex());
686
//     qDebug() << "res" << res.rowCount(QModelIndex()) << res.columnCount(QModelIndex());
687
688
    // get the mimeData from the "selected" indexes
689
    QModelIndexList selectedIndexes;
690
    for (int i = 0; i < selection.count(); ++i)
691
        selectedIndexes << src.index(selection.at(i).first, selection.at(i).second, QModelIndex());
692
    QMimeData *md = src.mimeData(selectedIndexes);
693
    // do the drop
694
    dst.dropMimeData(md, Qt::CopyAction, dst_position.first, dst_position.second, QModelIndex());
695
    delete md;
696
697
    // compare to the expected results
698
    QCOMPARE(dst.rowCount(QModelIndex()), res.rowCount(QModelIndex()));
699
    QCOMPARE(dst.columnCount(QModelIndex()), res.columnCount(QModelIndex()));
700
    for (int r = 0; r < dst.rowCount(QModelIndex()); ++r) {
701
        for (int c = 0; c < dst.columnCount(QModelIndex()); ++c) {
702
            QModelIndex dst_idx = dst.index(r, c, QModelIndex());
703
            QModelIndex res_idx = res.index(r, c, QModelIndex());
704
            QMap<int, QVariant> dst_data = dst.itemData(dst_idx);
705
            QMap<int, QVariant> res_data = res.itemData(res_idx);
706
            //if(dst_data != res_data)
707
            //    qDebug() << r << c << dst_data.value(0).toString() << res_data.value(0).toString();
708
            QCOMPARE(dst_data , res_data);
709
        }
710
    }
711
712
}
713
714
715
void tst_QAbstractItemModel::changePersistentIndex()
716
{
717
    QtTestModel model(3, 3);
718
    QModelIndex a = model.index(1, 2, QModelIndex());
719
    QModelIndex b = model.index(2, 1, QModelIndex());
720
    QPersistentModelIndex p(a);
721
    QVERIFY(p == a);
722
    model.setPersistent(a, b);
723
    QVERIFY(p == b);
724
}
725
726
void tst_QAbstractItemModel::movePersistentIndex()
727
{
728
    QtTestModel model(3, 3);
729
730
    QPersistentModelIndex a = model.index(1, 1);
731
    QVERIFY(a.isValid());
732
    QCOMPARE(a.row(), 1);
733
    QCOMPARE(a.column(), 1);
734
735
    model.insertRow(0);
736
    QCOMPARE(a.row(), 2);
737
738
    model.insertRow(1);
739
    QCOMPARE(a.row(), 3);
740
741
    model.insertColumn(0);
742
    QCOMPARE(a.column(), 2);
743
}
744
745
void tst_QAbstractItemModel::removeRows()
746
{
747
    QtTestModel model(10, 10);
748
749
    QSignalSpy rowsAboutToBeRemovedSpy(&model, SIGNAL(rowsAboutToBeRemoved( const QModelIndex &, int , int )));
750
    QSignalSpy rowsRemovedSpy(&model, SIGNAL(rowsRemoved( const QModelIndex &, int, int )));
751
752
    QCOMPARE(model.removeRows(6, 4), true);
753
    QCOMPARE(rowsAboutToBeRemovedSpy.count(), 1);
754
    QCOMPARE(rowsRemovedSpy.count(), 1);
755
}
756
757
void tst_QAbstractItemModel::removeColumns()
758
{
759
    QtTestModel model(10, 10);
760
761
    QSignalSpy columnsAboutToBeRemovedSpy(&model, SIGNAL(columnsAboutToBeRemoved( const QModelIndex &, int , int )));
762
    QSignalSpy columnsRemovedSpy(&model, SIGNAL(columnsRemoved( const QModelIndex &, int, int )));
763
764
    QCOMPARE(model.removeColumns(6, 4), true);
765
    QCOMPARE(columnsAboutToBeRemovedSpy.count(), 1);
766
    QCOMPARE(columnsRemovedSpy.count(), 1);
767
}
768
769
void tst_QAbstractItemModel::insertRows()
770
{
771
    QtTestModel model(10, 10);
772
773
    QSignalSpy rowsAboutToBeInsertedSpy(&model, SIGNAL(rowsAboutToBeInserted( const QModelIndex &, int , int )));
774
    QSignalSpy rowsInsertedSpy(&model, SIGNAL(rowsInserted( const QModelIndex &, int, int )));
775
776
    QCOMPARE(model.insertRows(6, 4), true);
777
    QCOMPARE(rowsAboutToBeInsertedSpy.count(), 1);
778
    QCOMPARE(rowsInsertedSpy.count(), 1);
779
}
780
781
void tst_QAbstractItemModel::insertColumns()
782
{
783
    QtTestModel model(10, 10);
784
785
    QSignalSpy columnsAboutToBeInsertedSpy(&model, SIGNAL(columnsAboutToBeInserted( const QModelIndex &, int , int )));
786
    QSignalSpy columnsInsertedSpy(&model, SIGNAL(columnsInserted( const QModelIndex &, int, int )));
787
788
    QCOMPARE(model.insertColumns(6, 4), true);
789
    QCOMPARE(columnsAboutToBeInsertedSpy.count(), 1);
790
    QCOMPARE(columnsInsertedSpy.count(), 1);
791
}
792
793
void tst_QAbstractItemModel::reset()
794
{
795
    QtTestModel model(10, 10);
796
797
    QSignalSpy resetSpy(&model, SIGNAL(modelReset()));
798
    model.reset();
799
    QCOMPARE(resetSpy.count(), 1);
800
}
801
802
void tst_QAbstractItemModel::complexChangesWithPersistent()
803
{
804
    QtTestModel model(10, 10);
805
    QPersistentModelIndex a = model.index(1, 1, QModelIndex());
806
    QPersistentModelIndex b = model.index(9, 7, QModelIndex());
807
    QPersistentModelIndex c = model.index(5, 6, QModelIndex());
808
    QPersistentModelIndex d = model.index(3, 9, QModelIndex());
809
    QPersistentModelIndex e[10];
810
    for (int i=0; i <10 ; i++) {
811
        e[i] = model.index(2, i , QModelIndex());
812
    }
813
814
    QVERIFY(a == model.index(1, 1, QModelIndex()));
815
    QVERIFY(b == model.index(9, 7, QModelIndex()));
816
    QVERIFY(c == model.index(5, 6, QModelIndex()));
817
    QVERIFY(d == model.index(3, 9, QModelIndex()));
818
    for (int i=0; i <8 ; i++)
819
        QVERIFY(e[i] == model.index(2, i , QModelIndex()));
820
821
    //remove a bunch of columns
822
    model.removeColumns(2, 4);
823
824
    QVERIFY(a == model.index(1, 1, QModelIndex()));
825
    QVERIFY(b == model.index(9, 3, QModelIndex()));
826
    QVERIFY(c == model.index(5, 2, QModelIndex()));
827
    QVERIFY(d == model.index(3, 5, QModelIndex()));
828
    for (int i=0; i <2 ; i++)
829
        QVERIFY(e[i] == model.index(2, i , QModelIndex()));
830
    for (int i=2; i <6 ; i++)
831
        QVERIFY(!e[i].isValid());
832
    for (int i=6; i <10 ; i++)
833
        QVERIFY(e[i] == model.index(2, i-4 , QModelIndex()));
834
835
    //move some indexes around
836
    model.setPersistent(model.index(1, 1 , QModelIndex()), model.index(9, 3 , QModelIndex()));
837
    model.setPersistent(model.index(9, 3 , QModelIndex()), model.index(8, 4 , QModelIndex()));
838
839
    QVERIFY(a == model.index(9, 3, QModelIndex()));
840
    QVERIFY(b == model.index(8, 4, QModelIndex()));
841
    QVERIFY(c == model.index(5, 2, QModelIndex()));
842
    QVERIFY(d == model.index(3, 5, QModelIndex()));
843
    for (int i=0; i <2 ; i++)
844
        QVERIFY(e[i] == model.index(2, i , QModelIndex()));
845
    for (int i=2; i <6 ; i++)
846
        QVERIFY(!e[i].isValid());
847
    for (int i=6; i <10 ; i++)
848
        QVERIFY(e[i] == model.index(2, i-4 , QModelIndex()));
849
850
    //inserting a bunch of columns
851
    model.insertColumns(2, 2);
852
    QVERIFY(a == model.index(9, 5, QModelIndex()));
853
    QVERIFY(b == model.index(8, 6, QModelIndex()));
854
    QVERIFY(c == model.index(5, 4, QModelIndex()));
855
    QVERIFY(d == model.index(3, 7, QModelIndex()));
856
    for (int i=0; i <2 ; i++)
857
        QVERIFY(e[i] == model.index(2, i , QModelIndex()));
858
    for (int i=2; i <6 ; i++)
859
        QVERIFY(!e[i].isValid());
860
    for (int i=6; i <10 ; i++)
861
        QVERIFY(e[i] == model.index(2, i-2 , QModelIndex()));
862
863
}
864
865
void tst_QAbstractItemModel::testMoveSameParentDown_data()
866
{
867
    QTest::addColumn<int>("startRow");
868
    QTest::addColumn<int>("endRow");
869
    QTest::addColumn<int>("destRow");
870
    // We can't put the actual parent index for the move in here because m_model is not defined until init() is run.
871
    QTest::addColumn<bool>("topLevel");
872
873
    // Move from the start to the middle
874
    QTest::newRow("move01") << 0 << 2 << 8 << true;
875
    // Move from the start to the end
876
    QTest::newRow("move02") << 0 << 2 << 10 << true;
877
    // Move from the middle to the middle
878
    QTest::newRow("move03") << 3 << 5 << 8 << true;
879
    // Move from the middle to the end
880
    QTest::newRow("move04") << 3 << 5 << 10 << true;
881
882
    QTest::newRow("move05") << 0 << 2 << 8 << false;
883
    QTest::newRow("move06") << 0 << 2 << 10 << false;
884
    QTest::newRow("move07") << 3 << 5 << 8 << false;
885
    QTest::newRow("move08") << 3 << 5 << 10 << false;
886
}
887
888
void tst_QAbstractItemModel::testMoveSameParentDown()
889
{
890
    QFETCH( int, startRow);
891
    QFETCH( int, endRow);
892
    QFETCH( int, destRow);
893
    QFETCH( bool, topLevel);
894
895
    QModelIndex moveParent = topLevel ? QModelIndex() : m_model->index(5, 0);
896
897
    QList<QPersistentModelIndex> persistentList;
898
    QModelIndexList indexList;
899
900
    for (int column = 0; column < m_model->columnCount(); ++column)
901
    {
902
        for (int row= 0; row < m_model->rowCount(); ++row)
903
        {
904
            QModelIndex idx = m_model->index(row, column);
905
            QVERIFY(idx.isValid());
906
            indexList << idx;
907
            persistentList << QPersistentModelIndex(idx);
908
        }
909
    }
910
911
    QModelIndex parent = m_model->index(5, 0);
912
    for (int column = 0; column < m_model->columnCount(); ++column)
913
    {
914
        for (int row= 0; row < m_model->rowCount(parent); ++row)
915
        {
916
            QModelIndex idx = m_model->index(row, column, parent);
917
            QVERIFY(idx.isValid());
918
            indexList << idx;
919
            persistentList << QPersistentModelIndex(idx);
920
        }
921
    }
922
923
    QSignalSpy beforeSpy(m_model, SIGNAL(rowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)));
924
    QSignalSpy afterSpy(m_model, SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)));
925
926
    ModelMoveCommand *moveCommand = new ModelMoveCommand(m_model, this);
927
    moveCommand->setNumCols(4);
928
    if (!topLevel)
929
        moveCommand->setAncestorRowNumbers(QList<int>() << 5);
930
    moveCommand->setStartRow(startRow);
931
    moveCommand->setEndRow(endRow);
932
    moveCommand->setDestRow(destRow);
933
    if (!topLevel)
934
        moveCommand->setDestAncestors(QList<int>() << 5);
935
    moveCommand->doCommand();
936
937
    QVariantList beforeSignal = beforeSpy.takeAt(0);
938
    QVariantList afterSignal = afterSpy.takeAt(0);
939
940
    QCOMPARE(beforeSignal.size(), 5);
941
    QCOMPARE(beforeSignal.at(0).value<QModelIndex>(), moveParent);
942
    QCOMPARE(beforeSignal.at(1).toInt(), startRow);
943
    QCOMPARE(beforeSignal.at(2).toInt(), endRow);
944
    QCOMPARE(beforeSignal.at(3).value<QModelIndex>(), moveParent);
945
    QCOMPARE(beforeSignal.at(4).toInt(), destRow);
946
947
    QCOMPARE(afterSignal.size(), 5);
948
    QCOMPARE(afterSignal.at(0).value<QModelIndex>(), moveParent);
949
    QCOMPARE(afterSignal.at(1).toInt(), startRow);
950
    QCOMPARE(afterSignal.at(2).toInt(), endRow);
951
    QCOMPARE(afterSignal.at(3).value<QModelIndex>(), moveParent);
952
    QCOMPARE(afterSignal.at(4).toInt(), destRow);
953
954
    for (int i = 0; i < indexList.size(); i++)
955
    {
956
        QModelIndex idx = indexList.at(i);
957
        QModelIndex persistentIndex = persistentList.at(i);
958
        if (idx.parent() == moveParent)
959
        {
960
            int row = idx.row();
961
            if ( row >= startRow)
962
            {
963
                if (row <= endRow)
964
                {
965
                    QCOMPARE(row + destRow - endRow - 1, persistentIndex.row() );
966
                    QCOMPARE(idx.column(), persistentIndex.column());
967
                    QCOMPARE(idx.parent(), persistentIndex.parent());
968
                    QCOMPARE(idx.model(), persistentIndex.model());
969
                } else if ( row < destRow)
970
                {
971
                    QCOMPARE(row - (endRow - startRow + 1), persistentIndex.row() );
972
                    QCOMPARE(idx.column(), persistentIndex.column());
973
                    QCOMPARE(idx.parent(), persistentIndex.parent());
974
                    QCOMPARE(idx.model(), persistentIndex.model());
975
                } else
976
                {
977
                     QCOMPARE(idx, persistentIndex);
978
                }
979
            } else
980
            {
981
                QCOMPARE(idx, persistentIndex);
982
            }
983
        } else
984
        {
985
            QCOMPARE(idx, persistentIndex);
986
        }
987
    }
988
}
989
990
void tst_QAbstractItemModel::testMoveSameParentUp_data()
991
{
992
    QTest::addColumn<int>("startRow");
993
    QTest::addColumn<int>("endRow");
994
    QTest::addColumn<int>("destRow");
995
    QTest::addColumn<bool>("topLevel");
996
997
    // Move from the middle to the start
998
    QTest::newRow("move01") << 5 << 7 << 0 << true;
999
    // Move from the end to the start
1000
    QTest::newRow("move02") << 8 << 9 << 0 << true;
1001
    // Move from the middle to the middle
1002
    QTest::newRow("move03") << 5 << 7 << 2 << true;
1003
    // Move from the end to the middle
1004
    QTest::newRow("move04") << 8 << 9 << 5 << true;
1005
1006
    QTest::newRow("move05") << 5 << 7 << 0 << false;
1007
    QTest::newRow("move06") << 8 << 9 << 0 << false;
1008
    QTest::newRow("move07") << 5 << 7 << 2 << false;
1009
    QTest::newRow("move08") << 8 << 9 << 5 << false;
1010
}
1011
1012
void tst_QAbstractItemModel::testMoveSameParentUp()
1013
{
1014
1015
    QFETCH( int, startRow);
1016
    QFETCH( int, endRow);
1017
    QFETCH( int, destRow);
1018
    QFETCH( bool, topLevel);
1019
1020
    QModelIndex moveParent = topLevel ? QModelIndex() : m_model->index(5, 0);
1021
1022
    QList<QPersistentModelIndex> persistentList;
1023
    QModelIndexList indexList;
1024
1025
    for (int column = 0; column < m_model->columnCount(); ++column)
1026
    {
1027
        for (int row= 0; row < m_model->rowCount(); ++row)
1028
        {
1029
            QModelIndex idx = m_model->index(row, column);
1030
            QVERIFY(idx.isValid());
1031
            indexList << idx;
1032
            persistentList << QPersistentModelIndex(idx);
1033
        }
1034
    }
1035
1036
    QModelIndex parent = m_model->index(2, 0);
1037
    for (int column = 0; column < m_model->columnCount(); ++column)
1038
    {
1039
        for (int row= 0; row < m_model->rowCount(parent); ++row)
1040
        {
1041
            QModelIndex idx = m_model->index(row, column, parent);
1042
            QVERIFY(idx.isValid());
1043
            indexList << idx;
1044
            persistentList << QPersistentModelIndex(idx);
1045
        }
1046
    }
1047
1048
    QSignalSpy beforeSpy(m_model, SIGNAL(rowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)));
1049
    QSignalSpy afterSpy(m_model, SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)));
1050
1051
1052
    ModelMoveCommand *moveCommand = new ModelMoveCommand(m_model, this);
1053
    moveCommand->setNumCols(4);
1054
    if (!topLevel)
1055
        moveCommand->setAncestorRowNumbers(QList<int>() << 5);
1056
    moveCommand->setStartRow(startRow);
1057
    moveCommand->setEndRow(endRow);
1058
    moveCommand->setDestRow(destRow);
1059
    if (!topLevel)
1060
        moveCommand->setDestAncestors(QList<int>() << 5);
1061
    moveCommand->doCommand();
1062
1063
    QVariantList beforeSignal = beforeSpy.takeAt(0);
1064
    QVariantList afterSignal = afterSpy.takeAt(0);
1065
1066
    QCOMPARE(beforeSignal.size(), 5);
1067
    QCOMPARE(beforeSignal.at(0).value<QModelIndex>(), moveParent);
1068
    QCOMPARE(beforeSignal.at(1).toInt(), startRow);
1069
    QCOMPARE(beforeSignal.at(2).toInt(), endRow);
1070
    QCOMPARE(beforeSignal.at(3).value<QModelIndex>(), moveParent);
1071
    QCOMPARE(beforeSignal.at(4).toInt(), destRow);
1072
1073
    QCOMPARE(afterSignal.size(), 5);
1074
    QCOMPARE(afterSignal.at(0).value<QModelIndex>(), moveParent);
1075
    QCOMPARE(afterSignal.at(1).toInt(), startRow);
1076
    QCOMPARE(afterSignal.at(2).toInt(), endRow);
1077
    QCOMPARE(afterSignal.at(3).value<QModelIndex>(), moveParent);
1078
    QCOMPARE(afterSignal.at(4).toInt(), destRow);
1079
1080
1081
    for (int i = 0; i < indexList.size(); i++)
1082
    {
1083
        QModelIndex idx = indexList.at(i);
1084
        QModelIndex persistentIndex = persistentList.at(i);
1085
        if (idx.parent() == moveParent)
1086
        {
1087
            int row = idx.row();
1088
            if ( row >= destRow)
1089
            {
1090
                if (row < startRow)
1091
                {
1092
                    QCOMPARE(row + endRow - startRow + 1, persistentIndex.row() );
1093
                    QCOMPARE(idx.column(), persistentIndex.column());
1094
                    QCOMPARE(idx.parent(), persistentIndex.parent());
1095
                    QCOMPARE(idx.model(), persistentIndex.model());
1096
                } else if ( row <= endRow)
1097
                {
1098
                    QCOMPARE(row + destRow - startRow, persistentIndex.row() );
1099
                    QCOMPARE(idx.column(), persistentIndex.column());
1100
                    QCOMPARE(idx.parent(), persistentIndex.parent());
1101
                    QCOMPARE(idx.model(), persistentIndex.model());
1102
                } else
1103
                {
1104
                    QCOMPARE(idx, persistentIndex);
1105
                }
1106
            } else
1107
            {
1108
                QCOMPARE(idx, persistentIndex);
1109
            }
1110
        } else
1111
        {
1112
            QCOMPARE(idx, persistentIndex);
1113
        }
1114
    }
1115
}
1116
1117
void tst_QAbstractItemModel::testMoveThroughProxy()
1118
{
1119
    QSortFilterProxyModel *proxy = new QSortFilterProxyModel(this);
1120
    proxy->setSourceModel(m_model);
1121
1122
    QList<QPersistentModelIndex> persistentList;
1123
1124
    persistentList.append(proxy->index(0, 0));
1125
    persistentList.append(proxy->index(0, 0, proxy->mapFromSource(m_model->index(5, 0))));
1126
1127
    ModelMoveCommand *moveCommand = new ModelMoveCommand(m_model, this);
1128
    moveCommand->setNumCols(4);
1129
    moveCommand->setAncestorRowNumbers(QList<int>() << 5);
1130
    moveCommand->setStartRow(0);
1131
    moveCommand->setEndRow(0);
1132
    moveCommand->setDestRow(0);
1133
    moveCommand->doCommand();
1134
}
1135
1136
void tst_QAbstractItemModel::testMoveToGrandParent_data()
1137
{
1138
    QTest::addColumn<int>("startRow");
1139
    QTest::addColumn<int>("endRow");
1140
    QTest::addColumn<int>("destRow");
1141
1142
    // Move from the start to the middle
1143
    QTest::newRow("move01") << 0 << 2 << 8;
1144
    // Move from the start to the end
1145
    QTest::newRow("move02") << 0 << 2 << 10;
1146
    // Move from the middle to the middle
1147
    QTest::newRow("move03") << 3 << 5 << 8;
1148
    // Move from the middle to the end
1149
    QTest::newRow("move04") << 3 << 5 << 10;
1150
1151
    // Move from the middle to the start
1152
    QTest::newRow("move05") << 5 << 7 << 0;
1153
    // Move from the end to the start
1154
    QTest::newRow("move06") << 8 << 9 << 0;
1155
    // Move from the middle to the middle
1156
    QTest::newRow("move07") << 5 << 7 << 2;
1157
    // Move from the end to the middle
1158
    QTest::newRow("move08") << 8 << 9 << 5;
1159
1160
    // Moving to the same row in a different parent doesn't confuse things.
1161
    QTest::newRow("move09") << 8 << 8 << 8;
1162
1163
    // Moving to the row of my parent and its neighbours doesn't confuse things
1164
    QTest::newRow("move09") << 8 << 8 << 4;
1165
    QTest::newRow("move10") << 8 << 8 << 5;
1166
    QTest::newRow("move11") << 8 << 8 << 6;
1167
1168
    // Moving everything from one parent to another
1169
    QTest::newRow("move12") << 0 << 9 << 10;
1170
    QTest::newRow("move13") << 0 << 9 << 0;
1171
}
1172
1173
void tst_QAbstractItemModel::testMoveToGrandParent()
1174
{
1175
1176
    QFETCH( int, startRow);
1177
    QFETCH( int, endRow);
1178
    QFETCH( int, destRow);
1179
1180
    QList<QPersistentModelIndex> persistentList;
1181
    QModelIndexList indexList;
1182
    QModelIndexList parentsList;
1183
1184
    for (int column = 0; column < m_model->columnCount(); ++column)
1185
    {
1186
        for (int row= 0; row < m_model->rowCount(); ++row)
1187
        {
1188
            QModelIndex idx = m_model->index(row, column);
1189
            QVERIFY(idx.isValid());
1190
            indexList << idx;
1191
            parentsList << idx.parent();
1192
            persistentList << QPersistentModelIndex(idx);
1193
        }
1194
    }
1195
1196
    QModelIndex sourceIndex = m_model->index(5, 0);
1197
    for (int column = 0; column < m_model->columnCount(); ++column)
1198
    {
1199
        for (int row= 0; row < m_model->rowCount(sourceIndex); ++row)
1200
        {
1201
            QModelIndex idx = m_model->index(row, column, sourceIndex);
1202
            QVERIFY(idx.isValid());
1203
            indexList << idx;
1204
            parentsList << idx.parent();
1205
            persistentList << QPersistentModelIndex(idx);
1206
        }
1207
    }
1208
1209
    QSignalSpy beforeSpy(m_model, SIGNAL(rowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)));
1210
    QSignalSpy afterSpy(m_model, SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)));
1211
1212
    QPersistentModelIndex persistentSource = sourceIndex;
1213
1214
    ModelMoveCommand *moveCommand = new ModelMoveCommand(m_model, this);
1215
    moveCommand->setAncestorRowNumbers(QList<int>() << 5);
1216
    moveCommand->setNumCols(4);
1217
    moveCommand->setStartRow(startRow);
1218
    moveCommand->setEndRow(endRow);
1219
    moveCommand->setDestRow(destRow);
1220
    moveCommand->doCommand();
1221
1222
    QVariantList beforeSignal = beforeSpy.takeAt(0);
1223
    QVariantList afterSignal = afterSpy.takeAt(0);
1224
1225
    QCOMPARE(beforeSignal.size(), 5);
1226
    QCOMPARE(beforeSignal.at(0).value<QModelIndex>(), sourceIndex);
1227
    QCOMPARE(beforeSignal.at(1).toInt(), startRow);
1228
    QCOMPARE(beforeSignal.at(2).toInt(), endRow);
1229
    QCOMPARE(beforeSignal.at(3).value<QModelIndex>(), QModelIndex());
1230
    QCOMPARE(beforeSignal.at(4).toInt(), destRow);
1231
1232
    QCOMPARE(afterSignal.size(), 5);
1233
    QCOMPARE(afterSignal.at(0).value<QModelIndex>(), static_cast<QModelIndex>(persistentSource));
1234
    QCOMPARE(afterSignal.at(1).toInt(), startRow);
1235
    QCOMPARE(afterSignal.at(2).toInt(), endRow);
1236
    QCOMPARE(afterSignal.at(3).value<QModelIndex>(), QModelIndex());
1237
    QCOMPARE(afterSignal.at(4).toInt(), destRow);
1238
1239
    for (int i = 0; i < indexList.size(); i++)
1240
    {
1241
        QModelIndex idx = indexList.at(i);
1242
        QModelIndex idxParent = parentsList.at(i);
1243
        QModelIndex persistentIndex = persistentList.at(i);
1244
        int row = idx.row();
1245
        if (idxParent == QModelIndex())
1246
        {
1247
            if ( row >= destRow)
1248
            {
1249
                    QCOMPARE(row + endRow - startRow + 1, persistentIndex.row() );
1250
                    QCOMPARE(idx.column(), persistentIndex.column());
1251
                    QCOMPARE(idxParent, persistentIndex.parent());
1252
                    QCOMPARE(idx.model(), persistentIndex.model());
1253
            } else
1254
            {
1255
                QCOMPARE(idx, persistentIndex);
1256
            }
1257
        } else
1258
        {
1259
            if (row < startRow)
1260
            {
1261
                QCOMPARE(idx, persistentIndex);
1262
            } else if (row <= endRow)
1263
            {
1264
                QCOMPARE(row + destRow - startRow, persistentIndex.row() );
1265
                QCOMPARE(idx.column(), persistentIndex.column());
1266
                QCOMPARE(QModelIndex(), persistentIndex.parent());
1267
                QCOMPARE(idx.model(), persistentIndex.model());
1268
            } else {
1269
                QCOMPARE(row - (endRow - startRow + 1), persistentIndex.row() );
1270
                QCOMPARE(idx.column(), persistentIndex.column());
1271
1272
                if (idxParent.row() >= destRow)
1273
                {
1274
                    QModelIndex adjustedParent;
1275
                    adjustedParent = idxParent.sibling( idxParent.row() + endRow - startRow + 1,    idxParent.column());
1276
                    QCOMPARE(adjustedParent, persistentIndex.parent());
1277
                } else
1278
                {
1279
                    QCOMPARE(idxParent, persistentIndex.parent());
1280
                }
1281
                QCOMPARE(idx.model(), persistentIndex.model());
1282
            }
1283
        }
1284
    }
1285
}
1286
1287
void tst_QAbstractItemModel::testMoveToSibling_data()
1288
{
1289
    QTest::addColumn<int>("startRow");
1290
    QTest::addColumn<int>("endRow");
1291
    QTest::addColumn<int>("destRow");
1292
1293
    // Move from the start to the middle
1294
    QTest::newRow("move01") << 0 << 2 << 8;
1295
    // Move from the start to the end
1296
    QTest::newRow("move02") << 0 << 2 << 10;
1297
    // Move from the middle to the middle
1298
    QTest::newRow("move03") << 2 << 4 << 8;
1299
    // Move from the middle to the end
1300
    QTest::newRow("move04") << 2 << 4 << 10;
1301
1302
    // Move from the middle to the start
1303
    QTest::newRow("move05") << 8 << 8 << 0;
1304
    // Move from the end to the start
1305
    QTest::newRow("move06") << 8 << 9 << 0;
1306
    // Move from the middle to the middle
1307
    QTest::newRow("move07") << 6 << 8 << 2;
1308
    // Move from the end to the middle
1309
    QTest::newRow("move08") << 8 << 9 << 5;
1310
1311
    // Moving to the same row in a different parent doesn't confuse things.
1312
    QTest::newRow("move09") << 8 << 8 << 8;
1313
1314
    // Moving to the row of my target and its neighbours doesn't confuse things
1315
    QTest::newRow("move09") << 8 << 8 << 4;
1316
    QTest::newRow("move10") << 8 << 8 << 5;
1317
    QTest::newRow("move11") << 8 << 8 << 6;
1318
1319
    // Move such that the destination parent no longer valid after the move.
1320
    // The destination parent is always QMI(5, 0), but after this move the
1321
    // row count is 5, so (5, 0) (used internally in QAIM) no longer refers to a valid index.
1322
    QTest::newRow("move12") << 0 << 4 << 0;
1323
}
1324
1325
void tst_QAbstractItemModel::testMoveToSibling()
1326
{
1327
1328
    QFETCH( int, startRow);
1329
    QFETCH( int, endRow);
1330
    QFETCH( int, destRow);
1331
1332
    QList<QPersistentModelIndex> persistentList;
1333
    QModelIndexList indexList;
1334
    QModelIndexList parentsList;
1335
1336
    const int column = 0;
1337
1338
    for (int i= 0; i < m_model->rowCount(); ++i)
1339
    {
1340
        QModelIndex idx = m_model->index(i, column);
1341
        QVERIFY(idx.isValid());
1342
        indexList << idx;
1343
        parentsList << idx.parent();
1344
        persistentList << QPersistentModelIndex(idx);
1345
    }
1346
1347
    QModelIndex destIndex = m_model->index(5, 0);
1348
    QModelIndex sourceIndex;
1349
    for (int i= 0; i < m_model->rowCount(destIndex); ++i)
1350
    {
1351
        QModelIndex idx = m_model->index(i, column, destIndex);
1352
        QVERIFY(idx.isValid());
1353
        indexList << idx;
1354
        parentsList << idx.parent();
1355
        persistentList << QPersistentModelIndex(idx);
1356
    }
1357
1358
    QSignalSpy beforeSpy(m_model, SIGNAL(rowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)));
1359
    QSignalSpy afterSpy(m_model, SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)));
1360
1361
    QPersistentModelIndex persistentDest = destIndex;
1362
1363
    ModelMoveCommand *moveCommand = new ModelMoveCommand(m_model, this);
1364
    moveCommand->setNumCols(4);
1365
    moveCommand->setStartRow(startRow);
1366
    moveCommand->setEndRow(endRow);
1367
    moveCommand->setDestAncestors(QList<int>() << 5);
1368
    moveCommand->setDestRow(destRow);
1369
    moveCommand->doCommand();
1370
1371
    QVariantList beforeSignal = beforeSpy.takeAt(0);
1372
    QVariantList afterSignal = afterSpy.takeAt(0);
1373
1374
    QCOMPARE(beforeSignal.size(), 5);
1375
    QCOMPARE(beforeSignal.at(0).value<QModelIndex>(), sourceIndex);
1376
    QCOMPARE(beforeSignal.at(1).toInt(), startRow);
1377
    QCOMPARE(beforeSignal.at(2).toInt(), endRow);
1378
    QCOMPARE(beforeSignal.at(3).value<QModelIndex>(), destIndex);
1379
    QCOMPARE(beforeSignal.at(4).toInt(), destRow);
1380
1381
    QCOMPARE(afterSignal.size(), 5);
1382
    QCOMPARE(afterSignal.at(0).value<QModelIndex>(), sourceIndex);
1383
    QCOMPARE(afterSignal.at(1).toInt(), startRow);
1384
    QCOMPARE(afterSignal.at(2).toInt(), endRow);
1385
    QCOMPARE(afterSignal.at(3).value<QModelIndex>(), static_cast<QModelIndex>(persistentDest));
1386
    QCOMPARE(afterSignal.at(4).toInt(), destRow);
1387
1388
    for (int i = 0; i < indexList.size(); i++)
1389
    {
1390
        QModelIndex idx = indexList.at(i);
1391
        QModelIndex idxParent = parentsList.at(i);
1392
        QModelIndex persistentIndex = persistentList.at(i);
1393
1394
        QModelIndex adjustedDestination = destIndex.sibling(destIndex.row() - (endRow - startRow + 1), destIndex.column());
1395
        int row = idx.row();
1396
        if (idxParent == destIndex)
1397
        {
1398
            if ( row >= destRow)
1399
            {
1400
                    QCOMPARE(row + endRow - startRow + 1, persistentIndex.row() );
1401
                    QCOMPARE(idx.column(), persistentIndex.column());
1402
                    if (idxParent.row() > startRow)
1403
                    {
1404
                        QCOMPARE(adjustedDestination, persistentIndex.parent());
1405
                    } else {
1406
                        QCOMPARE(destIndex, persistentIndex.parent());
1407
                    }
1408
                    QCOMPARE(idx.model(), persistentIndex.model());
1409
            } else
1410
            {
1411
                QCOMPARE(idx, persistentIndex);
1412
            }
1413
        } else
1414
        {
1415
            if (row < startRow)
1416
            {
1417
                QCOMPARE(idx, persistentIndex);
1418
            } else if (row <= endRow)
1419
            {
1420
                QCOMPARE(row + destRow - startRow, persistentIndex.row() );
1421
                QCOMPARE(idx.column(), persistentIndex.column());
1422
                if (destIndex.row() > startRow)
1423
                {
1424
                    QCOMPARE(adjustedDestination, persistentIndex.parent());
1425
                } else {
1426
                    QCOMPARE(destIndex, persistentIndex.parent());
1427
                }
1428
1429
                QCOMPARE(idx.model(), persistentIndex.model());
1430
1431
            } else {
1432
                QCOMPARE(row - (endRow - startRow + 1), persistentIndex.row() );
1433
                QCOMPARE(idx.column(), persistentIndex.column());
1434
                QCOMPARE(idxParent, persistentIndex.parent());
1435
                QCOMPARE(idx.model(), persistentIndex.model());
1436
            }
1437
        }
1438
    }
1439
}
1440
1441
void tst_QAbstractItemModel::testMoveToUncle_data()
1442
{
1443
1444
    QTest::addColumn<int>("startRow");
1445
    QTest::addColumn<int>("endRow");
1446
    QTest::addColumn<int>("destRow");
1447
1448
    // Move from the start to the middle
1449
    QTest::newRow("move01") << 0 << 2 << 8;
1450
    // Move from the start to the end
1451
    QTest::newRow("move02") << 0 << 2 << 10;
1452
    // Move from the middle to the middle
1453
    QTest::newRow("move03") << 3 << 5 << 8;
1454
    // Move from the middle to the end
1455
    QTest::newRow("move04") << 3 << 5 << 10;
1456
1457
    // Move from the middle to the start
1458
    QTest::newRow("move05") << 5 << 7 << 0;
1459
    // Move from the end to the start
1460
    QTest::newRow("move06") << 8 << 9 << 0;
1461
    // Move from the middle to the middle
1462
    QTest::newRow("move07") << 5 << 7 << 2;
1463
    // Move from the end to the middle
1464
    QTest::newRow("move08") << 8 << 9 << 5;
1465
1466
    // Moving to the same row in a different parent doesn't confuse things.
1467
    QTest::newRow("move09") << 8 << 8 << 8;
1468
1469
    // Moving to the row of my parent and its neighbours doesn't confuse things
1470
    QTest::newRow("move09") << 8 << 8 << 4;
1471
    QTest::newRow("move10") << 8 << 8 << 5;
1472
    QTest::newRow("move11") << 8 << 8 << 6;
1473
1474
    // Moving everything from one parent to another
1475
    QTest::newRow("move12") << 0 << 9 << 10;
1476
}
1477
1478
void tst_QAbstractItemModel::testMoveToUncle()
1479
{
1480
    // Need to have some extra rows available.
1481
    ModelInsertCommand *insertCommand = new ModelInsertCommand(m_model, this);
1482
    insertCommand->setAncestorRowNumbers(QList<int>() << 9);
1483
    insertCommand->setNumCols(4);
1484
    insertCommand->setStartRow(0);
1485
    insertCommand->setEndRow(9);
1486
    insertCommand->doCommand();
1487
1488
    QFETCH( int, startRow);
1489
    QFETCH( int, endRow);
1490
    QFETCH( int, destRow);
1491
1492
    QList<QPersistentModelIndex> persistentList;
1493
    QModelIndexList indexList;
1494
    QModelIndexList parentsList;
1495
1496
    const int column = 0;
1497
1498
    QModelIndex sourceIndex = m_model->index(9, 0);
1499
    for (int i= 0; i < m_model->rowCount(sourceIndex); ++i)
1500
    {
1501
        QModelIndex idx = m_model->index(i, column, sourceIndex);
1502
        QVERIFY(idx.isValid());
1503
        indexList << idx;
1504
        parentsList << idx.parent();
1505
        persistentList << QPersistentModelIndex(idx);
1506
    }
1507
1508
    QModelIndex destIndex = m_model->index(5, 0);
1509
    for (int i= 0; i < m_model->rowCount(destIndex); ++i)
1510
    {
1511
        QModelIndex idx = m_model->index(i, column, destIndex);
1512
        QVERIFY(idx.isValid());
1513
        indexList << idx;
1514
        parentsList << idx.parent();
1515
        persistentList << QPersistentModelIndex(idx);
1516
    }
1517
1518
    QSignalSpy beforeSpy(m_model, SIGNAL(rowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)));
1519
    QSignalSpy afterSpy(m_model, SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)));
1520
1521
    ModelMoveCommand *moveCommand = new ModelMoveCommand(m_model, this);
1522
    moveCommand->setAncestorRowNumbers(QList<int>() << 9);
1523
    moveCommand->setNumCols(4);
1524
    moveCommand->setStartRow(startRow);
1525
    moveCommand->setEndRow(endRow);
1526
    moveCommand->setDestAncestors(QList<int>() << 5);
1527
    moveCommand->setDestRow(destRow);
1528
    moveCommand->doCommand();
1529
1530
    QVariantList beforeSignal = beforeSpy.takeAt(0);
1531
    QVariantList afterSignal = afterSpy.takeAt(0);
1532
1533
    QCOMPARE(beforeSignal.size(), 5);
1534
    QCOMPARE(beforeSignal.at(0).value<QModelIndex>(), sourceIndex);
1535
    QCOMPARE(beforeSignal.at(1).toInt(), startRow);
1536
    QCOMPARE(beforeSignal.at(2).toInt(), endRow);
1537
    QCOMPARE(beforeSignal.at(3).value<QModelIndex>(), destIndex);
1538
    QCOMPARE(beforeSignal.at(4).toInt(), destRow);
1539
1540
    QCOMPARE(afterSignal.size(), 5);
1541
    QCOMPARE(afterSignal.at(0).value<QModelIndex>(), sourceIndex);
1542
    QCOMPARE(afterSignal.at(1).toInt(), startRow);
1543
    QCOMPARE(afterSignal.at(2).toInt(), endRow);
1544
    QCOMPARE(afterSignal.at(3).value<QModelIndex>(), destIndex);
1545
    QCOMPARE(afterSignal.at(4).toInt(), destRow);
1546
1547
    for (int i = 0; i < indexList.size(); i++)
1548
    {
1549
        QModelIndex idx = indexList.at(i);
1550
        QModelIndex idxParent = parentsList.at(i);
1551
        QModelIndex persistentIndex = persistentList.at(i);
1552
1553
        int row = idx.row();
1554
        if (idxParent == destIndex)
1555
        {
1556
            if ( row >= destRow)
1557
            {
1558
                    QCOMPARE(row + endRow - startRow + 1, persistentIndex.row() );
1559
                    QCOMPARE(idx.column(), persistentIndex.column());
1560
                    QCOMPARE(destIndex, persistentIndex.parent());
1561
                    QCOMPARE(idx.model(), persistentIndex.model());
1562
            } else
1563
            {
1564
                QCOMPARE(idx, persistentIndex);
1565
            }
1566
        } else
1567
        {
1568
            if (row < startRow)
1569
            {
1570
                QCOMPARE(idx, persistentIndex);
1571
            } else if (row <= endRow)
1572
            {
1573
                QCOMPARE(row + destRow - startRow, persistentIndex.row() );
1574
                QCOMPARE(idx.column(), persistentIndex.column());
1575
                QCOMPARE(destIndex, persistentIndex.parent());
1576
                QCOMPARE(idx.model(), persistentIndex.model());
1577
1578
            } else {
1579
                QCOMPARE(row - (endRow - startRow + 1), persistentIndex.row() );
1580
                QCOMPARE(idx.column(), persistentIndex.column());
1581
                QCOMPARE(idxParent, persistentIndex.parent());
1582
                QCOMPARE(idx.model(), persistentIndex.model());
1583
            }
1584
        }
1585
    }
1586
}
1587
1588
void tst_QAbstractItemModel::testMoveToDescendants()
1589
{
1590
    // Attempt to move a row to its ancestors depth rows deep.
1591
    const int depth = 6;
1592
1593
    // Need to have some extra rows available in a tree.
1594
    QList<int> rows;
1595
    ModelInsertCommand *insertCommand;
1596
    for (int i = 0; i < depth; i++)
1597
    {
1598
        insertCommand = new ModelInsertCommand(m_model, this);
1599
        insertCommand->setAncestorRowNumbers(rows);
1600
        insertCommand->setNumCols(4);
1601
        insertCommand->setStartRow(0);
1602
        insertCommand->setEndRow(9);
1603
        insertCommand->doCommand();
1604
        rows << 9;
1605
    }
1606
1607
    QList<QPersistentModelIndex> persistentList;
1608
    QModelIndexList indexList;
1609
    QModelIndexList parentsList;
1610
1611
    const int column = 0;
1612
1613
    QModelIndex sourceIndex = m_model->index(9, 0);
1614
    for (int i= 0; i < m_model->rowCount(sourceIndex); ++i)
1615
    {
1616
        QModelIndex idx = m_model->index(i, column, sourceIndex);
1617
        QVERIFY(idx.isValid());
1618
        indexList << idx;
1619
        parentsList << idx.parent();
1620
        persistentList << QPersistentModelIndex(idx);
1621
    }
1622
1623
    QModelIndex destIndex = m_model->index(5, 0);
1624
    for (int i= 0; i < m_model->rowCount(destIndex); ++i)
1625
    {
1626
        QModelIndex idx = m_model->index(i, column, destIndex);
1627
        QVERIFY(idx.isValid());
1628
        indexList << idx;
1629
        parentsList << idx.parent();
1630
        persistentList << QPersistentModelIndex(idx);
1631
    }
1632
1633
    QSignalSpy beforeSpy(m_model, SIGNAL(rowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)));
1634
    QSignalSpy afterSpy(m_model, SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)));
1635
1636
    ModelMoveCommand *moveCommand;
1637
    QList<int> ancestors;
1638
    while (ancestors.size() < depth)
1639
    {
1640
        ancestors << 9;
1641
        for (int row = 0; row <= 9; row++)
1642
        {
1643
            moveCommand = new ModelMoveCommand(m_model, this);
1644
            moveCommand->setNumCols(4);
1645
            moveCommand->setStartRow(9);
1646
            moveCommand->setEndRow(9);
1647
            moveCommand->setDestAncestors(ancestors);
1648
            moveCommand->setDestRow(row);
1649
            moveCommand->doCommand();
1650
1651
            QVERIFY(beforeSpy.size() == 0);
1652
            QVERIFY(afterSpy.size() == 0);
1653
        }
1654
    }
1655
}
1656
1657
void tst_QAbstractItemModel::testMoveWithinOwnRange_data()
1658
{
1659
    QTest::addColumn<int>("startRow");
1660
    QTest::addColumn<int>("endRow");
1661
    QTest::addColumn<int>("destRow");
1662
1663
    QTest::newRow("move01") << 0 << 0 << 0;
1664
    QTest::newRow("move02") << 0 << 0 << 1;
1665
    QTest::newRow("move03") << 0 << 5 << 0;
1666
    QTest::newRow("move04") << 0 << 5 << 1;
1667
    QTest::newRow("move05") << 0 << 5 << 2;
1668
    QTest::newRow("move06") << 0 << 5 << 3;
1669
    QTest::newRow("move07") << 0 << 5 << 4;
1670
    QTest::newRow("move08") << 0 << 5 << 5;
1671
    QTest::newRow("move09") << 0 << 5 << 6;
1672
    QTest::newRow("move08") << 3 << 5 << 5;
1673
    QTest::newRow("move08") << 3 << 5 << 6;
1674
    QTest::newRow("move09") << 4 << 5 << 5;
1675
    QTest::newRow("move10") << 4 << 5 << 6;
1676
    QTest::newRow("move11") << 5 << 5 << 5;
1677
    QTest::newRow("move12") << 5 << 5 << 6;
1678
    QTest::newRow("move13") << 5 << 9 << 9;
1679
    QTest::newRow("move14") << 5 << 9 << 10;
1680
    QTest::newRow("move15") << 6 << 9 << 9;
1681
    QTest::newRow("move16") << 6 << 9 << 10;
1682
    QTest::newRow("move17") << 7 << 9 << 9;
1683
    QTest::newRow("move18") << 7 << 9 << 10;
1684
    QTest::newRow("move19") << 8 << 9 << 9;
1685
    QTest::newRow("move20") << 8 << 9 << 10;
1686
    QTest::newRow("move21") << 9 << 9 << 9;
1687
    QTest::newRow("move22") << 0 << 9 << 10;
1688
1689
}
1690
1691
void tst_QAbstractItemModel::testMoveWithinOwnRange()
1692
{
1693
1694
    QFETCH( int, startRow);
1695
    QFETCH( int, endRow);
1696
    QFETCH( int, destRow);
1697
1698
1699
    QSignalSpy beforeSpy(m_model, SIGNAL(rowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)));
1700
    QSignalSpy afterSpy(m_model, SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)));
1701
1702
    ModelMoveCommand *moveCommand = new ModelMoveCommand(m_model, this);
1703
    moveCommand->setNumCols(4);
1704
    moveCommand->setStartRow(startRow);
1705
    moveCommand->setEndRow(endRow);
1706
    moveCommand->setDestRow(destRow);
1707
    moveCommand->doCommand();
1708
1709
    QVERIFY(beforeSpy.size() == 0);
1710
    QVERIFY(afterSpy.size() == 0);
1711
1712
1713
}
1714
1715
class ListenerObject : public QObject
1716
{
1717
  Q_OBJECT
1718
public:
1719
    ListenerObject(QAbstractProxyModel *parent);
1720
1721
protected:
1722
    void fillIndexStores(const QModelIndex &parent);
1723
1724
public slots:
1725
    void slotAboutToBeReset();
1726
    void slotReset();
1727
1728
private:
1729
    QAbstractProxyModel *m_model;
1730
    QList<QPersistentModelIndex> m_persistentIndexes;
1731
    QModelIndexList m_nonPersistentIndexes;
1732
};
1733
1734
1735
ListenerObject::ListenerObject(QAbstractProxyModel *parent)
1736
    : QObject(parent), m_model(parent)
1737
{
1738
    connect(m_model, SIGNAL(modelAboutToBeReset()), SLOT(slotAboutToBeReset()));
1739
    connect(m_model, SIGNAL(modelReset()), SLOT(slotReset()));
1740
1741
    fillIndexStores(QModelIndex());
1742
}
1743
1744
void ListenerObject::fillIndexStores(const QModelIndex &parent)
1745
{
1746
    const int column = 0;
1747
    int row = 0;
1748
    QModelIndex idx = m_model->index(row, column, parent);
1749
    while (idx.isValid())
1750
    {
1751
        m_persistentIndexes << QPersistentModelIndex(idx);
1752
        m_nonPersistentIndexes << idx;
1753
        if (m_model->hasChildren(idx))
1754
        {
1755
            fillIndexStores(idx);
1756
        }
1757
        ++row;
1758
        idx = m_model->index(row, column, parent);
1759
    }
1760
}
1761
1762
void ListenerObject::slotAboutToBeReset()
1763
{
1764
    // Nothing has been changed yet. All indexes should be the same.
1765
    for (int i = 0; i < m_persistentIndexes.size(); ++i)
1766
    {
1767
        QModelIndex idx = m_persistentIndexes.at(i);
1768
        QVERIFY(idx == m_nonPersistentIndexes.at(i));
1769
        QVERIFY(m_model->mapToSource(idx).isValid());
1770
    }
1771
}
1772
1773
void ListenerObject::slotReset()
1774
{
1775
    foreach(const QModelIndex &idx, m_persistentIndexes)
1776
    {
1777
        QVERIFY(!idx.isValid());
1778
    }
1779
}
1780
1781
1782
void tst_QAbstractItemModel::testReset()
1783
{
1784
    QSignalSpy beforeResetSpy(m_model, SIGNAL(modelAboutToBeReset()));
1785
    QSignalSpy afterResetSpy(m_model, SIGNAL(modelReset()));
1786
1787
1788
    QSortFilterProxyModel *nullProxy = new QSortFilterProxyModel(this);
1789
    nullProxy->setSourceModel(m_model);
1790
1791
    // Makes sure the model and proxy are in a consistent state. before and after reset.
1792
    new ListenerObject(nullProxy);
1793
1794
    ModelResetCommandFixed *resetCommand = new ModelResetCommandFixed(m_model, this);
1795
1796
    resetCommand->setNumCols(4);
1797
    resetCommand->setStartRow(0);
1798
    resetCommand->setEndRow(0);
1799
    resetCommand->setDestRow(0);
1800
    resetCommand->setDestAncestors(QList<int>() << 5);
1801
    resetCommand->doCommand();
1802
1803
    // Verify that the correct signals were emitted
1804
    QVERIFY(beforeResetSpy.size() == 1);
1805
    QVERIFY(afterResetSpy.size() == 1);
1806
1807
    // Verify that the move actually happened.
1808
    QVERIFY(m_model->rowCount() == 9);
1809
    QModelIndex destIndex = m_model->index(4, 0);
1810
    QVERIFY(m_model->rowCount(destIndex) == 11);
1811
1812
}
1813
1814
1815
QTEST_MAIN(tst_QAbstractItemModel)
1816
#include "tst_qabstractitemmodel.moc"