From 319482a6b33ce1bd365457054aca49a51d885e07 Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Fri, 23 Oct 2009 09:14:39 +0200 Subject: Drag and drop in QListWidget would not preserve the selection Now, when dropping items, these will remain selected, and in the same visual order as when dragged. Auto-test included for the items moving part. For the rest, it's a drag-and-drop thing. Reviewed-by: Olivier --- src/gui/itemviews/qlistwidget.cpp | 31 ++++++++++------ src/gui/itemviews/qlistwidget_p.h | 3 +- tests/auto/qlistwidget/tst_qlistwidget.cpp | 59 ++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 13 deletions(-) diff --git a/src/gui/itemviews/qlistwidget.cpp b/src/gui/itemviews/qlistwidget.cpp index a978d0f..5dd1d76 100644 --- a/src/gui/itemviews/qlistwidget.cpp +++ b/src/gui/itemviews/qlistwidget.cpp @@ -169,6 +169,20 @@ QListWidgetItem *QListModel::take(int row) return item; } +void QListModel::move(int srcRow, int dstRow) +{ + if (srcRow == dstRow + || srcRow < 0 || srcRow >= items.count() + || dstRow < 0 || dstRow >= items.count()) + return; + + beginMoveRows(QModelIndex(), srcRow, srcRow, QModelIndex(), dstRow); + if (srcRow < dstRow) + --dstRow; + items.move(srcRow, dstRow); + endMoveRows(); +} + int QListModel::rowCount(const QModelIndex &parent) const { return parent.isValid() ? 0 : items.count(); @@ -1804,22 +1818,15 @@ void QListWidget::dropEvent(QDropEvent *event) { if (persIndexes.contains(topIndex)) return; + qSort(persIndexes); // The dropped items will remain in the same visual order. QPersistentModelIndex dropRow = model()->index(row, col, topIndex); - QList taken; - for (int i = 0; i < persIndexes.count(); ++i) - taken.append(takeItem(persIndexes.at(i).row())); - - // insert them back in at their new positions + int r = row == -1 ? count() : (dropRow.row() >= 0 ? dropRow.row() : row); for (int i = 0; i < persIndexes.count(); ++i) { - // Either at a specific point or appended - if (row == -1) { - insertItem(count(), taken.takeFirst()); - } else { - int r = dropRow.row() >= 0 ? dropRow.row() : row; - insertItem(qMin(r, count()), taken.takeFirst()); - } + const QPersistentModelIndex &pIndex = persIndexes.at(i); + d->listModel()->move(pIndex.row(), r); + r = pIndex.row() + 1; // Dropped items are inserted contiguously and in the right order. } event->accept(); diff --git a/src/gui/itemviews/qlistwidget_p.h b/src/gui/itemviews/qlistwidget_p.h index 69cfa26..b5f28e3 100644 --- a/src/gui/itemviews/qlistwidget_p.h +++ b/src/gui/itemviews/qlistwidget_p.h @@ -77,7 +77,7 @@ public: { return *i2 < *i1; } }; -class QListModel : public QAbstractListModel +class Q_AUTOTEST_EXPORT QListModel : public QAbstractListModel { Q_OBJECT public: @@ -90,6 +90,7 @@ public: void insert(int row, const QStringList &items); void remove(QListWidgetItem *item); QListWidgetItem *take(int row); + void move(int srcRow, int dstRow); int rowCount(const QModelIndex &parent = QModelIndex()) const; diff --git a/tests/auto/qlistwidget/tst_qlistwidget.cpp b/tests/auto/qlistwidget/tst_qlistwidget.cpp index e825c8f..5c6ed54 100644 --- a/tests/auto/qlistwidget/tst_qlistwidget.cpp +++ b/tests/auto/qlistwidget/tst_qlistwidget.cpp @@ -46,6 +46,7 @@ #include #include +#include //TESTED_CLASS= //TESTED_FILES= @@ -95,6 +96,8 @@ private slots: void insertItem(); void insertItems_data(); void insertItems(); + void moveItemsPriv_data(); + void moveItemsPriv(); void itemAssignment(); void item_data(); @@ -849,6 +852,62 @@ void tst_QListWidget::removeItems() } +void tst_QListWidget::moveItemsPriv_data() +{ + QTest::addColumn("rowCount"); + QTest::addColumn("srcRow"); + QTest::addColumn("dstRow"); + QTest::addColumn("shouldHaveSignaled"); + + QTest::newRow("Empty") << 0 << 0 << 0 << false; + QTest::newRow("Overflow src") << 5 << 5 << 2 << false; + QTest::newRow("Underflow src") << 5 << -1 << 2 << false; + QTest::newRow("Overflow dst") << 5 << 2 << 5 << false; + QTest::newRow("Underflow dst") << 5 << 2 << -1 << false; + QTest::newRow("Same place") << 5 << 2 << 2 << false; + QTest::newRow("Up") << 5 << 4 << 2 << true; + QTest::newRow("Down") << 5 << 2 << 4 << true; +} + +void tst_QListWidget::moveItemsPriv() +{ + QFETCH(int, rowCount); + QFETCH(int, srcRow); + QFETCH(int, dstRow); + QFETCH(bool, shouldHaveSignaled); + + for (int r = 0; r < rowCount; ++r) + new QListWidgetItem(QString::number(r), testWidget); + + QListModel *model = dynamic_cast(testWidget->model()); + QVERIFY(model); + QSignalSpy beginMoveSpy(model, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int))); + QSignalSpy movedSpy(model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int))); + model->move(srcRow, dstRow); + + if (shouldHaveSignaled) { + if (srcRow < dstRow) + QCOMPARE(testWidget->item(dstRow - 1)->text(), QString::number(srcRow)); + else + QCOMPARE(testWidget->item(dstRow)->text(), QString::number(srcRow)); + + QCOMPARE(beginMoveSpy.count(), 1); + const QList &beginMoveArgs = beginMoveSpy.takeFirst(); + QCOMPARE(beginMoveArgs.at(1).toInt(), srcRow); + QCOMPARE(beginMoveArgs.at(2).toInt(), srcRow); + QCOMPARE(beginMoveArgs.at(4).toInt(), dstRow); + + QCOMPARE(movedSpy.count(), 1); + const QList &movedArgs = movedSpy.takeFirst(); + QCOMPARE(movedArgs.at(1).toInt(), srcRow); + QCOMPARE(movedArgs.at(2).toInt(), srcRow); + QCOMPARE(movedArgs.at(4).toInt(), dstRow); + } else { + QCOMPARE(beginMoveSpy.count(), 0); + QCOMPARE(movedSpy.count(), 0); + } +} + void tst_QListWidget::itemStreaming_data() { QTest::addColumn("text"); -- cgit v0.12 From c7e8c1844819bc9b078403f8cdbad9c104452a30 Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Mon, 26 Oct 2009 12:52:30 +0100 Subject: Fixed typo Would not have introduced any bug as invald QModelIndex are currently initialised with -1 for row and column. Reviewed-by: trust me --- src/gui/itemviews/qitemselectionmodel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/itemviews/qitemselectionmodel.cpp b/src/gui/itemviews/qitemselectionmodel.cpp index dfebe03..f2ccb6e 100644 --- a/src/gui/itemviews/qitemselectionmodel.cpp +++ b/src/gui/itemviews/qitemselectionmodel.cpp @@ -599,7 +599,7 @@ void QItemSelectionModelPrivate::_q_rowsAboutToBeRemoved(const QModelIndex &pare while (itParent.isValid() && itParent.parent() != parent) itParent = itParent.parent(); - if (parent.isValid() && start <= itParent.row() && itParent.row() <= end) { + if (itParent.isValid() && start <= itParent.row() && itParent.row() <= end) { deselected.append(*it); it = ranges.erase(it); } else { -- cgit v0.12 From 9c78eb972041a066e455bf04d63f3290afacb982 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Mon, 26 Oct 2009 15:15:59 +0100 Subject: stabilize test and fix warning --- src/gui/kernel/qguiplatformplugin.cpp | 2 ++ tests/auto/qlistview/tst_qlistview.cpp | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/gui/kernel/qguiplatformplugin.cpp b/src/gui/kernel/qguiplatformplugin.cpp index 6e074a1..b01d40f 100644 --- a/src/gui/kernel/qguiplatformplugin.cpp +++ b/src/gui/kernel/qguiplatformplugin.cpp @@ -288,6 +288,8 @@ int QGuiPlatformPlugin::platformHint(PlatformHint hint) #endif //by default keep ret = 0 so QCommonStyle will use the style default break; + default: + break; } return ret; } diff --git a/tests/auto/qlistview/tst_qlistview.cpp b/tests/auto/qlistview/tst_qlistview.cpp index 3968529..65ab12d 100644 --- a/tests/auto/qlistview/tst_qlistview.cpp +++ b/tests/auto/qlistview/tst_qlistview.cpp @@ -1785,12 +1785,12 @@ void tst_QListView::task262152_setModelColumnNavigate() view.show(); QTest::qWaitForWindowShown(&view); - QTest::qWait(10); + QTest::qWait(100); QTest::keyClick(&view, Qt::Key_Down); - QTest::qWait(10); + QTest::qWait(100); QCOMPARE(view.currentIndex(), model.index(1,1)); QTest::keyClick(&view, Qt::Key_Down); - QTest::qWait(10); + QTest::qWait(100); QCOMPARE(view.currentIndex(), model.index(2,1)); } -- cgit v0.12 From 2d750192e73244f5b4ad6b451f264728d42669be Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Mon, 26 Oct 2009 15:53:47 +0100 Subject: Fixed crash when setting header data in QSqlQueryModel. The crash (Q_ASSERT_X failure) happened when a proxy model was being attached to the QSqlQueryModel, and no query was set yet. The headerDataChanged() signal was being received by the proxy model who wouldn't check its "proxyfied" data bounds. The patch introduces a behaviour change. However, this change makes the usage of QSqlQueryModel::setHeaderData() to be more in accordance with the current documentation, and to behave in the same way as for QStandardItemModel, QTreeModel, and QTableModel. Task-number: QTBUG-4963 Reviewed-by: Olivier --- src/sql/models/qsqlquerymodel.cpp | 2 +- tests/auto/qsqlquerymodel/tst_qsqlquerymodel.cpp | 18 ++++++++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/sql/models/qsqlquerymodel.cpp b/src/sql/models/qsqlquerymodel.cpp index a72ad8c..1719239 100644 --- a/src/sql/models/qsqlquerymodel.cpp +++ b/src/sql/models/qsqlquerymodel.cpp @@ -417,7 +417,7 @@ bool QSqlQueryModel::setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role) { Q_D(QSqlQueryModel); - if (orientation != Qt::Horizontal || section < 0) + if (orientation != Qt::Horizontal || section < 0 || columnCount() <= section) return false; if (d->headers.size() <= section) diff --git a/tests/auto/qsqlquerymodel/tst_qsqlquerymodel.cpp b/tests/auto/qsqlquerymodel/tst_qsqlquerymodel.cpp index 3131f35..02b48fa 100644 --- a/tests/auto/qsqlquerymodel/tst_qsqlquerymodel.cpp +++ b/tests/auto/qsqlquerymodel/tst_qsqlquerymodel.cpp @@ -96,6 +96,7 @@ private slots: void task_180617(); void task_180617_data() { generic_data(); } + void task_QTBUG_4963_setHeaderDataWithProxyModel(); private: void generic_data(const QString &engine=QString()); @@ -428,6 +429,8 @@ void tst_QSqlQueryModel::setHeaderData() QVERIFY(!model.setHeaderData(5, Qt::Vertical, "foo")); QVERIFY(model.headerData(5, Qt::Vertical).isValid()); + model.setQuery(QSqlQuery("select * from " + qTableName("test"), db)); + qRegisterMetaType("Qt::Orientation"); QSignalSpy spy(&model, SIGNAL(headerDataChanged(Qt::Orientation, int, int))); QVERIFY(model.setHeaderData(2, Qt::Horizontal, "bar")); @@ -437,10 +440,8 @@ void tst_QSqlQueryModel::setHeaderData() QCOMPARE(spy.value(0).value(1).toInt(), 2); QCOMPARE(spy.value(0).value(2).toInt(), 2); - QVERIFY(model.setHeaderData(7, Qt::Horizontal, "foo", Qt::ToolTipRole)); - QVERIFY(model.headerData(7, Qt::Horizontal, Qt::ToolTipRole).isValid()); - - model.setQuery(QSqlQuery("select * from " + qTableName("test"), db)); + QVERIFY(!model.setHeaderData(7, Qt::Horizontal, "foo", Qt::ToolTipRole)); + QVERIFY(!model.headerData(7, Qt::Horizontal, Qt::ToolTipRole).isValid()); bool isToUpper = db.driverName().startsWith("QIBASE") || db.driverName().startsWith("QOCI") || db.driverName().startsWith("QDB2"); QCOMPARE(model.headerData(0, Qt::Horizontal).toString(), isToUpper ? QString("ID") : QString("id")); @@ -603,5 +604,14 @@ void tst_QSqlQueryModel::task_180617() QCOMPARE(view.rowAt(0), -1); } +void tst_QSqlQueryModel::task_QTBUG_4963_setHeaderDataWithProxyModel() +{ + QSqlQueryModel plainModel; + QSortFilterProxyModel proxyModel; + proxyModel.setSourceModel(&plainModel); + QVERIFY(!plainModel.setHeaderData(0, Qt::Horizontal, QObject::tr("ID"))); + // And it should not crash. +} + QTEST_MAIN(tst_QSqlQueryModel) #include "tst_qsqlquerymodel.moc" -- cgit v0.12 From 68ab3b34571cfdde4002de9982388f9eec4d9939 Mon Sep 17 00:00:00 2001 From: Thierry Bastian Date: Mon, 26 Oct 2009 15:54:18 +0100 Subject: Fixed a bug in QMenuBar in RTL that would display menu at the wrong place This could happen when adding actions in response to the aboutToShow signal. Task-number: QT-2596 Reviewed-by: ogoffart --- src/gui/widgets/qmenu.cpp | 4 ++++ src/gui/widgets/qmenubar.cpp | 29 ++++++++++++----------------- tests/auto/qmenubar/tst_qmenubar.cpp | 29 ++++++++++++++++++++++++++++- 3 files changed, 44 insertions(+), 18 deletions(-) diff --git a/src/gui/widgets/qmenu.cpp b/src/gui/widgets/qmenu.cpp index ea25901..1b5d1cd 100644 --- a/src/gui/widgets/qmenu.cpp +++ b/src/gui/widgets/qmenu.cpp @@ -1878,6 +1878,10 @@ void QMenu::popup(const QPoint &p, QAction *atAction) if(snapToMouse) //position flowing left from the mouse pos.setX(mouse.x()-size.width()); + //if in a menubar, it should be right-aligned + if (qobject_cast(d->causedPopup.widget)) + pos.rx() -= size.width(); + if (pos.x() < screen.left()+desktopFrame) pos.setX(qMax(p.x(), screen.left()+desktopFrame)); if (pos.x()+size.width()-1 > screen.right()-desktopFrame) diff --git a/src/gui/widgets/qmenubar.cpp b/src/gui/widgets/qmenubar.cpp index f2f0722..689d2e1 100644 --- a/src/gui/widgets/qmenubar.cpp +++ b/src/gui/widgets/qmenubar.cpp @@ -336,30 +336,25 @@ void QMenuBarPrivate::popupAction(QAction *action, bool activateFirst) const bool fitUp = (q->mapToGlobal(adjustedActionRect.topLeft()).y() >= popup_size.height()); const bool fitDown = (pos.y() + popup_size.height() <= screenRect.bottom()); + const bool rtl = q->isRightToLeft(); const int actionWidth = adjustedActionRect.width(); if (!fitUp && !fitDown) { //we should shift the menu - bool shouldShiftToRight = !q->isRightToLeft(); - if (q->isRightToLeft() && popup_size.width() > pos.x()) + bool shouldShiftToRight = !rtl; + if (rtl && popup_size.width() > pos.x()) shouldShiftToRight = true; else if (actionWidth + popup_size.width() + pos.x() > screenRect.right()) shouldShiftToRight = false; - if (shouldShiftToRight) - pos.rx() += actionWidth; - else - pos.rx() -= popup_size.width(); - } else if (q->isRightToLeft()) { - pos.setX(pos.x()-(popup_size.width() - actionWidth)); - } - - if(pos.x() < screenRect.x()) { - pos.setX(screenRect.x()); - } else { - const int off = pos.x()+popup_size.width() - screenRect.right(); - if(off > 0) - pos.setX(qMax(screenRect.x(), pos.x()-off)); - + if (shouldShiftToRight) { + pos.rx() += actionWidth + (rtl ? popup_size.width() : 0); + } else { + //shift to left + if (!rtl) + pos.rx() -= popup_size.width(); + } + } else if (rtl) { + pos.rx() += actionWidth; } if(!defaultPopDown || (fitUp && !fitDown)) diff --git a/tests/auto/qmenubar/tst_qmenubar.cpp b/tests/auto/qmenubar/tst_qmenubar.cpp index 07aa9f4..4291c3e 100644 --- a/tests/auto/qmenubar/tst_qmenubar.cpp +++ b/tests/auto/qmenubar/tst_qmenubar.cpp @@ -86,6 +86,18 @@ private: uint sel_count; }; +class Menu : public QMenu +{ + Q_OBJECT + public slots: + void addActions() + { + //this will change the geometry of the menu + addAction("action1"); + addAction("action2"); + } +}; + class tst_QMenuBar : public QObject { Q_OBJECT @@ -1442,7 +1454,7 @@ void tst_QMenuBar::check_menuPosition() #ifdef Q_OS_WINCE_WM QSKIP("Qt/CE uses native menubar", SkipAll); #endif - QMenu menu; + Menu menu; #ifdef QT3_SUPPORT initComplexMenubar(); #else @@ -1496,6 +1508,21 @@ void tst_QMenuBar::check_menuPosition() menu.close(); } + //in RTL, the menu should be stuck at the right of the action geometry + { + Qt::LayoutDirection dir = qApp->layoutDirection(); + qApp->setLayoutDirection(Qt::RightToLeft); + menu.clear(); + QObject::connect(&menu, SIGNAL(aboutToShow()), &menu, SLOT(addActions())); + QRect mbItemRect = mw->menuBar()->actionGeometry(menu_action); + mbItemRect.moveTo(mw->menuBar()->mapToGlobal(mbItemRect.topLeft())); + QTest::keyClick(mw, Qt::Key_M, Qt::AltModifier ); + QVERIFY(menu.isActiveWindow()); + QCOMPARE(menu.geometry().right(), mbItemRect.right()); + menu.close(); + qApp->setLayoutDirection(dir); + } + } void tst_QMenuBar::task223138_triggered() -- cgit v0.12 From 0f6ab9612eba6c5418991443b65a10820d6b5a1f Mon Sep 17 00:00:00 2001 From: Leonardo Sobral Cunha Date: Tue, 27 Oct 2009 09:56:28 +0100 Subject: Stabilize sequential animation startDelay autotest on win Reviewed-by: thierry --- .../tst_qsequentialanimationgroup.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/tests/auto/qsequentialanimationgroup/tst_qsequentialanimationgroup.cpp b/tests/auto/qsequentialanimationgroup/tst_qsequentialanimationgroup.cpp index aa6801a..f6afc5b 100644 --- a/tests/auto/qsequentialanimationgroup/tst_qsequentialanimationgroup.cpp +++ b/tests/auto/qsequentialanimationgroup/tst_qsequentialanimationgroup.cpp @@ -929,16 +929,13 @@ void tst_QSequentialAnimationGroup::startDelay() group.addPause(125); QCOMPARE(group.totalDuration(), 375); - QEventLoop loop; - QObject::connect(&group, SIGNAL(finished()), &loop, SLOT(quit())); - - QTime time; - time.start(); group.start(); - loop.exec(); + QCOMPARE(group.state(), QAnimationGroup::Running); - QVERIFY(time.elapsed() >= 375); - QVERIFY(time.elapsed() < 1000); + QTest::qWait(500); + + QVERIFY(group.currentTime() == 375); + QCOMPARE(group.state(), QAnimationGroup::Stopped); } void tst_QSequentialAnimationGroup::clearGroup() -- cgit v0.12