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 <QtTest/QtTest> |
30 | #include <qabstractproxymodel.h> |
31 | #include <QItemSelection> |
32 | #include <qstandarditemmodel.h> |
33 | |
34 | class tst_QAbstractProxyModel : public QObject |
35 | { |
36 | Q_OBJECT |
37 | |
38 | private slots: |
39 | void qabstractproxymodel(); |
40 | void data_data(); |
41 | void data(); |
42 | void flags_data(); |
43 | void flags(); |
44 | void headerData_data(); |
45 | void headerData(); |
46 | void itemData_data(); |
47 | void itemData(); |
48 | void mapFromSource_data(); |
49 | void mapFromSource(); |
50 | void mapSelectionFromSource_data(); |
51 | void mapSelectionFromSource(); |
52 | void mapSelectionToSource_data(); |
53 | void mapSelectionToSource(); |
54 | void mapToSource_data(); |
55 | void mapToSource(); |
56 | void revert(); |
57 | void setSourceModel(); |
58 | void submit_data(); |
59 | void submit(); |
60 | void testRoleNames(); |
61 | void testSwappingRowsProxy(); |
62 | void testDragAndDrop(); |
63 | }; |
64 | |
65 | // Subclass that exposes the protected functions. |
66 | class SubQAbstractProxyModel : public QAbstractProxyModel |
67 | { |
68 | public: |
69 | // QAbstractProxyModel::mapFromSource is a pure virtual function. |
70 | QModelIndex mapFromSource(QModelIndex const& sourceIndex) const |
71 | { Q_UNUSED(sourceIndex); return QModelIndex(); } |
72 | |
73 | // QAbstractProxyModel::mapToSource is a pure virtual function. |
74 | QModelIndex mapToSource(QModelIndex const& proxyIndex) const |
75 | { Q_UNUSED(proxyIndex); return QModelIndex(); } |
76 | |
77 | QModelIndex index(int, int, const QModelIndex&) const |
78 | { |
79 | return QModelIndex(); |
80 | } |
81 | |
82 | QModelIndex parent(const QModelIndex&) const |
83 | { |
84 | return QModelIndex(); |
85 | } |
86 | |
87 | int rowCount(const QModelIndex&) const |
88 | { |
89 | return 0; |
90 | } |
91 | |
92 | int columnCount(const QModelIndex&) const |
93 | { |
94 | return 0; |
95 | } |
96 | }; |
97 | |
98 | void tst_QAbstractProxyModel::qabstractproxymodel() |
99 | { |
100 | SubQAbstractProxyModel model; |
101 | model.data(proxyIndex: QModelIndex()); |
102 | model.flags(index: QModelIndex()); |
103 | model.headerData(section: 0, orientation: Qt::Vertical, role: 0); |
104 | model.itemData(index: QModelIndex()); |
105 | model.mapFromSource(sourceIndex: QModelIndex()); |
106 | model.mapSelectionFromSource(selection: QItemSelection()); |
107 | model.mapSelectionToSource(selection: QItemSelection()); |
108 | model.mapToSource(proxyIndex: QModelIndex()); |
109 | model.revert(); |
110 | model.setSourceModel(0); |
111 | QCOMPARE(model.sourceModel(), (QAbstractItemModel*)0); |
112 | model.submit(); |
113 | } |
114 | |
115 | void tst_QAbstractProxyModel::data_data() |
116 | { |
117 | QTest::addColumn<QModelIndex>(name: "proxyIndex" ); |
118 | QTest::addColumn<int>(name: "role" ); |
119 | QTest::addColumn<QVariant>(name: "data" ); |
120 | QTest::newRow(dataTag: "null" ) << QModelIndex() << 0 << QVariant(); |
121 | } |
122 | |
123 | // public QVariant data(QModelIndex const& proxyIndex, int role = Qt::DisplayRole) const |
124 | void tst_QAbstractProxyModel::data() |
125 | { |
126 | QFETCH(QModelIndex, proxyIndex); |
127 | QFETCH(int, role); |
128 | QFETCH(QVariant, data); |
129 | |
130 | SubQAbstractProxyModel model; |
131 | QCOMPARE(model.data(proxyIndex, role), data); |
132 | } |
133 | |
134 | Q_DECLARE_METATYPE(Qt::ItemFlags) |
135 | void tst_QAbstractProxyModel::flags_data() |
136 | { |
137 | QTest::addColumn<QModelIndex>(name: "index" ); |
138 | QTest::addColumn<Qt::ItemFlags>(name: "flags" ); |
139 | QTest::newRow(dataTag: "null" ) << QModelIndex() << Qt::ItemFlags{}; |
140 | } |
141 | |
142 | // public Qt::ItemFlags flags(QModelIndex const& index) const |
143 | void tst_QAbstractProxyModel::flags() |
144 | { |
145 | QFETCH(QModelIndex, index); |
146 | QFETCH(Qt::ItemFlags, flags); |
147 | |
148 | SubQAbstractProxyModel model; |
149 | QCOMPARE(model.flags(index), flags); |
150 | } |
151 | |
152 | Q_DECLARE_METATYPE(Qt::Orientation) |
153 | Q_DECLARE_METATYPE(Qt::ItemDataRole) |
154 | void tst_QAbstractProxyModel::() |
155 | { |
156 | QTest::addColumn<int>(name: "section" ); |
157 | QTest::addColumn<Qt::Orientation>(name: "orientation" ); |
158 | QTest::addColumn<Qt::ItemDataRole>(name: "role" ); |
159 | QTest::addColumn<QVariant>(name: "headerData" ); |
160 | QTest::newRow(dataTag: "null" ) << 0 << Qt::Vertical << Qt::UserRole << QVariant(); |
161 | } |
162 | |
163 | // public QVariant headerData(int section, Qt::Orientation orientation, int role) const |
164 | void tst_QAbstractProxyModel::() |
165 | { |
166 | QFETCH(int, section); |
167 | QFETCH(Qt::Orientation, orientation); |
168 | QFETCH(Qt::ItemDataRole, role); |
169 | QFETCH(QVariant, ); |
170 | |
171 | SubQAbstractProxyModel model; |
172 | QCOMPARE(model.headerData(section, orientation, role), headerData); |
173 | } |
174 | |
175 | void tst_QAbstractProxyModel::itemData_data() |
176 | { |
177 | QTest::addColumn<QModelIndex>(name: "index" ); |
178 | QTest::addColumn<int>(name: "count" ); |
179 | |
180 | QTest::newRow(dataTag: "null" ) << QModelIndex() << 0; |
181 | } |
182 | |
183 | // public QMap<int,QVariant> itemData(QModelIndex const& index) const |
184 | void tst_QAbstractProxyModel::itemData() |
185 | { |
186 | QFETCH(QModelIndex, index); |
187 | QFETCH(int, count); |
188 | SubQAbstractProxyModel model; |
189 | QCOMPARE(model.itemData(index).count(), count); |
190 | } |
191 | |
192 | void tst_QAbstractProxyModel::mapFromSource_data() |
193 | { |
194 | QTest::addColumn<QModelIndex>(name: "sourceIndex" ); |
195 | QTest::addColumn<QModelIndex>(name: "mapFromSource" ); |
196 | QTest::newRow(dataTag: "null" ) << QModelIndex() << QModelIndex(); |
197 | } |
198 | |
199 | // public QModelIndex mapFromSource(QModelIndex const& sourceIndex) const |
200 | void tst_QAbstractProxyModel::mapFromSource() |
201 | { |
202 | QFETCH(QModelIndex, sourceIndex); |
203 | QFETCH(QModelIndex, mapFromSource); |
204 | |
205 | SubQAbstractProxyModel model; |
206 | QCOMPARE(model.mapFromSource(sourceIndex), mapFromSource); |
207 | } |
208 | |
209 | void tst_QAbstractProxyModel::mapSelectionFromSource_data() |
210 | { |
211 | QTest::addColumn<QItemSelection>(name: "selection" ); |
212 | QTest::addColumn<QItemSelection>(name: "mapSelectionFromSource" ); |
213 | QTest::newRow(dataTag: "null" ) << QItemSelection() << QItemSelection(); |
214 | QTest::newRow(dataTag: "empty" ) << QItemSelection(QModelIndex(), QModelIndex()) << QItemSelection(QModelIndex(), QModelIndex()); |
215 | } |
216 | |
217 | // public QItemSelection mapSelectionFromSource(QItemSelection const& selection) const |
218 | void tst_QAbstractProxyModel::mapSelectionFromSource() |
219 | { |
220 | QFETCH(QItemSelection, selection); |
221 | QFETCH(QItemSelection, mapSelectionFromSource); |
222 | |
223 | SubQAbstractProxyModel model; |
224 | QCOMPARE(model.mapSelectionFromSource(selection), mapSelectionFromSource); |
225 | } |
226 | |
227 | void tst_QAbstractProxyModel::mapSelectionToSource_data() |
228 | { |
229 | QTest::addColumn<QItemSelection>(name: "selection" ); |
230 | QTest::addColumn<QItemSelection>(name: "mapSelectionToSource" ); |
231 | QTest::newRow(dataTag: "null" ) << QItemSelection() << QItemSelection(); |
232 | QTest::newRow(dataTag: "empty" ) << QItemSelection(QModelIndex(), QModelIndex()) << QItemSelection(QModelIndex(), QModelIndex()); |
233 | } |
234 | |
235 | // public QItemSelection mapSelectionToSource(QItemSelection const& selection) const |
236 | void tst_QAbstractProxyModel::mapSelectionToSource() |
237 | { |
238 | QFETCH(QItemSelection, selection); |
239 | QFETCH(QItemSelection, mapSelectionToSource); |
240 | |
241 | SubQAbstractProxyModel model; |
242 | QCOMPARE(model.mapSelectionToSource(selection), mapSelectionToSource); |
243 | } |
244 | |
245 | void tst_QAbstractProxyModel::mapToSource_data() |
246 | { |
247 | QTest::addColumn<QModelIndex>(name: "proxyIndex" ); |
248 | QTest::addColumn<QModelIndex>(name: "mapToSource" ); |
249 | QTest::newRow(dataTag: "null" ) << QModelIndex() << QModelIndex(); |
250 | } |
251 | |
252 | // public QModelIndex mapToSource(QModelIndex const& proxyIndex) const |
253 | void tst_QAbstractProxyModel::mapToSource() |
254 | { |
255 | QFETCH(QModelIndex, proxyIndex); |
256 | QFETCH(QModelIndex, mapToSource); |
257 | |
258 | SubQAbstractProxyModel model; |
259 | QCOMPARE(model.mapToSource(proxyIndex), mapToSource); |
260 | } |
261 | |
262 | // public void revert() |
263 | void tst_QAbstractProxyModel::revert() |
264 | { |
265 | SubQAbstractProxyModel model; |
266 | model.revert(); |
267 | } |
268 | |
269 | // public void setSourceModel(QAbstractItemModel* sourceModel) |
270 | void tst_QAbstractProxyModel::setSourceModel() |
271 | { |
272 | SubQAbstractProxyModel model; |
273 | |
274 | QCOMPARE(model.property("sourceModel" ), QVariant::fromValue<QAbstractItemModel*>(0)); |
275 | QStandardItemModel *sourceModel = new QStandardItemModel(&model); |
276 | model.setSourceModel(sourceModel); |
277 | QCOMPARE(model.sourceModel(), static_cast<QAbstractItemModel*>(sourceModel)); |
278 | |
279 | QCOMPARE(model.property("sourceModel" ).value<QObject*>(), static_cast<QObject*>(sourceModel)); |
280 | QCOMPARE(model.property("sourceModel" ).value<QAbstractItemModel*>(), sourceModel); |
281 | |
282 | QStandardItemModel *sourceModel2 = new QStandardItemModel(&model); |
283 | model.setSourceModel(sourceModel2); |
284 | QCOMPARE(model.sourceModel(), static_cast<QAbstractItemModel*>(sourceModel2)); |
285 | |
286 | QCOMPARE(model.property("sourceModel" ).value<QObject*>(), static_cast<QObject*>(sourceModel2)); |
287 | QCOMPARE(model.property("sourceModel" ).value<QAbstractItemModel*>(), sourceModel2); |
288 | |
289 | delete sourceModel2; |
290 | QCOMPARE(model.sourceModel(), static_cast<QAbstractItemModel*>(0)); |
291 | } |
292 | |
293 | void tst_QAbstractProxyModel::submit_data() |
294 | { |
295 | QTest::addColumn<bool>(name: "submit" ); |
296 | QTest::newRow(dataTag: "null" ) << true; |
297 | } |
298 | |
299 | // public bool submit() |
300 | void tst_QAbstractProxyModel::submit() |
301 | { |
302 | QFETCH(bool, submit); |
303 | |
304 | SubQAbstractProxyModel model; |
305 | QCOMPARE(model.submit(), submit); |
306 | } |
307 | |
308 | class StandardItemModelWithCustomRoleNames : public QStandardItemModel |
309 | { |
310 | public: |
311 | enum CustomRole { |
312 | CustomRole1 = Qt::UserRole, |
313 | CustomRole2 |
314 | }; |
315 | |
316 | QHash<int, QByteArray> roleNames() const override |
317 | { |
318 | auto result = QStandardItemModel::roleNames(); |
319 | result.insert(key: CustomRole1, QByteArrayLiteral("custom1" )); |
320 | result.insert(key: CustomRole2, QByteArrayLiteral("custom2" )); |
321 | return result; |
322 | } |
323 | }; |
324 | |
325 | class AnotherStandardItemModelWithCustomRoleNames : public QStandardItemModel |
326 | { |
327 | public: |
328 | enum CustomRole { |
329 | AnotherCustomRole1 = Qt::UserRole + 10, // Different to StandardItemModelWithCustomRoleNames::CustomRole1 |
330 | AnotherCustomRole2 |
331 | }; |
332 | |
333 | QHash<int, QByteArray> roleNames() const override |
334 | { |
335 | return {{AnotherCustomRole1, QByteArrayLiteral("another_custom1" )}, |
336 | {AnotherCustomRole2, QByteArrayLiteral("another_custom2" )}}; |
337 | } |
338 | }; |
339 | |
340 | /** |
341 | Verifies that @p subSet is a subset of @p superSet. That is, all keys in @p subSet exist in @p superSet and have the same values. |
342 | */ |
343 | static void verifySubSetOf(const QHash<int, QByteArray> &superSet, const QHash<int, QByteArray> &subSet) |
344 | { |
345 | QHash<int, QByteArray>::const_iterator it = subSet.constBegin(); |
346 | const QHash<int, QByteArray>::const_iterator end = subSet.constEnd(); |
347 | for ( ; it != end; ++it ) { |
348 | QVERIFY(superSet.contains(it.key())); |
349 | QCOMPARE(it.value(), superSet.value(it.key())); |
350 | } |
351 | } |
352 | |
353 | void tst_QAbstractProxyModel::testRoleNames() |
354 | { |
355 | QStandardItemModel defaultModel; |
356 | StandardItemModelWithCustomRoleNames model; |
357 | QHash<int, QByteArray> rootModelRoleNames = model.roleNames(); |
358 | QHash<int, QByteArray> defaultModelRoleNames = defaultModel.roleNames(); |
359 | |
360 | verifySubSetOf( superSet: rootModelRoleNames, subSet: defaultModelRoleNames); |
361 | QVERIFY( rootModelRoleNames.size() == defaultModelRoleNames.size() + 2 ); |
362 | QVERIFY( rootModelRoleNames.contains(StandardItemModelWithCustomRoleNames::CustomRole1)); |
363 | QVERIFY( rootModelRoleNames.contains(StandardItemModelWithCustomRoleNames::CustomRole2)); |
364 | QVERIFY( rootModelRoleNames.value(StandardItemModelWithCustomRoleNames::CustomRole1) == "custom1" ); |
365 | QVERIFY( rootModelRoleNames.value(StandardItemModelWithCustomRoleNames::CustomRole2) == "custom2" ); |
366 | |
367 | SubQAbstractProxyModel proxy1; |
368 | proxy1.setSourceModel(&model); |
369 | QHash<int, QByteArray> proxy1RoleNames = proxy1.roleNames(); |
370 | verifySubSetOf( superSet: proxy1RoleNames, subSet: defaultModelRoleNames ); |
371 | QVERIFY( proxy1RoleNames.size() == defaultModelRoleNames.size() + 2 ); |
372 | QVERIFY( proxy1RoleNames.contains(StandardItemModelWithCustomRoleNames::CustomRole1)); |
373 | QVERIFY( proxy1RoleNames.contains(StandardItemModelWithCustomRoleNames::CustomRole2)); |
374 | QVERIFY( proxy1RoleNames.value(StandardItemModelWithCustomRoleNames::CustomRole1) == "custom1" ); |
375 | QVERIFY( proxy1RoleNames.value(StandardItemModelWithCustomRoleNames::CustomRole2) == "custom2" ); |
376 | |
377 | SubQAbstractProxyModel proxy2; |
378 | proxy2.setSourceModel(&proxy1); |
379 | QHash<int, QByteArray> proxy2RoleNames = proxy2.roleNames(); |
380 | verifySubSetOf( superSet: proxy2RoleNames, subSet: defaultModelRoleNames ); |
381 | QVERIFY( proxy2RoleNames.size() == defaultModelRoleNames.size() + 2 ); |
382 | QVERIFY( proxy2RoleNames.contains(StandardItemModelWithCustomRoleNames::CustomRole1)); |
383 | QVERIFY( proxy2RoleNames.contains(StandardItemModelWithCustomRoleNames::CustomRole2)); |
384 | QVERIFY( proxy2RoleNames.value(StandardItemModelWithCustomRoleNames::CustomRole1) == "custom1" ); |
385 | QVERIFY( proxy2RoleNames.value(StandardItemModelWithCustomRoleNames::CustomRole2) == "custom2" ); |
386 | } |
387 | |
388 | // This class only supports very simple table models |
389 | class SwappingProxy : public QAbstractProxyModel |
390 | { |
391 | static int swapRow(const int row) |
392 | { |
393 | if (row == 2) { |
394 | return 3; |
395 | } else if (row == 3) { |
396 | return 2; |
397 | } else { |
398 | return row; |
399 | } |
400 | } |
401 | public: |
402 | virtual QModelIndex index(int row, int column, const QModelIndex &parentIdx) const |
403 | { |
404 | if (!sourceModel()) |
405 | return QModelIndex(); |
406 | if (row < 0 || column < 0) |
407 | return QModelIndex(); |
408 | if (row >= sourceModel()->rowCount()) |
409 | return QModelIndex(); |
410 | if (column >= sourceModel()->columnCount()) |
411 | return QModelIndex(); |
412 | return createIndex(arow: row, acolumn: column, adata: parentIdx.internalPointer()); |
413 | } |
414 | |
415 | virtual QModelIndex parent(const QModelIndex &parentIdx) const |
416 | { |
417 | // well, we're a 2D model |
418 | Q_UNUSED(parentIdx); |
419 | return QModelIndex(); |
420 | } |
421 | |
422 | virtual int rowCount(const QModelIndex &parentIdx) const |
423 | { |
424 | if (parentIdx.isValid() || !sourceModel()) |
425 | return 0; |
426 | return sourceModel()->rowCount(); |
427 | } |
428 | |
429 | virtual int columnCount(const QModelIndex &parentIdx) const |
430 | { |
431 | if (parentIdx.isValid() || !sourceModel()) |
432 | return 0; |
433 | return sourceModel()->rowCount(); |
434 | } |
435 | |
436 | virtual QModelIndex mapToSource(const QModelIndex &proxyIndex) const |
437 | { |
438 | if (!proxyIndex.isValid()) |
439 | return QModelIndex(); |
440 | if (!sourceModel()) |
441 | return QModelIndex(); |
442 | Q_ASSERT(!proxyIndex.parent().isValid()); |
443 | return sourceModel()->index(row: swapRow(row: proxyIndex.row()), column: proxyIndex.column(), parent: QModelIndex()); |
444 | } |
445 | |
446 | virtual QModelIndex mapFromSource(const QModelIndex &sourceIndex) const |
447 | { |
448 | if (!sourceIndex.isValid()) |
449 | return QModelIndex(); |
450 | if (!sourceModel()) |
451 | return QModelIndex(); |
452 | Q_ASSERT(!sourceIndex.parent().isValid()); |
453 | return index(row: swapRow(row: sourceIndex.row()), column: sourceIndex.column(), parentIdx: QModelIndex()); |
454 | } |
455 | }; |
456 | |
457 | void tst_QAbstractProxyModel::testSwappingRowsProxy() |
458 | { |
459 | QStandardItemModel defaultModel; |
460 | defaultModel.setRowCount(4); |
461 | defaultModel.setColumnCount(2); |
462 | for (int row = 0; row < defaultModel.rowCount(); ++row) { |
463 | defaultModel.setItem(row, column: 0, item: new QStandardItem(QString::number(row) + QLatin1Char('A'))); |
464 | defaultModel.setItem(row, column: 1, item: new QStandardItem(QString::number(row) + QLatin1Char('B'))); |
465 | } |
466 | SwappingProxy proxy; |
467 | proxy.setSourceModel(&defaultModel); |
468 | QCOMPARE(proxy.data(proxy.index(0, 0, QModelIndex())), QVariant("0A" )); |
469 | QCOMPARE(proxy.data(proxy.index(0, 1, QModelIndex())), QVariant("0B" )); |
470 | QCOMPARE(proxy.data(proxy.index(1, 0, QModelIndex())), QVariant("1A" )); |
471 | QCOMPARE(proxy.data(proxy.index(1, 1, QModelIndex())), QVariant("1B" )); |
472 | QCOMPARE(proxy.data(proxy.index(2, 0, QModelIndex())), QVariant("3A" )); |
473 | QCOMPARE(proxy.data(proxy.index(2, 1, QModelIndex())), QVariant("3B" )); |
474 | QCOMPARE(proxy.data(proxy.index(3, 0, QModelIndex())), QVariant("2A" )); |
475 | QCOMPARE(proxy.data(proxy.index(3, 1, QModelIndex())), QVariant("2B" )); |
476 | |
477 | for (int row = 0; row < defaultModel.rowCount(); ++row) { |
478 | QModelIndex left = proxy.index(row, column: 0, parentIdx: QModelIndex()); |
479 | QModelIndex right = proxy.index(row, column: 1, parentIdx: QModelIndex()); |
480 | QCOMPARE(left.siblingAtColumn(1), right); |
481 | QCOMPARE(right.siblingAtColumn(0), left); |
482 | } |
483 | } |
484 | |
485 | class StandardItemModelWithCustomDragAndDrop : public QStandardItemModel |
486 | { |
487 | public: |
488 | QStringList mimeTypes() const { return QStringList() << QStringLiteral("foo/mimetype" ); } |
489 | Qt::DropActions supportedDragActions() const { return Qt::CopyAction | Qt::LinkAction; } |
490 | Qt::DropActions supportedDropActions() const { return Qt::MoveAction; } |
491 | }; |
492 | |
493 | void tst_QAbstractProxyModel::testDragAndDrop() |
494 | { |
495 | StandardItemModelWithCustomDragAndDrop sourceModel; |
496 | SubQAbstractProxyModel proxy; |
497 | proxy.setSourceModel(&sourceModel); |
498 | QCOMPARE(proxy.mimeTypes(), sourceModel.mimeTypes()); |
499 | QCOMPARE(proxy.supportedDragActions(), sourceModel.supportedDragActions()); |
500 | QCOMPARE(proxy.supportedDropActions(), sourceModel.supportedDropActions()); |
501 | } |
502 | |
503 | |
504 | QTEST_MAIN(tst_QAbstractProxyModel) |
505 | #include "tst_qabstractproxymodel.moc" |
506 | |
507 | |