/**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the Technology Preview License Agreement accompanying ** this package. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain ** additional rights. These rights are described in the Nokia Qt LGPL ** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this ** package. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** ** ** ** ** ** ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../../shared/util.h" //TESTED_CLASS= //TESTED_FILES= // Will try to wait for the condition while allowing event processing // for a maximum of 5 seconds. #define TRY_COMPARE(expr, expected) \ do { \ const int step = 50; \ for (int q = 0; q < 5000 && ((expr) != (expected)); q+=step) { \ QTest::qWait(step); \ } \ QCOMPARE(expr, expected); \ } while(0) class TestView : public QAbstractItemView { Q_OBJECT public: inline void tst_dataChanged(const QModelIndex &tl, const QModelIndex &br) { dataChanged(tl, br); } inline void tst_setHorizontalStepsPerItem(int steps) { setHorizontalStepsPerItem(steps); } inline int tst_horizontalStepsPerItem() const { return horizontalStepsPerItem(); } inline void tst_setVerticalStepsPerItem(int steps) { setVerticalStepsPerItem(steps); } inline int tst_verticalStepsPerItem() const { return verticalStepsPerItem(); } inline void tst_rowsInserted(const QModelIndex &parent, int start, int end) { rowsInserted(parent, start, end); } inline void tst_rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) { rowsAboutToBeRemoved(parent, start, end); } inline void tst_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) { selectionChanged(selected, deselected); } inline void tst_currentChanged(const QModelIndex ¤t, const QModelIndex &previous) { currentChanged(current, previous); } inline void tst_updateEditorData() { updateEditorData(); } inline void tst_updateEditorGeometries() { updateEditorGeometries(); } inline void tst_updateGeometries() { updateGeometries(); } inline void tst_verticalScrollbarAction(int action) { verticalScrollbarAction(action); } inline void tst_horizontalScrollbarAction(int action) { horizontalScrollbarAction(action); } inline void tst_verticalScrollbarValueChanged(int value) { verticalScrollbarValueChanged(value); } inline void tst_horizontalScrollbarValueChanged(int value) { horizontalScrollbarValueChanged(value); } inline void tst_closeEditor(QWidget *editor, QAbstractItemDelegate::EndEditHint hint) { closeEditor(editor, hint); } inline void tst_commitData(QWidget *editor) { commitData(editor); } inline void tst_editorDestroyed(QObject *editor) { editorDestroyed(editor); } enum tst_CursorAction { MoveUp = QAbstractItemView::MoveUp, MoveDown = QAbstractItemView::MoveDown, MoveLeft = QAbstractItemView::MoveLeft, MoveRight = QAbstractItemView::MoveRight, MoveHome = QAbstractItemView::MoveHome, MoveEnd = QAbstractItemView::MoveEnd, MovePageUp = QAbstractItemView::MovePageUp, MovePageDown = QAbstractItemView::MovePageDown, MoveNext = QAbstractItemView::MoveNext, MovePrevious = QAbstractItemView::MovePrevious }; inline QModelIndex tst_moveCursor(tst_CursorAction cursorAction, Qt::KeyboardModifiers modifiers) { return moveCursor(QAbstractItemView::CursorAction(cursorAction), modifiers); } inline int tst_horizontalOffset() const { return horizontalOffset(); } inline int tst_verticalOffset() const { return verticalOffset(); } inline bool tst_isIndexHidden(const QModelIndex &index) const { return isIndexHidden(index); } inline void tst_setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags command) { setSelection(rect, command); } inline QRegion tst_visualRegionForSelection(const QItemSelection &selection) const { return visualRegionForSelection(selection); } inline QModelIndexList tst_selectedIndexes() const { return selectedIndexes(); } inline bool tst_edit(const QModelIndex &index, EditTrigger trigger, QEvent *event) { return edit(index, trigger, event); } inline QItemSelectionModel::SelectionFlags tst_selectionCommand(const QModelIndex &index, const QEvent *event = 0) const { return selectionCommand(index, event); } #ifndef QT_NO_DRAGANDDROP inline void tst_startDrag(Qt::DropActions supportedActions) { startDrag(supportedActions); } #endif inline QStyleOptionViewItem tst_viewOptions() const { return viewOptions(); } enum tst_State { NoState = QAbstractItemView::NoState, DraggingState = QAbstractItemView::DraggingState, DragSelectingState = QAbstractItemView::DragSelectingState, EditingState = QAbstractItemView::EditingState, ExpandingState = QAbstractItemView::ExpandingState, CollapsingState = QAbstractItemView::CollapsingState }; inline tst_State tst_state() const { return (tst_State)state(); } inline void tst_setState(tst_State state) { setState(QAbstractItemView::State(state)); } inline void tst_startAutoScroll() { startAutoScroll(); } inline void tst_stopAutoScroll() { stopAutoScroll(); } inline void tst_doAutoScroll() { doAutoScroll(); } }; class tst_QAbstractItemView : public QObject { Q_OBJECT public: tst_QAbstractItemView(); virtual ~tst_QAbstractItemView(); void basic_tests(TestView *view); private slots: void getSetCheck(); void emptyModels_data(); void emptyModels(); void setModel_data(); void setModel(); void noModel(); void dragSelect(); void rowDelegate(); void columnDelegate(); void selectAll(); void ctrlA(); void persistentEditorFocus(); void setItemDelegate(); void setItemDelegate_data(); // The dragAndDrop() test doesn't work, and is thus disabled on Mac and Windows // for the following reasons: // Mac: use of GetCurrentEventButtonState() in QDragManager::drag() // Win: unknown reason #if !defined(Q_OS_MAC) && !defined(Q_OS_WIN) #if 0 void dragAndDrop(); void dragAndDropOnChild(); #endif #endif void noFallbackToRoot(); void setCurrentIndex_data(); void setCurrentIndex(); void task221955_selectedEditor(); void task250754_fontChange(); void task200665_itemEntered(); void task257481_emptyEditor(); void shiftArrowSelectionAfterScrolling(); void shiftSelectionAfterRubberbandSelection(); }; class MyAbstractItemDelegate : public QAbstractItemDelegate { public: MyAbstractItemDelegate() : QAbstractItemDelegate() {}; void paint(QPainter *, const QStyleOptionViewItem &, const QModelIndex &) const {} QSize sizeHint(const QStyleOptionViewItem &, const QModelIndex &) const { return QSize(); } QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &) const { return new QWidget(parent); } }; // Testing get/set functions void tst_QAbstractItemView::getSetCheck() { QListView view; TestView *obj1 = reinterpret_cast(&view); // QAbstractItemDelegate * QAbstractItemView::itemDelegate() // void QAbstractItemView::setItemDelegate(QAbstractItemDelegate *) MyAbstractItemDelegate *var1 = new MyAbstractItemDelegate; obj1->setItemDelegate(var1); QCOMPARE((QAbstractItemDelegate*)var1, obj1->itemDelegate()); obj1->setItemDelegate((QAbstractItemDelegate *)0); QCOMPARE((QAbstractItemDelegate *)0, obj1->itemDelegate()); delete var1; // EditTriggers QAbstractItemView::editTriggers() // void QAbstractItemView::setEditTriggers(EditTriggers) obj1->setEditTriggers(QAbstractItemView::EditTriggers(QAbstractItemView::NoEditTriggers)); QCOMPARE(QAbstractItemView::EditTriggers(QAbstractItemView::NoEditTriggers), obj1->editTriggers()); obj1->setEditTriggers(QAbstractItemView::EditTriggers(QAbstractItemView::CurrentChanged)); QCOMPARE(QAbstractItemView::EditTriggers(QAbstractItemView::CurrentChanged), obj1->editTriggers()); obj1->setEditTriggers(QAbstractItemView::EditTriggers(QAbstractItemView::DoubleClicked)); QCOMPARE(QAbstractItemView::EditTriggers(QAbstractItemView::DoubleClicked), obj1->editTriggers()); obj1->setEditTriggers(QAbstractItemView::EditTriggers(QAbstractItemView::SelectedClicked)); QCOMPARE(QAbstractItemView::EditTriggers(QAbstractItemView::SelectedClicked), obj1->editTriggers()); obj1->setEditTriggers(QAbstractItemView::EditTriggers(QAbstractItemView::EditKeyPressed)); QCOMPARE(QAbstractItemView::EditTriggers(QAbstractItemView::EditKeyPressed), obj1->editTriggers()); obj1->setEditTriggers(QAbstractItemView::EditTriggers(QAbstractItemView::AnyKeyPressed)); QCOMPARE(QAbstractItemView::EditTriggers(QAbstractItemView::AnyKeyPressed), obj1->editTriggers()); obj1->setEditTriggers(QAbstractItemView::EditTriggers(QAbstractItemView::AllEditTriggers)); QCOMPARE(QAbstractItemView::EditTriggers(QAbstractItemView::AllEditTriggers), obj1->editTriggers()); // bool QAbstractItemView::tabKeyNavigation() // void QAbstractItemView::setTabKeyNavigation(bool) obj1->setTabKeyNavigation(false); QCOMPARE(false, obj1->tabKeyNavigation()); obj1->setTabKeyNavigation(true); QCOMPARE(true, obj1->tabKeyNavigation()); // bool QAbstractItemView::dragEnabled() // void QAbstractItemView::setDragEnabled(bool) #ifndef QT_NO_DRAGANDDROP obj1->setDragEnabled(false); QCOMPARE(false, obj1->dragEnabled()); obj1->setDragEnabled(true); QCOMPARE(true, obj1->dragEnabled()); #endif // bool QAbstractItemView::alternatingRowColors() // void QAbstractItemView::setAlternatingRowColors(bool) obj1->setAlternatingRowColors(false); QCOMPARE(false, obj1->alternatingRowColors()); obj1->setAlternatingRowColors(true); QCOMPARE(true, obj1->alternatingRowColors()); // State QAbstractItemView::state() // void QAbstractItemView::setState(State) obj1->tst_setState(TestView::tst_State(TestView::NoState)); QCOMPARE(TestView::tst_State(TestView::NoState), obj1->tst_state()); obj1->tst_setState(TestView::tst_State(TestView::DraggingState)); QCOMPARE(TestView::tst_State(TestView::DraggingState), obj1->tst_state()); obj1->tst_setState(TestView::tst_State(TestView::DragSelectingState)); QCOMPARE(TestView::tst_State(TestView::DragSelectingState), obj1->tst_state()); obj1->tst_setState(TestView::tst_State(TestView::EditingState)); QCOMPARE(TestView::tst_State(TestView::EditingState), obj1->tst_state()); obj1->tst_setState(TestView::tst_State(TestView::ExpandingState)); QCOMPARE(TestView::tst_State(TestView::ExpandingState), obj1->tst_state()); obj1->tst_setState(TestView::tst_State(TestView::CollapsingState)); QCOMPARE(TestView::tst_State(TestView::CollapsingState), obj1->tst_state()); // QWidget QAbstractScrollArea::viewport() // void setViewport(QWidget*) QWidget *vp = new QWidget; obj1->setViewport(vp); QCOMPARE(vp, obj1->viewport()); QCOMPARE(16, obj1->autoScrollMargin()); obj1->setAutoScrollMargin(20); QCOMPARE(20, obj1->autoScrollMargin()); obj1->setAutoScrollMargin(16); QCOMPARE(16, obj1->autoScrollMargin()); } tst_QAbstractItemView::tst_QAbstractItemView() { } tst_QAbstractItemView::~tst_QAbstractItemView() { } void tst_QAbstractItemView::emptyModels_data() { QTest::addColumn("viewType"); QTest::newRow("QListView") << "QListView"; QTest::newRow("QTableView") << "QTableView"; QTest::newRow("QTreeView") << "QTreeView"; QTest::newRow("QHeaderView") << "QHeaderView"; } void tst_QAbstractItemView::emptyModels() { QFETCH(QString, viewType); TestView *view = 0; if (viewType == "QListView") view = reinterpret_cast(new QListView()); else if (viewType == "QTableView") view = reinterpret_cast(new QTableView()); else if (viewType == "QTreeView") view = reinterpret_cast(new QTreeView()); else if (viewType == "QHeaderView") view = reinterpret_cast(new QHeaderView(Qt::Vertical)); else QVERIFY(0); view->show(); QVERIFY(!view->model()); QVERIFY(!view->selectionModel()); //QVERIFY(view->itemDelegate() != 0); basic_tests(view); delete view; } void tst_QAbstractItemView::setModel_data() { QTest::addColumn("viewType"); QTest::newRow("QListView") << "QListView"; QTest::newRow("QTableView") << "QTableView"; QTest::newRow("QTreeView") << "QTreeView"; QTest::newRow("QHeaderView") << "QHeaderView"; } void tst_QAbstractItemView::setModel() { QFETCH(QString, viewType); TestView *view = 0; if (viewType == "QListView") view = reinterpret_cast(new QListView()); else if (viewType == "QTableView") view = reinterpret_cast(new QTableView()); else if (viewType == "QTreeView") view = reinterpret_cast(new QTreeView()); else if (viewType == "QHeaderView") view = reinterpret_cast(new QHeaderView(Qt::Vertical)); else QVERIFY(0); view->show(); QStandardItemModel model(20,20); view->setModel(0); view->setModel(&model); basic_tests(view); delete view; } void tst_QAbstractItemView::basic_tests(TestView *view) { // setSelectionModel // Will assert as it should //view->setSelectionModel(0); // setItemDelegate //view->setItemDelegate(0); // Will asswert as it should // setSelectionMode view->setSelectionMode(QAbstractItemView::SingleSelection); QCOMPARE(view->selectionMode(), QAbstractItemView::SingleSelection); view->setSelectionMode(QAbstractItemView::ContiguousSelection); QCOMPARE(view->selectionMode(), QAbstractItemView::ContiguousSelection); view->setSelectionMode(QAbstractItemView::ExtendedSelection); QCOMPARE(view->selectionMode(), QAbstractItemView::ExtendedSelection); view->setSelectionMode(QAbstractItemView::MultiSelection); QCOMPARE(view->selectionMode(), QAbstractItemView::MultiSelection); view->setSelectionMode(QAbstractItemView::NoSelection); QCOMPARE(view->selectionMode(), QAbstractItemView::NoSelection); // setSelectionBehavior view->setSelectionBehavior(QAbstractItemView::SelectItems); QCOMPARE(view->selectionBehavior(), QAbstractItemView::SelectItems); view->setSelectionBehavior(QAbstractItemView::SelectRows); QCOMPARE(view->selectionBehavior(), QAbstractItemView::SelectRows); view->setSelectionBehavior(QAbstractItemView::SelectColumns); QCOMPARE(view->selectionBehavior(), QAbstractItemView::SelectColumns); // setEditTriggers view->setEditTriggers(QAbstractItemView::EditKeyPressed); QCOMPARE(view->editTriggers(), QAbstractItemView::EditKeyPressed); view->setEditTriggers(QAbstractItemView::NoEditTriggers); QCOMPARE(view->editTriggers(), QAbstractItemView::NoEditTriggers); view->setEditTriggers(QAbstractItemView::CurrentChanged); QCOMPARE(view->editTriggers(), QAbstractItemView::CurrentChanged); view->setEditTriggers(QAbstractItemView::DoubleClicked); QCOMPARE(view->editTriggers(), QAbstractItemView::DoubleClicked); view->setEditTriggers(QAbstractItemView::SelectedClicked); QCOMPARE(view->editTriggers(), QAbstractItemView::SelectedClicked); view->setEditTriggers(QAbstractItemView::AnyKeyPressed); QCOMPARE(view->editTriggers(), QAbstractItemView::AnyKeyPressed); view->setEditTriggers(QAbstractItemView::AllEditTriggers); QCOMPARE(view->editTriggers(), QAbstractItemView::AllEditTriggers); // setAutoScroll view->setAutoScroll(false); QCOMPARE(view->hasAutoScroll(), false); view->setAutoScroll(true); QCOMPARE(view->hasAutoScroll(), true); // setTabKeyNavigation view->setTabKeyNavigation(false); QCOMPARE(view->tabKeyNavigation(), false); view->setTabKeyNavigation(true); QCOMPARE(view->tabKeyNavigation(), true); #ifndef QT_NO_DRAGANDDROP // setDropIndicatorShown view->setDropIndicatorShown(false); QCOMPARE(view->showDropIndicator(), false); view->setDropIndicatorShown(true); QCOMPARE(view->showDropIndicator(), true); // setDragEnabled view->setDragEnabled(false); QCOMPARE(view->dragEnabled(), false); view->setDragEnabled(true); QCOMPARE(view->dragEnabled(), true); #endif // setAlternatingRowColors view->setAlternatingRowColors(false); QCOMPARE(view->alternatingRowColors(), false); view->setAlternatingRowColors(true); QCOMPARE(view->alternatingRowColors(), true); // setIconSize view->setIconSize(QSize(16, 16)); QCOMPARE(view->iconSize(), QSize(16, 16)); view->setIconSize(QSize(32, 32)); QCOMPARE(view->iconSize(), QSize(32, 32)); // Should this happen? view->setIconSize(QSize(-1, -1)); QCOMPARE(view->iconSize(), QSize(-1, -1)); QCOMPARE(view->currentIndex(), QModelIndex()); QCOMPARE(view->rootIndex(), QModelIndex()); view->keyboardSearch(""); view->keyboardSearch("foo"); view->keyboardSearch("1"); QCOMPARE(view->visualRect(QModelIndex()), QRect()); view->scrollTo(QModelIndex()); QCOMPARE(view->sizeHintForIndex(QModelIndex()), QSize()); QCOMPARE(view->indexAt(QPoint(-1, -1)), QModelIndex()); if (!view->model()){ QCOMPARE(view->indexAt(QPoint(10, 10)), QModelIndex()); QCOMPARE(view->sizeHintForRow(0), -1); QCOMPARE(view->sizeHintForColumn(0), -1); }else if (view->itemDelegate()){ view->sizeHintForRow(0); view->sizeHintForColumn(0); } view->openPersistentEditor(QModelIndex()); view->closePersistentEditor(QModelIndex()); view->reset(); view->setRootIndex(QModelIndex()); view->doItemsLayout(); view->selectAll(); view->edit(QModelIndex()); view->clearSelection(); view->setCurrentIndex(QModelIndex()); // protected methods view->tst_dataChanged(QModelIndex(), QModelIndex()); view->tst_rowsInserted(QModelIndex(), -1, -1); view->tst_rowsAboutToBeRemoved(QModelIndex(), -1, -1); view->tst_selectionChanged(QItemSelection(), QItemSelection()); if (view->model()){ view->tst_currentChanged(QModelIndex(), QModelIndex()); view->tst_currentChanged(QModelIndex(), view->model()->index(0,0)); } view->tst_updateEditorData(); view->tst_updateEditorGeometries(); view->tst_updateGeometries(); view->tst_verticalScrollbarAction(QAbstractSlider::SliderSingleStepAdd); view->tst_horizontalScrollbarAction(QAbstractSlider::SliderSingleStepAdd); view->tst_verticalScrollbarValueChanged(10); view->tst_horizontalScrollbarValueChanged(10); view->tst_closeEditor(0, QAbstractItemDelegate::NoHint); view->tst_commitData(0); view->tst_editorDestroyed(0); view->tst_setHorizontalStepsPerItem(2); view->tst_horizontalStepsPerItem(); view->tst_setVerticalStepsPerItem(2); view->tst_verticalStepsPerItem(); // Will assert as it should // view->setIndexWidget(QModelIndex(), 0); view->tst_moveCursor(TestView::MoveUp, Qt::NoModifier); view->tst_horizontalOffset(); view->tst_verticalOffset(); // view->tst_isIndexHidden(QModelIndex()); // will (correctly) assert if(view->model()) view->tst_isIndexHidden(view->model()->index(0,0)); view->tst_setSelection(QRect(0, 0, 10, 10), QItemSelectionModel::ClearAndSelect); view->tst_setSelection(QRect(-1, -1, -1, -1), QItemSelectionModel::ClearAndSelect); view->tst_visualRegionForSelection(QItemSelection()); view->tst_selectedIndexes(); view->tst_edit(QModelIndex(), QAbstractItemView::NoEditTriggers, 0); view->tst_selectionCommand(QModelIndex(), 0); #ifndef QT_NO_DRAGANDDROP if (!view->model()) view->tst_startDrag(Qt::CopyAction); view->tst_viewOptions(); view->tst_setState(TestView::NoState); QVERIFY(view->tst_state()==TestView::NoState); view->tst_setState(TestView::DraggingState); QVERIFY(view->tst_state()==TestView::DraggingState); view->tst_setState(TestView::DragSelectingState); QVERIFY(view->tst_state()==TestView::DragSelectingState); view->tst_setState(TestView::EditingState); QVERIFY(view->tst_state()==TestView::EditingState); view->tst_setState(TestView::ExpandingState); QVERIFY(view->tst_state()==TestView::ExpandingState); view->tst_setState(TestView::CollapsingState); QVERIFY(view->tst_state()==TestView::CollapsingState); #endif view->tst_startAutoScroll(); view->tst_stopAutoScroll(); view->tst_doAutoScroll(); // testing mouseFoo and key functions // QTest::mousePress(view, Qt::LeftButton, Qt::NoModifier, QPoint(0,0)); // mouseMove(view, Qt::LeftButton, Qt::NoModifier, QPoint(10,10)); // QTest::mouseRelease(view, Qt::LeftButton, Qt::NoModifier, QPoint(10,10)); // QTest::mouseClick(view, Qt::LeftButton, Qt::NoModifier, QPoint(10,10)); // mouseDClick(view, Qt::LeftButton, Qt::NoModifier, QPoint(10,10)); // QTest::keyClick(view, Qt::Key_A); } void tst_QAbstractItemView::noModel() { // From task #85415 QStandardItemModel model(20,20); QTreeView view; view.setModel(&model); // Make the viewport smaller than the contents, so that we can scroll view.resize(100,100); view.show(); // make sure that the scrollbars are not at value 0 view.scrollTo(view.model()->index(10,10)); QApplication::processEvents(); view.setModel(0); // Due to the model is removed, this will generate a valueChanged signal on both scrollbars. (value to 0) QApplication::processEvents(); QCOMPARE(view.model(), (QAbstractItemModel*)0); } void tst_QAbstractItemView::dragSelect() { // From task #86108 QStandardItemModel model(64,64); QTableView view; view.setModel(&model); view.setVisible(true); const int delay = 2; for (int i = 0; i < 2; ++i) { bool tracking = (i == 1); view.setMouseTracking(false); QTest::mouseMove(&view, QPoint(0, 0), delay); view.setMouseTracking(tracking); QTest::mouseMove(&view, QPoint(50, 50), delay); QVERIFY(view.selectionModel()->selectedIndexes().isEmpty()); } } void tst_QAbstractItemView::rowDelegate() { QStandardItemModel model(4,4); MyAbstractItemDelegate delegate; QTableView view; view.setModel(&model); view.setItemDelegateForRow(3, &delegate); view.show(); QModelIndex index = model.index(3, 0); view.openPersistentEditor(index); QWidget *w = view.indexWidget(index); QVERIFY(w); QCOMPARE(w->metaObject()->className(), "QWidget"); } void tst_QAbstractItemView::columnDelegate() { QStandardItemModel model(4,4); MyAbstractItemDelegate delegate; QTableView view; view.setModel(&model); view.setItemDelegateForColumn(3, &delegate); view.show(); QModelIndex index = model.index(0, 3); view.openPersistentEditor(index); QWidget *w = view.indexWidget(index); QVERIFY(w); QCOMPARE(w->metaObject()->className(), "QWidget"); } void tst_QAbstractItemView::selectAll() { QStandardItemModel model(4,4); QTableView view; view.setModel(&model); TestView *tst_view = (TestView*)&view; QCOMPARE(tst_view->tst_selectedIndexes().count(), 0); view.selectAll(); QCOMPARE(tst_view->tst_selectedIndexes().count(), 4*4); } void tst_QAbstractItemView::ctrlA() { QStandardItemModel model(4,4); QTableView view; view.setModel(&model); TestView *tst_view = (TestView*)&view; QCOMPARE(tst_view->tst_selectedIndexes().count(), 0); QTest::keyClick(&view, Qt::Key_A, Qt::ControlModifier); QCOMPARE(tst_view->tst_selectedIndexes().count(), 4*4); } void tst_QAbstractItemView::persistentEditorFocus() { // one row, three columns QStandardItemModel model(1, 3); for(int i = 0; i < model.columnCount(); ++i) model.setData(model.index(0, i), i); QTableView view; view.setModel(&model); view.openPersistentEditor(model.index(0, 1)); view.openPersistentEditor(model.index(0, 2)); //these are spinboxes because we put numbers inside QList list = qFindChildren(view.viewport()); QCOMPARE(list.count(), 2); //these should be the 2 editors view.setCurrentIndex(model.index(0, 0)); QCOMPARE(view.currentIndex(), model.index(0, 0)); view.show(); QTRY_VERIFY(view.isVisible()); for (int i = 0; i < list.count(); ++i) { TRY_COMPARE(list.at(i)->isVisible(), true); QPoint p = QPoint(5, 5); QMouseEvent mouseEvent(QEvent::MouseButtonPress, p, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); qApp->sendEvent(list.at(i), &mouseEvent); if (!qApp->focusWidget()) QSKIP("Some window managers don't handle focus that well", SkipAll); QTRY_COMPARE(qApp->focusWidget(), static_cast(list.at(i))); } } #if !defined(Q_OS_MAC) && !defined(Q_OS_WIN) #if 0 static void sendMouseMove(QWidget *widget, QPoint pos = QPoint()) { if (pos.isNull()) pos = widget->rect().center(); QMouseEvent event(QEvent::MouseMove, pos, widget->mapToGlobal(pos), Qt::NoButton, 0, 0); QCursor::setPos(widget->mapToGlobal(pos)); qApp->processEvents(); #if defined(Q_WS_X11) qt_x11_wait_for_window_manager(widget); #endif QApplication::sendEvent(widget, &event); } static void sendMousePress( QWidget *widget, QPoint pos = QPoint(), Qt::MouseButton button = Qt::LeftButton) { if (pos.isNull()) pos = widget->rect().center(); QMouseEvent event(QEvent::MouseButtonPress, pos, widget->mapToGlobal(pos), button, 0, 0); QApplication::sendEvent(widget, &event); } static void sendMouseRelease( QWidget *widget, QPoint pos = QPoint(), Qt::MouseButton button = Qt::LeftButton) { if (pos.isNull()) pos = widget->rect().center(); QMouseEvent event(QEvent::MouseButtonRelease, pos, widget->mapToGlobal(pos), button, 0, 0); QApplication::sendEvent(widget, &event); } class DnDTestModel : public QStandardItemModel { Q_OBJECT bool dropMimeData(const QMimeData *md, Qt::DropAction action, int r, int c, const QModelIndex &p) { dropAction_result = action; QStandardItemModel::dropMimeData(md, action, r, c, p); return true; } Qt::DropActions supportedDropActions() const { return Qt::CopyAction | Qt::MoveAction; } Qt::DropAction dropAction_result; public: DnDTestModel() : QStandardItemModel(20, 20), dropAction_result(Qt::IgnoreAction) { for (int i = 0; i < rowCount(); ++i) setData(index(i, 0), QString("%1").arg(i)); } Qt::DropAction dropAction() const { return dropAction_result; } }; class DnDTestView : public QTreeView { Q_OBJECT QPoint dropPoint; Qt::DropAction dropAction; void dragEnterEvent(QDragEnterEvent *event) { QAbstractItemView::dragEnterEvent(event); } void dropEvent(QDropEvent *event) { event->setDropAction(dropAction); QTreeView::dropEvent(event); } void timerEvent(QTimerEvent *event) { killTimer(event->timerId()); sendMouseMove(this, dropPoint); sendMouseRelease(this); } void mousePressEvent(QMouseEvent *e) { QTreeView::mousePressEvent(e); startTimer(0); setState(DraggingState); startDrag(dropAction); } public: DnDTestView(Qt::DropAction dropAction, QAbstractItemModel *model) : dropAction(dropAction) { header()->hide(); setModel(model); setDragDropMode(QAbstractItemView::DragDrop); setAcceptDrops(true); setDragEnabled(true); } void dragAndDrop(QPoint drag, QPoint drop) { dropPoint = drop; setCurrentIndex(indexAt(drag)); sendMousePress(viewport(), drag); } }; class DnDTestWidget : public QWidget { Q_OBJECT Qt::DropAction dropAction_request; Qt::DropAction dropAction_result; QWidget *dropTarget; void timerEvent(QTimerEvent *event) { killTimer(event->timerId()); sendMouseMove(dropTarget); sendMouseRelease(dropTarget); } void mousePressEvent(QMouseEvent *) { QDrag *drag = new QDrag(this); QMimeData *mimeData = new QMimeData; mimeData->setData("application/x-qabstractitemmodeldatalist", QByteArray("")); drag->setMimeData(mimeData); startTimer(0); dropAction_result = drag->start(dropAction_request); } public: Qt::DropAction dropAction() const { return dropAction_result; } void dragAndDrop(QWidget *dropTarget, Qt::DropAction dropAction) { this->dropTarget = dropTarget; dropAction_request = dropAction; sendMousePress(this); } }; void tst_QAbstractItemView::dragAndDrop() { // From Task 137729 #ifdef Q_WS_QWS QSKIP("Embedded drag-and-drop not good enough yet...", SkipAll); #endif const int attempts = 10; int successes = 0; for (int i = 0; i < attempts; ++i) { Qt::DropAction dropAction = Qt::MoveAction; DnDTestModel model; DnDTestView view(dropAction, &model); DnDTestWidget widget; const int size = 200; widget.setFixedSize(size, size); view.setFixedSize(size, size); widget.move(0, 0); view.move(int(size * 1.5), int(size * 1.5)); widget.show(); view.show(); #if defined(Q_WS_X11) qt_x11_wait_for_window_manager(&widget); qt_x11_wait_for_window_manager(&view); #endif widget.dragAndDrop(&view, dropAction); if (model.dropAction() == dropAction && widget.dropAction() == dropAction) ++successes; } if (successes < attempts) { QString msg = QString("# successes (%1) < # attempts (%2)").arg(successes).arg(attempts); QWARN(msg.toLatin1()); } QVERIFY(successes > 0); // allow for some "event unstability" (i.e. unless // successes == 0, QAbstractItemView is probably ok!) } void tst_QAbstractItemView::dragAndDropOnChild() { #ifdef Q_WS_QWS QSKIP("Embedded drag-and-drop not good enough yet...", SkipAll); #endif const int attempts = 10; int successes = 0; for (int i = 0; i < attempts; ++i) { Qt::DropAction dropAction = Qt::MoveAction; DnDTestModel model; QModelIndex parent = model.index(0, 0); model.insertRow(0, parent); model.insertColumn(0, parent); QModelIndex child = model.index(0, 0, parent); model.setData(child, "child"); QCOMPARE(model.rowCount(parent), 1); DnDTestView view(dropAction, &model); view.setExpanded(parent, true); view.setDragDropMode(QAbstractItemView::InternalMove); const int size = 200; view.setFixedSize(size, size); view.move(int(size * 1.5), int(size * 1.5)); view.show(); #if defined(Q_WS_X11) qt_x11_wait_for_window_manager(&view); #endif view.dragAndDrop(view.visualRect(parent).center(), view.visualRect(child).center()); if (model.dropAction() == dropAction) ++successes; } QVERIFY(successes == 0); } #endif // 0 #endif // !Q_OS_MAC && !Q_OS_WIN class TestModel : public QStandardItemModel { public: TestModel(int rows, int columns) : QStandardItemModel(rows, columns) { setData_count = 0; } virtual bool setData(const QModelIndex &/*index*/, const QVariant &/*value*/, int /*role = Qt::EditRole*/) { ++setData_count; return true; } int setData_count; }; typedef QList IntList; Q_DECLARE_METATYPE(IntList) void tst_QAbstractItemView::setItemDelegate_data() { // default is rows, a -1 will switch to columns QTest::addColumn("rowsOrColumnsWithDelegate"); QTest::addColumn("cellToEdit"); QTest::newRow("4 columndelegates") << (IntList() << -1 << 0 << 1 << 2 << 3) << QPoint(0, 0); QTest::newRow("2 identical rowdelegates on the same row") << (IntList() << 0 << 0) << QPoint(0, 0); QTest::newRow("2 identical columndelegates on the same column") << (IntList() << -1 << 2 << 2) << QPoint(2, 0); QTest::newRow("2 duplicate delegates, 1 row and 1 column") << (IntList() << 0 << -1 << 2) << QPoint(2, 0); QTest::newRow("4 duplicate delegates, 2 row and 2 column") << (IntList() << 0 << 0 << -1 << 2 << 2) << QPoint(2, 0); } void tst_QAbstractItemView::setItemDelegate() { QFETCH(IntList, rowsOrColumnsWithDelegate); QFETCH(QPoint, cellToEdit); QTableView v; QItemDelegate *delegate = new QItemDelegate(&v); TestModel model(5, 5); v.setModel(&model); bool row = true; foreach (int rc, rowsOrColumnsWithDelegate) { if (rc == -1) { row = !row; } else { if (row) { v.setItemDelegateForRow(rc, delegate); } else { v.setItemDelegateForColumn(rc, delegate); } } } v.show(); #ifdef Q_WS_X11 qt_x11_wait_for_window_manager(&v); QCursor::setPos(v.geometry().center()); QApplication::syncX(); #endif QTest::qWait(20); QApplication::setActiveWindow(&v); QModelIndex index = model.index(cellToEdit.y(), cellToEdit.x()); v.edit(index); // This will close the editor TRY_COMPARE(QApplication::focusWidget() == 0, false); QWidget *editor = QApplication::focusWidget(); QVERIFY(editor); editor->hide(); delete editor; QCOMPARE(model.setData_count, 1); delete delegate; } void tst_QAbstractItemView::noFallbackToRoot() { QStandardItemModel model(0, 1); for (int i = 0; i < 5; ++i) model.appendRow(new QStandardItem("top" + QString::number(i))); QStandardItem *par1 = model.item(1); for (int j = 0; j < 15; ++j) par1->appendRow(new QStandardItem("sub" + QString::number(j))); QStandardItem *par2 = par1->child(2); for (int k = 0; k < 10; ++k) par2->appendRow(new QStandardItem("bot" + QString::number(k))); QStandardItem *it1 = par2->child(5); QModelIndex parent1 = model.indexFromItem(par1); QModelIndex parent2 = model.indexFromItem(par2); QModelIndex item1 = model.indexFromItem(it1); QTreeView v; v.setModel(&model); v.setRootIndex(parent1); v.setCurrentIndex(item1); QCOMPARE(v.currentIndex(), item1); QVERIFY(model.removeRows(0, 10, parent2)); QCOMPARE(v.currentIndex(), parent2); QVERIFY(model.removeRows(0, 15, parent1)); QCOMPARE(v.currentIndex(), QModelIndex()); } void tst_QAbstractItemView::setCurrentIndex_data() { QTest::addColumn("viewType"); QTest::addColumn("itemFlags"); QTest::addColumn("result"); QStringList widgets; widgets << "QListView" << "QTreeView" << "QHeaderView" << "QTableView"; foreach(QString widget, widgets) { QTest::newRow((widget+QLatin1String(": no flags")).toLocal8Bit().constData()) << widget << (int)0 << false; QTest::newRow((widget+QLatin1String(": checkable")).toLocal8Bit().constData()) << widget << (int)Qt::ItemIsUserCheckable << false; QTest::newRow((widget+QLatin1String(": selectable")).toLocal8Bit().constData()) << widget << (int)Qt::ItemIsSelectable << false; QTest::newRow((widget+QLatin1String(": enabled")).toLocal8Bit().constData()) << widget << (int)Qt::ItemIsEnabled << true; QTest::newRow((widget+QLatin1String(": enabled|selectable")).toLocal8Bit().constData()) << widget << (int)(Qt::ItemIsSelectable|Qt::ItemIsEnabled) << true; } } void tst_QAbstractItemView::setCurrentIndex() { QFETCH(QString, viewType); QFETCH(int, itemFlags); QFETCH(bool, result); TestView *view = 0; if (viewType == "QListView") view = reinterpret_cast(new QListView()); else if (viewType == "QTableView") view = reinterpret_cast(new QTableView()); else if (viewType == "QTreeView") view = reinterpret_cast(new QTreeView()); else if (viewType == "QHeaderView") view = reinterpret_cast(new QHeaderView(Qt::Vertical)); else QVERIFY(0); view->show(); QStandardItemModel *model = new QStandardItemModel(view); QStandardItem *item = new QStandardItem("first item"); item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); model->appendRow(item); item = new QStandardItem("test item"); item->setFlags(Qt::ItemFlags(itemFlags)); model->appendRow(item); view->setModel(model); view->setCurrentIndex(model->index(0,0)); QVERIFY(view->currentIndex() == model->index(0,0)); view->setCurrentIndex(model->index(1,0)); QVERIFY(view->currentIndex() == model->index(result ? 1 : 0,0)); delete view; } void tst_QAbstractItemView::task221955_selectedEditor() { QPushButton *button; QTreeWidget tree; tree.setColumnCount(2); tree.addTopLevelItem(new QTreeWidgetItem(QStringList() << "Foo" <<"1")); tree.addTopLevelItem(new QTreeWidgetItem(QStringList() << "Bar" <<"2")); tree.addTopLevelItem(new QTreeWidgetItem(QStringList() << "Baz" <<"3")); QTreeWidgetItem *dummy = new QTreeWidgetItem(); tree.addTopLevelItem(dummy); tree.setItemWidget(dummy, 0, button = new QPushButton("More...")); button->setAutoFillBackground(true); // as recommended in doc tree.show(); tree.setFocus(); tree.setCurrentIndex(tree.model()->index(1,0)); QTest::qWait(100); QApplication::setActiveWindow(&tree); QVERIFY(! tree.selectionModel()->selectedIndexes().contains(tree.model()->index(3,0))); //We set the focus to the button, the index need to be selected button->setFocus(); QTest::qWait(100); QVERIFY(tree.selectionModel()->selectedIndexes().contains(tree.model()->index(3,0))); tree.setCurrentIndex(tree.model()->index(1,0)); QVERIFY(! tree.selectionModel()->selectedIndexes().contains(tree.model()->index(3,0))); //Same thing but with the flag NoSelection, nothing can be selected. tree.setFocus(); tree.setSelectionMode(QAbstractItemView::NoSelection); tree.clearSelection(); QVERIFY(tree.selectionModel()->selectedIndexes().isEmpty()); QTest::qWait(10); button->setFocus(); QTest::qWait(50); QVERIFY(tree.selectionModel()->selectedIndexes().isEmpty()); } void tst_QAbstractItemView::task250754_fontChange() { QString app_css = qApp->styleSheet(); qApp->setStyleSheet("/* */"); QWidget w; QTreeView tree(&w); QVBoxLayout *vLayout = new QVBoxLayout(&w); vLayout->addWidget(&tree); QStandardItemModel *m = new QStandardItemModel(this); for (int i=0; i<5; ++i) { QStandardItem *item = new QStandardItem(QString("Item number %1").arg(i)); for (int j=0; j<5; ++j) { QStandardItem *child = new QStandardItem(QString("Child Item number %1").arg(j)); item->setChild(j, 0, child); } m->setItem(i, 0, item); } tree.setModel(m); w.show(); w.resize(150,150); QTest::qWait(30); QFont font = tree.font(); font.setPointSize(5); tree.setFont(font); QTest::qWait(30); QVERIFY(!tree.verticalScrollBar()->isVisible()); font.setPointSize(45); tree.setFont(font); QTest::qWait(30); //now with the huge items, the scrollbar must be visible QVERIFY(tree.verticalScrollBar()->isVisible()); qApp->setStyleSheet(app_css); } void tst_QAbstractItemView::task200665_itemEntered() { //we test that view will emit entered //when the scrollbar move but not the mouse itself QStandardItemModel model(1000,1); QListView view; view.setModel(&model); view.show(); QTest::qWait(200); QRect rect = view.visualRect(model.index(0,0)); QCursor::setPos( view.viewport()->mapToGlobal(rect.center()) ); QSignalSpy spy(&view, SIGNAL(entered(QModelIndex))); view.verticalScrollBar()->setValue(view.verticalScrollBar()->maximum()); QCOMPARE(spy.count(), 1); } void tst_QAbstractItemView::task257481_emptyEditor() { QIcon icon = qApp->style()->standardIcon(QStyle::SP_ComputerIcon); QStandardItemModel model; model.appendRow( new QStandardItem(icon, QString()) ); model.appendRow( new QStandardItem(icon, "Editor works") ); model.appendRow( new QStandardItem( QString() ) ); QTreeView treeView; treeView.setRootIsDecorated(false); treeView.setModel(&model); treeView.show(); treeView.edit(model.index(0,0)); QList lineEditors = qFindChildren(treeView.viewport()); QCOMPARE(lineEditors.count(), 1); QVERIFY(!lineEditors.first()->size().isEmpty()); QTest::qWait(30); treeView.edit(model.index(1,0)); lineEditors = qFindChildren(treeView.viewport()); QCOMPARE(lineEditors.count(), 1); QVERIFY(!lineEditors.first()->size().isEmpty()); QTest::qWait(30); treeView.edit(model.index(2,0)); lineEditors = qFindChildren(treeView.viewport()); QCOMPARE(lineEditors.count(), 1); QVERIFY(!lineEditors.first()->size().isEmpty()); } void tst_QAbstractItemView::shiftArrowSelectionAfterScrolling() { QStandardItemModel model; for (int i=0; i<10; ++i) { QStandardItem *item = new QStandardItem(QString("%1").arg(i)); model.setItem(i, 0, item); } QListView view; view.setFixedSize(150, 250); view.setFlow(QListView::LeftToRight); view.setGridSize(QSize(100, 100)); view.setSelectionMode(QListView::ExtendedSelection); view.setViewMode(QListView::IconMode); view.setModel(&model); view.show(); QTest::qWait(30); QModelIndex index0 = model.index(0, 0); QModelIndex index1 = model.index(1, 0); QModelIndex index9 = model.index(9, 0); view.selectionModel()->setCurrentIndex(index0, QItemSelectionModel::NoUpdate); QCOMPARE(view.currentIndex(), index0); view.scrollTo(index9); QTest::keyClick(&view, Qt::Key_Down, Qt::ShiftModifier); QCOMPARE(view.currentIndex(), index1); QModelIndexList selected = view.selectionModel()->selectedIndexes(); QCOMPARE(selected.count(), 2); QVERIFY(selected.contains(index0)); QVERIFY(selected.contains(index1)); } void tst_QAbstractItemView::shiftSelectionAfterRubberbandSelection() { QStandardItemModel model; for (int i=0; i<3; ++i) { QStandardItem *item = new QStandardItem(QString("%1").arg(i)); model.setItem(i, 0, item); } QListView view; view.setFixedSize(150, 450); view.setFlow(QListView::LeftToRight); view.setGridSize(QSize(100, 100)); view.setSelectionMode(QListView::ExtendedSelection); view.setViewMode(QListView::IconMode); view.setModel(&model); view.show(); QTest::qWait(30); QModelIndex index0 = model.index(0, 0); QModelIndex index1 = model.index(1, 0); QModelIndex index2 = model.index(2, 0); view.setCurrentIndex(index0); QCOMPARE(view.currentIndex(), index0); // Determine the points where the rubberband selection starts and ends QPoint pressPos = view.visualRect(index1).bottomRight() + QPoint(1, 1); QPoint releasePos = view.visualRect(index1).center(); QVERIFY(!view.indexAt(pressPos).isValid()); QCOMPARE(view.indexAt(releasePos), index1); // Select item 1 using a rubberband selection // The mouse move event has to be created manually because the QTest framework does not // contain a function for mouse moves with buttons pressed QTest::mousePress(view.viewport(), Qt::LeftButton, Qt::NoModifier, pressPos); QMouseEvent moveEvent(QEvent::MouseMove, releasePos, Qt::NoButton, Qt::LeftButton, Qt::NoModifier); bool moveEventReceived = qApp->notify(view.viewport(), &moveEvent); QVERIFY(moveEventReceived); QTest::mouseRelease(view.viewport(), Qt::LeftButton, Qt::NoModifier, releasePos); QCOMPARE(view.currentIndex(), index1); // Shift-click item 2 QPoint item2Pos = view.visualRect(index2).center(); QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::ShiftModifier, item2Pos); QCOMPARE(view.currentIndex(), index2); // Verify that the selection worked OK QModelIndexList selected = view.selectionModel()->selectedIndexes(); QCOMPARE(selected.count(), 2); QVERIFY(selected.contains(index1)); QVERIFY(selected.contains(index2)); // Select item 0 to revert the selection view.setCurrentIndex(index0); QCOMPARE(view.currentIndex(), index0); // Repeat the same steps as above, but with a Shift-Arrow selection QTest::mousePress(view.viewport(), Qt::LeftButton, Qt::NoModifier, pressPos); QMouseEvent moveEvent2(QEvent::MouseMove, releasePos, Qt::NoButton, Qt::LeftButton, Qt::NoModifier); moveEventReceived = qApp->notify(view.viewport(), &moveEvent2); QVERIFY(moveEventReceived); QTest::mouseRelease(view.viewport(), Qt::LeftButton, Qt::NoModifier, releasePos); QCOMPARE(view.currentIndex(), index1); // Press Shift-Down QTest::keyClick(&view, Qt::Key_Down, Qt::ShiftModifier); QCOMPARE(view.currentIndex(), index2); // Verify that the selection worked OK selected = view.selectionModel()->selectedIndexes(); QCOMPARE(selected.count(), 2); QVERIFY(selected.contains(index1)); QVERIFY(selected.contains(index2)); } QTEST_MAIN(tst_QAbstractItemView) #include "tst_qabstractitemview.moc"