From fee256e6414d634dcc17ed8cfbec34780878a194 Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Wed, 10 Apr 2019 10:55:40 +0200 Subject: Autotest: add syncView tests for QQuickTableView Change-Id: I0c311a4cc7d0765e234739c005cb68a60cfee129 Reviewed-by: Mitch Curtis --- .../quick/qquicktableview/data/syncviewsimple.qml | 122 ++++++++++ .../quick/qquicktableview/tst_qquicktableview.cpp | 257 ++++++++++++++++++++- 2 files changed, 372 insertions(+), 7 deletions(-) create mode 100644 tests/auto/quick/qquicktableview/data/syncviewsimple.qml (limited to 'tests') diff --git a/tests/auto/quick/qquicktableview/data/syncviewsimple.qml b/tests/auto/quick/qquicktableview/data/syncviewsimple.qml new file mode 100644 index 0000000000..012cceaa9d --- /dev/null +++ b/tests/auto/quick/qquicktableview/data/syncviewsimple.qml @@ -0,0 +1,122 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.14 +import QtQuick.Window 2.3 + +Item { + width: 640 + height: 450 + + property alias tableView: mainTableView + property alias tableViewH: tableViewH + property alias tableViewV: tableViewV + property alias tableViewHV: tableViewHV + + Column { + spacing: 10 + TableView { + id: tableViewH + objectName: "Hor" + width: 600 + height: 100 + anchors.margins: 1 + clip: true + delegate: tableViewDelegate + syncView: mainTableView + syncDirection: Qt.Horizontal + } + + TableView { + id: tableViewV + objectName: "Ver" + width: 600 + height: 100 + anchors.margins: 1 + clip: true + delegate: tableViewDelegate + syncView: mainTableView + syncDirection: Qt.Vertical + } + + TableView { + id: tableViewHV + objectName: "HorVer" + width: 600 + height: 100 + anchors.margins: 1 + clip: true + delegate: tableViewDelegate + syncView: mainTableView + } + + TableView { + id: mainTableView + objectName: "root" + width: 600 + height: 100 + anchors.margins: 1 + clip: true + delegate: tableViewDelegate + columnSpacing: 1 + rowSpacing: 1 + + columnWidthProvider: function(c) { return 50 + c } + rowHeightProvider: function(r) { return 25 + r } + } + } + + Component { + id: tableViewDelegate + Rectangle { + objectName: "tableViewDelegate" + color: "lightgray" + border.width: 1 + implicitWidth: 30 + implicitHeight: 60 + + Text { + anchors.centerIn: parent + font.pixelSize: 10 + text: parent.TableView.view.objectName + "\n" + column + ", " + row + } + } + } + +} diff --git a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp index 6c339c16d1..4267fb1f4c 100644 --- a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp +++ b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp @@ -57,17 +57,17 @@ static const char *kModelDataBindingProp = "modelDataBinding"; Q_DECLARE_METATYPE(QMarginsF); -#define DECLARE_TABLEVIEW_VARIABLES \ - auto tableView = view->rootObject()->property(kTableViewPropName).value(); \ - QVERIFY(tableView); \ - auto tableViewPrivate = QQuickTableViewPrivate::get(tableView); \ - Q_UNUSED(tableViewPrivate) +#define GET_QML_TABLEVIEW(PROPNAME) \ + auto PROPNAME = view->rootObject()->property(#PROPNAME).value(); \ + QVERIFY(PROPNAME); \ + auto PROPNAME ## Private = QQuickTableViewPrivate::get(PROPNAME); \ + Q_UNUSED(PROPNAME ## Private) #define LOAD_TABLEVIEW(fileName) \ view->setSource(testFileUrl(fileName)); \ view->show(); \ QVERIFY(QTest::qWaitForWindowActive(view)); \ - DECLARE_TABLEVIEW_VARIABLES + GET_QML_TABLEVIEW(tableView) #define LOAD_TABLEVIEW_ASYNC(fileName) \ view->setSource(testFileUrl("asyncloader.qml")); \ @@ -77,7 +77,7 @@ Q_DECLARE_METATYPE(QMarginsF); loader->setSource(QUrl::fromLocalFile("data/" fileName)); \ QTRY_VERIFY(loader->item()); \ QCOMPARE(loader->status(), QQuickLoader::Status::Ready); \ - DECLARE_TABLEVIEW_VARIABLES + GET_QML_TABLEVIEW(tableView) #define WAIT_UNTIL_POLISHED \ QVERIFY(QQuickTest::qIsPolishScheduled(tableView)); \ @@ -162,6 +162,11 @@ private slots: void hideRowsAndColumns_data(); void hideRowsAndColumns(); void checkThatRevisionedPropertiesCannotBeUsedInOldImports(); + void checkSyncView_rootView_data(); + void checkSyncView_rootView(); + void checkSyncView_childViews_data(); + void checkSyncView_childViews(); + void checkSyncView_differentSizedModels(); }; tst_QQuickTableView::tst_QQuickTableView() @@ -2148,6 +2153,244 @@ void tst_QQuickTableView::checkThatRevisionedPropertiesCannotBeUsedInOldImports( QCOMPARE(resolvedColumn, 42); } +void tst_QQuickTableView::checkSyncView_rootView_data() +{ + QTest::addColumn("flickToPos"); + + QTest::newRow("pos:110") << 110.; + QTest::newRow("pos:2010") << 2010.; +} + +void tst_QQuickTableView::checkSyncView_rootView() +{ + // Check that if you flick on the root tableview (the view that has + // no other view as syncView), all the other tableviews will sync + // their content view position according to their syncDirection flag. + QFETCH(qreal, flickToPos); + LOAD_TABLEVIEW("syncviewsimple.qml"); + GET_QML_TABLEVIEW(tableViewH); + GET_QML_TABLEVIEW(tableViewV); + GET_QML_TABLEVIEW(tableViewHV); + QQuickTableView *views[] = {tableViewH, tableViewV, tableViewHV}; + + auto model = TestModelAsVariant(100, 100); + + tableView->setModel(model); + for (auto view : views) + view->setModel(model); + + tableView->setContentX(flickToPos); + tableView->setContentY(flickToPos); + + WAIT_UNTIL_POLISHED; + + // Check that geometry properties are mirrored + QCOMPARE(tableViewH->columnSpacing(), tableView->columnSpacing()); + QCOMPARE(tableViewH->rowSpacing(), 0); + QCOMPARE(tableViewH->contentWidth(), tableView->contentWidth()); + QCOMPARE(tableViewV->columnSpacing(), 0); + QCOMPARE(tableViewV->rowSpacing(), tableView->rowSpacing()); + QCOMPARE(tableViewV->contentHeight(), tableView->contentHeight()); + + // Check that viewport is in sync after the flick + QCOMPARE(tableView->contentX(), flickToPos); + QCOMPARE(tableView->contentY(), flickToPos); + QCOMPARE(tableViewH->contentX(), tableView->contentX()); + QCOMPARE(tableViewH->contentY(), 0); + QCOMPARE(tableViewV->contentX(), 0); + QCOMPARE(tableViewV->contentY(), tableView->contentY()); + QCOMPARE(tableViewHV->contentX(), tableView->contentX()); + QCOMPARE(tableViewHV->contentY(), tableView->contentY()); + + // Check that topLeft cell is in sync after the flick + QCOMPARE(tableViewHPrivate->leftColumn(), tableViewPrivate->leftColumn()); + QCOMPARE(tableViewHPrivate->rightColumn(), tableViewPrivate->rightColumn()); + QCOMPARE(tableViewHPrivate->topRow(), 0); + QCOMPARE(tableViewVPrivate->leftColumn(), 0); + QCOMPARE(tableViewVPrivate->topRow(), tableViewPrivate->topRow()); + QCOMPARE(tableViewHVPrivate->leftColumn(), tableViewPrivate->leftColumn()); + QCOMPARE(tableViewHVPrivate->topRow(), tableViewPrivate->topRow()); + + // Check that the geometry of the tables are in sync after the flick + QCOMPARE(tableViewHPrivate->loadedTableOuterRect.left(), tableViewPrivate->loadedTableOuterRect.left()); + QCOMPARE(tableViewHPrivate->loadedTableOuterRect.right(), tableViewPrivate->loadedTableOuterRect.right()); + QCOMPARE(tableViewHPrivate->loadedTableOuterRect.top(), 0); + + QCOMPARE(tableViewVPrivate->loadedTableOuterRect.top(), tableViewPrivate->loadedTableOuterRect.top()); + QCOMPARE(tableViewVPrivate->loadedTableOuterRect.bottom(), tableViewPrivate->loadedTableOuterRect.bottom()); + QCOMPARE(tableViewVPrivate->loadedTableOuterRect.left(), 0); + + QCOMPARE(tableViewHVPrivate->loadedTableOuterRect, tableViewPrivate->loadedTableOuterRect); +} + +void tst_QQuickTableView::checkSyncView_childViews_data() +{ + QTest::addColumn("viewIndexToFlick"); + QTest::addColumn("flickToPos"); + + QTest::newRow("tableViewH, pos:100") << 0 << 100.; + QTest::newRow("tableViewV, pos:100") << 1 << 100.; + QTest::newRow("tableViewHV, pos:100") << 2 << 100.; + QTest::newRow("tableViewH, pos:2000") << 0 << 2000.; + QTest::newRow("tableViewV, pos:2000") << 1 << 2000.; + QTest::newRow("tableViewHV, pos:2000") << 2 << 2000.; +} + +void tst_QQuickTableView::checkSyncView_childViews() +{ + // Check that if you flick on a tableview that has a syncView, the + // syncView will move to the new position as well, which will also + // recursivly move all other connected child views of the syncView. + QFETCH(int, viewIndexToFlick); + QFETCH(qreal, flickToPos); + LOAD_TABLEVIEW("syncviewsimple.qml"); + GET_QML_TABLEVIEW(tableViewH); + GET_QML_TABLEVIEW(tableViewV); + GET_QML_TABLEVIEW(tableViewHV); + QQuickTableView *views[] = {tableViewH, tableViewV, tableViewHV}; + QQuickTableView *viewToFlick = views[viewIndexToFlick]; + QQuickTableViewPrivate *viewToFlickPrivate = QQuickTableViewPrivate::get(viewToFlick); + + auto model = TestModelAsVariant(100, 100); + + tableView->setModel(model); + for (auto view : views) + view->setModel(model); + + viewToFlick->setContentX(flickToPos); + viewToFlick->setContentY(flickToPos); + + WAIT_UNTIL_POLISHED; + + // The view the user flicks on can always be flicked in both directions + // (unless is has a flickingDirection set, which is not the case here). + QCOMPARE(viewToFlick->contentX(), flickToPos); + QCOMPARE(viewToFlick->contentY(), flickToPos); + + // The root view (tableView) will move in sync according + // to the syncDirection of the view being flicked. + if (viewToFlick->syncDirection() & Qt::Horizontal) { + QCOMPARE(tableView->contentX(), flickToPos); + QCOMPARE(tableViewPrivate->leftColumn(), viewToFlickPrivate->leftColumn()); + QCOMPARE(tableViewPrivate->rightColumn(), viewToFlickPrivate->rightColumn()); + QCOMPARE(tableViewPrivate->loadedTableOuterRect.left(), viewToFlickPrivate->loadedTableOuterRect.left()); + QCOMPARE(tableViewPrivate->loadedTableOuterRect.right(), viewToFlickPrivate->loadedTableOuterRect.right()); + } else { + QCOMPARE(tableView->contentX(), 0); + QCOMPARE(tableViewPrivate->leftColumn(), 0); + QCOMPARE(tableViewPrivate->loadedTableOuterRect.left(), 0); + } + + if (viewToFlick->syncDirection() & Qt::Vertical) { + QCOMPARE(tableView->contentY(), flickToPos); + QCOMPARE(tableViewPrivate->topRow(), viewToFlickPrivate->topRow()); + QCOMPARE(tableViewPrivate->bottomRow(), viewToFlickPrivate->bottomRow()); + QCOMPARE(tableViewPrivate->loadedTableOuterRect.top(), viewToFlickPrivate->loadedTableOuterRect.top()); + QCOMPARE(tableViewPrivate->loadedTableOuterRect.bottom(), viewToFlickPrivate->loadedTableOuterRect.bottom()); + } else { + QCOMPARE(tableView->contentY(), 0); + QCOMPARE(tableViewPrivate->topRow(), 0); + QCOMPARE(tableViewPrivate->loadedTableOuterRect.top(), 0); + } + + // The other views should continue to stay in sync with + // the root view, unless it was the view being flicked. + if (viewToFlick != tableViewH) { + QCOMPARE(tableViewH->contentX(), tableView->contentX()); + QCOMPARE(tableViewH->contentY(), 0); + QCOMPARE(tableViewHPrivate->leftColumn(), tableViewPrivate->leftColumn()); + QCOMPARE(tableViewHPrivate->rightColumn(), tableViewPrivate->rightColumn()); + QCOMPARE(tableViewHPrivate->loadedTableOuterRect.left(), tableViewPrivate->loadedTableOuterRect.left()); + QCOMPARE(tableViewHPrivate->loadedTableOuterRect.right(), tableViewPrivate->loadedTableOuterRect.right()); + QCOMPARE(tableViewHPrivate->topRow(), 0); + QCOMPARE(tableViewHPrivate->loadedTableOuterRect.top(), 0); + } + + if (viewToFlick != tableViewV) { + QCOMPARE(tableViewV->contentX(), 0); + QCOMPARE(tableViewV->contentY(), tableView->contentY()); + QCOMPARE(tableViewVPrivate->topRow(), tableViewPrivate->topRow()); + QCOMPARE(tableViewVPrivate->bottomRow(), tableViewPrivate->bottomRow()); + QCOMPARE(tableViewVPrivate->loadedTableOuterRect.top(), tableViewPrivate->loadedTableOuterRect.top()); + QCOMPARE(tableViewVPrivate->loadedTableOuterRect.bottom(), tableViewPrivate->loadedTableOuterRect.bottom()); + QCOMPARE(tableViewVPrivate->leftColumn(), 0); + QCOMPARE(tableViewVPrivate->loadedTableOuterRect.left(), 0); + } + + if (viewToFlick != tableViewHV) { + QCOMPARE(tableViewHV->contentX(), tableView->contentX()); + QCOMPARE(tableViewHV->contentY(), tableView->contentY()); + QCOMPARE(tableViewHVPrivate->leftColumn(), tableViewPrivate->leftColumn()); + QCOMPARE(tableViewHVPrivate->rightColumn(), tableViewPrivate->rightColumn()); + QCOMPARE(tableViewHVPrivate->topRow(), tableViewPrivate->topRow()); + QCOMPARE(tableViewHVPrivate->bottomRow(), tableViewPrivate->bottomRow()); + QCOMPARE(tableViewHVPrivate->loadedTableOuterRect, tableViewPrivate->loadedTableOuterRect); + } +} + +void tst_QQuickTableView::checkSyncView_differentSizedModels() +{ + // Check that you can have two tables in a syncView relation, where + // the sync "child" has fewer rows/columns than the syncView. In that + // case, it will be possible to flick the syncView further out than + // the child have rows/columns to follow. This causes some extra + // challenges for TableView to ensure that they are still kept in + // sync once you later flick the syncView back to a point where both + // tables ends up visible. This test will check this sitiation. + LOAD_TABLEVIEW("syncviewsimple.qml"); + GET_QML_TABLEVIEW(tableViewH); + GET_QML_TABLEVIEW(tableViewV); + GET_QML_TABLEVIEW(tableViewHV); + + auto tableViewModel = TestModelAsVariant(100, 100); + auto tableViewHModel = TestModelAsVariant(100, 50); + auto tableViewVModel = TestModelAsVariant(50, 100); + auto tableViewHVModel = TestModelAsVariant(5, 5); + + tableView->setModel(tableViewModel); + tableViewH->setModel(tableViewHModel); + tableViewV->setModel(tableViewVModel); + tableViewHV->setModel(tableViewHVModel); + + WAIT_UNTIL_POLISHED; + + // Flick far out, beyond the smaller tables, which will + // also force a rebuild (and as such, cause layout properties + // like average cell width to be temporarily out of sync). + tableView->setContentX(5000); + QVERIFY(tableViewPrivate->scheduledRebuildOptions); + + WAIT_UNTIL_POLISHED; + + // Check that the smaller tables are now flicked out of view + qreal leftEdge = tableViewPrivate->loadedTableOuterRect.left(); + QVERIFY(tableViewHPrivate->loadedTableOuterRect.right() < leftEdge); + QVERIFY(tableViewHVPrivate->loadedTableOuterRect.right() < leftEdge); + + // Flick slowly back so that we don't trigger a rebuild (since + // we want to check that we stay in sync also when not rebuilding). + while (tableView->contentX() > 200) { + tableView->setContentX(tableView->contentX() - 200); + QVERIFY(!tableViewPrivate->rebuildOptions); + QVERIFY(!tableViewPrivate->polishScheduled); + } + + leftEdge = tableViewPrivate->loadedTableOuterRect.left(); + const int leftColumn = tableViewPrivate->leftColumn(); + QCOMPARE(tableViewHPrivate->loadedTableOuterRect.left(), leftEdge); + QCOMPARE(tableViewHPrivate->leftColumn(), leftColumn); + + // Because the tableView was fast flicked and then slowly flicked back, the + // left column is now 49, which is actually far too high, since we're almost + // at the beginning of the content view. But this "miscalculation" is expected + // when the column widths are increasing for each column, like they do in this + // test. In that case, the algorithm that predicts where each column should end + // up gets slightly confused. Anyway, check that tableViewHV, that has only + // 5 columns, is not showing any columns, since it should always stay in sync with + // syncView regardless of the content view position. + QVERIFY(tableViewHVPrivate->loadedColumns.isEmpty()); +} + QTEST_MAIN(tst_QQuickTableView) #include "tst_qquicktableview.moc" -- cgit v1.2.3 From 5032ff5c2b48d53e4580bb7d50b1f6de081263b0 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Thu, 4 Apr 2019 15:41:18 +0200 Subject: Move workerscript to its own module Change-Id: I778cfe842ddf1c600a837d8f2061a338887eed95 Reviewed-by: Lars Knoll --- tests/auto/qml/qquickworkerscript/qquickworkerscript.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/auto/qml/qquickworkerscript/qquickworkerscript.pro b/tests/auto/qml/qquickworkerscript/qquickworkerscript.pro index be8b9089a2..f58fd4543f 100644 --- a/tests/auto/qml/qquickworkerscript/qquickworkerscript.pro +++ b/tests/auto/qml/qquickworkerscript/qquickworkerscript.pro @@ -8,4 +8,4 @@ include (../../shared/util.pri) TESTDATA = data/* -QT += core-private gui-private qml-private testlib +QT += core-private gui-private qml-private testlib qmlworkerscript-private -- cgit v1.2.3 From 4a4842118d2303a8d851d1d8b85fe182d3fe492a Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Mon, 6 May 2019 16:03:37 +0200 Subject: Accessibility: Make sure StaticText is marked read-only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test more of the text properties. This is still very incomplete, but a small step forward. Also make sure that editable text reports the editable state. Fixes: QTBUG-75002 Change-Id: I9e43c980d8fa91671acb4e40e5d9162854884ee7 Reviewed-by: Jan Arve Sæther --- .../quick/qquickaccessible/data/statictext.qml | 31 -------------- tests/auto/quick/qquickaccessible/data/text.qml | 49 ++++++++++++++++++++++ .../qquickaccessible/tst_qquickaccessible.cpp | 46 ++++++++++++++++++-- 3 files changed, 92 insertions(+), 34 deletions(-) delete mode 100644 tests/auto/quick/qquickaccessible/data/statictext.qml create mode 100644 tests/auto/quick/qquickaccessible/data/text.qml (limited to 'tests') diff --git a/tests/auto/quick/qquickaccessible/data/statictext.qml b/tests/auto/quick/qquickaccessible/data/statictext.qml deleted file mode 100644 index 1092f33daf..0000000000 --- a/tests/auto/quick/qquickaccessible/data/statictext.qml +++ /dev/null @@ -1,31 +0,0 @@ -import QtQuick 2.0 - -Item { - width: 400 - height: 400 - Accessible.name: "root" - Accessible.role: Accessible.Client - - Text { - x: 100 - y: 20 - width: 200 - height: 50 - text : "Hello Accessibility" - - // Setting any value of the attached property - // makes an item accessible. - Accessible.name: text - } - - Text { - x: 100 - y: 40 - width: 100 - height: 40 - text : "Hello 2" - Accessible.role: Accessible.StaticText - Accessible.name: "The Hello 2 accessible text" - Accessible.description: "A text description" - } -} diff --git a/tests/auto/quick/qquickaccessible/data/text.qml b/tests/auto/quick/qquickaccessible/data/text.qml new file mode 100644 index 0000000000..88f292a61f --- /dev/null +++ b/tests/auto/quick/qquickaccessible/data/text.qml @@ -0,0 +1,49 @@ +import QtQuick 2.0 + +Item { + width: 400 + height: 400 + Accessible.name: "root" + Accessible.role: Accessible.Client + + Text { + x: 100 + y: 20 + width: 200 + height: 50 + text : "Hello Accessibility" + + // Setting any value of the attached property + // makes an item accessible. + Accessible.name: text + } + + Text { + x: 100 + y: 40 + width: 100 + height: 40 + text : "Hello 2" + Accessible.role: Accessible.StaticText + Accessible.name: "The Hello 2 accessible text" + Accessible.description: "A text description" + } + + TextInput { + x: 100 + y: 80 + width: 200 + height: 40 + text: "A text input" + Accessible.role: Accessible.EditableText + } + + TextEdit { + x: 100 + y: 120 + width: 200 + height: 100 + text: "A multi-line text edit\nTesting Accessibility." + Accessible.role: Accessible.EditableText + } +} diff --git a/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp b/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp index 1bfeb94161..243d87f212 100644 --- a/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp +++ b/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp @@ -130,7 +130,7 @@ void tst_QQuickAccessible::commonTests_data() { QTest::addColumn("accessibleRoleFileName"); - QTest::newRow("StaticText") << "statictext.qml"; + QTest::newRow("Text") << "text.qml"; QTest::newRow("PushButton") << "pushbutton.qml"; } @@ -302,7 +302,7 @@ void tst_QQuickAccessible::basicPropertiesTest() QCOMPARE(app->childCount(), 0); QQuickView *window = new QQuickView(); - window->setSource(testFileUrl("statictext.qml")); + window->setSource(testFileUrl("text.qml")); window->show(); QCOMPARE(app->childCount(), 1); @@ -312,7 +312,7 @@ void tst_QQuickAccessible::basicPropertiesTest() QAccessibleInterface *item = iface->child(0); QVERIFY(item); - QCOMPARE(item->childCount(), 2); + QCOMPARE(item->childCount(), 4); QCOMPARE(item->rect().size(), QSize(400, 400)); QCOMPARE(item->role(), QAccessible::Client); QCOMPARE(iface->indexOfChild(item), 0); @@ -338,10 +338,50 @@ void tst_QQuickAccessible::basicPropertiesTest() QCOMPARE(text2->rect().y(), item->rect().y() + 40); QCOMPARE(text2->role(), QAccessible::StaticText); QCOMPARE(item->indexOfChild(text2), 1); + QCOMPARE(text2->state().editable, 0); + QCOMPARE(text2->state().readOnly, 1); QCOMPARE(iface->indexOfChild(text2), -1); QCOMPARE(text2->indexOfChild(item), -1); + // TextInput + QAccessibleInterface *textInput = item->child(2); + QVERIFY(textInput); + QCOMPARE(textInput->childCount(), 0); + QCOMPARE(textInput->role(), QAccessible::EditableText); + QCOMPARE(textInput->state().editable, 1); + QCOMPARE(textInput->state().readOnly, 0); + QCOMPARE(textInput->state().multiLine, 0); + QCOMPARE(textInput->state().focusable, 1); + QCOMPARE(textInput->text(QAccessible::Value), "A text input"); + auto textInterface = textInput->textInterface(); + QVERIFY(textInterface); + auto editableTextInterface = textInput->editableTextInterface(); + QEXPECT_FAIL("", "EditableTextInterface is not implemented", Continue); + QVERIFY(editableTextInterface); + auto newText = QString("a new text"); + textInput->setText(QAccessible::Value, newText); + QCOMPARE(textInput->text(QAccessible::Value), newText); + + // TextEdit + QAccessibleInterface *textEdit = item->child(3); + QVERIFY(textEdit); + QCOMPARE(textEdit->childCount(), 0); + QCOMPARE(textEdit->role(), QAccessible::EditableText); + QCOMPARE(textEdit->state().editable, 1); + QCOMPARE(textEdit->state().readOnly, 0); + QCOMPARE(textEdit->state().focusable, 1); + QCOMPARE(textEdit->text(QAccessible::Value), "A multi-line text edit\nTesting Accessibility."); + auto textEditTextInterface = textEdit->textInterface(); + QVERIFY(textEditTextInterface); + auto textEditEditableTextInterface = textEdit->editableTextInterface(); + QEXPECT_FAIL("", "EditableTextInterface is not implemented", Continue); + QVERIFY(textEditEditableTextInterface); + textEdit->setText(QAccessible::Value, newText); + QCOMPARE(textEdit->text(QAccessible::Value), newText); + QEXPECT_FAIL("", "multi line is not implemented", Continue); + QCOMPARE(textInput->state().multiLine, 1); + delete window; QTestAccessibility::clearEvents(); } -- cgit v1.2.3 From 12829b50fc85587c9c08c834efd63ebe8ccbbcd2 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Wed, 8 May 2019 11:05:39 +0200 Subject: Register QObject along with QQmlComponent as basic type of the language Apparently we need it somewhere. Before the restructuring of imports all QtQml types were automatically registered on QQmlEnginePrivate::init(). We don't do this anymore, so we need to register the basic building blocks of the language separately now. Fixes: QTBUG-75645 Change-Id: I77fe23f709304586cd16986650b0056ea87bcd45 Reviewed-by: Liang Qi Reviewed-by: Mitch Curtis Reviewed-by: Simon Hausmann --- tests/auto/qml/qqmllanguage/data/bareQmlImport.errors.txt | 0 tests/auto/qml/qqmllanguage/data/bareQmlImport.qml | 6 ++++++ tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp | 2 ++ 3 files changed, 8 insertions(+) create mode 100644 tests/auto/qml/qqmllanguage/data/bareQmlImport.errors.txt create mode 100644 tests/auto/qml/qqmllanguage/data/bareQmlImport.qml (limited to 'tests') diff --git a/tests/auto/qml/qqmllanguage/data/bareQmlImport.errors.txt b/tests/auto/qml/qqmllanguage/data/bareQmlImport.errors.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/auto/qml/qqmllanguage/data/bareQmlImport.qml b/tests/auto/qml/qqmllanguage/data/bareQmlImport.qml new file mode 100644 index 0000000000..3567cdb5a3 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/bareQmlImport.qml @@ -0,0 +1,6 @@ +import QML 1.0 +QtObject { + property Component component: Component { + QtObject {} + } +} diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index b97c75e2ce..08dab99e0f 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -620,6 +620,8 @@ void tst_qqmllanguage::errors_data() QTest::newRow("fuzzed.1") << "fuzzed.1.qml" << "fuzzed.1.errors.txt" << false; QTest::newRow("fuzzed.2") << "fuzzed.2.qml" << "fuzzed.2.errors.txt" << false; + + QTest::newRow("bareQmlImport") << "bareQmlImport.qml" << "bareQmlImport.errors.txt" << false; } -- cgit v1.2.3 From d12cc4f6b58ecb5f44458002fe9b74d0c84f10ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Arve=20S=C3=A6ther?= Date: Tue, 7 May 2019 14:58:29 +0200 Subject: Don't overwrite states if role is assigned after a state We therefore need to keep track of which states have been explicitly set or not in order to know which ones should get initialized with their defaults. Change-Id: I49fdae82288f04ea4f50d45735a93434ac02abec Reviewed-by: Frederik Gladhorn --- tests/auto/quick/qquickaccessible/data/text.qml | 11 +++++++++ .../qquickaccessible/tst_qquickaccessible.cpp | 26 +++++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/auto/quick/qquickaccessible/data/text.qml b/tests/auto/quick/qquickaccessible/data/text.qml index 88f292a61f..6daeacfd81 100644 --- a/tests/auto/quick/qquickaccessible/data/text.qml +++ b/tests/auto/quick/qquickaccessible/data/text.qml @@ -46,4 +46,15 @@ Item { text: "A multi-line text edit\nTesting Accessibility." Accessible.role: Accessible.EditableText } + + Text { + x: 100 + y: 160 + width: 100 + height: 40 + text : "Hello 3" + Accessible.name: text + Accessible.description: "description" + } + } diff --git a/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp b/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp index 243d87f212..c5fdb6c1b9 100644 --- a/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp +++ b/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp @@ -312,7 +312,7 @@ void tst_QQuickAccessible::basicPropertiesTest() QAccessibleInterface *item = iface->child(0); QVERIFY(item); - QCOMPARE(item->childCount(), 4); + QCOMPARE(item->childCount(), 5); QCOMPARE(item->rect().size(), QSize(400, 400)); QCOMPARE(item->role(), QAccessible::Client); QCOMPARE(iface->indexOfChild(item), 0); @@ -382,6 +382,30 @@ void tst_QQuickAccessible::basicPropertiesTest() QEXPECT_FAIL("", "multi line is not implemented", Continue); QCOMPARE(textInput->state().multiLine, 1); + // Text "Hello 3" + QAccessibleInterface *text3 = item->child(4); + QVERIFY(text3); + QCOMPARE(text3->childCount(), 0); + QCOMPARE(text3->text(QAccessible::Name), QLatin1String("Hello 3")); + QCOMPARE(text3->role(), QAccessible::StaticText); + QCOMPARE(item->indexOfChild(text3), 4); + QCOMPARE(text3->state().editable, 0); + QCOMPARE(text3->state().readOnly, 0); + // test implicit state values due to role change + QQuickAccessibleAttached *attached = QQuickAccessibleAttached::attachedProperties(text3->object()); + attached->setRole(QAccessible::StaticText); + QCOMPARE(text3->role(), QAccessible::StaticText); + QCOMPARE(text3->state().readOnly, 1); + + // see if implicit changes back + attached->setRole(QAccessible::EditableText); + QEXPECT_FAIL("", "EditableText does not implicitly set readOnly to false", Continue); + QCOMPARE(text3->state().readOnly, 0); + // explicitly set state + attached->set_readOnly(false); + attached->setRole(QAccessible::StaticText); + QCOMPARE(text3->state().readOnly, 0); + delete window; QTestAccessibility::clearEvents(); } -- cgit v1.2.3 From dafdc9d701b0b3a33e3eac0a723d80717a02f4f8 Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Mon, 6 May 2019 19:42:49 +0200 Subject: QQuickTableView: sync viewport rect with syncView when rebuilding When moving contentX/Y, we also need to ensure that the viewport rect reflects the change. Otherwise we'll end up loading rows and columns somewhere else then under the viewport. Change-Id: Ifbd3d66b9b3a822414aefde9b5bd088274dfa2ad Reviewed-by: Mitch Curtis --- .../quick/qquicktableview/tst_qquicktableview.cpp | 102 ++++++++++++++++++++- 1 file changed, 99 insertions(+), 3 deletions(-) (limited to 'tests') diff --git a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp index 4267fb1f4c..0f5ad57127 100644 --- a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp +++ b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp @@ -79,9 +79,10 @@ Q_DECLARE_METATYPE(QMarginsF); QCOMPARE(loader->status(), QQuickLoader::Status::Ready); \ GET_QML_TABLEVIEW(tableView) -#define WAIT_UNTIL_POLISHED \ - QVERIFY(QQuickTest::qIsPolishScheduled(tableView)); \ - QVERIFY(QQuickTest::qWaitForItemPolished(tableView)) +#define WAIT_UNTIL_POLISHED_ARG(item) \ + QVERIFY(QQuickTest::qIsPolishScheduled(item)); \ + QVERIFY(QQuickTest::qWaitForItemPolished(item)) +#define WAIT_UNTIL_POLISHED WAIT_UNTIL_POLISHED_ARG(tableView) class tst_QQuickTableView : public QQmlDataTest { @@ -167,6 +168,8 @@ private slots: void checkSyncView_childViews_data(); void checkSyncView_childViews(); void checkSyncView_differentSizedModels(); + void checkSyncView_connect_late_data(); + void checkSyncView_connect_late(); }; tst_QQuickTableView::tst_QQuickTableView() @@ -2391,6 +2394,99 @@ void tst_QQuickTableView::checkSyncView_differentSizedModels() QVERIFY(tableViewHVPrivate->loadedColumns.isEmpty()); } +void tst_QQuickTableView::checkSyncView_connect_late_data() +{ + QTest::addColumn("flickToPos"); + + QTest::newRow("pos:110") << 110.; + QTest::newRow("pos:2010") << 2010.; +} + +void tst_QQuickTableView::checkSyncView_connect_late() +{ + // Check that if you assign a syncView to a TableView late, and + // after the views have been flicked around, they will still end up in sync. + QFETCH(qreal, flickToPos); + LOAD_TABLEVIEW("syncviewsimple.qml"); + GET_QML_TABLEVIEW(tableViewH); + GET_QML_TABLEVIEW(tableViewV); + GET_QML_TABLEVIEW(tableViewHV); + QQuickTableView *views[] = {tableViewH, tableViewV, tableViewHV}; + + auto model = TestModelAsVariant(100, 100); + + tableView->setModel(model); + + // Start with no syncView connections + for (auto view : views) { + view->setSyncView(nullptr); + view->setModel(model); + } + + WAIT_UNTIL_POLISHED; + + tableView->setContentX(flickToPos); + tableView->setContentY(flickToPos); + + WAIT_UNTIL_POLISHED; + + // Check that viewport is not in sync after the flick + QCOMPARE(tableView->contentX(), flickToPos); + QCOMPARE(tableView->contentY(), flickToPos); + QCOMPARE(tableViewH->contentX(), 0); + QCOMPARE(tableViewH->contentY(), 0); + QCOMPARE(tableViewV->contentX(), 0); + QCOMPARE(tableViewV->contentY(), 0); + QCOMPARE(tableViewHV->contentX(), 0); + QCOMPARE(tableViewHV->contentY(), 0); + + // Assign the syncView late. This should make + // all the views end up in sync. + for (auto view : views) { + view->setSyncView(tableView); + WAIT_UNTIL_POLISHED_ARG(view); + } + + // Check that geometry properties are mirrored + QCOMPARE(tableViewH->columnSpacing(), tableView->columnSpacing()); + QCOMPARE(tableViewH->rowSpacing(), 0); + QCOMPARE(tableViewH->contentWidth(), tableView->contentWidth()); + QCOMPARE(tableViewV->columnSpacing(), 0); + QCOMPARE(tableViewV->rowSpacing(), tableView->rowSpacing()); + QCOMPARE(tableViewV->contentHeight(), tableView->contentHeight()); + + // Check that viewport is in sync after the flick + QCOMPARE(tableView->contentX(), flickToPos); + QCOMPARE(tableView->contentY(), flickToPos); + QCOMPARE(tableViewH->contentX(), tableView->contentX()); + QCOMPARE(tableViewH->contentY(), 0); + QCOMPARE(tableViewV->contentX(), 0); + QCOMPARE(tableViewV->contentY(), tableView->contentY()); + QCOMPARE(tableViewHV->contentX(), tableView->contentX()); + QCOMPARE(tableViewHV->contentY(), tableView->contentY()); + + // Check that topLeft cell is in sync after the flick + QCOMPARE(tableViewHPrivate->leftColumn(), tableViewPrivate->leftColumn()); + QCOMPARE(tableViewHPrivate->rightColumn(), tableViewPrivate->rightColumn()); + QCOMPARE(tableViewHPrivate->topRow(), 0); + QCOMPARE(tableViewVPrivate->leftColumn(), 0); + QCOMPARE(tableViewVPrivate->topRow(), tableViewPrivate->topRow()); + QCOMPARE(tableViewHVPrivate->leftColumn(), tableViewPrivate->leftColumn()); + QCOMPARE(tableViewHVPrivate->topRow(), tableViewPrivate->topRow()); + + // Check that the geometry of the tables are in sync after the flick + QCOMPARE(tableViewHPrivate->loadedTableOuterRect.left(), tableViewPrivate->loadedTableOuterRect.left()); + QCOMPARE(tableViewHPrivate->loadedTableOuterRect.right(), tableViewPrivate->loadedTableOuterRect.right()); + QCOMPARE(tableViewHPrivate->loadedTableOuterRect.top(), 0); + + QCOMPARE(tableViewVPrivate->loadedTableOuterRect.top(), tableViewPrivate->loadedTableOuterRect.top()); + QCOMPARE(tableViewVPrivate->loadedTableOuterRect.bottom(), tableViewPrivate->loadedTableOuterRect.bottom()); + QCOMPARE(tableViewVPrivate->loadedTableOuterRect.left(), 0); + + QCOMPARE(tableViewHVPrivate->loadedTableOuterRect, tableViewPrivate->loadedTableOuterRect); + +} + QTEST_MAIN(tst_QQuickTableView) #include "tst_qquicktableview.moc" -- cgit v1.2.3 From 3fff03048a48aa7ead6e888165b2ae5a118d675c Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Thu, 2 May 2019 10:26:48 +0200 Subject: QQuickTableView: change implementation of enforceTableAtOrigin() We set the size of the content view to be the size of the complete table. The problem is that the exact size will always be just a prediction, since we would otherwise need to iterate over all rows and column up front, to be able calculate the exact size. This is not acceptable when using non-trival table models. A side effect of this, is that is will be possible to flick the viewport further out than the actual end of the table, if the content view turns out to be larger than the table itself. From before we used to just move the whole table back into the viewport when that happened, which could be seen as a sudden jump of the table to a new position. This change will improve this logic so that we can avoid most visual jumps. Instead of moving the table around, QQuickFlickable supports moving the origin instead. So when we see that the table is not in sync with the content view, we simple move the origin to the edge of the table. The effect is that any flicking or ongoing momentum animation in QQuickFlickable will continue as if nothing happened. This is also the same logic used by QQuickListView. Change-Id: I6060b7e84b9489c8fa569e6ff41b958e3871f8e7 Reviewed-by: Mitch Curtis --- .../quick/qquicktableview/tst_qquicktableview.cpp | 161 +++++++++++++++++++++ 1 file changed, 161 insertions(+) (limited to 'tests') diff --git a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp index 0f5ad57127..d03f08ec6a 100644 --- a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp +++ b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp @@ -123,6 +123,9 @@ private slots: void checkContentWidthAndHeight(); void checkPageFlicking(); void checkExplicitContentWidthAndHeight(); + void checkExtents_origin(); + void checkExtents_endExtent(); + void checkExtents_moveTableToEdge(); void checkContentXY(); void noDelegate(); void changeDelegateDuringUpdate(); @@ -760,6 +763,164 @@ void tst_QQuickTableView::checkExplicitContentWidthAndHeight() QCOMPARE(tableView->contentHeight(), 1000); } +void tst_QQuickTableView::checkExtents_origin() +{ + // Check that if the beginning of the content view doesn't match the + // actual size of the table, origin will be adjusted to make it fit. + LOAD_TABLEVIEW("contentwidthheight.qml"); + + const int rows = 10; + const int columns = rows; + const qreal columnWidth = 100; + const qreal rowHeight = 100; + const qreal actualTableSize = columns * columnWidth; + + // Set a content size that is far too large + // compared to the size of the table. + tableView->setContentWidth(actualTableSize * 2); + tableView->setContentHeight(actualTableSize * 2); + tableView->setRowSpacing(0); + tableView->setColumnSpacing(0); + tableView->setLeftMargin(0); + tableView->setRightMargin(0); + tableView->setTopMargin(0); + tableView->setBottomMargin(0); + + auto model = TestModelAsVariant(rows, columns); + tableView->setModel(model); + + WAIT_UNTIL_POLISHED; + + // Flick slowly to column 5 (to avoid rebuilds). Flick two columns at a + // time to ensure that we create a gap before TableView gets a chance to + // adjust endExtent first. This gap on the right side will make TableView + // move the table to move to the edge. Because of this, the table will not + // be aligned at the start of the content view when we next flick back again. + // And this will cause origin to move. + for (int x = 0; x <= 6; x += 2) { + tableView->setContentX(x * columnWidth); + tableView->setContentY(x * rowHeight); + } + + // Check that the table has now been moved one column to the right + // (One column because that's how far outside the table we ended up flicking above). + QCOMPARE(tableViewPrivate->loadedTableOuterRect.right(), actualTableSize + columnWidth); + + // Flick back one column at a time so that TableView detects that the first + // column is not at the origin before the "table move" logic kicks in. This + // will make TableView adjust the origin. + for (int x = 6; x >= 0; x -= 1) { + tableView->setContentX(x * columnWidth); + tableView->setContentY(x * rowHeight); + } + + // The origin will be moved with the same offset that the table was + // moved on the right side earlier, which is one column length. + QCOMPARE(tableViewPrivate->origin.x(), columnWidth); + QCOMPARE(tableViewPrivate->origin.y(), rowHeight); +} + +void tst_QQuickTableView::checkExtents_endExtent() +{ + // Check that if we the content view size doesn't match the actual size + // of the table, endExtent will be adjusted to make it fit (so that + // e.g the the flicking will bounce to a stop at the edge of the table). + LOAD_TABLEVIEW("contentwidthheight.qml"); + + const int rows = 10; + const int columns = rows; + const qreal columnWidth = 100; + const qreal rowHeight = 100; + const qreal actualTableSize = columns * columnWidth; + + // Set a content size that is far too large + // compared to the size of the table. + tableView->setContentWidth(actualTableSize * 2); + tableView->setContentHeight(actualTableSize * 2); + tableView->setRowSpacing(0); + tableView->setColumnSpacing(0); + tableView->setLeftMargin(0); + tableView->setRightMargin(0); + tableView->setTopMargin(0); + tableView->setBottomMargin(0); + + auto model = TestModelAsVariant(rows, columns); + tableView->setModel(model); + + WAIT_UNTIL_POLISHED; + + // Flick slowly to column 5 (to avoid rebuilds). This will flick the table to + // the last column in the model. But since there still is a lot space left in + // the content view, endExtent will be set accordingly to compensate. + for (int x = 1; x <= 5; x++) + tableView->setContentX(x * columnWidth); + QCOMPARE(tableViewPrivate->rightColumn(), columns - 1); + qreal expectedEndExtentWidth = actualTableSize - tableView->contentWidth(); + QCOMPARE(tableViewPrivate->endExtent.width(), expectedEndExtentWidth); + + for (int y = 1; y <= 5; y++) + tableView->setContentY(y * rowHeight); + QCOMPARE(tableViewPrivate->bottomRow(), rows - 1); + qreal expectedEndExtentHeight = actualTableSize - tableView->contentHeight(); + QCOMPARE(tableViewPrivate->endExtent.height(), expectedEndExtentHeight); +} + +void tst_QQuickTableView::checkExtents_moveTableToEdge() +{ + // Check that if we the content view size doesn't match the actual + // size of the table, and we fast-flick the viewport to outside + // the table, we end up moving the table back into the viewport to + // avoid any visual glitches. + LOAD_TABLEVIEW("contentwidthheight.qml"); + + const int rows = 10; + const int columns = rows; + const qreal columnWidth = 100; + const qreal rowHeight = 100; + const qreal actualTableSize = columns * columnWidth; + + // Set a content size that is far to large + // compared to the size of the table. + tableView->setContentWidth(actualTableSize * 2); + tableView->setContentHeight(actualTableSize * 2); + tableView->setRowSpacing(0); + tableView->setColumnSpacing(0); + tableView->setLeftMargin(0); + tableView->setRightMargin(0); + tableView->setTopMargin(0); + tableView->setBottomMargin(0); + + auto model = TestModelAsVariant(rows, columns); + tableView->setModel(model); + + WAIT_UNTIL_POLISHED; + + // Flick slowly to column 5 (to avoid rebuilds). Flick two columns at a + // time to ensure that we create a gap before TableView gets a chance to + // adjust endExtent first. This gap on the right side will make TableView + // move the table to the edge (in addition to adjusting the extents, but that + // will happen in a subsequent polish, and is not for this test verify). + for (int x = 0; x <= 6; x += 2) + tableView->setContentX(x * columnWidth); + QCOMPARE(tableViewPrivate->rightColumn(), columns - 1); + QCOMPARE(tableViewPrivate->loadedTableOuterRect, tableViewPrivate->viewportRect); + + for (int y = 0; y <= 6; y += 2) + tableView->setContentY(y * rowHeight); + QCOMPARE(tableViewPrivate->bottomRow(), rows - 1); + QCOMPARE(tableViewPrivate->loadedTableOuterRect, tableViewPrivate->viewportRect); + + for (int x = 6; x >= 0; x -= 2) + tableView->setContentX(x * columnWidth); + QCOMPARE(tableViewPrivate->leftColumn(), 0); + QCOMPARE(tableViewPrivate->loadedTableOuterRect, tableViewPrivate->viewportRect); + + for (int y = 6; y >= 0; y -= 2) + tableView->setContentY(y * rowHeight); + QCOMPARE(tableViewPrivate->topRow(), 0); + QCOMPARE(tableViewPrivate->loadedTableOuterRect, tableViewPrivate->viewportRect); +} + void tst_QQuickTableView::checkContentXY() { // Check that you can bind contentX and contentY to -- cgit v1.2.3 From 7f7d87c68da4cb29b2b2b9c324c6863228da0c26 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Tue, 7 May 2019 12:47:33 +0200 Subject: Split CompiledData::CompilationUnit in two We need a CompilationUnit that only holds the data needed for compilation and another one that is executable by the runtime. Change-Id: I704d859ba028576a18460f5e3a59f210f64535d3 Reviewed-by: Simon Hausmann --- .../qml/ecmascripttests/qjstest/test262runner.cpp | 2 +- tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp | 30 ++++++++++++++-------- tests/auto/qml/qqmllanguage/testtypes.cpp | 6 ++--- tests/auto/qml/qqmllanguage/testtypes.h | 18 ++++++------- tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp | 6 ++--- .../qml/qqmltranslation/tst_qqmltranslation.cpp | 6 +++-- 6 files changed, 40 insertions(+), 28 deletions(-) (limited to 'tests') diff --git a/tests/auto/qml/ecmascripttests/qjstest/test262runner.cpp b/tests/auto/qml/ecmascripttests/qjstest/test262runner.cpp index cbe3be2e70..33efcb4da4 100644 --- a/tests/auto/qml/ecmascripttests/qjstest/test262runner.cpp +++ b/tests/auto/qml/ecmascripttests/qjstest/test262runner.cpp @@ -509,7 +509,7 @@ static bool executeTest(const QByteArray &data, bool runAsModule = false, const QVector modulesToLoad = { rootModuleUrl }; while (!modulesToLoad.isEmpty()) { QUrl url = modulesToLoad.takeFirst(); - QQmlRefPointer module; + QQmlRefPointer module; QFile f(url.toLocalFile()); if (f.open(QIODevice::ReadOnly)) { diff --git a/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp index e86b7bf5fe..2987e420fe 100644 --- a/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp +++ b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -118,7 +119,8 @@ struct TestCompiler { closeMapping(); testFilePath = baseDirectory + QStringLiteral("/test.qml"); - cacheFilePath = QV4::CompiledData::CompilationUnit::localCacheFilePath(QUrl::fromLocalFile(testFilePath)); + cacheFilePath = QV4::ExecutableCompilationUnit::localCacheFilePath( + QUrl::fromLocalFile(testFilePath)); mappedFile.setFileName(cacheFilePath); } @@ -185,8 +187,10 @@ struct TestCompiler bool verify() { - QQmlRefPointer unit = QV4::Compiler::Codegen::createUnitForLoading(); - return unit->loadFromDisk(QUrl::fromLocalFile(testFilePath), QFileInfo(testFilePath).lastModified(), &lastErrorString); + QQmlRefPointer unit + = QV4::ExecutableCompilationUnit::create(); + return unit->loadFromDisk(QUrl::fromLocalFile(testFilePath), + QFileInfo(testFilePath).lastModified(), &lastErrorString); } void closeMapping() @@ -263,8 +267,9 @@ void tst_qmldiskcache::loadLocalAsFallback() f.write(reinterpret_cast(&unit), sizeof(unit)); } - QQmlRefPointer unit = QV4::Compiler::Codegen::createUnitForLoading(); - bool loaded = unit->loadFromDisk(QUrl::fromLocalFile(testCompiler.testFilePath), QFileInfo(testCompiler.testFilePath).lastModified(), + QQmlRefPointer unit = QV4::ExecutableCompilationUnit::create(); + bool loaded = unit->loadFromDisk(QUrl::fromLocalFile(testCompiler.testFilePath), + QFileInfo(testCompiler.testFilePath).lastModified(), &testCompiler.lastErrorString); QVERIFY2(loaded, qPrintable(testCompiler.lastErrorString)); QCOMPARE(unit->objectCount(), 1); @@ -572,7 +577,8 @@ void tst_qmldiskcache::fileSelectors() QVERIFY(!obj.isNull()); QCOMPARE(obj->property("value").toInt(), 42); - QFile cacheFile(QV4::CompiledData::CompilationUnit::localCacheFilePath(QUrl::fromLocalFile(testFilePath))); + QFile cacheFile(QV4::ExecutableCompilationUnit::localCacheFilePath( + QUrl::fromLocalFile(testFilePath))); QVERIFY2(cacheFile.exists(), qPrintable(cacheFile.fileName())); } @@ -587,7 +593,8 @@ void tst_qmldiskcache::fileSelectors() QVERIFY(!obj.isNull()); QCOMPARE(obj->property("value").toInt(), 100); - QFile cacheFile(QV4::CompiledData::CompilationUnit::localCacheFilePath(QUrl::fromLocalFile(selectedTestFilePath))); + QFile cacheFile(QV4::ExecutableCompilationUnit::localCacheFilePath( + QUrl::fromLocalFile(selectedTestFilePath))); QVERIFY2(cacheFile.exists(), qPrintable(cacheFile.fileName())); } } @@ -737,7 +744,8 @@ void tst_qmldiskcache::stableOrderOfDependentCompositeTypes() QVERIFY2(firstDependentTypeClassName.contains("QMLTYPE"), firstDependentTypeClassName.constData()); QVERIFY2(secondDependentTypeClassName.contains("QMLTYPE"), secondDependentTypeClassName.constData()); - const QString testFileCachePath = QV4::CompiledData::CompilationUnit::localCacheFilePath(QUrl::fromLocalFile(testFilePath)); + const QString testFileCachePath = QV4::ExecutableCompilationUnit::localCacheFilePath( + QUrl::fromLocalFile(testFilePath)); QVERIFY(QFile::exists(testFileCachePath)); QDateTime initialCacheTimeStamp = QFileInfo(testFileCachePath).lastModified(); @@ -815,7 +823,8 @@ void tst_qmldiskcache::singletonDependency() QCOMPARE(obj->property("value").toInt(), 42); } - const QString testFileCachePath = QV4::CompiledData::CompilationUnit::localCacheFilePath(QUrl::fromLocalFile(testFilePath)); + const QString testFileCachePath = QV4::ExecutableCompilationUnit::localCacheFilePath( + QUrl::fromLocalFile(testFilePath)); QVERIFY(QFile::exists(testFileCachePath)); QDateTime initialCacheTimeStamp = QFileInfo(testFileCachePath).lastModified(); @@ -872,7 +881,8 @@ void tst_qmldiskcache::cppRegisteredSingletonDependency() QCOMPARE(value.toInt(), 42); } - const QString testFileCachePath = QV4::CompiledData::CompilationUnit::localCacheFilePath(QUrl::fromLocalFile(testFilePath)); + const QString testFileCachePath = QV4::ExecutableCompilationUnit::localCacheFilePath( + QUrl::fromLocalFile(testFilePath)); QVERIFY(QFile::exists(testFileCachePath)); QDateTime initialCacheTimeStamp = QFileInfo(testFileCachePath).lastModified(); diff --git a/tests/auto/qml/qqmllanguage/testtypes.cpp b/tests/auto/qml/qqmllanguage/testtypes.cpp index f9a6ee8e5a..d6215307bf 100644 --- a/tests/auto/qml/qqmllanguage/testtypes.cpp +++ b/tests/auto/qml/qqmllanguage/testtypes.cpp @@ -125,7 +125,7 @@ QVariant myCustomVariantTypeConverter(const QString &data) } -void CustomBindingParser::applyBindings(QObject *object, const QQmlRefPointer &compilationUnit, const QList &bindings) +void CustomBindingParser::applyBindings(QObject *object, const QQmlRefPointer &compilationUnit, const QList &bindings) { CustomBinding *customBinding = qobject_cast(object); Q_ASSERT(customBinding); @@ -154,7 +154,7 @@ void CustomBinding::componentComplete() } } -void EnumSupportingCustomParser::verifyBindings(const QQmlRefPointer &compilationUnit, const QList &bindings) +void EnumSupportingCustomParser::verifyBindings(const QQmlRefPointer &compilationUnit, const QList &bindings) { if (bindings.count() != 1) { error(bindings.first(), QStringLiteral("Custom parser invoked incorrectly for unit test")); @@ -184,7 +184,7 @@ void EnumSupportingCustomParser::verifyBindings(const QQmlRefPointer &, const QList &bindings) +void SimpleObjectCustomParser::applyBindings(QObject *object, const QQmlRefPointer &, const QList &bindings) { SimpleObjectWithCustomParser *o = qobject_cast(object); Q_ASSERT(o); diff --git a/tests/auto/qml/qqmllanguage/testtypes.h b/tests/auto/qml/qqmllanguage/testtypes.h index bb6e9582c2..0618d2b20f 100644 --- a/tests/auto/qml/qqmllanguage/testtypes.h +++ b/tests/auto/qml/qqmllanguage/testtypes.h @@ -781,15 +781,15 @@ class MyCustomParserType : public QObject class MyCustomParserTypeParser : public QQmlCustomParser { public: - virtual void verifyBindings(const QQmlRefPointer &, const QList &) {} - virtual void applyBindings(QObject *, const QQmlRefPointer &, const QList &) {} + virtual void verifyBindings(const QQmlRefPointer &, const QList &) {} + virtual void applyBindings(QObject *, const QQmlRefPointer &, const QList &) {} }; class EnumSupportingCustomParser : public QQmlCustomParser { public: - virtual void verifyBindings(const QQmlRefPointer &, const QList &); - virtual void applyBindings(QObject *, const QQmlRefPointer &, const QList &) {} + virtual void verifyBindings(const QQmlRefPointer &, const QList &); + virtual void applyBindings(QObject *, const QQmlRefPointer &, const QList &) {} }; class MyParserStatus : public QObject, public QQmlParserStatus @@ -1275,15 +1275,15 @@ public: void setTarget(QObject *newTarget) { m_target = newTarget; } QPointer m_target; - QQmlRefPointer compilationUnit; + QQmlRefPointer compilationUnit; QList bindings; QByteArray m_bindingData; }; class CustomBindingParser : public QQmlCustomParser { - virtual void verifyBindings(const QQmlRefPointer &, const QList &) {} - virtual void applyBindings(QObject *, const QQmlRefPointer &, const QList &); + virtual void verifyBindings(const QQmlRefPointer &, const QList &) {} + virtual void applyBindings(QObject *, const QQmlRefPointer &, const QList &); }; class SimpleObjectWithCustomParser : public QObject @@ -1328,8 +1328,8 @@ private: class SimpleObjectCustomParser : public QQmlCustomParser { - virtual void verifyBindings(const QQmlRefPointer &, const QList &) {} - virtual void applyBindings(QObject *, const QQmlRefPointer &, const QList &); + virtual void verifyBindings(const QQmlRefPointer &, const QList &) {} + virtual void applyBindings(QObject *, const QQmlRefPointer &, const QList &); }; class RootObjectInCreationTester : public QObject diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index 08dab99e0f..8cbb39974e 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -2225,7 +2225,7 @@ void tst_qqmllanguage::scriptStringWithoutSourceCode() QV4::CompiledData::Unit *qmlUnit = reinterpret_cast(malloc(readOnlyQmlUnit->unitSize)); memcpy(qmlUnit, readOnlyQmlUnit, readOnlyQmlUnit->unitSize); qmlUnit->flags &= ~QV4::CompiledData::Unit::StaticData; - QQmlRefPointer compilationUnit = td->compilationUnit(); + QQmlRefPointer compilationUnit = td->compilationUnit(); compilationUnit->setUnitData(qmlUnit); const QV4::CompiledData::Object *rootObject = compilationUnit->objectAt(/*root object*/0); @@ -2235,9 +2235,9 @@ void tst_qqmllanguage::scriptStringWithoutSourceCode() const QV4::CompiledData::Binding *binding = rootObject->bindingTable() + i; if (compilationUnit->stringAt(binding->propertyNameIndex) != QString("scriptProperty")) continue; - QCOMPARE(binding->valueAsScriptString(compilationUnit.data()), QString("intProperty")); + QCOMPARE(compilationUnit->bindingValueAsScriptString(binding), QString("intProperty")); const_cast(binding)->stringIndex = 0; // empty string index - QVERIFY(binding->valueAsScriptString(compilationUnit.data()).isEmpty()); + QVERIFY(compilationUnit->bindingValueAsScriptString(binding).isEmpty()); break; } QVERIFY(i < rootObject->nBindings); diff --git a/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp b/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp index 809a9bd9db..3b17df9872 100644 --- a/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp +++ b/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp @@ -85,7 +85,8 @@ void tst_qqmltranslation::translation() << QStringLiteral("disambiguation") << QStringLiteral("singular") << QStringLiteral("plural"); - const QV4::CompiledData::Object *rootObject = compilationUnit->objectAt(/*root object*/0); + const QV4::CompiledData::Object *rootObject + = compilationUnit->qmlData->objectAt(/*root object*/0); const QV4::CompiledData::Binding *binding = rootObject->bindingTable(); for (quint32 i = 0; i < rootObject->nBindings; ++i, ++binding) { const QString propertyName = compilationUnit->stringAt(binding->propertyNameIndex); @@ -139,7 +140,8 @@ void tst_qqmltranslation::idTranslation() QV4::CompiledData::CompilationUnit *compilationUnit = typeData->compilationUnit(); QVERIFY(compilationUnit); - const QV4::CompiledData::Object *rootObject = compilationUnit->objectAt(/*root object*/0); + const QV4::CompiledData::Object *rootObject + = compilationUnit->qmlData->objectAt(/*root object*/0); const QV4::CompiledData::Binding *binding = rootObject->bindingTable(); for (quint32 i = 0; i < rootObject->nBindings; ++i, ++binding) { const QString propertyName = compilationUnit->stringAt(binding->propertyNameIndex); -- cgit v1.2.3 From f228af06c2c712302ee1dcdaf761cd24504b473e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Arve=20S=C3=A6ther?= Date: Wed, 8 May 2019 16:56:55 +0200 Subject: Add snapMode to DragHandler This changes snap behavior slightly. Basically, it does not snap anymore if the target() item is an ancestor of the parentItem(). In addition, we add a property that enables users to change the behavior. (SnapIfPressedOutsideTarget has the old behavior) [ChangeLog][QtQuick][Event Handlers] Added DragHandler.snapMode which can be used to configure under which conditions the dragged item is snapped to be below the cursor. The default mode is SnapAuto. The old behavior can be obtained through the SnapIfPressedOutsideTarget mode. Fixes: QTBUG-75661 Change-Id: Ibc00e8fbe31b779f8e817af1505e76425467d27a Reviewed-by: Shawn Rutledge --- .../qquickdraghandler/data/snapMode.qml | 86 ++++++++++++++++++++++ .../qquickdraghandler/qquickdraghandler.pro | 1 + .../qquickdraghandler/tst_qquickdraghandler.cpp | 74 +++++++++++++++++++ 3 files changed, 161 insertions(+) create mode 100644 tests/auto/quick/pointerhandlers/qquickdraghandler/data/snapMode.qml (limited to 'tests') diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/data/snapMode.qml b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/snapMode.qml new file mode 100644 index 0000000000..d6eb791700 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/snapMode.qml @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.12 + +Item { + id: root + objectName: "snapMode" + width: 640 + height: 480 + + Rectangle { + id: rect1 + objectName: "rect1" + width: 90 + height: 100 + x: 100 + y: 100 + color: "teal" + + Rectangle { + width: parent.width/2 + height: parent.width/2 + x: width/2 + y: -x + color: dragHandler1.active ? "red" : "salmon" + + DragHandler { + id: dragHandler1 + objectName: "dragHandler1" + target: rect1 + } + } + } + + + Rectangle { + id: rect2 + objectName: "rect2" + width: 90 + height: 100 + x: 200 + y: 100 + color: "teal" + + DragHandler { + id: dragHandler2 + objectName: "dragHandler2" + target: rect2b + } + + Rectangle { + id: rect2b + width: parent.width/2 + height: parent.width/2 + anchors.horizontalCenter: parent.horizontalCenter + y: -width/2 + color: dragHandler2.active ? "red" : "salmon" + } + } +} diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/qquickdraghandler.pro b/tests/auto/quick/pointerhandlers/qquickdraghandler/qquickdraghandler.pro index 42c4e46c4f..6258fb9392 100644 --- a/tests/auto/quick/pointerhandlers/qquickdraghandler/qquickdraghandler.pro +++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/qquickdraghandler.pro @@ -19,3 +19,4 @@ OTHER_FILES += data/DragAnywhereSlider.qml \ data/grabberstate.qml \ data/multipleSliders.qml \ data/reparenting.qml \ + data/snapMode.qml \ diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp b/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp index cc8c567e5c..7636bb38f1 100644 --- a/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp +++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp @@ -56,6 +56,8 @@ private slots: void touchDrag(); void mouseDrag(); void dragFromMargin(); + void snapMode_data(); + void snapMode(); void touchDragMulti(); void touchDragMultiSliders_data(); void touchDragMultiSliders(); @@ -284,6 +286,78 @@ void tst_DragHandler::dragFromMargin() // QTBUG-74966 QCOMPARE(dragHandler->centroid().pressedButtons(), Qt::NoButton); } +void tst_DragHandler::snapMode_data() +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QTest::addColumn("subTree"); + QTest::addColumn("snapMode"); + QTest::addColumn("startDragPos"); + QTest::addColumn("dragMovement"); + QTest::addColumn("expectedMovement"); + + struct TestEntry { + const char *desc; + const char *subTree; + QQuickDragHandler::SnapMode mode; + QPoint startDragPos; + QPoint dragMovement; + QPoint expectedMovement; + }; + + TestEntry testdata[] = { + {"outside the target", "rect1", QQuickDragHandler::SnapAuto, QPoint(45, -10), QPoint(dragThreshold*2, 0), QPoint(dragThreshold*2, 0)}, + {"inside the target", "rect1", QQuickDragHandler::SnapAuto, QPoint(45, 10), QPoint(dragThreshold*2, 0), QPoint(dragThreshold*2, 0)}, + {"outside the target", "rect1", QQuickDragHandler::SnapAlways, QPoint(45, -10), QPoint(dragThreshold*2, 0), QPoint(dragThreshold*2, -50-10)}, + {"outside the target", "rect1", QQuickDragHandler::NoSnap, QPoint(45, -10), QPoint(dragThreshold*2, 0), QPoint(dragThreshold*2, 0)}, + {"outside the target", "rect1", QQuickDragHandler::SnapIfPressedOutsideTarget, QPoint(45, -10), QPoint(dragThreshold*2, 0), QPoint(dragThreshold*2, -50-10)}, + {"inside the target", "rect1", QQuickDragHandler::SnapIfPressedOutsideTarget, QPoint(45, 10), QPoint(dragThreshold*2, 0), QPoint(dragThreshold*2, 0)}, + //targets y pos moves from -25 to (25 + dragThreshold*2) because of snapping to center: + {"outside target, should snap", "rect2", QQuickDragHandler::SnapAuto, QPoint(45, 50), QPoint(0, dragThreshold*2), QPoint(0, 25 + 25 + dragThreshold*2)}, + {"inside target, shouldn't snap", "rect2", QQuickDragHandler::SnapAuto, QPoint(45, 10), QPoint(0, dragThreshold*2), QPoint(0, dragThreshold*2)} + }; + + for (const TestEntry& e : testdata) { + const QMetaEnum menum = QMetaEnum::fromType(); + const QString dataTag = QString::fromLatin1("%1, %2, %3").arg(e.subTree).arg(menum.valueToKey(e.mode)).arg(e.desc); + QTest::newRow(dataTag.toUtf8().constData()) << e.subTree << (int)e.mode + << e.startDragPos << e.dragMovement << e.expectedMovement; + } +} + +void tst_DragHandler::snapMode() +{ + QFETCH(QString, subTree); + QFETCH(QPoint, startDragPos); + QFETCH(QPoint, dragMovement); + QFETCH(int, snapMode); + QFETCH(QPoint, expectedMovement); + + QScopedPointer windowPtr; + createView(windowPtr, "snapMode.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *rect1 = window->rootObject()->findChild(subTree); + QVERIFY(rect1); + QQuickItem *rect1b = rect1->childItems().first(); + QVERIFY(rect1b); + QQuickDragHandler *dragHandler1 = rect1->findChild(); + QVERIFY(dragHandler1); + dragHandler1->setSnapMode((QQuickDragHandler::SnapMode)snapMode); + QQuickItem *dragTarget = dragHandler1->target(); + QPointF oldTargetPos = dragTarget->position(); + + QPoint p1 = rect1->mapToScene(QPointF(startDragPos)).toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QVERIFY(!dragHandler1->active()); + p1 += dragMovement; + QTest::mouseMove(window, p1); + QTRY_VERIFY(dragHandler1->active()); + QCOMPARE(dragTarget->position(), oldTargetPos + expectedMovement); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(!dragHandler1->active()); + QCOMPARE(dragHandler1->centroid().pressedButtons(), Qt::NoButton); +} + void tst_DragHandler::touchDragMulti() { const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); -- cgit v1.2.3 From f38e071f5b353cbf9ce6c6c104bd82099ae0aa14 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Mon, 29 Apr 2019 10:42:00 +0200 Subject: Restore value bindings when disabling a Binding element We previously only restored script bindings that were replaced by a Binding. Now we handle both. [ChangeLog] QML Binding elements now support restoring previous values of the bound property when the binding is disabled. This will be the default behavior in Qt 5.15. Reliance on the old behavior of only restoring binding, not literal values results in a warning now. Fixes: QTBUG-33444 Change-Id: I833403b0645c08eee486fbd4acf5d3c7de2ef73a Reviewed-by: Michael Brasser --- .../auto/qml/qqmlbinding/data/restoreBinding2.qml | 55 ++++++++++++++++ .../auto/qml/qqmlbinding/data/restoreBinding3.qml | 56 ++++++++++++++++ .../auto/qml/qqmlbinding/data/restoreBinding4.qml | 59 +++++++++++++++++ tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp | 75 ++++++++++++++++++++++ 4 files changed, 245 insertions(+) create mode 100644 tests/auto/qml/qqmlbinding/data/restoreBinding2.qml create mode 100644 tests/auto/qml/qqmlbinding/data/restoreBinding3.qml create mode 100644 tests/auto/qml/qqmlbinding/data/restoreBinding4.qml (limited to 'tests') diff --git a/tests/auto/qml/qqmlbinding/data/restoreBinding2.qml b/tests/auto/qml/qqmlbinding/data/restoreBinding2.qml new file mode 100644 index 0000000000..b42f975fe0 --- /dev/null +++ b/tests/auto/qml/qqmlbinding/data/restoreBinding2.qml @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQml 2.14 + +Rectangle { + height: 400 + width: 400 + + Rectangle { + property bool when: true + + id: myItem + objectName: "myItem" + height: 300 + width: 200 + } + + property var boundValue: 100 + + Binding { + restoreMode: Binding.RestoreValue + objectName: "theBinding" + target: myItem + property: "height" + when: myItem.when + value: boundValue + } +} diff --git a/tests/auto/qml/qqmlbinding/data/restoreBinding3.qml b/tests/auto/qml/qqmlbinding/data/restoreBinding3.qml new file mode 100644 index 0000000000..1f63457ab6 --- /dev/null +++ b/tests/auto/qml/qqmlbinding/data/restoreBinding3.qml @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQml 2.14 + +Rectangle { + height: 400 + width: 400 + + Rectangle { + property bool when: true + + id: myItem + objectName: "myItem" + height: 300 + width: 200 + property var foo: 42 + } + + property var boundValue: 13 + + Binding { + restoreMode: Binding.RestoreBindingOrValue + objectName: "theBinding" + target: myItem + property: "foo" + when: myItem.when + value: boundValue + } +} diff --git a/tests/auto/qml/qqmlbinding/data/restoreBinding4.qml b/tests/auto/qml/qqmlbinding/data/restoreBinding4.qml new file mode 100644 index 0000000000..f34c3b40cf --- /dev/null +++ b/tests/auto/qml/qqmlbinding/data/restoreBinding4.qml @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQml 2.14 + +Rectangle { + height: 400 + width: 400 + + Rectangle { + property bool when: true + + id: myItem + objectName: "myItem" + height: 300 + width: 200 + property var foo: original + property bool fooCheck: foo === original && foo.bar() === 42 + } + + property var original: ({ bar: function() { return 42 } }) + + property var boundValue: 13 + + Binding { + restoreMode: Binding.RestoreBinding + objectName: "theBinding" + target: myItem + property: "foo" + when: myItem.when + value: boundValue + } +} diff --git a/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp b/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp index 34cf21024d..717fd5dbd1 100644 --- a/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp +++ b/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp @@ -42,6 +42,9 @@ private slots: void binding(); void whenAfterValue(); void restoreBinding(); + void restoreBindingValue(); + void restoreBindingVarValue(); + void restoreBindingJSValue(); void restoreBindingWithLoop(); void restoreBindingWithoutCrash(); void deletedObject(); @@ -134,6 +137,78 @@ void tst_qqmlbinding::restoreBinding() delete rect; } +void tst_qqmlbinding::restoreBindingValue() +{ + QQmlEngine engine; + QQmlComponent c(&engine, testFileUrl("restoreBinding2.qml")); + QScopedPointer rect(qobject_cast(c.create())); + QVERIFY(!rect.isNull()); + + auto myItem = qobject_cast(rect->findChild("myItem")); + QVERIFY(myItem != nullptr); + + QCOMPARE(myItem->height(), 100); + myItem->setProperty("when", QVariant(false)); + QCOMPARE(myItem->height(), 300); // make sure the original value was restored + + myItem->setProperty("when", QVariant(true)); + QCOMPARE(myItem->height(), 100); // make sure the value specified in Binding is set + rect->setProperty("boundValue", 200); + QCOMPARE(myItem->height(), 200); // make sure the changed binding value is set + myItem->setProperty("when", QVariant(false)); + // make sure that the original value is back, not e.g. the value from before the + // change (i.e. 100) + QCOMPARE(myItem->height(), 300); +} + +void tst_qqmlbinding::restoreBindingVarValue() +{ + QQmlEngine engine; + QQmlComponent c(&engine, testFileUrl("restoreBinding3.qml")); + QScopedPointer rect(qobject_cast(c.create())); + QVERIFY(!rect.isNull()); + + auto myItem = qobject_cast(rect->findChild("myItem")); + QVERIFY(myItem != nullptr); + + QCOMPARE(myItem->property("foo"), 13); + myItem->setProperty("when", QVariant(false)); + QCOMPARE(myItem->property("foo"), 42); // make sure the original value was restored + + myItem->setProperty("when", QVariant(true)); + QCOMPARE(myItem->property("foo"), 13); // make sure the value specified in Binding is set + rect->setProperty("boundValue", 31337); + QCOMPARE(myItem->property("foo"), 31337); // make sure the changed binding value is set + myItem->setProperty("when", QVariant(false)); + // make sure that the original value is back, not e.g. the value from before the + // change (i.e. 100) + QCOMPARE(myItem->property("foo"), 42); +} + +void tst_qqmlbinding::restoreBindingJSValue() +{ + QQmlEngine engine; + QQmlComponent c(&engine, testFileUrl("restoreBinding4.qml")); + QScopedPointer rect(qobject_cast(c.create())); + QVERIFY(!rect.isNull()); + + auto myItem = qobject_cast(rect->findChild("myItem")); + QVERIFY(myItem != nullptr); + + QCOMPARE(myItem->property("fooCheck"), false); + myItem->setProperty("when", QVariant(false)); + QCOMPARE(myItem->property("fooCheck"), true); // make sure the original value was restored + + myItem->setProperty("when", QVariant(true)); + QCOMPARE(myItem->property("fooCheck"), false); // make sure the value specified in Binding is set + rect->setProperty("boundValue", 31337); + QCOMPARE(myItem->property("fooCheck"), false); // make sure the changed binding value is set + myItem->setProperty("when", QVariant(false)); + // make sure that the original value is back, not e.g. the value from before the change + QCOMPARE(myItem->property("fooCheck"), true); + +} + void tst_qqmlbinding::restoreBindingWithLoop() { QQmlEngine engine; -- cgit v1.2.3 From e9852df2d7c1064c95ff4c4463587ad713e68334 Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Mon, 6 May 2019 17:07:21 +0200 Subject: QQuickTableView: don't recalculate content width while flicking There are now three mechanisms in TableView that works together to ensure that the table ends up edge-to-edge with the content view. They are applied in the following order: 1. Adjust the content size, based on the predicted size of the table. 2. Adjust the origin and endExtend on the fly, if the content size is wrong. 3. Move the table directly to where it should be, in case we don't have time to wait for the origin to change. We could have, strictly speaking, setteled with just one of them, but choose to use them all at the same time for best flicking experience. Still, 1. and 2. sometimes step on each others feet when they both detect that something is a bit off, and adjust. So rather than adjusting the size of the content view every time we load a new row or column, we just keep the first prediction. And then we leave all later ajustments to 2. and 3. This turns out to be a more stable, and will avoid some glitches that occur when flicking using a scrollbar, if several mechanisms kick in at the same time. Change-Id: Ib551a0bf8f6ee59ac9b3556b9462c91adb9cc80b Reviewed-by: Mitch Curtis --- .../quick/qquicktableview/tst_qquicktableview.cpp | 89 +++++----------------- 1 file changed, 17 insertions(+), 72 deletions(-) (limited to 'tests') diff --git a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp index d03f08ec6a..fbe56abda5 100644 --- a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp +++ b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp @@ -563,7 +563,7 @@ void tst_QQuickTableView::checkForceLayoutFunction() void tst_QQuickTableView::checkContentWidthAndHeight() { - // Check that contentWidth/Height reports the correct size of the the + // Check that contentWidth/Height reports the correct size of the // table, based on knowledge of the rows and columns that has been loaded. LOAD_TABLEVIEW("contentwidthheight.qml"); @@ -574,11 +574,7 @@ void tst_QQuickTableView::checkContentWidthAndHeight() const int tableSize = 100; const int cellSizeSmall = 100; - const int cellSizeLarge = 200; const int spacing = 1; - const int smallCellCount = 20; - const int largeCellCount = tableSize - smallCellCount; - const qreal accumulatedSpacing = ((tableSize - 1) * spacing); auto model = TestModelAsVariant(tableSize, tableSize); tableView->setModel(model); @@ -591,71 +587,12 @@ void tst_QQuickTableView::checkContentWidthAndHeight() QCOMPARE(tableViewPrivate->averageEdgeSize.width(), cellSizeSmall); QCOMPARE(tableViewPrivate->averageEdgeSize.height(), cellSizeSmall); - // Flick in 5 more rows and columns, but not so far that we start loading in - // the ones that are bigger. Loading in more rows and columns of the same - // size as the initial ones should not change the first prediction. - qreal flickTo = ((cellSizeSmall + spacing) * 5); - tableView->setContentX(flickTo); - tableView->setContentY(flickTo); + // Flick to the end, and check that content width/height stays unchanged + tableView->setContentX(tableView->contentWidth() - tableView->width()); + tableView->setContentY(tableView->contentHeight() - tableView->height()); QCOMPARE(tableView->contentWidth(), expectedSizeInit); QCOMPARE(tableView->contentHeight(), expectedSizeInit); - QCOMPARE(tableViewPrivate->averageEdgeSize.width(), cellSizeSmall); - QCOMPARE(tableViewPrivate->averageEdgeSize.height(), cellSizeSmall); - - // Flick to row and column 20 (smallCellCount), since there the row and - // column sizes increases with 100. Check that TableView then adjusts - // contentWidth and contentHeight accordingly. - flickTo = ((cellSizeSmall + spacing) * smallCellCount) - spacing; - tableView->setContentX(flickTo); - tableView->setContentY(flickTo); - - // Since we move the viewport more than a page, tableview - // will jump to the new position and do a rebuild. - QVERIFY(tableViewPrivate->scheduledRebuildOptions); - WAIT_UNTIL_POLISHED; - - // Check that the average cell size is now matching the - // large cells since they fill up the whole view. - QCOMPARE(tableViewPrivate->averageEdgeSize.width(), cellSizeLarge); - QCOMPARE(tableViewPrivate->averageEdgeSize.height(), cellSizeLarge); - - const int largeSizeCellCountInView = qCeil(tableView->width() / cellSizeLarge); - const int columnCount = smallCellCount + largeSizeCellCountInView; - QCOMPARE(tableViewPrivate->leftColumn(), smallCellCount); - QCOMPARE(tableViewPrivate->rightColumn(), columnCount - 1); - - const qreal firstHalfLength = smallCellCount * cellSizeSmall; - const qreal secondHalfOneScreenLength = largeSizeCellCountInView * cellSizeLarge; - const qreal lengthAfterFlick = firstHalfLength + secondHalfOneScreenLength; - - // Check that loadedTableOuterRect has been calculated correct thus far - const qreal spacingAfterFlick = (smallCellCount + largeSizeCellCountInView - 1) * spacing; - QCOMPARE(tableViewPrivate->loadedTableOuterRect.left(), flickTo + spacing); - QCOMPARE(tableViewPrivate->loadedTableOuterRect.right(), lengthAfterFlick + spacingAfterFlick); - QCOMPARE(tableViewPrivate->loadedTableOuterRect.top(), flickTo + spacing); - QCOMPARE(tableViewPrivate->loadedTableOuterRect.bottom(), lengthAfterFlick + spacingAfterFlick); - - // At this point, we should have the exact content width/height set, because - // TableView knows where the large cells start in the viewport, and how many - // columns that remain in the model. It will assume that the rest of the the - // columns have the same average size as the ones currently inside the viewport. - const qreal expectedContentSize = (smallCellCount * cellSizeSmall) + (largeCellCount * cellSizeLarge) + accumulatedSpacing; - QCOMPARE(tableView->contentWidth(), expectedContentSize); - QCOMPARE(tableView->contentHeight(), expectedContentSize); - - // Flick to the end (row/column 100, and overshoot a bit), and - // check that we then end up with the exact content width/height. - const qreal secondHalfLength = largeCellCount * cellSizeLarge; - const qreal expectedFullSize = (firstHalfLength + secondHalfLength) + accumulatedSpacing; - const qreal overshoot = 100; - const qreal endPosX = expectedFullSize - tableView->width() + overshoot; - const qreal endPosY = expectedFullSize - tableView->height() + overshoot; - tableView->setContentX(endPosX); - tableView->setContentY(endPosY); - - QCOMPARE(tableView->contentWidth(), expectedFullSize); - QCOMPARE(tableView->contentHeight(), expectedFullSize); // Flick back to start tableView->setContentX(0); @@ -667,7 +604,7 @@ void tst_QQuickTableView::checkContentWidthAndHeight() QVERIFY(tableViewPrivate->scheduledRebuildOptions); WAIT_UNTIL_POLISHED; - // We should now have the same content width/height as when we started + // We should still have the same content width/height as when we started QCOMPARE(tableView->contentWidth(), expectedSizeInit); QCOMPARE(tableView->contentHeight(), expectedSizeInit); } @@ -1303,8 +1240,11 @@ void tst_QQuickTableView::checkSpacingValues() tableView->polish(); WAIT_UNTIL_POLISHED; - QCOMPARE(tableView->contentWidth(), columnCount * (delegateWidth + tableView->columnSpacing()) - tableView->columnSpacing()); - QCOMPARE(tableView->contentHeight(), rowCount * (delegateHeight + tableView->rowSpacing()) - tableView->rowSpacing()); + + const qreal expectedInitialContentWidth = columnCount * (delegateWidth + tableView->columnSpacing()) - tableView->columnSpacing(); + const qreal expectedInitialContentHeight = rowCount * (delegateHeight + tableView->rowSpacing()) - tableView->rowSpacing(); + QCOMPARE(tableView->contentWidth(), expectedInitialContentWidth); + QCOMPARE(tableView->contentHeight(), expectedInitialContentHeight); // Valid spacing assignment tableView->setRowSpacing(42); @@ -1314,8 +1254,13 @@ void tst_QQuickTableView::checkSpacingValues() tableView->polish(); WAIT_UNTIL_POLISHED; - QCOMPARE(tableView->contentWidth(), columnCount * (delegateWidth + tableView->columnSpacing()) - tableView->columnSpacing()); - QCOMPARE(tableView->contentHeight(), rowCount * (delegateHeight + tableView->rowSpacing()) - tableView->rowSpacing()); + + // Even after changing spacing, TableView will keep the initial guesstimated content size. The + // reason is that deciding the content size based on the currently visible row/columns/spacing + // will almost always be at a little bit wrong at best. So instead of pretending that TableView + // knows what the size of the full table is, it sticks with the first guesstimate. + QCOMPARE(tableView->contentWidth(), expectedInitialContentWidth); + QCOMPARE(tableView->contentHeight(), expectedInitialContentHeight); // Invalid assignments (should ignore) tableView->setRowSpacing(-1); -- cgit v1.2.3 From 540134d66dd0a235ace91ddc28940d2d88c24ac3 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Fri, 10 May 2019 15:48:50 +0200 Subject: Move valueAsNumber into ExecutableCompilationUnit This reduces our dependence on QV4::Value in the devtools. Change-Id: I4b3f937bc08c16f7e2543fdc5cc34c0cfb121f8f Reviewed-by: Simon Hausmann --- tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp index 2987e420fe..c215e9620d 100644 --- a/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp +++ b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp @@ -328,7 +328,10 @@ void tst_qmldiskcache::regenerateAfterChange() const QV4::CompiledData::Object *obj = qmlUnit->objectAt(0); QCOMPARE(quint32(obj->nBindings), quint32(2)); QCOMPARE(quint32(obj->bindingTable()->type), quint32(QV4::CompiledData::Binding::Type_Number)); - QCOMPARE(obj->bindingTable()->valueAsNumber(reinterpret_cast(testUnit->constants())), double(42)); + + QCOMPARE(reinterpret_cast(testUnit->constants()) + [obj->bindingTable()->value.constantValueIndex].doubleValue(), + double(42)); QCOMPARE(quint32(testUnit->functionTableSize), quint32(1)); -- cgit v1.2.3 From 375b8d0fbecb1acf4596b5103c12fac2b592a927 Mon Sep 17 00:00:00 2001 From: Michal Klocek Date: Thu, 9 May 2019 12:38:22 +0200 Subject: Add test for cached getter lookup Task-number: QTBUG-75335 Change-Id: I14480018f2429eb5ec744a50640642eee09ce3f3 Reviewed-by: Simon Hausmann --- .../auto/qml/qqmlengine/data/CachedGetterLookup.qml | 20 ++++++++++++++++++++ tests/auto/qml/qqmlengine/tst_qqmlengine.cpp | 11 +++++++++++ 2 files changed, 31 insertions(+) create mode 100644 tests/auto/qml/qqmlengine/data/CachedGetterLookup.qml (limited to 'tests') diff --git a/tests/auto/qml/qqmlengine/data/CachedGetterLookup.qml b/tests/auto/qml/qqmlengine/data/CachedGetterLookup.qml new file mode 100644 index 0000000000..1a2a7ff341 --- /dev/null +++ b/tests/auto/qml/qqmlengine/data/CachedGetterLookup.qml @@ -0,0 +1,20 @@ +import QtQuick 2.12 + +QtObject { + Component.onCompleted: { + // create getter + var getFoo = function(o) { return o.foo; } + + // create two diffrent shapes for x,y + var x = { foo:1 , bar:2 } + var y = { bar:2 , foo:1 } + + // initialize inline cache with getFoo + getFoo(x); + getFoo(y); + + // hit getter lookup with string "crash" + getFoo('crash'); + } +} + diff --git a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp index b9cb6b70d2..0cb6753020 100644 --- a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp +++ b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp @@ -81,6 +81,7 @@ private slots: void cppSignalAndEval(); void singletonInstance(); void aggressiveGc(); + void cachedGetterLookup_qtbug_75335(); public slots: QObject *createAQObjectForOwnershipTest () @@ -1056,6 +1057,16 @@ void tst_qqmlengine::aggressiveGc() qputenv("QV4_MM_AGGRESSIVE_GC", origAggressiveGc); } +void tst_qqmlengine::cachedGetterLookup_qtbug_75335() +{ + QQmlEngine engine; + const QUrl testUrl = testFileUrl("CachedGetterLookup.qml"); + QQmlComponent component(&engine, testUrl); + QVERIFY(component.isReady()); + QScopedPointer object(component.create()); + QVERIFY(object != nullptr); +} + QTEST_MAIN(tst_qqmlengine) #include "tst_qqmlengine.moc" -- cgit v1.2.3 From 23f78b6b76fb9350a472485e34857e1a4842e5d3 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Fri, 1 Mar 2019 22:40:54 +0100 Subject: TextEdit: use I-beam cursor by default, pointing cursor for links But do not interfere with any custom cursor that user code sets: remember and restore it when the mouse is no longer hovering a link. Task-number: QTBUG-14769 Fixes: QTBUG-50482 Change-Id: Ia4633c22d0ad42d07203d4dc3e330b90a5f94a7c Reviewed-by: Mitch Curtis --- tests/auto/quick/qquicktextedit/qquicktextedit.pro | 1 + .../quick/qquicktextedit/tst_qquicktextedit.cpp | 56 ++++++++++++++++++++++ 2 files changed, 57 insertions(+) (limited to 'tests') diff --git a/tests/auto/quick/qquicktextedit/qquicktextedit.pro b/tests/auto/quick/qquicktextedit/qquicktextedit.pro index ea6e8bc60d..576e25d092 100644 --- a/tests/auto/quick/qquicktextedit/qquicktextedit.pro +++ b/tests/auto/quick/qquicktextedit/qquicktextedit.pro @@ -8,6 +8,7 @@ SOURCES += tst_qquicktextedit.cpp \ HEADERS += ../../shared/testhttpserver.h include (../../shared/util.pri) +include (../shared/util.pri) TESTDATA = data/* diff --git a/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp b/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp index da15ca6b48..80ba05b634 100644 --- a/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp +++ b/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp @@ -48,6 +48,7 @@ #include #include #include "../../shared/util.h" +#include "../shared/viewtestutil.h" #include "../../shared/platformquirks.h" #include "../../shared/platforminputcontext.h" #include @@ -62,6 +63,11 @@ Q_DECLARE_METATYPE(QQuickTextEdit::SelectionMode) Q_DECLARE_METATYPE(Qt::Key) DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD) +static bool isPlatformWayland() +{ + return !QGuiApplication::platformName().compare(QLatin1String("wayland"), Qt::CaseInsensitive); +} + QString createExpectedFileIfNotFound(const QString& filebasename, const QImage& actual) { // XXX This will be replaced by some clever persistent platform image store. @@ -132,6 +138,7 @@ private slots: void positionAt_data(); void positionAt(); + void linkHover(); void linkInteraction(); void cursorDelegate_data(); @@ -2506,10 +2513,59 @@ void tst_qquicktextedit::positionAt() QVERIFY(texteditObject->positionAt(x0 / 2, y1) > 0); } +#if QT_CONFIG(cursor) +void tst_qquicktextedit::linkHover() +{ + if (isPlatformWayland()) + QSKIP("Wayland: QCursor::setPos() doesn't work."); + + QQuickView window(testFileUrl("linkInteraction.qml")); + window.setFlag(Qt::FramelessWindowHint); + QVERIFY(window.rootObject() != nullptr); + QQuickViewTestUtil::centerOnScreen(&window); + QQuickViewTestUtil::moveMouseAway(&window); + window.show(); + window.requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(&window)); + QQuickTextEdit *texteditObject = qobject_cast(window.rootObject()); + QVERIFY(texteditObject != nullptr); + + QSignalSpy hover(texteditObject, SIGNAL(linkHovered(QString))); + + const QString link("http://example.com/"); + const QPoint linkPos = window.mapToGlobal(texteditObject->positionToRectangle(7).center().toPoint()); + const QPoint textPos = window.mapToGlobal(texteditObject->positionToRectangle(2).center().toPoint()); + + QCursor::setPos(linkPos); + QTRY_COMPARE(hover.count(), 1); + QCOMPARE(window.cursor().shape(), Qt::PointingHandCursor); + QCOMPARE(hover.last()[0].toString(), link); + + QCursor::setPos(textPos); + QTRY_COMPARE(hover.count(), 2); + QCOMPARE(window.cursor().shape(), Qt::IBeamCursor); + QCOMPARE(hover.last()[0].toString(), QString()); + + texteditObject->setCursor(Qt::OpenHandCursor); + + QCursor::setPos(linkPos); + QTRY_COMPARE(hover.count(), 3); + QCOMPARE(window.cursor().shape(), Qt::PointingHandCursor); + QCOMPARE(hover.last()[0].toString(), link); + + QCursor::setPos(textPos); + QTRY_COMPARE(hover.count(), 4); + QCOMPARE(window.cursor().shape(), Qt::OpenHandCursor); + QCOMPARE(hover.last()[0].toString(), QString()); +} +#endif + void tst_qquicktextedit::linkInteraction() { QQuickView window(testFileUrl("linkInteraction.qml")); QVERIFY(window.rootObject() != nullptr); + QQuickViewTestUtil::centerOnScreen(&window); + QQuickViewTestUtil::moveMouseAway(&window); window.show(); window.requestActivate(); QVERIFY(QTest::qWaitForWindowActive(&window)); -- cgit v1.2.3 From 56fbc277a1acc49d9ead4c89edd250a021ef2a01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Arve=20S=C3=A6ther?= Date: Tue, 14 May 2019 12:13:01 +0200 Subject: Do not synthesize a double click event if the event point moved too far We need to respect QPlatformTheme::TouchDoubleTapDistance Fixes: QTBUG-75770 Change-Id: I2adc7097bb29cb93beb2609a8a806a666856a0c8 Reviewed-by: Shawn Rutledge --- tests/auto/quick/qquickwindow/tst_qquickwindow.cpp | 56 ++++++++++++++++++++++ 1 file changed, 56 insertions(+) (limited to 'tests') diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp index 4cf7fa7119..f08b9207d1 100644 --- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp +++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp @@ -353,6 +353,11 @@ protected: m_mouseEvents << *event; } + void mouseDoubleClickEvent(QMouseEvent *event) override { + qCDebug(lcTests) << event; + m_mouseEvents << *event; + } + public: QList m_mouseEvents; QList m_touchEvents; @@ -401,6 +406,8 @@ private slots: void mouseFromTouch_basic(); void synthMouseFromTouch_data(); void synthMouseFromTouch(); + void synthMouseDoubleClickFromTouch_data(); + void synthMouseDoubleClickFromTouch(); void clearWindow(); @@ -1241,6 +1248,55 @@ void tst_qquickwindow::synthMouseFromTouch() QCOMPARE(ev.source(), Qt::MouseEventSynthesizedByQt); } +void tst_qquickwindow::synthMouseDoubleClickFromTouch_data() +{ + QTest::addColumn("movement"); + QTest::addColumn("distanceBetweenPresses"); + QTest::addColumn("expectedSynthesizedDoubleClickEvent"); + + QTest::newRow("normal") << QPoint(0, 0) << QPoint(0, 0) << true; + QTest::newRow("with 1 pixel wiggle") << QPoint(1, 1) << QPoint(1, 1) << true; + QTest::newRow("too much distance to second tap") << QPoint(0, 0) << QPoint(50, 0) << false; + QTest::newRow("too much drag") << QPoint(50, 0) << QPoint(0, 0) << false; + QTest::newRow("too much drag and too much distance to second tap") << QPoint(50, 0) << QPoint(50, 0) << false; +} + +void tst_qquickwindow::synthMouseDoubleClickFromTouch() +{ + QFETCH(QPoint, movement); + QFETCH(QPoint, distanceBetweenPresses); + QFETCH(bool, expectedSynthesizedDoubleClickEvent); + + QCoreApplication::setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, true); + QScopedPointer window(new MouseRecordingWindow); + QScopedPointer item(new MouseRecordingItem(false, nullptr)); + item->setParentItem(window->contentItem()); + window->resize(250, 250); + window->setPosition(100, 100); + window->setTitle(QTest::currentTestFunction()); + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window.data())); + QTest::qWait(100); + + QPoint p1 = item->mapToScene(item->clipRect().center()).toPoint(); + QTest::touchEvent(window.data(), touchDevice).press(0, p1, window.data()); + QTest::touchEvent(window.data(), touchDevice).move(0, p1 + movement, window.data()); + QTest::touchEvent(window.data(), touchDevice).release(0, p1 + movement, window.data()); + + QPoint p2 = p1 + distanceBetweenPresses; + QTest::touchEvent(window.data(), touchDevice).press(1, p2, window.data()); + QTest::touchEvent(window.data(), touchDevice).move(1, p2 + movement, window.data()); + QTest::touchEvent(window.data(), touchDevice).release(1, p2 + movement, window.data()); + + const int eventCount = item->m_mouseEvents.count(); + QVERIFY(eventCount >= 2); + + const int nDoubleClicks = std::count_if(item->m_mouseEvents.constBegin(), item->m_mouseEvents.constEnd(), [](const QMouseEvent &ev) { return (ev.type() == QEvent::MouseButtonDblClick); } ); + const bool foundDoubleClick = (nDoubleClicks == 1); + QCOMPARE(foundDoubleClick, expectedSynthesizedDoubleClickEvent); + +} + void tst_qquickwindow::clearWindow() { QQuickWindow *window = new QQuickWindow; -- cgit v1.2.3 From fb4c12a9db86a4b886058cc937c3c20b798bd2e2 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Wed, 22 May 2019 10:57:12 +0200 Subject: Blacklist tst_QQuickListView::currentIndex() on macOS 10.12 Task-number: QTBUG-75960 Change-Id: I3321bf54a11c1daf8d4e1818c5b860359c34fdec Reviewed-by: Shawn Rutledge --- tests/auto/quick/qquicklistview/BLACKLIST | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'tests') diff --git a/tests/auto/quick/qquicklistview/BLACKLIST b/tests/auto/quick/qquicklistview/BLACKLIST index 893f95dcea..6dd7302661 100644 --- a/tests/auto/quick/qquicklistview/BLACKLIST +++ b/tests/auto/quick/qquicklistview/BLACKLIST @@ -9,3 +9,7 @@ opensuse-42.1 [contentHeightWithDelayRemove] osx-10.12 + +#QTBUG-75960 +[currentIndex] +osx-10.12 -- cgit v1.2.3 From 4ce9717c6de3f69556b90d97c40fcfc5bb54b6d4 Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Fri, 22 Mar 2019 11:41:15 +0100 Subject: Manual test, TableView: improve test with syncView functionality Add some more TableViews and buttons that can be used to test the new syncView functionality. Change-Id: I0ad649598ef2ff08487c9a0b450861c27535c62c Reviewed-by: Mitch Curtis --- .../manual/tableview/abstracttablemodel/Button.qml | 2 +- tests/manual/tableview/abstracttablemodel/main.qml | 156 +++++++++++++++++---- 2 files changed, 132 insertions(+), 26 deletions(-) (limited to 'tests') diff --git a/tests/manual/tableview/abstracttablemodel/Button.qml b/tests/manual/tableview/abstracttablemodel/Button.qml index 2d4dcde80d..7057e33633 100644 --- a/tests/manual/tableview/abstracttablemodel/Button.qml +++ b/tests/manual/tableview/abstracttablemodel/Button.qml @@ -40,7 +40,7 @@ import QtQuick 2.12 Rectangle { - width: 100 + width: 110 height: 40 border.width: 1 color: "lightgreen" diff --git a/tests/manual/tableview/abstracttablemodel/main.qml b/tests/manual/tableview/abstracttablemodel/main.qml index 52967a1a0d..4b9158f03c 100644 --- a/tests/manual/tableview/abstracttablemodel/main.qml +++ b/tests/manual/tableview/abstracttablemodel/main.qml @@ -37,10 +37,11 @@ ** ****************************************************************************/ -import QtQuick 2.12 +import QtQuick 2.14 import QtQuick.Window 2.3 import QtQml.Models 2.2 import TestTableModel 0.1 +import QtQuick.Controls 2.5 Window { id: window @@ -54,7 +55,7 @@ Window { TestTableModel { id: tableModel rowCount: 200 - columnCount: 5000 + columnCount: 200 } Rectangle { @@ -62,45 +63,150 @@ Window { anchors.margins: 10 color: "darkgray" - Row { + Column { id: menu x: 2 y: 2 - spacing: 1 - Button { - text: "Add row" - onClicked: tableModel.insertRows(selectedY, 1) + + Row { + spacing: 1 + Button { + text: "Add row" + onClicked: tableModel.insertRows(selectedY, 1) + } + Button { + text: "Remove row" + onClicked: tableModel.removeRows(selectedY, 1) + } + Button { + text: "Add column" + onClicked: tableModel.insertColumns(selectedX, 1) + } + Button { + text: "Remove column" + onClicked: tableModel.removeColumns(selectedX, 1) + } } - Button { - text: "Remove row" - onClicked: tableModel.removeRows(selectedY, 1) + + Row { + spacing: 1 + Button { + text: "fast-flick
center table" + onClicked: { + tableView.contentX += tableView.width * 1.2 + } + } + Button { + text: "flick to end
center table" + onClicked: { + tableView.contentX = tableView.contentWidth - tableView.width + } + } + Button { + text: "fast-flick
headers" + onClicked: { + leftHeader.contentY += 1000 + topHeader.contentX += 1000 + } + } + Button { + text: "set/unset
master bindings" + onClicked: { + leftHeader.syncView = leftHeader.syncView ? null : tableView + topHeader.syncView = topHeader.syncView ? null : tableView + } + } + Button { + text: "inc space" + onClicked: { + tableView.columnSpacing += 1 + tableView.rowSpacing += 1 + } + } + } + Text { + text: "Selected: x:" + selectedX + ", y:" + selectedY } - Button { - text: "Add column" - onClicked: tableModel.insertColumns(selectedX, 1) + } + + TableView { + id: topHeader + objectName: "topHeader" + anchors.left: tableView.left + width: tableView.width + anchors.top: menu.bottom + height: 30 + clip: true + ScrollBar.horizontal: ScrollBar {} + + model: TestTableModel { + rowCount: 1 + columnCount: 200 } - Button { - text: "Remove column" - onClicked: tableModel.removeColumns(selectedX, 1) + + delegate: Rectangle { + implicitHeight: topHeader.height + implicitWidth: 20 + color: "lightgray" + Text { text: column } } + + columnSpacing: 1 + rowSpacing: 1 + + syncDirection: Qt.Horizontal } - Text { - anchors.right: parent.right - anchors.top: parent.top - anchors.margins: 2 - text: "x:" + selectedX + ", y:" + selectedY + + TableView { + id: leftHeader + objectName: "leftHeader" + anchors.left: parent.left + anchors.top: tableView.top + height: tableView.height + width: 30 + clip: true + ScrollBar.vertical: ScrollBar {} + + model: TestTableModel { + rowCount: 200 + columnCount: 1 + } + + delegate: Rectangle { + implicitHeight: 50 + implicitWidth: leftHeader.width + color: "lightgray" + Text { text: row } + } + + columnSpacing: 1 + rowSpacing: 1 + + syncDirection: Qt.Vertical } TableView { id: tableView - anchors.left: parent.left + objectName: "tableview" + anchors.left: leftHeader.right anchors.right: parent.right - anchors.top: menu.bottom + anchors.top: topHeader.bottom anchors.bottom: parent.bottom - anchors.margins: 2 + width: 200 clip: true + columnWidthProvider: function(c) { + if (c > 30) + return 100 + else + return 200; + } + ScrollBar.horizontal: ScrollBar {} + ScrollBar.vertical: ScrollBar {} - model: tableModel + model: TestTableModel { + rowCount: 200 + columnCount: 60 + } delegate: tableViewDelegate columnSpacing: 1 rowSpacing: 1 -- cgit v1.2.3 From 9d61684d70c8691d81536b7b519388586e2cbbb8 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 27 May 2019 09:40:17 +0200 Subject: Don't set childMode on a StateMachine This leads to invalid state machines and is rejected since cfdbfcebbda5f26b89c70df6b191b17ef242e9d7 in qtbase. Rather, add a separate state in between to set the ParallelStates mode. Change-Id: Ia08b286da4c60a26d3043179250f81fb4328864f Fixes: QTBUG-75976 Reviewed-by: Edward Welbourne Reviewed-by: Liang Qi --- .../qmltest/statemachine/tst_parallelmachine.qml | 32 ++++++++++++---------- 1 file changed, 18 insertions(+), 14 deletions(-) (limited to 'tests') diff --git a/tests/auto/qmltest/statemachine/tst_parallelmachine.qml b/tests/auto/qmltest/statemachine/tst_parallelmachine.qml index be7d73fbe5..eb996c7718 100644 --- a/tests/auto/qmltest/statemachine/tst_parallelmachine.qml +++ b/tests/auto/qmltest/statemachine/tst_parallelmachine.qml @@ -32,25 +32,29 @@ import QtQml.StateMachine 1.0 TestCase { StateMachine { id: myStateMachine - childMode: State.ParallelStates + initialState: rootState State { - id: childState1 + id: rootState childMode: State.ParallelStates State { - id: childState11 + id: childState1 + childMode: State.ParallelStates + State { + id: childState11 + } + State { + id: childState12 + } } State { - id: childState12 - } - } - State { - id: childState2 - initialState: childState21 - State { - id: childState21 - } - State { - id: childState22 + id: childState2 + initialState: childState21 + State { + id: childState21 + } + State { + id: childState22 + } } } } -- cgit v1.2.3