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
45
#include <qabstractitemview.h>
46
#include <qstandarditemmodel.h>
47
#include <qapplication.h>
48
#include <qlistview.h>
49
#include <qlistwidget.h>
50
#include <qtableview.h>
51
#include <qtablewidget.h>
52
#include <qtreeview.h>
53
#include <qtreewidget.h>
54
#include <qheaderview.h>
55
#include <qspinbox.h>
56
#include <qitemdelegate.h>
57
#include <qpushbutton.h>
58
#include <qscrollbar.h>
59
#include <qboxlayout.h>
60
#include <qlineedit.h>
61
#include "../../shared/util.h"
62
63
//TESTED_CLASS=
64
//TESTED_FILES=
65
66
// Will try to wait for the condition while allowing event processing
67
// for a maximum of 5 seconds.
68
#define TRY_COMPARE(expr, expected) \
69
    do { \
70
        const int step = 50; \
71
        for (int q = 0; q < 5000 && ((expr) != (expected)); q+=step) { \
72
            QTest::qWait(step); \
73
        } \
74
        QCOMPARE(expr, expected); \
75
    } while(0)
76
77
class TestView : public QAbstractItemView
78
{
79
    Q_OBJECT
80
public:
81
    inline void tst_dataChanged(const QModelIndex &tl, const QModelIndex &br)
82
        { dataChanged(tl, br); }
83
    inline void tst_setHorizontalStepsPerItem(int steps)
84
        { setHorizontalStepsPerItem(steps); }
85
    inline int tst_horizontalStepsPerItem() const
86
        { return horizontalStepsPerItem(); }
87
    inline void tst_setVerticalStepsPerItem(int steps)
88
        { setVerticalStepsPerItem(steps); }
89
    inline int tst_verticalStepsPerItem() const
90
        { return verticalStepsPerItem(); }
91
92
    inline void tst_rowsInserted(const QModelIndex &parent, int start, int end)
93
        { rowsInserted(parent, start, end); }
94
    inline void tst_rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
95
        { rowsAboutToBeRemoved(parent, start, end); }
96
    inline void tst_selectionChanged(const QItemSelection &selected,
97
                                     const QItemSelection &deselected)
98
        { selectionChanged(selected, deselected); }
99
    inline void tst_currentChanged(const QModelIndex &current, const QModelIndex &previous)
100
        { currentChanged(current, previous); }
101
    inline void tst_updateEditorData()
102
        { updateEditorData(); }
103
    inline void tst_updateEditorGeometries()
104
        { updateEditorGeometries(); }
105
    inline void tst_updateGeometries()
106
        { updateGeometries(); }
107
    inline void tst_verticalScrollbarAction(int action)
108
        { verticalScrollbarAction(action); }
109
    inline void tst_horizontalScrollbarAction(int action)
110
        { horizontalScrollbarAction(action); }
111
    inline void tst_verticalScrollbarValueChanged(int value)
112
        { verticalScrollbarValueChanged(value); }
113
    inline void tst_horizontalScrollbarValueChanged(int value)
114
        { horizontalScrollbarValueChanged(value); }
115
    inline void tst_closeEditor(QWidget *editor, QAbstractItemDelegate::EndEditHint hint)
116
        { closeEditor(editor, hint); }
117
    inline void tst_commitData(QWidget *editor)
118
        { commitData(editor); }
119
    inline void tst_editorDestroyed(QObject *editor)
120
        { editorDestroyed(editor); }
121
    enum tst_CursorAction {
122
        MoveUp = QAbstractItemView::MoveUp,
123
        MoveDown = QAbstractItemView::MoveDown,
124
        MoveLeft = QAbstractItemView::MoveLeft,
125
        MoveRight = QAbstractItemView::MoveRight,
126
        MoveHome = QAbstractItemView::MoveHome,
127
        MoveEnd = QAbstractItemView::MoveEnd,
128
        MovePageUp = QAbstractItemView::MovePageUp,
129
        MovePageDown = QAbstractItemView::MovePageDown,
130
        MoveNext = QAbstractItemView::MoveNext,
131
        MovePrevious = QAbstractItemView::MovePrevious
132
    };
133
    inline QModelIndex tst_moveCursor(tst_CursorAction cursorAction,
134
                                      Qt::KeyboardModifiers modifiers)
135
        { return moveCursor(QAbstractItemView::CursorAction(cursorAction), modifiers); }
136
    inline int tst_horizontalOffset() const
137
        { return horizontalOffset(); }
138
    inline int tst_verticalOffset() const
139
        { return verticalOffset(); }
140
    inline bool tst_isIndexHidden(const QModelIndex &index) const
141
        { return isIndexHidden(index); }
142
    inline void tst_setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags command)
143
        { setSelection(rect, command); }
144
    inline QRegion tst_visualRegionForSelection(const QItemSelection &selection) const
145
        { return visualRegionForSelection(selection); }
146
    inline QModelIndexList tst_selectedIndexes() const
147
        { return selectedIndexes(); }
148
    inline bool tst_edit(const QModelIndex &index, EditTrigger trigger, QEvent *event)
149
        { return edit(index, trigger, event); }
150
    inline QItemSelectionModel::SelectionFlags tst_selectionCommand(const QModelIndex &index,
151
                                                                    const QEvent *event = 0) const
152
        { return selectionCommand(index, event); }
153
#ifndef QT_NO_DRAGANDDROP
154
    inline void tst_startDrag(Qt::DropActions supportedActions)
155
        { startDrag(supportedActions); }
156
#endif
157
    inline QStyleOptionViewItem tst_viewOptions() const
158
        { return viewOptions(); }
159
    enum tst_State {
160
        NoState = QAbstractItemView::NoState,
161
        DraggingState = QAbstractItemView::DraggingState,
162
        DragSelectingState = QAbstractItemView::DragSelectingState,
163
        EditingState = QAbstractItemView::EditingState,
164
        ExpandingState = QAbstractItemView::ExpandingState,
165
        CollapsingState = QAbstractItemView::CollapsingState
166
    };
167
    inline tst_State tst_state() const
168
        { return (tst_State)state(); }
169
    inline void tst_setState(tst_State state)
170
        { setState(QAbstractItemView::State(state)); }
171
    inline void tst_startAutoScroll()
172
        { startAutoScroll(); }
173
    inline void tst_stopAutoScroll()
174
        { stopAutoScroll(); }
175
    inline void tst_doAutoScroll()
176
        { doAutoScroll(); }
177
};
178
179
class tst_QAbstractItemView : public QObject
180
{
181
    Q_OBJECT
182
183
public:
184
185
    tst_QAbstractItemView();
186
    virtual ~tst_QAbstractItemView();
187
    void basic_tests(TestView *view);
188
189
public slots:
190
    void initTestCase();
191
    void cleanupTestCase();
192
193
private slots:
194
    void getSetCheck();
195
    void emptyModels_data();
196
    void emptyModels();
197
    void setModel_data();
198
    void setModel();
199
    void noModel();
200
    void dragSelect();
201
    void rowDelegate();
202
    void columnDelegate();
203
    void selectAll();
204
    void ctrlA();
205
    void persistentEditorFocus();
206
    void setItemDelegate();
207
    void setItemDelegate_data();
208
	// The dragAndDrop() test doesn't work, and is thus disabled on Mac and Windows
209
	// for the following reasons:
210
	//   Mac: use of GetCurrentEventButtonState() in QDragManager::drag()
211
	//   Win: unknown reason
212
#if !defined(Q_OS_MAC) && !defined(Q_OS_WIN)
213
#if 0
214
    void dragAndDrop();
215
    void dragAndDropOnChild();
216
#endif
217
#endif
218
    void noFallbackToRoot();
219
    void setCurrentIndex_data();
220
    void setCurrentIndex();
221
222
    void task221955_selectedEditor();
223
    void task250754_fontChange();
224
    void task200665_itemEntered();
225
    void task257481_emptyEditor();
226
    void shiftArrowSelectionAfterScrolling();
227
    void shiftSelectionAfterRubberbandSelection();
228
    void ctrlRubberbandSelection();
229
    void QTBUG6407_extendedSelection();
230
    void QTBUG6753_selectOnSelection();
231
};
232
233
class MyAbstractItemDelegate : public QAbstractItemDelegate
234
{
235
public:
236
    MyAbstractItemDelegate() : QAbstractItemDelegate() {};
237
    void paint(QPainter *, const QStyleOptionViewItem &, const QModelIndex &) const {}
238
    QSize sizeHint(const QStyleOptionViewItem &, const QModelIndex &) const { return QSize(); }
239
    QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &,
240
                          const QModelIndex &) const { return new QWidget(parent); }
241
};
242
243
// Testing get/set functions
244
void tst_QAbstractItemView::getSetCheck()
245
{
246
    QListView view;
247
    TestView *obj1 = reinterpret_cast<TestView*>(&view);
248
    // QAbstractItemDelegate * QAbstractItemView::itemDelegate()
249
    // void QAbstractItemView::setItemDelegate(QAbstractItemDelegate *)
250
    MyAbstractItemDelegate *var1 = new MyAbstractItemDelegate;
251
    obj1->setItemDelegate(var1);
252
    QCOMPARE((QAbstractItemDelegate*)var1, obj1->itemDelegate());
253
    obj1->setItemDelegate((QAbstractItemDelegate *)0);
254
    QCOMPARE((QAbstractItemDelegate *)0, obj1->itemDelegate());
255
    delete var1;
256
257
    // EditTriggers QAbstractItemView::editTriggers()
258
    // void QAbstractItemView::setEditTriggers(EditTriggers)
259
    obj1->setEditTriggers(QAbstractItemView::EditTriggers(QAbstractItemView::NoEditTriggers));
260
    QCOMPARE(QAbstractItemView::EditTriggers(QAbstractItemView::NoEditTriggers), obj1->editTriggers());
261
    obj1->setEditTriggers(QAbstractItemView::EditTriggers(QAbstractItemView::CurrentChanged));
262
    QCOMPARE(QAbstractItemView::EditTriggers(QAbstractItemView::CurrentChanged), obj1->editTriggers());
263
    obj1->setEditTriggers(QAbstractItemView::EditTriggers(QAbstractItemView::DoubleClicked));
264
    QCOMPARE(QAbstractItemView::EditTriggers(QAbstractItemView::DoubleClicked), obj1->editTriggers());
265
    obj1->setEditTriggers(QAbstractItemView::EditTriggers(QAbstractItemView::SelectedClicked));
266
    QCOMPARE(QAbstractItemView::EditTriggers(QAbstractItemView::SelectedClicked), obj1->editTriggers());
267
    obj1->setEditTriggers(QAbstractItemView::EditTriggers(QAbstractItemView::EditKeyPressed));
268
    QCOMPARE(QAbstractItemView::EditTriggers(QAbstractItemView::EditKeyPressed), obj1->editTriggers());
269
    obj1->setEditTriggers(QAbstractItemView::EditTriggers(QAbstractItemView::AnyKeyPressed));
270
    QCOMPARE(QAbstractItemView::EditTriggers(QAbstractItemView::AnyKeyPressed), obj1->editTriggers());
271
    obj1->setEditTriggers(QAbstractItemView::EditTriggers(QAbstractItemView::AllEditTriggers));
272
    QCOMPARE(QAbstractItemView::EditTriggers(QAbstractItemView::AllEditTriggers), obj1->editTriggers());
273
274
    // bool QAbstractItemView::tabKeyNavigation()
275
    // void QAbstractItemView::setTabKeyNavigation(bool)
276
    obj1->setTabKeyNavigation(false);
277
    QCOMPARE(false, obj1->tabKeyNavigation());
278
    obj1->setTabKeyNavigation(true);
279
    QCOMPARE(true, obj1->tabKeyNavigation());
280
281
    // bool QAbstractItemView::dragEnabled()
282
    // void QAbstractItemView::setDragEnabled(bool)
283
#ifndef QT_NO_DRAGANDDROP
284
    obj1->setDragEnabled(false);
285
    QCOMPARE(false, obj1->dragEnabled());
286
    obj1->setDragEnabled(true);
287
    QCOMPARE(true, obj1->dragEnabled());
288
#endif
289
    // bool QAbstractItemView::alternatingRowColors()
290
    // void QAbstractItemView::setAlternatingRowColors(bool)
291
    obj1->setAlternatingRowColors(false);
292
    QCOMPARE(false, obj1->alternatingRowColors());
293
    obj1->setAlternatingRowColors(true);
294
    QCOMPARE(true, obj1->alternatingRowColors());
295
296
    // State QAbstractItemView::state()
297
    // void QAbstractItemView::setState(State)
298
    obj1->tst_setState(TestView::tst_State(TestView::NoState));
299
    QCOMPARE(TestView::tst_State(TestView::NoState), obj1->tst_state());
300
    obj1->tst_setState(TestView::tst_State(TestView::DraggingState));
301
    QCOMPARE(TestView::tst_State(TestView::DraggingState), obj1->tst_state());
302
    obj1->tst_setState(TestView::tst_State(TestView::DragSelectingState));
303
    QCOMPARE(TestView::tst_State(TestView::DragSelectingState), obj1->tst_state());
304
    obj1->tst_setState(TestView::tst_State(TestView::EditingState));
305
    QCOMPARE(TestView::tst_State(TestView::EditingState), obj1->tst_state());
306
    obj1->tst_setState(TestView::tst_State(TestView::ExpandingState));
307
    QCOMPARE(TestView::tst_State(TestView::ExpandingState), obj1->tst_state());
308
    obj1->tst_setState(TestView::tst_State(TestView::CollapsingState));
309
    QCOMPARE(TestView::tst_State(TestView::CollapsingState), obj1->tst_state());
310
311
    // QWidget QAbstractScrollArea::viewport()
312
    // void setViewport(QWidget*)
313
    QWidget *vp = new QWidget;
314
    obj1->setViewport(vp);
315
    QCOMPARE(vp, obj1->viewport());
316
317
    QCOMPARE(16, obj1->autoScrollMargin());
318
    obj1->setAutoScrollMargin(20);
319
    QCOMPARE(20, obj1->autoScrollMargin());
320
    obj1->setAutoScrollMargin(16);
321
    QCOMPARE(16, obj1->autoScrollMargin());
322
}
323
324
tst_QAbstractItemView::tst_QAbstractItemView()
325
{
326
}
327
328
tst_QAbstractItemView::~tst_QAbstractItemView()
329
{
330
}
331
332
void tst_QAbstractItemView::initTestCase()
333
{
334
#ifdef Q_OS_WINCE_WM
335
    qApp->setAutoMaximizeThreshold(-1);
336
#endif
337
}
338
339
void tst_QAbstractItemView::cleanupTestCase()
340
{
341
}
342
343
void tst_QAbstractItemView::emptyModels_data()
344
{
345
    QTest::addColumn<QString>("viewType");
346
347
    QTest::newRow("QListView") << "QListView";
348
    QTest::newRow("QTableView") << "QTableView";
349
    QTest::newRow("QTreeView") << "QTreeView";
350
    QTest::newRow("QHeaderView") << "QHeaderView";
351
}
352
353
void tst_QAbstractItemView::emptyModels()
354
{
355
    QFETCH(QString, viewType);
356
357
    TestView *view = 0;
358
    if (viewType == "QListView")
359
        view = reinterpret_cast<TestView*>(new QListView());
360
    else if (viewType == "QTableView")
361
        view = reinterpret_cast<TestView*>(new QTableView());
362
    else if (viewType == "QTreeView")
363
        view = reinterpret_cast<TestView*>(new QTreeView());
364
    else if (viewType == "QHeaderView")
365
        view = reinterpret_cast<TestView*>(new QHeaderView(Qt::Vertical));
366
    else
367
        QVERIFY(0);
368
    view->show();
369
370
    QVERIFY(!view->model());
371
    QVERIFY(!view->selectionModel());
372
    //QVERIFY(view->itemDelegate() != 0);
373
374
    basic_tests(view);
375
    delete view;
376
}
377
378
void tst_QAbstractItemView::setModel_data()
379
{
380
    QTest::addColumn<QString>("viewType");
381
382
    QTest::newRow("QListView") << "QListView";
383
    QTest::newRow("QTableView") << "QTableView";
384
    QTest::newRow("QTreeView") << "QTreeView";
385
    QTest::newRow("QHeaderView") << "QHeaderView";
386
}
387
388
void tst_QAbstractItemView::setModel()
389
{
390
    QFETCH(QString, viewType);
391
    TestView *view = 0;
392
    if (viewType == "QListView")
393
        view = reinterpret_cast<TestView*>(new QListView());
394
    else if (viewType == "QTableView")
395
        view = reinterpret_cast<TestView*>(new QTableView());
396
    else if (viewType == "QTreeView")
397
        view = reinterpret_cast<TestView*>(new QTreeView());
398
    else if (viewType == "QHeaderView")
399
        view = reinterpret_cast<TestView*>(new QHeaderView(Qt::Vertical));
400
    else
401
        QVERIFY(0);
402
    view->show();
403
404
    QStandardItemModel model(20,20);
405
    view->setModel(0);
406
    view->setModel(&model);
407
    basic_tests(view);
408
    delete view;
409
}
410
411
void tst_QAbstractItemView::basic_tests(TestView *view)
412
{
413
    // setSelectionModel
414
    // Will assert as it should
415
    //view->setSelectionModel(0);
416
    // setItemDelegate
417
    //view->setItemDelegate(0);
418
    // Will asswert as it should
419
420
    // setSelectionMode
421
    view->setSelectionMode(QAbstractItemView::SingleSelection);
422
    QCOMPARE(view->selectionMode(), QAbstractItemView::SingleSelection);
423
    view->setSelectionMode(QAbstractItemView::ContiguousSelection);
424
    QCOMPARE(view->selectionMode(), QAbstractItemView::ContiguousSelection);
425
    view->setSelectionMode(QAbstractItemView::ExtendedSelection);
426
    QCOMPARE(view->selectionMode(), QAbstractItemView::ExtendedSelection);
427
    view->setSelectionMode(QAbstractItemView::MultiSelection);
428
    QCOMPARE(view->selectionMode(), QAbstractItemView::MultiSelection);
429
    view->setSelectionMode(QAbstractItemView::NoSelection);
430
    QCOMPARE(view->selectionMode(), QAbstractItemView::NoSelection);
431
432
    // setSelectionBehavior
433
    view->setSelectionBehavior(QAbstractItemView::SelectItems);
434
    QCOMPARE(view->selectionBehavior(), QAbstractItemView::SelectItems);
435
    view->setSelectionBehavior(QAbstractItemView::SelectRows);
436
    QCOMPARE(view->selectionBehavior(), QAbstractItemView::SelectRows);
437
    view->setSelectionBehavior(QAbstractItemView::SelectColumns);
438
    QCOMPARE(view->selectionBehavior(), QAbstractItemView::SelectColumns);
439
440
    // setEditTriggers
441
    view->setEditTriggers(QAbstractItemView::EditKeyPressed);
442
    QCOMPARE(view->editTriggers(), QAbstractItemView::EditKeyPressed);
443
    view->setEditTriggers(QAbstractItemView::NoEditTriggers);
444
    QCOMPARE(view->editTriggers(), QAbstractItemView::NoEditTriggers);
445
    view->setEditTriggers(QAbstractItemView::CurrentChanged);
446
    QCOMPARE(view->editTriggers(), QAbstractItemView::CurrentChanged);
447
    view->setEditTriggers(QAbstractItemView::DoubleClicked);
448
    QCOMPARE(view->editTriggers(), QAbstractItemView::DoubleClicked);
449
    view->setEditTriggers(QAbstractItemView::SelectedClicked);
450
    QCOMPARE(view->editTriggers(), QAbstractItemView::SelectedClicked);
451
    view->setEditTriggers(QAbstractItemView::AnyKeyPressed);
452
    QCOMPARE(view->editTriggers(), QAbstractItemView::AnyKeyPressed);
453
    view->setEditTriggers(QAbstractItemView::AllEditTriggers);
454
    QCOMPARE(view->editTriggers(), QAbstractItemView::AllEditTriggers);
455
456
    // setAutoScroll
457
    view->setAutoScroll(false);
458
    QCOMPARE(view->hasAutoScroll(), false);
459
    view->setAutoScroll(true);
460
    QCOMPARE(view->hasAutoScroll(), true);
461
462
    // setTabKeyNavigation
463
    view->setTabKeyNavigation(false);
464
    QCOMPARE(view->tabKeyNavigation(), false);
465
    view->setTabKeyNavigation(true);
466
    QCOMPARE(view->tabKeyNavigation(), true);
467
468
#ifndef QT_NO_DRAGANDDROP
469
    // setDropIndicatorShown
470
    view->setDropIndicatorShown(false);
471
    QCOMPARE(view->showDropIndicator(), false);
472
    view->setDropIndicatorShown(true);
473
    QCOMPARE(view->showDropIndicator(), true);
474
475
    // setDragEnabled
476
    view->setDragEnabled(false);
477
    QCOMPARE(view->dragEnabled(), false);
478
    view->setDragEnabled(true);
479
    QCOMPARE(view->dragEnabled(), true);
480
#endif
481
482
    // setAlternatingRowColors
483
    view->setAlternatingRowColors(false);
484
    QCOMPARE(view->alternatingRowColors(), false);
485
    view->setAlternatingRowColors(true);
486
    QCOMPARE(view->alternatingRowColors(), true);
487
488
    // setIconSize
489
    view->setIconSize(QSize(16, 16));
490
    QCOMPARE(view->iconSize(), QSize(16, 16));
491
    view->setIconSize(QSize(32, 32));
492
    QCOMPARE(view->iconSize(), QSize(32, 32));
493
    // Should this happen?
494
    view->setIconSize(QSize(-1, -1));
495
    QCOMPARE(view->iconSize(), QSize(-1, -1));
496
497
    QCOMPARE(view->currentIndex(), QModelIndex());
498
    QCOMPARE(view->rootIndex(), QModelIndex());
499
500
    view->keyboardSearch("");
501
    view->keyboardSearch("foo");
502
    view->keyboardSearch("1");
503
504
    QCOMPARE(view->visualRect(QModelIndex()), QRect());
505
506
    view->scrollTo(QModelIndex());
507
508
    QCOMPARE(view->sizeHintForIndex(QModelIndex()), QSize());
509
    QCOMPARE(view->indexAt(QPoint(-1, -1)), QModelIndex());
510
511
    if (!view->model()){
512
        QCOMPARE(view->indexAt(QPoint(10, 10)), QModelIndex());
513
        QCOMPARE(view->sizeHintForRow(0), -1);
514
        QCOMPARE(view->sizeHintForColumn(0), -1);
515
    }else if (view->itemDelegate()){
516
        view->sizeHintForRow(0);
517
        view->sizeHintForColumn(0);
518
    }
519
    view->openPersistentEditor(QModelIndex());
520
    view->closePersistentEditor(QModelIndex());
521
522
    view->reset();
523
    view->setRootIndex(QModelIndex());
524
    view->doItemsLayout();
525
    view->selectAll();
526
    view->edit(QModelIndex());
527
    view->clearSelection();
528
    view->setCurrentIndex(QModelIndex());
529
530
    // protected methods
531
    view->tst_dataChanged(QModelIndex(), QModelIndex());
532
    view->tst_rowsInserted(QModelIndex(), -1, -1);
533
    view->tst_rowsAboutToBeRemoved(QModelIndex(), -1, -1);
534
    view->tst_selectionChanged(QItemSelection(), QItemSelection());
535
    if (view->model()){
536
        view->tst_currentChanged(QModelIndex(), QModelIndex());
537
        view->tst_currentChanged(QModelIndex(), view->model()->index(0,0));
538
    }
539
    view->tst_updateEditorData();
540
    view->tst_updateEditorGeometries();
541
    view->tst_updateGeometries();
542
    view->tst_verticalScrollbarAction(QAbstractSlider::SliderSingleStepAdd);
543
    view->tst_horizontalScrollbarAction(QAbstractSlider::SliderSingleStepAdd);
544
    view->tst_verticalScrollbarValueChanged(10);
545
    view->tst_horizontalScrollbarValueChanged(10);
546
    view->tst_closeEditor(0, QAbstractItemDelegate::NoHint);
547
    view->tst_commitData(0);
548
    view->tst_editorDestroyed(0);
549
550
    view->tst_setHorizontalStepsPerItem(2);
551
    view->tst_horizontalStepsPerItem();
552
    view->tst_setVerticalStepsPerItem(2);
553
    view->tst_verticalStepsPerItem();
554
555
    // Will assert as it should
556
    // view->setIndexWidget(QModelIndex(), 0);
557
558
    view->tst_moveCursor(TestView::MoveUp, Qt::NoModifier);
559
    view->tst_horizontalOffset();
560
    view->tst_verticalOffset();
561
562
//    view->tst_isIndexHidden(QModelIndex()); // will (correctly) assert
563
    if(view->model())
564
        view->tst_isIndexHidden(view->model()->index(0,0));
565
566
    view->tst_setSelection(QRect(0, 0, 10, 10), QItemSelectionModel::ClearAndSelect);
567
    view->tst_setSelection(QRect(-1, -1, -1, -1), QItemSelectionModel::ClearAndSelect);
568
    view->tst_visualRegionForSelection(QItemSelection());
569
    view->tst_selectedIndexes();
570
571
    view->tst_edit(QModelIndex(), QAbstractItemView::NoEditTriggers, 0);
572
573
    view->tst_selectionCommand(QModelIndex(), 0);
574
575
#ifndef QT_NO_DRAGANDDROP
576
    if (!view->model())
577
        view->tst_startDrag(Qt::CopyAction);
578
579
    view->tst_viewOptions();
580
581
    view->tst_setState(TestView::NoState);
582
    QVERIFY(view->tst_state()==TestView::NoState);
583
    view->tst_setState(TestView::DraggingState);
584
    QVERIFY(view->tst_state()==TestView::DraggingState);
585
    view->tst_setState(TestView::DragSelectingState);
586
    QVERIFY(view->tst_state()==TestView::DragSelectingState);
587
    view->tst_setState(TestView::EditingState);
588
    QVERIFY(view->tst_state()==TestView::EditingState);
589
    view->tst_setState(TestView::ExpandingState);
590
    QVERIFY(view->tst_state()==TestView::ExpandingState);
591
    view->tst_setState(TestView::CollapsingState);
592
    QVERIFY(view->tst_state()==TestView::CollapsingState);
593
#endif
594
595
    view->tst_startAutoScroll();
596
    view->tst_stopAutoScroll();
597
    view->tst_doAutoScroll();
598
599
    // testing mouseFoo and key functions
600
//     QTest::mousePress(view, Qt::LeftButton, Qt::NoModifier, QPoint(0,0));
601
//     mouseMove(view, Qt::LeftButton, Qt::NoModifier, QPoint(10,10));
602
//     QTest::mouseRelease(view, Qt::LeftButton, Qt::NoModifier, QPoint(10,10));
603
//     QTest::mouseClick(view, Qt::LeftButton, Qt::NoModifier, QPoint(10,10));
604
//     mouseDClick(view, Qt::LeftButton, Qt::NoModifier, QPoint(10,10));
605
//     QTest::keyClick(view, Qt::Key_A);
606
}
607
608
void tst_QAbstractItemView::noModel()
609
{
610
    // From task #85415
611
612
    QStandardItemModel model(20,20);
613
    QTreeView view;
614
615
    view.setModel(&model);
616
    // Make the viewport smaller than the contents, so that we can scroll
617
    view.resize(100,100);
618
    view.show();
619
620
    // make sure that the scrollbars are not at value 0
621
    view.scrollTo(view.model()->index(10,10));
622
    QApplication::processEvents();
623
624
    view.setModel(0);
625
    // Due to the model is removed, this will generate a valueChanged signal on both scrollbars. (value to 0)
626
    QApplication::processEvents();
627
    QCOMPARE(view.model(), (QAbstractItemModel*)0);
628
}
629
630
void tst_QAbstractItemView::dragSelect()
631
{
632
    // From task #86108
633
634
    QStandardItemModel model(64,64);
635
636
    QTableView view;
637
    view.setModel(&model);
638
    view.setVisible(true);
639
640
    const int delay = 2;
641
    for (int i = 0; i < 2; ++i) {
642
        bool tracking = (i == 1);
643
        view.setMouseTracking(false);
644
        QTest::mouseMove(&view, QPoint(0, 0), delay);
645
        view.setMouseTracking(tracking);
646
        QTest::mouseMove(&view, QPoint(50, 50), delay);
647
        QVERIFY(view.selectionModel()->selectedIndexes().isEmpty());
648
    }
649
}
650
651
void tst_QAbstractItemView::rowDelegate()
652
{
653
    QStandardItemModel model(4,4);
654
    MyAbstractItemDelegate delegate;
655
656
    QTableView view;
657
    view.setModel(&model);
658
    view.setItemDelegateForRow(3, &delegate);
659
    view.show();
660
661
    QModelIndex index = model.index(3, 0);
662
    view.openPersistentEditor(index);
663
    QWidget *w = view.indexWidget(index);
664
    QVERIFY(w);
665
    QCOMPARE(w->metaObject()->className(), "QWidget");
666
}
667
668
void tst_QAbstractItemView::columnDelegate()
669
{
670
    QStandardItemModel model(4,4);
671
    MyAbstractItemDelegate delegate;
672
673
    QTableView view;
674
    view.setModel(&model);
675
    view.setItemDelegateForColumn(3, &delegate);
676
    view.show();
677
678
    QModelIndex index = model.index(0, 3);
679
    view.openPersistentEditor(index);
680
    QWidget *w = view.indexWidget(index);
681
    QVERIFY(w);
682
    QCOMPARE(w->metaObject()->className(), "QWidget");
683
}
684
685
void tst_QAbstractItemView::selectAll()
686
{
687
    QStandardItemModel model(4,4);
688
    QTableView view;
689
    view.setModel(&model);
690
691
    TestView *tst_view = (TestView*)&view;
692
693
    QCOMPARE(tst_view->tst_selectedIndexes().count(), 0);
694
    view.selectAll();
695
    QCOMPARE(tst_view->tst_selectedIndexes().count(), 4*4);
696
}
697
698
void tst_QAbstractItemView::ctrlA()
699
{
700
    QStandardItemModel model(4,4);
701
    QTableView view;
702
    view.setModel(&model);
703
704
    TestView *tst_view = (TestView*)&view;
705
706
    QCOMPARE(tst_view->tst_selectedIndexes().count(), 0);
707
    QTest::keyClick(&view, Qt::Key_A, Qt::ControlModifier);
708
    QCOMPARE(tst_view->tst_selectedIndexes().count(), 4*4);
709
}
710
711
void tst_QAbstractItemView::persistentEditorFocus()
712
{
713
    // one row, three columns
714
    QStandardItemModel model(1, 3);
715
    for(int i = 0; i < model.columnCount(); ++i)
716
        model.setData(model.index(0, i), i);
717
    QTableView view;
718
    view.setModel(&model);
719
720
    view.openPersistentEditor(model.index(0, 1));
721
    view.openPersistentEditor(model.index(0, 2));
722
723
    //these are spinboxes because we put numbers inside
724
    QList<QSpinBox*> list = qFindChildren<QSpinBox*>(view.viewport());
725
    QCOMPARE(list.count(), 2); //these should be the 2 editors
726
727
    view.setCurrentIndex(model.index(0, 0));
728
    QCOMPARE(view.currentIndex(), model.index(0, 0));
729
    view.show();
730
    QTRY_VERIFY(view.isVisible());
731
732
    for (int i = 0; i < list.count(); ++i) {
733
        TRY_COMPARE(list.at(i)->isVisible(), true);
734
        QPoint p = QPoint(5, 5);
735
        QMouseEvent mouseEvent(QEvent::MouseButtonPress, p, Qt::LeftButton,
736
                               Qt::LeftButton, Qt::NoModifier);
737
        qApp->sendEvent(list.at(i), &mouseEvent);
738
        if (!qApp->focusWidget())
739
            QSKIP("Some window managers don't handle focus that well", SkipAll);
740
        QTRY_COMPARE(qApp->focusWidget(), static_cast<QWidget *>(list.at(i)));
741
    }
742
}
743
744
745
#if !defined(Q_OS_MAC) && !defined(Q_OS_WIN)
746
747
#if 0
748
749
static void sendMouseMove(QWidget *widget, QPoint pos = QPoint())
750
{
751
    if (pos.isNull())
752
        pos = widget->rect().center();
753
    QMouseEvent event(QEvent::MouseMove, pos, widget->mapToGlobal(pos), Qt::NoButton, 0, 0);
754
    QCursor::setPos(widget->mapToGlobal(pos));
755
    qApp->processEvents();
756
#if defined(Q_WS_X11)
757
    qt_x11_wait_for_window_manager(widget);
758
#endif
759
    QApplication::sendEvent(widget, &event);
760
}
761
762
static void sendMousePress(
763
    QWidget *widget, QPoint pos = QPoint(), Qt::MouseButton button = Qt::LeftButton)
764
{
765
    if (pos.isNull())
766
         pos = widget->rect().center();
767
    QMouseEvent event(QEvent::MouseButtonPress, pos, widget->mapToGlobal(pos), button, 0, 0);
768
    QApplication::sendEvent(widget, &event);
769
}
770
771
static void sendMouseRelease(
772
    QWidget *widget, QPoint pos = QPoint(), Qt::MouseButton button = Qt::LeftButton)
773
{
774
    if (pos.isNull())
775
         pos = widget->rect().center();
776
    QMouseEvent event(QEvent::MouseButtonRelease, pos, widget->mapToGlobal(pos), button, 0, 0);
777
    QApplication::sendEvent(widget, &event);
778
}
779
780
class DnDTestModel : public QStandardItemModel
781
{
782
    Q_OBJECT
783
    bool dropMimeData(const QMimeData *md, Qt::DropAction action, int r, int c, const QModelIndex &p)
784
    {
785
        dropAction_result = action;
786
        QStandardItemModel::dropMimeData(md, action, r, c, p);
787
        return true;
788
    }
789
    Qt::DropActions supportedDropActions() const { return Qt::CopyAction | Qt::MoveAction; }
790
791
    Qt::DropAction dropAction_result;
792
public:
793
    DnDTestModel() : QStandardItemModel(20, 20), dropAction_result(Qt::IgnoreAction) {
794
        for (int i = 0; i < rowCount(); ++i)
795
            setData(index(i, 0), QString("%1").arg(i));
796
    }
797
    Qt::DropAction dropAction() const { return dropAction_result; }
798
};
799
800
class DnDTestView : public QTreeView
801
{
802
    Q_OBJECT
803
804
    QPoint dropPoint;
805
    Qt::DropAction dropAction;
806
807
    void dragEnterEvent(QDragEnterEvent *event)
808
    {
809
        QAbstractItemView::dragEnterEvent(event);
810
    }
811
812
    void dropEvent(QDropEvent *event)
813
    {
814
        event->setDropAction(dropAction);
815
        QTreeView::dropEvent(event);
816
    }
817
818
    void timerEvent(QTimerEvent *event)
819
    {
820
        killTimer(event->timerId());
821
        sendMouseMove(this, dropPoint);
822
        sendMouseRelease(this);
823
    }
824
825
    void mousePressEvent(QMouseEvent *e)
826
    {
827
        QTreeView::mousePressEvent(e);
828
829
        startTimer(0);
830
        setState(DraggingState);
831
        startDrag(dropAction);
832
    }
833
834
public:
835
    DnDTestView(Qt::DropAction dropAction, QAbstractItemModel *model)
836
        : dropAction(dropAction)
837
    {
838
        header()->hide();
839
        setModel(model);
840
        setDragDropMode(QAbstractItemView::DragDrop);
841
        setAcceptDrops(true);
842
        setDragEnabled(true);
843
    }
844
845
    void dragAndDrop(QPoint drag, QPoint drop)
846
    {
847
        dropPoint = drop;
848
        setCurrentIndex(indexAt(drag));
849
        sendMousePress(viewport(), drag);
850
    }
851
};
852
853
class DnDTestWidget : public QWidget
854
{
855
    Q_OBJECT
856
857
    Qt::DropAction dropAction_request;
858
    Qt::DropAction dropAction_result;
859
    QWidget *dropTarget;
860
861
    void timerEvent(QTimerEvent *event)
862
    {
863
        killTimer(event->timerId());
864
        sendMouseMove(dropTarget);
865
        sendMouseRelease(dropTarget);
866
    }
867
868
    void mousePressEvent(QMouseEvent *)
869
    {
870
        QDrag *drag = new QDrag(this);
871
        QMimeData *mimeData = new QMimeData;
872
        mimeData->setData("application/x-qabstractitemmodeldatalist", QByteArray(""));
873
        drag->setMimeData(mimeData);
874
        startTimer(0);
875
        dropAction_result = drag->start(dropAction_request);
876
    }
877
878
public:
879
    Qt::DropAction dropAction() const { return dropAction_result; }
880
881
    void dragAndDrop(QWidget *dropTarget, Qt::DropAction dropAction)
882
    {
883
        this->dropTarget = dropTarget;
884
        dropAction_request = dropAction;
885
        sendMousePress(this);
886
    }
887
};
888
889
void tst_QAbstractItemView::dragAndDrop()
890
{
891
    // From Task 137729
892
893
#ifdef Q_WS_QWS
894
    QSKIP("Embedded drag-and-drop not good enough yet...", SkipAll);
895
#endif
896
897
    const int attempts = 10;
898
    int successes = 0;
899
    for (int i = 0; i < attempts; ++i) {
900
        Qt::DropAction dropAction = Qt::MoveAction;
901
902
        DnDTestModel model;
903
        DnDTestView view(dropAction, &model);
904
        DnDTestWidget widget;
905
906
        const int size = 200;
907
        widget.setFixedSize(size, size);
908
        view.setFixedSize(size, size);
909
910
        widget.move(0, 0);
911
        view.move(int(size * 1.5), int(size * 1.5));
912
913
        widget.show();
914
        view.show();
915
#if defined(Q_WS_X11)
916
        qt_x11_wait_for_window_manager(&widget);
917
        qt_x11_wait_for_window_manager(&view);
918
#endif
919
920
        widget.dragAndDrop(&view, dropAction);
921
        if (model.dropAction() == dropAction
922
            && widget.dropAction() == dropAction)
923
            ++successes;
924
    }
925
926
    if (successes < attempts) {
927
        QString msg = QString("# successes (%1) < # attempts (%2)").arg(successes).arg(attempts);
928
        QWARN(msg.toLatin1());
929
    }
930
    QVERIFY(successes > 0); // allow for some "event unstability" (i.e. unless
931
                            // successes == 0, QAbstractItemView is probably ok!)
932
}
933
934
void tst_QAbstractItemView::dragAndDropOnChild()
935
{
936
#ifdef Q_WS_QWS
937
    QSKIP("Embedded drag-and-drop not good enough yet...", SkipAll);
938
#endif
939
940
    const int attempts = 10;
941
    int successes = 0;
942
    for (int i = 0; i < attempts; ++i) {
943
        Qt::DropAction dropAction = Qt::MoveAction;
944
945
        DnDTestModel model;
946
        QModelIndex parent = model.index(0, 0);
947
        model.insertRow(0, parent);
948
        model.insertColumn(0, parent);
949
        QModelIndex child = model.index(0, 0, parent);
950
        model.setData(child, "child");
951
        QCOMPARE(model.rowCount(parent), 1);
952
        DnDTestView view(dropAction, &model);
953
        view.setExpanded(parent, true);
954
        view.setDragDropMode(QAbstractItemView::InternalMove);
955
956
        const int size = 200;
957
        view.setFixedSize(size, size);
958
        view.move(int(size * 1.5), int(size * 1.5));
959
        view.show();
960
#if defined(Q_WS_X11)
961
        qt_x11_wait_for_window_manager(&view);
962
#endif
963
964
        view.dragAndDrop(view.visualRect(parent).center(),
965
                         view.visualRect(child).center());
966
        if (model.dropAction() == dropAction)
967
            ++successes;
968
    }
969
970
    QVERIFY(successes == 0);
971
}
972
973
#endif // 0
974
#endif // !Q_OS_MAC && !Q_OS_WIN
975
976
class TestModel : public QStandardItemModel
977
{
978
public:
979
    TestModel(int rows, int columns) : QStandardItemModel(rows, columns)
980
    {
981
        setData_count = 0;
982
    }
983
984
    virtual bool setData(const QModelIndex &/*index*/, const QVariant &/*value*/, int /*role = Qt::EditRole*/)
985
    {
986
        ++setData_count;
987
        return true;
988
    }
989
990
    int setData_count;
991
};
992
993
typedef QList<int> IntList;
994
Q_DECLARE_METATYPE(IntList)
995
996
void tst_QAbstractItemView::setItemDelegate_data()
997
{
998
    // default is rows, a -1 will switch to columns
999
    QTest::addColumn<IntList>("rowsOrColumnsWithDelegate");
1000
    QTest::addColumn<QPoint>("cellToEdit");
1001
    QTest::newRow("4 columndelegates")
1002
                << (IntList() << -1 << 0 << 1 << 2 << 3)
1003
                << QPoint(0, 0);
1004
    QTest::newRow("2 identical rowdelegates on the same row")
1005
                << (IntList() << 0 << 0)
1006
                << QPoint(0, 0);
1007
    QTest::newRow("2 identical columndelegates on the same column")
1008
                << (IntList() << -1 << 2 << 2)
1009
                << QPoint(2, 0);
1010
    QTest::newRow("2 duplicate delegates, 1 row and 1 column")
1011
                << (IntList() << 0 << -1 << 2)
1012
                << QPoint(2, 0);
1013
    QTest::newRow("4 duplicate delegates, 2 row and 2 column")
1014
                << (IntList() << 0 << 0 << -1 << 2 << 2)
1015
                << QPoint(2, 0);
1016
1017
}
1018
1019
void tst_QAbstractItemView::setItemDelegate()
1020
{
1021
    QFETCH(IntList, rowsOrColumnsWithDelegate);
1022
    QFETCH(QPoint, cellToEdit);
1023
    QTableView v;
1024
    QItemDelegate *delegate = new QItemDelegate(&v);
1025
    TestModel model(5, 5);
1026
    v.setModel(&model);
1027
1028
    bool row = true;
1029
    foreach (int rc, rowsOrColumnsWithDelegate) {
1030
        if (rc == -1) {
1031
            row = !row;
1032
        } else {
1033
            if (row) {
1034
                v.setItemDelegateForRow(rc, delegate);
1035
            } else {
1036
                v.setItemDelegateForColumn(rc, delegate);
1037
            }
1038
        }
1039
    }
1040
    v.show();
1041
#ifdef Q_WS_X11
1042
    qt_x11_wait_for_window_manager(&v);
1043
    QCursor::setPos(v.geometry().center());
1044
    QApplication::syncX();
1045
#endif
1046
    QTest::qWait(20);
1047
    QApplication::setActiveWindow(&v);
1048
1049
    QModelIndex index = model.index(cellToEdit.y(), cellToEdit.x());
1050
    v.edit(index);
1051
1052
    // This will close the editor
1053
    TRY_COMPARE(QApplication::focusWidget() == 0, false);
1054
    QWidget *editor = QApplication::focusWidget();
1055
    QVERIFY(editor);
1056
    editor->hide();
1057
    delete editor;
1058
    QCOMPARE(model.setData_count, 1);
1059
    delete delegate;
1060
}
1061
1062
void tst_QAbstractItemView::noFallbackToRoot()
1063
{
1064
    QStandardItemModel model(0, 1);
1065
    for (int i = 0; i < 5; ++i)
1066
        model.appendRow(new QStandardItem("top" + QString::number(i)));
1067
    QStandardItem *par1 = model.item(1);
1068
    for (int j = 0; j < 15; ++j)
1069
        par1->appendRow(new QStandardItem("sub" + QString::number(j)));
1070
    QStandardItem *par2 = par1->child(2);
1071
    for (int k = 0; k < 10; ++k)
1072
        par2->appendRow(new QStandardItem("bot" + QString::number(k)));
1073
    QStandardItem *it1 = par2->child(5);
1074
1075
    QModelIndex parent1 = model.indexFromItem(par1);
1076
    QModelIndex parent2 = model.indexFromItem(par2);
1077
    QModelIndex item1 = model.indexFromItem(it1);
1078
1079
    QTreeView v;
1080
    v.setModel(&model);
1081
    v.setRootIndex(parent1);
1082
    v.setCurrentIndex(item1);
1083
    QCOMPARE(v.currentIndex(), item1);
1084
    QVERIFY(model.removeRows(0, 10, parent2));
1085
    QCOMPARE(v.currentIndex(), parent2);
1086
    QVERIFY(model.removeRows(0, 15, parent1));
1087
    QCOMPARE(v.currentIndex(), QModelIndex());
1088
}
1089
1090
void tst_QAbstractItemView::setCurrentIndex_data()
1091
{
1092
    QTest::addColumn<QString>("viewType");
1093
    QTest::addColumn<int>("itemFlags");
1094
    QTest::addColumn<bool>("result");
1095
1096
    QStringList widgets;
1097
    widgets << "QListView" << "QTreeView" << "QHeaderView" << "QTableView";
1098
1099
    foreach(QString widget, widgets) {
1100
        QTest::newRow((widget+QLatin1String(": no flags")).toLocal8Bit().constData())
1101
            << widget << (int)0 << false;
1102
        QTest::newRow((widget+QLatin1String(": checkable")).toLocal8Bit().constData())
1103
            << widget << (int)Qt::ItemIsUserCheckable << false;
1104
        QTest::newRow((widget+QLatin1String(": selectable")).toLocal8Bit().constData())
1105
            << widget << (int)Qt::ItemIsSelectable << false;
1106
        QTest::newRow((widget+QLatin1String(": enabled")).toLocal8Bit().constData())
1107
            << widget << (int)Qt::ItemIsEnabled << true;
1108
        QTest::newRow((widget+QLatin1String(": enabled|selectable")).toLocal8Bit().constData())
1109
            << widget << (int)(Qt::ItemIsSelectable|Qt::ItemIsEnabled) << true;
1110
    }
1111
}
1112
1113
void tst_QAbstractItemView::setCurrentIndex()
1114
{
1115
    QFETCH(QString, viewType);
1116
    QFETCH(int, itemFlags);
1117
    QFETCH(bool, result);
1118
1119
    TestView *view = 0;
1120
    if (viewType == "QListView")
1121
        view = reinterpret_cast<TestView*>(new QListView());
1122
    else if (viewType == "QTableView")
1123
        view = reinterpret_cast<TestView*>(new QTableView());
1124
    else if (viewType == "QTreeView")
1125
        view = reinterpret_cast<TestView*>(new QTreeView());
1126
    else if (viewType == "QHeaderView")
1127
        view = reinterpret_cast<TestView*>(new QHeaderView(Qt::Vertical));
1128
    else
1129
        QVERIFY(0);
1130
    view->show();
1131
1132
    QStandardItemModel *model = new QStandardItemModel(view);
1133
    QStandardItem *item = new QStandardItem("first item");
1134
    item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
1135
    model->appendRow(item);
1136
1137
    item = new QStandardItem("test item");
1138
    item->setFlags(Qt::ItemFlags(itemFlags));
1139
    model->appendRow(item);
1140
1141
    view->setModel(model);
1142
1143
    view->setCurrentIndex(model->index(0,0));
1144
    QVERIFY(view->currentIndex() == model->index(0,0));
1145
    view->setCurrentIndex(model->index(1,0));
1146
    QVERIFY(view->currentIndex() == model->index(result ? 1 : 0,0));
1147
1148
    delete view;
1149
}
1150
1151
void tst_QAbstractItemView::task221955_selectedEditor()
1152
{
1153
    QPushButton *button;
1154
1155
    QTreeWidget tree;
1156
    tree.setColumnCount(2);
1157
1158
    tree.addTopLevelItem(new QTreeWidgetItem(QStringList() << "Foo" <<"1"));
1159
    tree.addTopLevelItem(new QTreeWidgetItem(QStringList() << "Bar" <<"2"));
1160
    tree.addTopLevelItem(new QTreeWidgetItem(QStringList() << "Baz" <<"3"));
1161
1162
    QTreeWidgetItem *dummy = new QTreeWidgetItem();
1163
    tree.addTopLevelItem(dummy);
1164
    tree.setItemWidget(dummy, 0, button = new QPushButton("More..."));
1165
    button->setAutoFillBackground(true);  // as recommended in doc
1166
1167
    tree.show();
1168
    tree.setFocus();
1169
    tree.setCurrentIndex(tree.model()->index(1,0));
1170
    QTest::qWait(100);
1171
    QApplication::setActiveWindow(&tree);
1172
1173
    QVERIFY(! tree.selectionModel()->selectedIndexes().contains(tree.model()->index(3,0)));
1174
1175
    //We set the focus to the button, the index need to be selected
1176
    button->setFocus();
1177
    QTest::qWait(100);
1178
    QVERIFY(tree.selectionModel()->selectedIndexes().contains(tree.model()->index(3,0)));
1179
1180
    tree.setCurrentIndex(tree.model()->index(1,0));
1181
    QVERIFY(! tree.selectionModel()->selectedIndexes().contains(tree.model()->index(3,0)));
1182
1183
    //Same thing but with the flag NoSelection,   nothing can be selected.
1184
    tree.setFocus();
1185
    tree.setSelectionMode(QAbstractItemView::NoSelection);
1186
    tree.clearSelection();
1187
    QVERIFY(tree.selectionModel()->selectedIndexes().isEmpty());
1188
    QTest::qWait(10);
1189
    button->setFocus();
1190
    QTest::qWait(50);
1191
    QVERIFY(tree.selectionModel()->selectedIndexes().isEmpty());
1192
}
1193
1194
void tst_QAbstractItemView::task250754_fontChange()
1195
{
1196
    QString app_css = qApp->styleSheet();
1197
    qApp->setStyleSheet("/*  */");
1198
1199
    QWidget w;
1200
    QTreeView tree(&w);
1201
    QVBoxLayout *vLayout = new QVBoxLayout(&w);
1202
    vLayout->addWidget(&tree);
1203
1204
    QStandardItemModel *m = new QStandardItemModel(this);
1205
    for (int i=0; i<5; ++i) {
1206
        QStandardItem *item = new QStandardItem(QString("Item number %1").arg(i));
1207
        for (int j=0; j<5; ++j) {
1208
            QStandardItem *child = new QStandardItem(QString("Child Item number %1").arg(j));
1209
            item->setChild(j, 0, child);
1210
        }
1211
        m->setItem(i, 0, item);
1212
    }
1213
    tree.setModel(m);
1214
1215
    w.show();
1216
    w.resize(150,240);
1217
    QTest::qWait(30);
1218
    QFont font = tree.font();
1219
    font.setPixelSize(10);
1220
    tree.setFont(font);
1221
    QTRY_VERIFY(!tree.verticalScrollBar()->isVisible());
1222
1223
    font.setPixelSize(60);
1224
    tree.setFont(font);
1225
    //now with the huge items, the scrollbar must be visible
1226
    QTRY_VERIFY(tree.verticalScrollBar()->isVisible());
1227
1228
    qApp->setStyleSheet(app_css);
1229
}
1230
1231
void tst_QAbstractItemView::task200665_itemEntered()
1232
{
1233
#ifdef Q_OS_WINCE_WM
1234
    QSKIP("On Windows Mobile the mouse tracking is unavailable at the moment", SkipAll);
1235
#endif
1236
    //we test that view will emit entered
1237
    //when the scrollbar move but not the mouse itself
1238
    QStandardItemModel model(1000,1);
1239
    QListView view;
1240
    view.setModel(&model);
1241
    view.show();
1242
    QTest::qWait(200);
1243
    QRect rect = view.visualRect(model.index(0,0));
1244
    QCursor::setPos( view.viewport()->mapToGlobal(rect.center()) );
1245
    QSignalSpy spy(&view, SIGNAL(entered(QModelIndex)));
1246
    view.verticalScrollBar()->setValue(view.verticalScrollBar()->maximum());
1247
    QCOMPARE(spy.count(), 1);
1248
1249
}
1250
1251
void tst_QAbstractItemView::task257481_emptyEditor()
1252
{
1253
    QIcon icon = qApp->style()->standardIcon(QStyle::SP_ComputerIcon);
1254
1255
    QStandardItemModel model;
1256
1257
    model.appendRow( new QStandardItem(icon, QString()) );
1258
    model.appendRow( new QStandardItem(icon, "Editor works") );
1259
    model.appendRow( new QStandardItem( QString() ) );
1260
1261
    QTreeView treeView;
1262
    treeView.setRootIsDecorated(false);
1263
    treeView.setModel(&model);
1264
    treeView.show();
1265
1266
    treeView.edit(model.index(0,0));
1267
    QList<QLineEdit *> lineEditors = qFindChildren<QLineEdit *>(treeView.viewport());
1268
    QCOMPARE(lineEditors.count(), 1);
1269
    QVERIFY(!lineEditors.first()->size().isEmpty());
1270
1271
    QTest::qWait(30);
1272
1273
    treeView.edit(model.index(1,0));
1274
    lineEditors = qFindChildren<QLineEdit *>(treeView.viewport());
1275
    QCOMPARE(lineEditors.count(), 1);
1276
    QVERIFY(!lineEditors.first()->size().isEmpty());
1277
1278
    QTest::qWait(30);
1279
1280
    treeView.edit(model.index(2,0));
1281
    lineEditors = qFindChildren<QLineEdit *>(treeView.viewport());
1282
    QCOMPARE(lineEditors.count(), 1);
1283
    QVERIFY(!lineEditors.first()->size().isEmpty());
1284
}
1285
1286
void tst_QAbstractItemView::shiftArrowSelectionAfterScrolling()
1287
{
1288
    QStandardItemModel model;
1289
    for (int i=0; i<10; ++i) {
1290
        QStandardItem *item = new QStandardItem(QString("%1").arg(i));
1291
        model.setItem(i, 0, item);
1292
    }
1293
1294
    QListView view;
1295
    view.setFixedSize(150, 250);
1296
    view.setFlow(QListView::LeftToRight);
1297
    view.setGridSize(QSize(100, 100));
1298
    view.setSelectionMode(QListView::ExtendedSelection);
1299
    view.setViewMode(QListView::IconMode);
1300
    view.setModel(&model);
1301
    view.show();
1302
    QTest::qWait(30);
1303
1304
    QModelIndex index0 = model.index(0, 0);
1305
    QModelIndex index1 = model.index(1, 0);
1306
    QModelIndex index9 = model.index(9, 0);
1307
1308
    view.selectionModel()->setCurrentIndex(index0, QItemSelectionModel::NoUpdate);
1309
    QCOMPARE(view.currentIndex(), index0);
1310
1311
    view.scrollTo(index9);
1312
    QTest::keyClick(&view, Qt::Key_Down, Qt::ShiftModifier);
1313
1314
    QCOMPARE(view.currentIndex(), index1);
1315
    QModelIndexList selected = view.selectionModel()->selectedIndexes();
1316
    QCOMPARE(selected.count(), 2);
1317
    QVERIFY(selected.contains(index0));
1318
    QVERIFY(selected.contains(index1));
1319
}
1320
1321
void tst_QAbstractItemView::shiftSelectionAfterRubberbandSelection()
1322
{
1323
    QStandardItemModel model;
1324
    for (int i=0; i<3; ++i) {
1325
        QStandardItem *item = new QStandardItem(QString("%1").arg(i));
1326
        model.setItem(i, 0, item);
1327
    }
1328
1329
    QListView view;
1330
    view.setFixedSize(150, 450);
1331
    view.setFlow(QListView::LeftToRight);
1332
    view.setGridSize(QSize(100, 100));
1333
    view.setSelectionMode(QListView::ExtendedSelection);
1334
    view.setViewMode(QListView::IconMode);
1335
    view.setModel(&model);
1336
    view.show();
1337
    QTest::qWait(30);
1338
1339
    QModelIndex index0 = model.index(0, 0);
1340
    QModelIndex index1 = model.index(1, 0);
1341
    QModelIndex index2 = model.index(2, 0);
1342
1343
    view.setCurrentIndex(index0);
1344
    QCOMPARE(view.currentIndex(), index0);
1345
1346
    // Determine the points where the rubberband selection starts and ends
1347
    QPoint pressPos = view.visualRect(index1).bottomRight() + QPoint(1, 1);
1348
    QPoint releasePos = view.visualRect(index1).center();
1349
    QVERIFY(!view.indexAt(pressPos).isValid());
1350
    QCOMPARE(view.indexAt(releasePos), index1);
1351
1352
    // Select item 1 using a rubberband selection
1353
    // The mouse move event has to be created manually because the QTest framework does not
1354
    // contain a function for mouse moves with buttons pressed
1355
    QTest::mousePress(view.viewport(), Qt::LeftButton, Qt::NoModifier, pressPos);
1356
    QMouseEvent moveEvent(QEvent::MouseMove, releasePos, Qt::NoButton, Qt::LeftButton, Qt::NoModifier);
1357
    bool moveEventReceived = qApp->notify(view.viewport(), &moveEvent);
1358
    QVERIFY(moveEventReceived);
1359
    QTest::mouseRelease(view.viewport(), Qt::LeftButton, Qt::NoModifier, releasePos);
1360
    QCOMPARE(view.currentIndex(), index1);
1361
1362
    // Shift-click item 2
1363
    QPoint item2Pos = view.visualRect(index2).center();
1364
    QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::ShiftModifier, item2Pos);
1365
    QCOMPARE(view.currentIndex(), index2);
1366
1367
    // Verify that the selection worked OK
1368
    QModelIndexList selected = view.selectionModel()->selectedIndexes();
1369
    QCOMPARE(selected.count(), 2);
1370
    QVERIFY(selected.contains(index1));
1371
    QVERIFY(selected.contains(index2));
1372
1373
    // Select item 0 to revert the selection
1374
    view.setCurrentIndex(index0);
1375
    QCOMPARE(view.currentIndex(), index0);
1376
1377
    // Repeat the same steps as above, but with a Shift-Arrow selection
1378
    QTest::mousePress(view.viewport(), Qt::LeftButton, Qt::NoModifier, pressPos);
1379
    QMouseEvent moveEvent2(QEvent::MouseMove, releasePos, Qt::NoButton, Qt::LeftButton, Qt::NoModifier);
1380
    moveEventReceived = qApp->notify(view.viewport(), &moveEvent2);
1381
    QVERIFY(moveEventReceived);
1382
    QTest::mouseRelease(view.viewport(), Qt::LeftButton, Qt::NoModifier, releasePos);
1383
    QCOMPARE(view.currentIndex(), index1);
1384
1385
    // Press Shift-Down
1386
    QTest::keyClick(&view, Qt::Key_Down, Qt::ShiftModifier);
1387
    QCOMPARE(view.currentIndex(), index2);
1388
1389
    // Verify that the selection worked OK
1390
    selected = view.selectionModel()->selectedIndexes();
1391
    QCOMPARE(selected.count(), 2);
1392
    QVERIFY(selected.contains(index1));
1393
    QVERIFY(selected.contains(index2));
1394
}
1395
1396
void tst_QAbstractItemView::ctrlRubberbandSelection()
1397
{
1398
    QStandardItemModel model;
1399
    for (int i=0; i<3; ++i) {
1400
        QStandardItem *item = new QStandardItem(QString("%1").arg(i));
1401
        model.setItem(i, 0, item);
1402
    }
1403
1404
    QListView view;
1405
    view.setFixedSize(150, 450);
1406
    view.setFlow(QListView::LeftToRight);
1407
    view.setGridSize(QSize(100, 100));
1408
    view.setSelectionMode(QListView::ExtendedSelection);
1409
    view.setViewMode(QListView::IconMode);
1410
    view.setModel(&model);
1411
    view.show();
1412
    QTest::qWait(30);
1413
1414
    QModelIndex index1 = model.index(1, 0);
1415
    QModelIndex index2 = model.index(2, 0);
1416
1417
    // Select item 1
1418
    view.setCurrentIndex(index1);
1419
    QModelIndexList selected = view.selectionModel()->selectedIndexes();
1420
    QCOMPARE(selected.count(), 1);
1421
    QVERIFY(selected.contains(index1));
1422
1423
    // Now press control and draw a rubberband around items 1 and 2.
1424
    // The mouse move event has to be created manually because the QTest framework does not
1425
    // contain a function for mouse moves with buttons pressed.
1426
    QPoint pressPos = view.visualRect(index1).topLeft() - QPoint(1, 1);
1427
    QPoint releasePos = view.visualRect(index2).bottomRight() + QPoint(1, 1);
1428
    QTest::mousePress(view.viewport(), Qt::LeftButton, Qt::ControlModifier, pressPos);
1429
    QMouseEvent moveEvent(QEvent::MouseMove, releasePos, Qt::NoButton, Qt::LeftButton, Qt::ControlModifier);
1430
    bool moveEventReceived = qApp->notify(view.viewport(), &moveEvent);
1431
    QVERIFY(moveEventReceived);
1432
    QTest::mouseRelease(view.viewport(), Qt::LeftButton, Qt::ControlModifier, releasePos);
1433
1434
    // Verify that item 2 is selected now
1435
    selected = view.selectionModel()->selectedIndexes();
1436
    QCOMPARE(selected.count(), 1);
1437
    QVERIFY(selected.contains(index2));
1438
}
1439
1440
void tst_QAbstractItemView::QTBUG6407_extendedSelection()
1441
{
1442
    QListWidget view;
1443
    view.setSelectionMode(QAbstractItemView::ExtendedSelection);
1444
    for(int i = 0; i < 50; ++i)
1445
        view.addItem(QString::number(i));
1446
1447
    QFont font = view.font();
1448
    font.setPixelSize(10);
1449
    view.setFont(font);
1450
    view.resize(200,240);
1451
1452
    view.show();
1453
    QApplication::setActiveWindow(&view);
1454
    QTest::qWaitForWindowShown(&view);
1455
    QTRY_COMPARE(static_cast<QWidget *>(&view), QApplication::activeWindow());
1456
1457
    view.verticalScrollBar()->setValue(view.verticalScrollBar()->maximum());
1458
    QTest::qWait(20);
1459
1460
    QModelIndex index49 = view.model()->index(49,0);
1461
    QPoint p = view.visualRect(index49).center();
1462
    QVERIFY(view.viewport()->rect().contains(p));
1463
    QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, p);
1464
    QCOMPARE(view.currentIndex(), index49);
1465
    QCOMPARE(view.selectedItems().count(), 1);
1466
1467
    QModelIndex index47 = view.model()->index(47,0);
1468
    p = view.visualRect(index47).center();
1469
    QVERIFY(view.viewport()->rect().contains(p));
1470
    QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::ShiftModifier, p);
1471
    QCOMPARE(view.currentIndex(), index47);
1472
    QCOMPARE(view.selectedItems().count(), 3); //49, 48, 47;
1473
1474
    QModelIndex index44 = view.model()->index(44,0);
1475
    p = view.visualRect(index44).center();
1476
    QVERIFY(view.viewport()->rect().contains(p));
1477
    QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::ShiftModifier, p);
1478
    QCOMPARE(view.currentIndex(), index44);
1479
    QCOMPARE(view.selectedItems().count(), 6); //49 .. 44;
1480
1481
}
1482
1483
void tst_QAbstractItemView::QTBUG6753_selectOnSelection()
1484
{
1485
    QTableWidget table(5, 5);
1486
    for (int i = 0; i < table.rowCount(); ++i)
1487
        for (int j = 0; j < table.columnCount(); ++j)
1488
            table.setItem(i, j, new QTableWidgetItem("choo-be-doo-wah"));
1489
1490
    table.show();
1491
    table.setSelectionMode(QAbstractItemView::ExtendedSelection);
1492
    table.selectAll();
1493
    QTest::qWaitForWindowShown(&table);
1494
    QModelIndex item = table.model()->index(1,1);
1495
    QRect itemRect = table.visualRect(item);
1496
    QTest::mouseMove(table.viewport(), itemRect.center());
1497
    QTest::mouseClick(table.viewport(), Qt::LeftButton, Qt::NoModifier, itemRect.center());
1498
    QTest::qWait(20);
1499
1500
    QCOMPARE(table.selectedItems().count(), 1);
1501
    QCOMPARE(table.selectedItems().first(), table.item(item.row(), item.column()));
1502
}
1503
1504
QTEST_MAIN(tst_QAbstractItemView)
1505
#include "tst_qabstractitemview.moc"