diff options
author | Charles Yin <charles.yin@nokia.com> | 2011-11-14 10:35:51 +1000 |
---|---|---|
committer | Charles Yin <charles.yin@nokia.com> | 2011-11-14 10:35:51 +1000 |
commit | fc54db69809a16f613f65a2761fab55d5911b02c (patch) | |
tree | a00d9284eb13f81f5b195f8a4c6cfee03edb4f17 /tests | |
parent | 35275892ca8a7046451b8e943985dd779fee4794 (diff) | |
parent | 2557ff5a940242b398dee65c3c79cec088164e32 (diff) | |
download | qtdeclarative-fc54db69809a16f613f65a2761fab55d5911b02c.tar.gz |
Merge branch 'master' into animation-refactor
Conflicts:
tools/qmlviewer/qdeclarativetester.cpp
tools/qmlviewer/qmlruntime.cpp
Change-Id: I48f0eb02df27e4b524f45927939b4c257452b0aa
Diffstat (limited to 'tests')
180 files changed, 8056 insertions, 953 deletions
diff --git a/tests/auto/declarative/debugger/debugger.pro b/tests/auto/declarative/debugger/debugger.pro index 869b3a8cd6..90c5d4bc7e 100644 --- a/tests/auto/declarative/debugger/debugger.pro +++ b/tests/auto/declarative/debugger/debugger.pro @@ -6,6 +6,7 @@ PRIVATETESTS += \ qdeclarativedebugservice \ qdeclarativedebugjs \ qdeclarativeinspector \ + qdeclarativedebugtrace \ qpacketprotocol contains(QT_CONFIG, private_tests) { diff --git a/tests/auto/declarative/debugger/qdeclarativedebugclient/tst_qdeclarativedebugclient.cpp b/tests/auto/declarative/debugger/qdeclarativedebugclient/tst_qdeclarativedebugclient.cpp index 1587eee060..82e25598e9 100644 --- a/tests/auto/declarative/debugger/qdeclarativedebugclient/tst_qdeclarativedebugclient.cpp +++ b/tests/auto/declarative/debugger/qdeclarativedebugclient/tst_qdeclarativedebugclient.cpp @@ -162,7 +162,7 @@ void tst_QDeclarativeDebugClient::sequentialConnect() QCOMPARE(m_conn->state(), QAbstractSocket::UnconnectedState); // Make sure that the disconnect is actually delivered to the server - QGuiApplication::processEvents(); + QTest::qWait(100); connection2.connectToHost("127.0.0.1", PORT); QTest::ignoreMessage(QtWarningMsg, "QDeclarativeDebugServer: Connection established"); diff --git a/tests/auto/declarative/debugger/qdeclarativedebugjs/qdeclarativedebugjs.pro b/tests/auto/declarative/debugger/qdeclarativedebugjs/qdeclarativedebugjs.pro index 1cbbbc1c58..a2286ae0d5 100644 --- a/tests/auto/declarative/debugger/qdeclarativedebugjs/qdeclarativedebugjs.pro +++ b/tests/auto/declarative/debugger/qdeclarativedebugjs/qdeclarativedebugjs.pro @@ -15,6 +15,6 @@ testDataFiles.path = . DEPLOYMENT += testDataFiles -CONFIG += parallel_test +CONFIG += parallel_test insignificant_test OTHER_FILES += data/test.qml data/test.js diff --git a/tests/auto/declarative/debugger/qdeclarativedebugjs/tst_qdeclarativedebugjs.cpp b/tests/auto/declarative/debugger/qdeclarativedebugjs/tst_qdeclarativedebugjs.cpp index 73cea4e2d7..1239c43a70 100644 --- a/tests/auto/declarative/debugger/qdeclarativedebugjs/tst_qdeclarativedebugjs.cpp +++ b/tests/auto/declarative/debugger/qdeclarativedebugjs/tst_qdeclarativedebugjs.cpp @@ -1078,17 +1078,15 @@ void tst_QDeclarativeDebugJS::setBreakpointInScriptOnTimerCallback() { int sourceLine = 49; client->setBreakpoint(QLatin1String(SCRIPT), QLatin1String(QMLFILE), sourceLine, -1, true); + //void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1) + sourceLine = 67; + client->setBreakpoint(QLatin1String(SCRIPT), QLatin1String(QMLFILE), sourceLine, -1, true); client->startDebugging(); QVERIFY(QDeclarativeDebugTest::waitForSignal(client, SIGNAL(stopped()))); client->evaluate("timer.running = true"); client->continueDebugging(QJSDebugClient::Continue); - //void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1) - - sourceLine = 67; - - client->setBreakpoint(QLatin1String(SCRIPT), QLatin1String(QMLFILE), sourceLine, -1, true); QVERIFY(QDeclarativeDebugTest::waitForSignal(client, SIGNAL(stopped()))); QString jsonString(client->response); @@ -1376,6 +1374,7 @@ void tst_QDeclarativeDebugJS::setExceptionBreak() client->startDebugging(); QVERIFY(QDeclarativeDebugTest::waitForSignal(client, SIGNAL(stopped()))); client->evaluate("root.raiseException = true"); + QVERIFY(QDeclarativeDebugTest::waitForSignal(client, SIGNAL(result()))); client->continueDebugging(QJSDebugClient::Continue); QVERIFY(QDeclarativeDebugTest::waitForSignal(client, SIGNAL(stopped()), 10000)); } @@ -1595,6 +1594,7 @@ void tst_QDeclarativeDebugJS::getScopes() QVERIFY(QDeclarativeDebugTest::waitForSignal(client, SIGNAL(stopped()))); client->scopes(); + QEXPECT_FAIL("", "Failing after v8 integration", Abort); QVERIFY(QDeclarativeDebugTest::waitForSignal(client, SIGNAL(result()))); } diff --git a/tests/auto/declarative/debugger/qdeclarativedebugtrace/data/test.qml b/tests/auto/declarative/debugger/qdeclarativedebugtrace/data/test.qml new file mode 100644 index 0000000000..9c36e13c5b --- /dev/null +++ b/tests/auto/declarative/debugger/qdeclarativedebugtrace/data/test.qml @@ -0,0 +1,5 @@ +import QtQuick 2.0 + +Item { + +} diff --git a/tests/auto/declarative/debugger/qdeclarativedebugtrace/qdeclarativedebugtrace.pro b/tests/auto/declarative/debugger/qdeclarativedebugtrace/qdeclarativedebugtrace.pro new file mode 100644 index 0000000000..9ddb51c66d --- /dev/null +++ b/tests/auto/declarative/debugger/qdeclarativedebugtrace/qdeclarativedebugtrace.pro @@ -0,0 +1,14 @@ +CONFIG += testcase +TARGET = tst_qdeclarativedebugtrace +macx:CONFIG -= app_bundle + +HEADERS += ../shared/debugutil_p.h + +SOURCES += tst_qdeclarativedebugtrace.cpp \ + ../shared/debugutil.cpp + +OTHER_FILES += data/test.qml + +CONFIG += parallel_test declarative_debug + +QT += core-private gui-private v8-private declarative-private network testlib diff --git a/tests/auto/declarative/debugger/qdeclarativedebugtrace/tst_qdeclarativedebugtrace.cpp b/tests/auto/declarative/debugger/qdeclarativedebugtrace/tst_qdeclarativedebugtrace.cpp new file mode 100644 index 0000000000..52271477e7 --- /dev/null +++ b/tests/auto/declarative/debugger/qdeclarativedebugtrace/tst_qdeclarativedebugtrace.cpp @@ -0,0 +1,252 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qtest.h> +#include <QLibraryInfo> + +#include "QtDeclarative/private/qdeclarativedebugtrace_p.h" +#include "../shared/debugutil_p.h" +#include "../../shared/util.h" + +#define PORT 13773 +#define STR_PORT "13773" + +class QDeclarativeDebugTraceClient : public QDeclarativeDebugClient +{ + Q_OBJECT + +public: + QDeclarativeDebugTraceClient(QDeclarativeDebugConnection *connection) + : QDeclarativeDebugClient(QLatin1String("CanvasFrameRate"), connection) + { + } + + QList<QDeclarativeDebugData> traceMessages; + + void setTraceStatus(bool enabled) { + QByteArray message; + QDataStream stream(&message, QIODevice::WriteOnly); + stream << enabled; + sendMessage(message); + } + +signals: + void complete(); + +protected: + void messageReceived(const QByteArray &message); +}; + +class tst_QDeclarativeDebugTrace : public QObject +{ + Q_OBJECT + +public: + tst_QDeclarativeDebugTrace() + : m_process(0) + , m_connection(0) + , m_client(0) + { + } + +private: + QDeclarativeDebugProcess *m_process; + QDeclarativeDebugConnection *m_connection; + QDeclarativeDebugTraceClient *m_client; + +private slots: + void init(); + void cleanup(); + + void connectWithTraceEnabled(); + void connectWithTraceDisabled(); +}; + +void QDeclarativeDebugTraceClient::messageReceived(const QByteArray &message) +{ + QByteArray msg = message; + QDataStream stream(&msg, QIODevice::ReadOnly); + + + QDeclarativeDebugData data; + data.time = -2; + data.messageType = -1; + data.detailType = -1; + data.line = -1; + data.framerate = -1; + data.animationcount = -1; + + stream >> data.time >> data.messageType; + + QVERIFY(data.time >= -1); + + switch (data.messageType) { + case (QDeclarativeDebugTrace::Event): { + stream >> data.detailType; + + switch (data.detailType) { + case QDeclarativeDebugTrace::AnimationFrame: { + stream >> data.framerate >> data.animationcount; + QVERIFY(data.framerate != -1); + QVERIFY(data.animationcount != -1); + break; + } + case QDeclarativeDebugTrace::FramePaint: + case QDeclarativeDebugTrace::Mouse: + case QDeclarativeDebugTrace::Key: + case QDeclarativeDebugTrace::StartTrace: + case QDeclarativeDebugTrace::EndTrace: + break; + default: { + QString failMsg = QString("Unknown event type:") + data.detailType; + QFAIL(qPrintable(failMsg)); + break; + } + } + break; + } + case QDeclarativeDebugTrace::Complete: { + emit complete(); + QVERIFY(stream.atEnd()); + return; + } + case QDeclarativeDebugTrace::RangeStart: { + stream >> data.detailType; + QVERIFY(data.detailType >= 0 && data.detailType < QDeclarativeDebugTrace::MaximumRangeType); + break; + } + case QDeclarativeDebugTrace::RangeEnd: { + stream >> data.detailType; + QVERIFY(data.detailType >= 0 && data.detailType < QDeclarativeDebugTrace::MaximumRangeType); + break; + } + case QDeclarativeDebugTrace::RangeData: { + stream >> data.detailType >> data.detailData; + QVERIFY(data.detailType >= 0 && data.detailType < QDeclarativeDebugTrace::MaximumRangeType); + break; + } + case QDeclarativeDebugTrace::RangeLocation: { + stream >> data.detailType >> data.detailData >> data.line; + QVERIFY(data.detailType >= 0 && data.detailType < QDeclarativeDebugTrace::MaximumRangeType); + QVERIFY(data.line >= -2); + break; + } + default: + QString failMsg = QString("Unknown message type:") + data.messageType; + QFAIL(qPrintable(failMsg)); + break; + } + QVERIFY(stream.atEnd()); + traceMessages.append(data); +} + +void tst_QDeclarativeDebugTrace::init() +{ + const QString executable = QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmlscene"; + QStringList arguments; + arguments << QString("-qmljsdebugger=port:"STR_PORT",block"); + arguments << QString(TESTDATA(QLatin1String("test.qml"))); + + m_process = new QDeclarativeDebugProcess(executable); + m_process->start(QStringList() << arguments); + if (!m_process->waitForSessionStart()) { + QString failMsg = QString("Could not launch app '%1'.\nApplication output:\n%2").arg( + executable, m_process->output()); + QFAIL(qPrintable(failMsg)); + } + + QDeclarativeDebugConnection *m_connection = new QDeclarativeDebugConnection(); + m_client = new QDeclarativeDebugTraceClient(m_connection); + + m_connection->connectToHost(QLatin1String("127.0.0.1"), PORT); +} + +void tst_QDeclarativeDebugTrace::cleanup() +{ + delete m_process; + delete m_connection; + delete m_client; +} + +void tst_QDeclarativeDebugTrace::connectWithTraceEnabled() +{ + QTRY_COMPARE(m_client->status(), QDeclarativeDebugClient::Enabled); + m_client->setTraceStatus(true); + m_client->setTraceStatus(false); + if (!QDeclarativeDebugTest::waitForSignal(m_client, SIGNAL(complete()))) { + QString failMsg + = QString("No trace received in time. App output: \n\n").arg(m_process->output()); + QFAIL(qPrintable(failMsg)); + } + + // must start with "StartTrace" + QCOMPARE(m_client->traceMessages.first().messageType, (int)QDeclarativeDebugTrace::Event); + QCOMPARE(m_client->traceMessages.first().detailType, (int)QDeclarativeDebugTrace::StartTrace); + + // must end with "EndTrace" + QCOMPARE(m_client->traceMessages.last().messageType, (int)QDeclarativeDebugTrace::Event); + QCOMPARE(m_client->traceMessages.last().detailType, (int)QDeclarativeDebugTrace::EndTrace); +} + +void tst_QDeclarativeDebugTrace::connectWithTraceDisabled() +{ + QTRY_COMPARE(m_client->status(), QDeclarativeDebugClient::Enabled); + m_client->setTraceStatus(false); + m_client->setTraceStatus(true); + m_client->setTraceStatus(false); + if (!QDeclarativeDebugTest::waitForSignal(m_client, SIGNAL(complete()))) { + QString failMsg + = QString("No trace received in time. App output: \n\n").arg(m_process->output()); + QFAIL(qPrintable(failMsg)); + } + + // must start with "StartTrace" + QCOMPARE(m_client->traceMessages.first().messageType, (int)QDeclarativeDebugTrace::Event); + QCOMPARE(m_client->traceMessages.first().detailType, (int)QDeclarativeDebugTrace::StartTrace); + + // must end with "EndTrace" + QCOMPARE(m_client->traceMessages.last().messageType, (int)QDeclarativeDebugTrace::Event); + QCOMPARE(m_client->traceMessages.last().detailType, (int)QDeclarativeDebugTrace::EndTrace); +} + +QTEST_MAIN(tst_QDeclarativeDebugTrace) + +#include "tst_qdeclarativedebugtrace.moc" diff --git a/tests/auto/declarative/debugger/qdeclarativeinspector/tst_qdeclarativeinspector.cpp b/tests/auto/declarative/debugger/qdeclarativeinspector/tst_qdeclarativeinspector.cpp index fe079d645e..5545f8e046 100644 --- a/tests/auto/declarative/debugger/qdeclarativeinspector/tst_qdeclarativeinspector.cpp +++ b/tests/auto/declarative/debugger/qdeclarativeinspector/tst_qdeclarativeinspector.cpp @@ -45,8 +45,7 @@ #include <QDebug> #include <QThread> -#include "../../../../src/plugins/qmltooling/qmldbg_inspector/qdeclarativeinspectorprotocol.h" -#include "../../../../shared/util.h" +#include "../../../../../src/plugins/qmltooling/shared/qdeclarativeinspectorprotocol.h" #include "../shared/debugutil_p.h" using namespace QmlJSDebugger; diff --git a/tests/auto/declarative/debugger/qdeclarativeinspector/tst_qdeclarativeinspector.pro b/tests/auto/declarative/debugger/qdeclarativeinspector/tst_qdeclarativeinspector.pro index 26e4208f59..63230c05a0 100644 --- a/tests/auto/declarative/debugger/qdeclarativeinspector/tst_qdeclarativeinspector.pro +++ b/tests/auto/declarative/debugger/qdeclarativeinspector/tst_qdeclarativeinspector.pro @@ -1,5 +1,5 @@ CONFIG += testcase -TARGET = tst_qdeclarativinspector +TARGET = tst_qdeclarativeinspector macx:CONFIG -= app_bundle HEADERS += ../shared/debugutil_p.h diff --git a/tests/auto/declarative/debugger/shared/debugutil.cpp b/tests/auto/declarative/debugger/shared/debugutil.cpp index 2c769be53f..154e20bdb3 100644 --- a/tests/auto/declarative/debugger/shared/debugutil.cpp +++ b/tests/auto/declarative/debugger/shared/debugutil.cpp @@ -148,18 +148,24 @@ bool QDeclarativeDebugProcess::waitForSessionStart() QString QDeclarativeDebugProcess::output() const { - return m_outputBuffer; + return m_output; } void QDeclarativeDebugProcess::processAppOutput() { m_mutex.lock(); - const QString appOutput = m_process.readAll(); - static QRegExp newline("[\n\r]{1,2}"); - QStringList lines = appOutput.split(newline); - foreach (const QString &line, lines) { - if (line.isEmpty()) - continue; + + QString newOutput = m_process.readAll(); + m_output.append(newOutput); + m_outputBuffer.append(newOutput); + + while (true) { + const int nlIndex = m_outputBuffer.indexOf(QLatin1Char('\n')); + if (nlIndex < 0) // no further complete lines + break; + const QString line = m_outputBuffer.left(nlIndex); + m_outputBuffer = m_outputBuffer.right(m_outputBuffer.size() - nlIndex - 1); + if (line.startsWith("Qml debugging is enabled")) // ignore continue; if (line.startsWith("QDeclarativeDebugServer:")) { @@ -172,7 +178,6 @@ void QDeclarativeDebugProcess::processAppOutput() continue; } } - m_outputBuffer.append(appOutput); } m_mutex.unlock(); } diff --git a/tests/auto/declarative/debugger/shared/debugutil_p.h b/tests/auto/declarative/debugger/shared/debugutil_p.h index 99a482cf2a..24b7e252cb 100644 --- a/tests/auto/declarative/debugger/shared/debugutil_p.h +++ b/tests/auto/declarative/debugger/shared/debugutil_p.h @@ -113,6 +113,7 @@ private: QString m_executable; QProcess m_process; QString m_outputBuffer; + QString m_output; QTimer m_timer; QEventLoop m_eventLoop; QMutex m_mutex; diff --git a/tests/auto/declarative/declarative.pro b/tests/auto/declarative/declarative.pro index cd4309486f..f2f127ffc1 100644 --- a/tests/auto/declarative/declarative.pro +++ b/tests/auto/declarative/declarative.pro @@ -62,6 +62,7 @@ PRIVATETESTS += \ !contains(QT_CONFIG,xmlpatterns):PRIVATETESTS -= qdeclarativexmllistmodel QUICKTESTS = \ + qquickanchors \ qquickanimatedimage \ qquickborderimage \ qquickcanvas \ @@ -77,10 +78,12 @@ QUICKTESTS = \ qquicklistview \ qquickloader \ qquickmousearea \ + qquickmultipointtoucharea \ qquickpathview \ qquickpincharea \ qquickpositioners \ qquickrepeater \ + qquickspriteimage \ qquicktext \ qquicktextedit \ qquicktextinput \ diff --git a/tests/auto/declarative/examples/examples.pro b/tests/auto/declarative/examples/examples.pro index e68a93c6d5..4ae24bb1a4 100644 --- a/tests/auto/declarative/examples/examples.pro +++ b/tests/auto/declarative/examples/examples.pro @@ -7,7 +7,5 @@ DEFINES += SRCDIR=\\\"$$PWD\\\" CONFIG += parallel_test #temporary -CONFIG += insignificant_test +CONFIG += insignificant_test #QTBUG-22672 QT += core-private gui-private declarative-private qtquick1-private widgets-private v8-private testlib - -qpa:CONFIG+=insignificant_test # QTBUG-20990, aborts diff --git a/tests/auto/declarative/qdeclarativeanimations/tst_qdeclarativeanimations.cpp b/tests/auto/declarative/qdeclarativeanimations/tst_qdeclarativeanimations.cpp index 6c375a5adf..b355a8097a 100644 --- a/tests/auto/declarative/qdeclarativeanimations/tst_qdeclarativeanimations.cpp +++ b/tests/auto/declarative/qdeclarativeanimations/tst_qdeclarativeanimations.cpp @@ -806,9 +806,11 @@ void tst_qdeclarativeanimations::attached() { QDeclarativeEngine engine; - QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("attached.qml"))); - QTest::ignoreMessage(QtDebugMsg, "off"); - QTest::ignoreMessage(QtDebugMsg, "on"); + QUrl url(QUrl::fromLocalFile(TESTDATA("attached.qml"))); + QDeclarativeComponent c(&engine, url); + QString messageFormat = QString(QLatin1String("%1 (%2:%3)")); + QTest::ignoreMessage(QtDebugMsg, messageFormat.arg(QLatin1String("off")).arg(url.toString()).arg(24).toLatin1()); + QTest::ignoreMessage(QtDebugMsg, messageFormat.arg(QLatin1String("on")).arg(url.toString()).arg(20).toLatin1()); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); QVERIFY(rect); } diff --git a/tests/auto/declarative/qdeclarativeapplication/tst_qdeclarativeapplication.cpp b/tests/auto/declarative/qdeclarativeapplication/tst_qdeclarativeapplication.cpp index db345e38fd..72313ab054 100644 --- a/tests/auto/declarative/qdeclarativeapplication/tst_qdeclarativeapplication.cpp +++ b/tests/auto/declarative/qdeclarativeapplication/tst_qdeclarativeapplication.cpp @@ -67,8 +67,6 @@ tst_qdeclarativeapplication::tst_qdeclarativeapplication() void tst_qdeclarativeapplication::active() { - QSKIP("QTBUG-21573"); - QDeclarativeComponent component(&engine); component.setData("import QtQuick 2.0; Item { property bool active: Qt.application.active }", QUrl::fromLocalFile("")); QQuickItem *item = qobject_cast<QQuickItem *>(component.create()); @@ -84,23 +82,28 @@ void tst_qdeclarativeapplication::active() view.show(); view.requestActivateWindow(); QTest::qWait(50); + QEXPECT_FAIL("", "QTBUG-21573", Abort); QTRY_COMPARE(view.status(), QQuickView::Ready); QCOMPARE(item->property("active").toBool(), QGuiApplication::activeWindow() != 0); - // not active again +#if 0 + // QGuiApplication has no equivalent of setActiveWindow(0). QTBUG-21573 + // Is this different to clearing the active state of the window or can it be removed? + // On Mac, setActiveWindow(0) on mac does not deactivate the current application, + // must switch to a different app or hide the current app to trigger this // on mac, setActiveWindow(0) on mac does not deactivate the current application // (you have to switch to a different app or hide the current app to trigger this) -#if !defined(Q_WS_MAC) -// QTBUG-21573 -// QGuiApplication::setActiveWindow(0); + + // not active again + QGuiApplication::setActiveWindow(0); QVERIFY(!item->property("active").toBool()); QCOMPARE(item->property("active").toBool(), QGuiApplication::activeWindow() != 0); #endif + } void tst_qdeclarativeapplication::layoutDirection() { - QSKIP("QTBUG-21573"); QDeclarativeComponent component(&engine); component.setData("import QtQuick 2.0; Item { property bool layoutDirection: Qt.application.layoutDirection }", QUrl::fromLocalFile("")); @@ -114,6 +117,7 @@ void tst_qdeclarativeapplication::layoutDirection() // mirrored QGuiApplication::setLayoutDirection(Qt::RightToLeft); + QEXPECT_FAIL("", "QTBUG-21573", Abort); QCOMPARE(Qt::LayoutDirection(item->property("layoutDirection").toInt()), Qt::RightToLeft); // not mirrored again diff --git a/tests/auto/declarative/qdeclarativebehaviors/data/startOnCompleted.qml b/tests/auto/declarative/qdeclarativebehaviors/data/startOnCompleted.qml new file mode 100644 index 0000000000..fdc3779a5c --- /dev/null +++ b/tests/auto/declarative/qdeclarativebehaviors/data/startOnCompleted.qml @@ -0,0 +1,15 @@ +import QtQuick 2.0 + +Rectangle { + width: 400 + height: 400 + + Rectangle { + id: innerRect + width: 100; height: 100 + color: "green" + Behavior on x { NumberAnimation {} } + } + + Component.onCompleted: innerRect.x = 100 +} diff --git a/tests/auto/declarative/qdeclarativebehaviors/data/valueType.qml b/tests/auto/declarative/qdeclarativebehaviors/data/valueType.qml new file mode 100644 index 0000000000..7bc8297dc7 --- /dev/null +++ b/tests/auto/declarative/qdeclarativebehaviors/data/valueType.qml @@ -0,0 +1,13 @@ +import QtQuick 2.0 +Rectangle { + width: 400 + height: 400 + + color.r: 1 + color.g: 0 + color.b: 1 + + Behavior on color.r { NumberAnimation { duration: 500; } } + + function changeR() { color.r = 0 } +} diff --git a/tests/auto/declarative/qdeclarativebehaviors/tst_qdeclarativebehaviors.cpp b/tests/auto/declarative/qdeclarativebehaviors/tst_qdeclarativebehaviors.cpp index 38a07eb3d4..35f8b6219d 100644 --- a/tests/auto/declarative/qdeclarativebehaviors/tst_qdeclarativebehaviors.cpp +++ b/tests/auto/declarative/qdeclarativebehaviors/tst_qdeclarativebehaviors.cpp @@ -66,6 +66,7 @@ private slots: void replaceBinding(); //void transitionOverrides(); void group(); + void valueType(); void emptyBehavior(); void explicitSelection(); void nonSelectingBehavior(); @@ -77,6 +78,7 @@ private slots: void runningTrue(); void sameValue(); void delayedRegistration(); + void startOnCompleted(); }; void tst_qdeclarativebehaviors::simpleBehavior() @@ -236,6 +238,19 @@ void tst_qdeclarativebehaviors::group() } } +void tst_qdeclarativebehaviors::valueType() +{ + QDeclarativeEngine engine; + QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("valueType.qml"))); + QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); + QVERIFY(rect); + + //QTBUG-20827 + QCOMPARE(rect->color(), QColor::fromRgb(255,0,255)); + + delete rect; +} + void tst_qdeclarativebehaviors::emptyBehavior() { QDeclarativeEngine engine; @@ -433,6 +448,25 @@ void tst_qdeclarativebehaviors::delayedRegistration() QTRY_COMPARE(innerRect->property("x").toInt(), int(100)); } +//QTBUG-22555 +void tst_qdeclarativebehaviors::startOnCompleted() +{ + QDeclarativeEngine engine; + + QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("startOnCompleted.qml"))); + QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); + QVERIFY(rect != 0); + + QQuickItem *innerRect = rect->findChild<QQuickRectangle*>(); + QVERIFY(innerRect != 0); + + QCOMPARE(innerRect->property("x").toInt(), int(0)); + + QTRY_COMPARE(innerRect->property("x").toInt(), int(100)); + + delete rect; +} + QTEST_MAIN(tst_qdeclarativebehaviors) #include "tst_qdeclarativebehaviors.moc" diff --git a/tests/auto/declarative/qdeclarativecontext/data/RefreshExpressionsType.qml b/tests/auto/declarative/qdeclarativecontext/data/RefreshExpressionsType.qml new file mode 100644 index 0000000000..b7c3427c85 --- /dev/null +++ b/tests/auto/declarative/qdeclarativecontext/data/RefreshExpressionsType.qml @@ -0,0 +1,5 @@ +import QtQuick 2.0 + +QtObject { + property var dummy: countCommand.doCommand(); +} diff --git a/tests/auto/declarative/qdeclarativecontext/data/refreshExpressions.qml b/tests/auto/declarative/qdeclarativecontext/data/refreshExpressions.qml new file mode 100644 index 0000000000..01e503f8dc --- /dev/null +++ b/tests/auto/declarative/qdeclarativecontext/data/refreshExpressions.qml @@ -0,0 +1,6 @@ +import QtQuick 2.0 + +QtObject { + property variant v1: RefreshExpressionsType {} + property variant v2: RefreshExpressionsType {} +} diff --git a/tests/auto/declarative/qdeclarativecontext/data/refreshExpressionsRootContext.qml b/tests/auto/declarative/qdeclarativecontext/data/refreshExpressionsRootContext.qml new file mode 100644 index 0000000000..bd82cd9552 --- /dev/null +++ b/tests/auto/declarative/qdeclarativecontext/data/refreshExpressionsRootContext.qml @@ -0,0 +1,6 @@ +import QtQuick 2.0 + +QtObject { + property var dummy: countCommand.doCommand(), unresolvedName +} + diff --git a/tests/auto/declarative/qdeclarativecontext/qdeclarativecontext.pro b/tests/auto/declarative/qdeclarativecontext/qdeclarativecontext.pro index 65af53a45d..5e48bec033 100644 --- a/tests/auto/declarative/qdeclarativecontext/qdeclarativecontext.pro +++ b/tests/auto/declarative/qdeclarativecontext/qdeclarativecontext.pro @@ -3,6 +3,10 @@ TARGET = tst_qdeclarativecontext SOURCES += tst_qdeclarativecontext.cpp macx:CONFIG -= app_bundle +testDataFiles.files = data +testDataFiles.path = . +DEPLOYMENT += testDataFiles + CONFIG += parallel_test -QT += core-private gui-private declarative-private testlib +QT += core-private gui-private declarative-private testlib v8-private diff --git a/tests/auto/declarative/qdeclarativecontext/tst_qdeclarativecontext.cpp b/tests/auto/declarative/qdeclarativecontext/tst_qdeclarativecontext.cpp index c241acac05..68599a2e83 100644 --- a/tests/auto/declarative/qdeclarativecontext/tst_qdeclarativecontext.cpp +++ b/tests/auto/declarative/qdeclarativecontext/tst_qdeclarativecontext.cpp @@ -45,6 +45,18 @@ #include <QDeclarativeContext> #include <QDeclarativeComponent> #include <QDeclarativeExpression> +#include <private/qdeclarativecontext_p.h> +#include "../shared/util.h" + +inline QUrl TEST_FILE(const QString &filename) +{ + return QUrl::fromLocalFile(TESTDATA(filename)); +} + +inline QUrl TEST_FILE(const char *filename) +{ + return TEST_FILE(QLatin1String(filename)); +} class tst_qdeclarativecontext : public QObject { @@ -64,6 +76,10 @@ private slots: void readOnlyContexts(); void nameForObject(); + void refreshExpressions(); + void refreshExpressionsCrash(); + void refreshExpressionsRootContext(); + private: QDeclarativeEngine engine; }; @@ -490,6 +506,144 @@ void tst_qdeclarativecontext::nameForObject() delete o; } +class DeleteCommand : public QObject +{ +Q_OBJECT +public: + DeleteCommand() : object(0) {} + + QObject *object; + +public slots: + void doCommand() { if (object) delete object; object = 0; } +}; + +// Calling refresh expressions would crash if an expression or context was deleted during +// the refreshing +void tst_qdeclarativecontext::refreshExpressionsCrash() +{ + { + QDeclarativeEngine engine; + + DeleteCommand command; + engine.rootContext()->setContextProperty("deleteCommand", &command); + // We use a fresh context here to bypass any root-context optimizations in + // the engine + QDeclarativeContext ctxt(engine.rootContext()); + + QDeclarativeComponent component(&engine); + component.setData("import QtQuick 2.0; QtObject { property var binding: deleteCommand.doCommand() }", QUrl()); + QVERIFY(component.isReady()); + + QObject *o1 = component.create(&ctxt); + QObject *o2 = component.create(&ctxt); + + command.object = o2; + + QDeclarativeContextData::get(&ctxt)->refreshExpressions(); + + delete o1; + } + { + QDeclarativeEngine engine; + + DeleteCommand command; + engine.rootContext()->setContextProperty("deleteCommand", &command); + // We use a fresh context here to bypass any root-context optimizations in + // the engine + QDeclarativeContext ctxt(engine.rootContext()); + + QDeclarativeComponent component(&engine); + component.setData("import QtQuick 2.0; QtObject { property var binding: deleteCommand.doCommand() }", QUrl()); + QVERIFY(component.isReady()); + + QObject *o1 = component.create(&ctxt); + QObject *o2 = component.create(&ctxt); + + command.object = o1; + + QDeclarativeContextData::get(&ctxt)->refreshExpressions(); + + delete o2; + } +} + +class CountCommand : public QObject +{ +Q_OBJECT +public: + CountCommand() : count(0) {} + + int count; + +public slots: + void doCommand() { ++count; } +}; + + +// Test that calling refresh expressions causes all the expressions to refresh +void tst_qdeclarativecontext::refreshExpressions() +{ + QDeclarativeEngine engine; + QDeclarativeComponent component(&engine, TEST_FILE("refreshExpressions.qml")); + QDeclarativeComponent component2(&engine, TEST_FILE("RefreshExpressionsType.qml")); + + CountCommand command; + engine.rootContext()->setContextProperty("countCommand", &command); + + // We use a fresh context here to bypass any root-context optimizations in + // the engine + QDeclarativeContext context(engine.rootContext()); + QDeclarativeContext context2(&context); + + QObject *o1 = component.create(&context); + QObject *o2 = component.create(&context2); + QObject *o3 = component2.create(&context); + + QCOMPARE(command.count, 5); + + QDeclarativeContextData::get(&context)->refreshExpressions(); + + QCOMPARE(command.count, 10); + + delete o3; + delete o2; + delete o1; +} + +// Test that updating the root context, only causes expressions in contexts with an +// unresolved name to reevaluate +void tst_qdeclarativecontext::refreshExpressionsRootContext() +{ + QDeclarativeEngine engine; + + CountCommand command; + engine.rootContext()->setContextProperty("countCommand", &command); + + QDeclarativeComponent component(&engine, TEST_FILE("refreshExpressions.qml")); + QDeclarativeComponent component2(&engine, TEST_FILE("refreshExpressionsRootContext.qml")); + + QDeclarativeContext context(engine.rootContext()); + QDeclarativeContext context2(engine.rootContext()); + + QString warning = component2.url().toString() + QLatin1String(":4: ReferenceError: Can't find variable: unresolvedName"); + + QObject *o1 = component.create(&context); + + QTest::ignoreMessage(QtWarningMsg, qPrintable(warning)); + QObject *o2 = component2.create(&context2); + + QCOMPARE(command.count, 3); + + QTest::ignoreMessage(QtWarningMsg, qPrintable(warning)); + QDeclarativeContextData::get(engine.rootContext())->refreshExpressions(); + + QCOMPARE(command.count, 4); + + delete o2; + delete o1; +} + QTEST_MAIN(tst_qdeclarativecontext) #include "tst_qdeclarativecontext.moc" diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/SequenceConversionComponent.qml b/tests/auto/declarative/qdeclarativeecmascript/data/SequenceConversionComponent.qml new file mode 100644 index 0000000000..0c7f60b062 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/SequenceConversionComponent.qml @@ -0,0 +1,7 @@ +import QtQuick 2.0 +import Qt.test 1.0 + +MySequenceConversionObject { + id: sccmsco + objectName: "sccmsco" +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/deleteWhileBindingRunning.qml b/tests/auto/declarative/qdeclarativeecmascript/data/deleteWhileBindingRunning.qml new file mode 100644 index 0000000000..b5cc59e2c0 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/deleteWhileBindingRunning.qml @@ -0,0 +1,5 @@ +import Qt.test 1.0 + +MyDeleteObject { + property int result: nestedObject.intProperty + deleteNestedObject +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/forInLoop.qml b/tests/auto/declarative/qdeclarativeecmascript/data/forInLoop.qml new file mode 100644 index 0000000000..f14367f177 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/forInLoop.qml @@ -0,0 +1,13 @@ +import QtQuick 2.0 + +QtObject { + property list<QtObject> objects + objects: [QtObject { objectName: "obj1" }, QtObject { objectName: "obj2" }, QtObject { objectName: "obj3" }] + property string listResult + + function listProperty() { + for (var i in objects) + listResult += i + "=" + objects[i].objectName + "|" + } +} + diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/nonNotifyable.qml b/tests/auto/declarative/qdeclarativeecmascript/data/nonNotifyable.qml new file mode 100644 index 0000000000..2b8b113c34 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/nonNotifyable.qml @@ -0,0 +1,6 @@ +import Qt.test 1.0 + +MyQmlObject { + id: root + property int test: root.value +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/qtbug_20344.qml b/tests/auto/declarative/qdeclarativeecmascript/data/qtbug_20344.qml new file mode 100644 index 0000000000..f490848caf --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/qtbug_20344.qml @@ -0,0 +1,6 @@ +import QtQuick 2.0 +import Qt.test 1.0 + +MyQmlObject { + Component.onCompleted: v8function() +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/readonlyDeclaration.qml b/tests/auto/declarative/qdeclarativeecmascript/data/readonlyDeclaration.qml new file mode 100644 index 0000000000..5377d2dcbf --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/readonlyDeclaration.qml @@ -0,0 +1,45 @@ +import QtQuick 2.0 + +QtObject { + property int dummy: 13 + + readonly property int test1: 19 + readonly property int test2: dummy * 49 + readonly property alias test3: other.test + + property bool test: false + + property var dummyObj: QtObject { + id: other + property int test: 9 + } + + Component.onCompleted: { + if (test1 != 19) return; + if (test2 != 637) return; + if (test3 != 9) return; + + var caught = false; + + caught = false; + try { test1 = 13 } catch (e) { caught = true; } + if (!caught) return; + + caught = false; + try { test2 = 13 } catch (e) { caught = true; } + if (!caught) return; + + caught = false; + try { test3 = 13 } catch (e) { caught = true; } + if (!caught) return; + + other.test = 13; + dummy = 9; + + if (test1 != 19) return; + if (test2 != 441) return; + if (test3 != 13) return; + + test = true; + } +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.array.qml b/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.array.qml new file mode 100644 index 0000000000..5eaa225708 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.array.qml @@ -0,0 +1,152 @@ +import QtQuick 2.0 +import Qt.test 1.0 + +Item { + id: root + objectName: "root" + + MySequenceConversionObject { + id: msco + objectName: "msco" + } + + property bool success: false + + property variant intList + property variant qrealList + property variant boolList + property variant stringList + + function indexedAccess() { + intList = msco.intListProperty; + var jsIntList = msco.intListProperty; + qrealList = msco.qrealListProperty; + var jsQrealList = msco.qrealListProperty; + boolList = msco.boolListProperty; + var jsBoolList = msco.boolListProperty; + stringList = msco.stringListProperty; + var jsStringList = msco.stringListProperty; + + // Three cases: direct property modification, variant copy modification, js var reference modification. + // Only the first and third should "write back" to the original QObject Q_PROPERTY; the second one + // should have no effect whatsoever to maintain "property variant" semantics (see e.g., valuetype). + success = true; + + msco.intListProperty[1] = 33; + if (msco.intListProperty[1] != 33) success = false; // ensure write back + intList[1] = 44; + if (intList[1] == 44) success = false; // ensure no effect + jsIntList[1] = 55; + if (jsIntList[1] != 55 + || jsIntList[1] != msco.intListProperty[1]) success = false; // ensure write back + + msco.qrealListProperty[1] = 33.3; + if (msco.qrealListProperty[1] != 33.3) success = false; // ensure write back + qrealList[1] = 44.4; + if (qrealList[1] == 44.4) success = false; // ensure no effect + jsQrealList[1] = 55.5; + if (jsQrealList[1] != 55.5 + || jsQrealList[1] != msco.qrealListProperty[1]) success = false; // ensure write back + + msco.boolListProperty[1] = true; + if (msco.boolListProperty[1] != true) success = false; // ensure write back + boolList[1] = true; + if (boolList[1] != false) success = false; // ensure no effect + jsBoolList[1] = false; + if (jsBoolList[1] != false + || jsBoolList[1] != msco.boolListProperty[1]) success = false; // ensure write back + + msco.stringListProperty[1] = "changed"; + if (msco.stringListProperty[1] != "changed") success = false; // ensure write back + stringList[1] = "changed"; + if (stringList[1] != "second") success = false; // ensure no effect + jsStringList[1] = "different"; + if (jsStringList[1] != "different" + || jsStringList[1] != msco.stringListProperty[1]) success = false; // ensure write back + } + + function arrayOperations() { + success = true; + var expected = 0; + var expectedStr = ""; + + // ecma262r3 defines array as implementing Length and Put. Test put here. + msco.intListProperty.asdf = 5; // shouldn't work, only indexes are valid names. + if (msco.intListProperty.asdf == 5) success = false; + msco.intListProperty[3] = 38; // should work. + if (msco.intListProperty[3] != 38) success = false; + msco.intListProperty[199] = 200; // should work, and should set length to 200. + if (msco.intListProperty[199] != 200) success = false; + if (msco.intListProperty.length != 200) success = false; + + // other operations are defined on the array prototype; see if they work. + msco.intListProperty = [ 0, 1, 2, 3, 4, 5, 6, 7 ]; + msco.intListProperty.splice(1,3, 33, 44, 55, 66); + expected = [ 0, 33, 44, 55, 66, 4, 5, 6, 7 ]; + if (msco.intListProperty.toString() != expected.toString()) success = false; + + msco.qrealListProperty = [ 0.1, 1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1 ]; + msco.qrealListProperty.splice(1,3, 33.33, 44.44, 55.55, 66.66); + expected = [ 0.1, 33.33, 44.44, 55.55, 66.66, 4.1, 5.1, 6.1, 7.1 ]; + if (msco.qrealListProperty.toString() != expected.toString()) success = false; + + msco.boolListProperty = [ false, true, true, false, false, true, false, true ]; + msco.boolListProperty.splice(1,3, false, true, false, false); + expected = [ false, false, true, false, false, false, true, false, true ]; + if (msco.boolListProperty.toString() != expected.toString()) success = false; + + msco.stringListProperty = [ "one", "two", "three", "four", "five", "six", "seven", "eight" ]; + msco.stringListProperty.splice(1,3, "nine", "ten", "eleven", "twelve"); + expected = [ "one", "nine", "ten", "eleven", "twelve", "five", "six", "seven", "eight" ]; + if (msco.stringListProperty.toString() != expected.toString()) success = false; + } + + property variant variantList: [ 1, 2, 3, 4, 5 ]; + property variant variantList2: [ 1, 2, 3, 4, 5 ]; + function testEqualitySemantics() { + // ensure equality semantics match JS array equality semantics + success = true; + + msco.intListProperty = [ 1, 2, 3, 4, 5 ]; + msco.intListProperty2 = [ 1, 2, 3, 4, 5 ]; + var jsIntList = [ 1, 2, 3, 4, 5 ]; + var jsIntList2 = [ 1, 2, 3, 4, 5 ]; + + if (jsIntList != jsIntList) success = false; + if (jsIntList == jsIntList2) success = false; + if (jsIntList == msco.intListProperty) success = false; + if (jsIntList == variantList) success = false; + + if (msco.intListProperty != msco.intListProperty) success = false; + if (msco.intListProperty == msco.intListProperty2) success = false; + if (msco.intListProperty == jsIntList) success = false; + if (msco.intListProperty == variantList) success = false; + + if (variantList == variantList) return false; + if (variantList == variantList2) return false; + if (variantList == msco.intListProperty) return false; + if (variantList == jsIntList) return false; + + if ((jsIntList == jsIntList2) != (jsIntList == msco.intListProperty)) success = false; + if ((jsIntList == jsIntList2) != (msco.intListProperty == msco.intListProperty2)) success = false; + if ((jsIntList == jsIntList) != (msco.intListProperty == msco.intListProperty)) success = false; + if ((jsIntList == variantList) != (msco.intListProperty == variantList)) success = false; + if ((variantList == jsIntList) != (variantList == msco.intListProperty)) success = false; + if ((msco.intListProperty == variantList) != (variantList == msco.intListProperty)) success = false; + } + + property bool referenceDeletion: false + function testReferenceDeletion() { + referenceDeletion = true; + var testObj = msco.generateTestObject(); + testObj.intListProperty = [1, 2, 3, 4, 5]; + var testSequence = testObj.intListProperty; + var prevString = testSequence.toString(); + var prevValueOf = testSequence.valueOf(); + var prevLength = testSequence.length; + msco.deleteTestObject(testObj); // delete referenced object. + if (testSequence.toString() == prevString) referenceDeletion = false; + if (testSequence.valueOf() == prevValueOf) referenceDeletion = false; + if (testSequence.length == prevLength) referenceDeletion = false; + } +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.bindings.error.qml b/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.bindings.error.qml new file mode 100644 index 0000000000..9c87dd293e --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.bindings.error.qml @@ -0,0 +1,19 @@ +import QtQuick 2.0 +import Qt.test 1.0 + +Item { + id: root + objectName: "root" + + MySequenceConversionObject { + id: msco + objectName: "msco" + intListProperty: [ 1, 2, 3, 6, 7 ] + } + + MySequenceConversionObject { + id: mscoTwo + objectName: "mscoTwo" + boolListProperty: msco.intListProperty + } +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.bindings.qml b/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.bindings.qml new file mode 100644 index 0000000000..8d83e9f9f5 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.bindings.qml @@ -0,0 +1,28 @@ +import QtQuick 2.0 +import Qt.test 1.0 + +Item { + id: root + objectName: "root" + + MySequenceConversionObject { + id: msco + objectName: "msco" + intListProperty: [ 1, 2, 3, 6, 7 ] + } + + MySequenceConversionObject { + id: mscoTwo + objectName: "mscoTwo" + intListProperty: msco.intListProperty + } + + property variant boundSequence: msco.intListProperty + property int boundElement: msco.intListProperty[3] + property variant boundSequenceTwo: mscoTwo.intListProperty + + Component.onCompleted: { + msco.intListProperty[3] = 12; + mscoTwo.intListProperty[4] = 14; + } +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.copy.qml b/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.copy.qml new file mode 100644 index 0000000000..f6614dad0c --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.copy.qml @@ -0,0 +1,160 @@ +import QtQuick 2.0 +import Qt.test 1.0 + +Item { + id: root + objectName: "root" + + MySequenceConversionObject { + id: msco + objectName: "msco" + } + + property bool success: true + + property variant intList + property variant qrealList + property variant boolList + property variant stringList + property variant urlList + property variant qstringList + + // this test ensures that the "copy resource" codepaths work + function testCopySequences() { + success = true; + + // create "copy resource" sequences + var jsIntList = msco.generateIntSequence(); + var jsQrealList = msco.generateQrealSequence(); + var jsBoolList = msco.generateBoolSequence(); + var jsStringList = msco.generateStringSequence(); + var jsUrlList = msco.generateUrlSequence(); + var jsQStringList = msco.generateQStringSequence(); + + if (jsIntList.toString() != [1, 2, 3].toString()) + success = false; + if (jsQrealList.toString() != [1.1, 2.2, 3.3].toString()) + success = false; + if (jsBoolList.toString() != [true, false, true].toString()) + success = false; + if (jsStringList.toString() != ["one", "two", "three"].toString()) + success = false; + if (jsUrlList.toString() != ["http://www.example1.com", "http://www.example2.com", "http://www.example3.com"].toString()) + success = false; + if (jsQStringList.toString() != ["one", "two", "three"].toString()) + success = false; + + // copy the sequence; should result in a new copy + intList = jsIntList; + qrealList = jsQrealList; + boolList = jsBoolList; + stringList = jsStringList; + urlList = jsUrlList; + qstringList = jsQStringList; + + // these operations shouldn't modify either variables - because + // we don't handle writing to the intermediate variant at list[index] + // for variant properties. + intList[1] = 8; + qrealList[1] = 8.8; + boolList[1] = true; + stringList[1] = "eight"; + urlList[1] = "http://www.example8.com"; + qstringList[1] = "eight"; + + if (jsIntList[1] == 8) + success = false; + if (jsQrealList[1] == 8.8) + success = false; + if (jsBoolList[1] == true) + success = false; + if (jsStringList[1] == "eight") + success = false; + if (jsUrlList[1] == "http://www.example8.com") + success = false; + if (jsQStringList[1] == "eight") + success = false; + + // assign a "copy resource" sequence to a QObject Q_PROPERTY + msco.intListProperty = intList; + msco.qrealListProperty = qrealList; + msco.boolListProperty = boolList; + msco.stringListProperty = stringList; + msco.urlListProperty = urlList; + msco.qstringListProperty = qstringList; + + if (msco.intListProperty.toString() != [1, 2, 3].toString()) + success = false; + if (msco.qrealListProperty.toString() != [1.1, 2.2, 3.3].toString()) + success = false; + if (msco.boolListProperty.toString() != [true, false, true].toString()) + success = false; + if (msco.stringListProperty.toString() != ["one", "two", "three"].toString()) + success = false; + if (msco.urlListProperty.toString() != ["http://www.example1.com", "http://www.example2.com", "http://www.example3.com"].toString()) + success = false; + if (msco.qstringListProperty.toString() != ["one", "two", "three"].toString()) + success = false; + + // now modify the QObject Q_PROPERTY (reference resource) sequences - shouldn't modify the copy resource sequences. + msco.intListProperty[2] = 9; + msco.qrealListProperty[2] = 9.9; + msco.boolListProperty[2] = false; + msco.stringListProperty[2] = "nine"; + msco.urlListProperty[2] = "http://www.example9.com"; + msco.qstringListProperty[2] = "nine"; + + if (intList[2] == 9) + success = false; + if (qrealList[2] == 9.9) + success = false; + if (boolList[2] == false) + success = false; + if (stringList[2] == "nine") + success = false; + if (urlList[2] == "http://www.example9.com") + success = false; + if (qstringList[2] == "nine") + success = false; + } + + property int intVal + property real qrealVal + property bool boolVal + property string stringVal + + // this test ensures that indexed access works for copy resource sequences. + function readSequenceCopyElements() { + success = true; + + var jsIntList = msco.generateIntSequence(); + var jsQrealList = msco.generateQrealSequence(); + var jsBoolList = msco.generateBoolSequence(); + var jsStringList = msco.generateStringSequence(); + + intVal = jsIntList[1]; + qrealVal = jsQrealList[1]; + boolVal = jsBoolList[1]; + stringVal = jsStringList[1]; + + if (intVal != 2) + success = false; + if (qrealVal != 2.2) + success = false; + if (boolVal != false) + success = false; + if (stringVal != "two") + success = false; + } + + // this test ensures that equality works for copy resource sequences. + function testEqualitySemantics() { + success = true; + + var jsIntList = msco.generateIntSequence(); + var jsIntList2 = msco.generateIntSequence(); + + if (jsIntList == jsIntList2) success = false; + if (jsIntList != jsIntList) success = false; + } +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.read.error.qml b/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.read.error.qml new file mode 100644 index 0000000000..12a76d7e7d --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.read.error.qml @@ -0,0 +1,21 @@ +import QtQuick 2.0 +import Qt.test 1.0 + +Item { + id: root + objectName: "root" + + MySequenceConversionObject { + id: msco + objectName: "msco" + } + + property int pointListLength: 0 + property variant pointList + + function performTest() { + // we have NOT registered QList<QPoint> as a type + pointListLength = msco.pointListProperty.length; + pointList = msco.pointListProperty; + } +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.read.qml b/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.read.qml new file mode 100644 index 0000000000..4a8a4a17b2 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.read.qml @@ -0,0 +1,105 @@ +import QtQuick 2.0 +import Qt.test 1.0 + +Item { + id: root + objectName: "root" + + MySequenceConversionObject { + id: msco + objectName: "msco" + } + + property int intListLength: 0 + property variant intList + property int qrealListLength: 0 + property variant qrealList + property int boolListLength: 0 + property variant boolList + property int stringListLength: 0 + property variant stringList + property int urlListLength: 0 + property variant urlList + property int qstringListLength: 0 + property variant qstringList + + function readSequences() { + intListLength = msco.intListProperty.length; + intList = msco.intListProperty; + qrealListLength = msco.qrealListProperty.length; + qrealList = msco.qrealListProperty; + boolListLength = msco.boolListProperty.length; + boolList = msco.boolListProperty; + stringListLength = msco.stringListProperty.length; + stringList = msco.stringListProperty; + urlListLength = msco.urlListProperty.length; + urlList = msco.urlListProperty; + qstringListLength = msco.qstringListProperty.length; + qstringList = msco.qstringListProperty; + } + + property int intVal + property real qrealVal + property bool boolVal + property string stringVal + property url urlVal + property string qstringVal + + function readSequenceElements() { + intVal = msco.intListProperty[1]; + qrealVal = msco.qrealListProperty[1]; + boolVal = msco.boolListProperty[1]; + stringVal = msco.stringListProperty[1]; + urlVal = msco.urlListProperty[1]; + qstringVal = msco.qstringListProperty[1]; + } + + property bool enumerationMatches + function enumerateSequenceElements() { + var jsIntList = [1, 2, 3, 4, 5]; + msco.intListProperty = [1, 2, 3, 4, 5]; + + var jsIntListProps = [] + var seqIntListProps = [] + + enumerationMatches = true; + for (var i in jsIntList) { + jsIntListProps.push(i); + if (jsIntList[i] != msco.intListProperty[i]) { + enumerationMatches = false; + } + } + for (var j in msco.intListProperty) { + seqIntListProps.push(j); + if (jsIntList[j] != msco.intListProperty[j]) { + enumerationMatches = false; + } + } + + if (jsIntListProps.length != seqIntListProps.length) { + enumerationMatches = false; + } + + var emptyList = []; + msco.stringListProperty = [] + if (emptyList.toString() != msco.stringListProperty.toString()) { + enumerationMatches = false; + } + if (emptyList.valueOf() != msco.stringListProperty.valueOf()) { + enumerationMatches = false; + } + } + + property bool referenceDeletion: false + function testReferenceDeletion() { + referenceDeletion = true; + var testObj = msco.generateTestObject(); + testObj.intListProperty = [1, 2, 3, 4, 5]; + var testSequence = testObj.intListProperty; + if (testSequence[4] != 5) + referenceDeletion = false; + msco.deleteTestObject(testObj); // delete referenced object. + if (testSequence[4] == 5) + referenceDeletion = false; + } +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.threads.qml b/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.threads.qml new file mode 100644 index 0000000000..aefad89ca4 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.threads.qml @@ -0,0 +1,74 @@ +import QtQuick 2.0 +import Qt.test 1.0 + +Item { + id: root + objectName: "root" + + MySequenceConversionObject { + id: msco + objectName: "msco" + } + + property bool success: false + property bool finished: false + + function testIntSequence() { + msco.intListProperty = [ 0, 1, 2, 3, 4, 5, 6, 7 ]; + worker.sendSequence(msco.intListProperty); + } + + function testQrealSequence() { + msco.qrealListProperty = [ 0.1, 1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1 ]; + worker.sendSequence(msco.qrealListProperty); + } + + function testBoolSequence() { + msco.boolListProperty = [ false, true, true, false, false, true, false, true ]; + worker.sendSequence(msco.boolListProperty); + } + + function testStringSequence() { + msco.stringListProperty = [ "one", "two", "three", "four" ]; + worker.sendSequence(msco.stringListProperty); + } + + function testQStringSequence() { + msco.qstringListProperty = [ "one", "two", "three", "four" ]; + worker.sendSequence(msco.qstringListProperty); + } + + function testUrlSequence() { + msco.urlListProperty = [ "www.example1.com", "www.example2.com", "www.example3.com", "www.example4.com" ]; + worker.sendSequence(msco.urlListProperty); + } + + function testVariantSequence() { + msco.variantListProperty = [ "one", true, 3, "four" ]; + worker.sendSequence(msco.variantListProperty); + } + + WorkerScript { + id: worker + source: "threadScript.js" + + property variant expected + property variant response + + function sendSequence(seq) { + root.success = false; + root.finished = false; + worker.expected = seq; + worker.sendMessage(seq); + } + + onMessage: { + worker.response = messageObject; + if (worker.response.toString() == worker.expected.toString()) + root.success = true; + else + root.success = false; + root.finished = true; + } + } +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.write.error.qml b/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.write.error.qml new file mode 100644 index 0000000000..75beafd1ee --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.write.error.qml @@ -0,0 +1,18 @@ +import QtQuick 2.0 +import Qt.test 1.0 + +Item { + id: root + objectName: "root" + + MySequenceConversionObject { + id: msco + objectName: "msco" + } + + function performTest() { + // we have NOT registered QList<QPoint> as a type + var pointList = [ Qt.point(7,7), Qt.point(8,8), Qt.point(9,9) ]; + msco.pointListProperty = pointList; // error. + } +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.write.qml b/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.write.qml new file mode 100644 index 0000000000..812de043b7 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.write.qml @@ -0,0 +1,109 @@ +import QtQuick 2.0 +import Qt.test 1.0 + +Item { + id: root + objectName: "root" + + MySequenceConversionObject { + id: msco + objectName: "msco" + } + + property bool success + + function writeSequences() { + success = true; + + var intList = [ 9, 8, 7, 6 ]; + msco.intListProperty = intList; + var qrealList = [ 9.9, 8.8, 7.7, 6.6 ]; + msco.qrealListProperty = qrealList; + var boolList = [ false, false, false, true ]; + msco.boolListProperty = boolList; + var stringList = [ "nine", "eight", "seven", "six" ] + msco.stringListProperty = stringList; + var urlList = [ "http://www.example9.com", "http://www.example8.com", "http://www.example7.com", "http://www.example6.com" ] + msco.urlListProperty = urlList; + var qstringList = [ "nine", "eight", "seven", "six" ] + msco.qstringListProperty = qstringList; + + if (msco.intListProperty[0] != 9 || msco.intListProperty[1] != 8 || msco.intListProperty[2] != 7 || msco.intListProperty[3] != 6) + success = false; + if (msco.qrealListProperty[0] != 9.9 || msco.qrealListProperty[1] != 8.8 || msco.qrealListProperty[2] != 7.7 || msco.qrealListProperty[3] != 6.6) + success = false; + if (msco.boolListProperty[0] != false || msco.boolListProperty[1] != false || msco.boolListProperty[2] != false || msco.boolListProperty[3] != true) + success = false; + if (msco.stringListProperty[0] != "nine" || msco.stringListProperty[1] != "eight" || msco.stringListProperty[2] != "seven" || msco.stringListProperty[3] != "six") + success = false; + if (msco.urlListProperty[0] != "http://www.example9.com" || msco.urlListProperty[1] != "http://www.example8.com" || msco.urlListProperty[2] != "http://www.example7.com" || msco.urlListProperty[3] != "http://www.example6.com") + success = false; + if (msco.qstringListProperty[0] != "nine" || msco.qstringListProperty[1] != "eight" || msco.qstringListProperty[2] != "seven" || msco.qstringListProperty[3] != "six") + success = false; + } + + function writeSequenceElements() { + // set up initial conditions. + writeSequences(); + success = true; + + // element set. + msco.intListProperty[3] = 2; + msco.qrealListProperty[3] = 2.2; + msco.boolListProperty[3] = false; + msco.stringListProperty[3] = "changed"; + msco.urlListProperty[3] = "http://www.examplechanged.com"; + msco.qstringListProperty[3] = "changed"; + + if (msco.intListProperty[0] != 9 || msco.intListProperty[1] != 8 || msco.intListProperty[2] != 7 || msco.intListProperty[3] != 2) + success = false; + if (msco.qrealListProperty[0] != 9.9 || msco.qrealListProperty[1] != 8.8 || msco.qrealListProperty[2] != 7.7 || msco.qrealListProperty[3] != 2.2) + success = false; + if (msco.boolListProperty[0] != false || msco.boolListProperty[1] != false || msco.boolListProperty[2] != false || msco.boolListProperty[3] != false) + success = false; + if (msco.stringListProperty[0] != "nine" || msco.stringListProperty[1] != "eight" || msco.stringListProperty[2] != "seven" || msco.stringListProperty[3] != "changed") + success = false; + if (msco.urlListProperty[0] != "http://www.example9.com" || msco.urlListProperty[1] != "http://www.example8.com" || msco.urlListProperty[2] != "http://www.example7.com" || msco.urlListProperty[3] != "http://www.examplechanged.com") + success = false; + if (msco.qstringListProperty[0] != "nine" || msco.qstringListProperty[1] != "eight" || msco.qstringListProperty[2] != "seven" || msco.qstringListProperty[3] != "changed") + success = false; + } + + function writeOtherElements() { + success = true; + var jsIntList = [1, 2, 3, 4, 5]; + msco.intListProperty = [1, 2, 3, 4, 5]; + + jsIntList[8] = 8; + msco.intListProperty[8] = 8; + if (jsIntList[8] != msco.intListProperty[8]) + success = false; + if (jsIntList.length != msco.intListProperty.length) + success = false; + + // NOTE: we can't exactly match the spec here -- we fill the sequence with a default (rather than empty) value + if (msco.intListProperty[5] != 0 || msco.intListProperty[6] != 0 || msco.intListProperty[7] != 0) + success = false; + + // should have no effect + var currLength = jsIntList.length; + jsIntList.someThing = 9; + msco.intListProperty.someThing = 9; + if (msco.intListProperty.length != currLength) + success = false; + } + + property bool referenceDeletion: false + function testReferenceDeletion() { + referenceDeletion = true; + var testObj = msco.generateTestObject(); + testObj.intListProperty = [1, 2, 3, 4, 5]; + var testSequence = testObj.intListProperty; + if (testSequence[4] != 5) + referenceDeletion = false; + msco.deleteTestObject(testObj); // delete referenced object. + testSequence[4] = 5; // shouldn't work, since referenced object no longer exists. + if (testSequence[4] == 5) + referenceDeletion = false; + } +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/threadScript.js b/tests/auto/declarative/qdeclarativeecmascript/data/threadScript.js new file mode 100644 index 0000000000..9f94de1bc1 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/threadScript.js @@ -0,0 +1,4 @@ +WorkerScript.onMessage = function(msg) { + WorkerScript.sendMessage(msg); +} + diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/typeOf.js b/tests/auto/declarative/qdeclarativeecmascript/data/typeOf.js new file mode 100644 index 0000000000..16a34234c0 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/typeOf.js @@ -0,0 +1,25 @@ +var test1 = typeof a + +var b = {} +var test2 = typeof b + +var c = 5 +var test3 = typeof c + +var d = "hello world" +var test4 = typeof d + +var e = function() {} +var test5 = typeof e + +var f = null +var test6 = typeof f + +var g = undefined +var test7 = typeof g + +var h = true +var test8 = typeof h + +var i = [] +var test9 = typeof i diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/typeOf.qml b/tests/auto/declarative/qdeclarativeecmascript/data/typeOf.qml new file mode 100644 index 0000000000..28f7debed5 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/typeOf.qml @@ -0,0 +1,26 @@ +import QtQuick 2.0 +import "typeOf.js" as TypeOf + +QtObject { + property string test1 + property string test2 + property string test3 + property string test4 + property string test5 + property string test6 + property string test7 + property string test8 + property string test9 + + Component.onCompleted: { + test1 = TypeOf.test1 + test2 = TypeOf.test2 + test3 = TypeOf.test3 + test4 = TypeOf.test4 + test5 = TypeOf.test5 + test6 = TypeOf.test6 + test7 = TypeOf.test7 + test8 = TypeOf.test8 + test9 = TypeOf.test9 + } +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/testtypes.cpp b/tests/auto/declarative/qdeclarativeecmascript/testtypes.cpp index 513705d697..721c719911 100644 --- a/tests/auto/declarative/qdeclarativeecmascript/testtypes.cpp +++ b/tests/auto/declarative/qdeclarativeecmascript/testtypes.cpp @@ -101,6 +101,12 @@ public: void setWidth(int) { } }; +void MyQmlObject::v8function(QDeclarativeV8Function *args) +{ + const char *error = "Exception thrown from within QObject slot"; + v8::ThrowException(v8::Exception::Error(v8::String::New(error))); +} + static QJSValue script_api(QDeclarativeEngine *engine, QJSEngine *scriptEngine) { Q_UNUSED(engine) @@ -161,6 +167,7 @@ void registerTypes() qmlRegisterExtendedType<DefaultPropertyExtendedObject, DefaultPropertyExtensionObject>("Qt.test", 1,0, "DefaultPropertyExtendedObject"); qmlRegisterType<OverrideDefaultPropertyObject>("Qt.test", 1,0, "OverrideDefaultPropertyObject"); qmlRegisterType<MyRevisionedClass>("Qt.test",1,0,"MyRevisionedClass"); + qmlRegisterType<MyDeleteObject>("Qt.test", 1,0, "MyDeleteObject"); qmlRegisterType<MyRevisionedClass,1>("Qt.test",1,1,"MyRevisionedClass"); // test scarce resource property binding post-evaluation optimisation @@ -196,6 +203,8 @@ void registerTypes() qmlRegisterType<MyDynamicCreationDestructionObject>("Qt.test", 1, 0, "MyDynamicCreationDestructionObject"); qmlRegisterType<WriteCounter>("Qt.test", 1, 0, "WriteCounter"); + + qmlRegisterType<MySequenceConversionObject>("Qt.test", 1, 0, "MySequenceConversionObject"); } #include "testtypes.moc" diff --git a/tests/auto/declarative/qdeclarativeecmascript/testtypes.h b/tests/auto/declarative/qdeclarativeecmascript/testtypes.h index 7684ddd438..06cc561c7f 100644 --- a/tests/auto/declarative/qdeclarativeecmascript/testtypes.h +++ b/tests/auto/declarative/qdeclarativeecmascript/testtypes.h @@ -59,6 +59,7 @@ #include <private/qv8gccallback_p.h> #include <private/qdeclarativeengine_p.h> +#include <private/qv8engine_p.h> class MyQmlAttachedObject : public QObject { @@ -184,6 +185,7 @@ public slots: void setString(const QString &s) { m_string = s; } void myinvokable(MyQmlObject *o) { myinvokableObject = o; } void variantMethod(const QVariant &v) { m_variant = v; } + void v8function(QDeclarativeV8Function*); private: friend class tst_qdeclarativeecmascript; @@ -1148,6 +1150,113 @@ private: int m_count; }; +class MySequenceConversionObject : public QObject +{ + Q_OBJECT + + Q_PROPERTY (QList<int> intListProperty READ intListProperty WRITE setIntListProperty NOTIFY intListPropertyChanged) + Q_PROPERTY (QList<int> intListProperty2 READ intListProperty2 WRITE setIntListProperty2 NOTIFY intListProperty2Changed) + Q_PROPERTY (QList<qreal> qrealListProperty READ qrealListProperty WRITE setQrealListProperty NOTIFY qrealListPropertyChanged) + Q_PROPERTY (QList<bool> boolListProperty READ boolListProperty WRITE setBoolListProperty NOTIFY boolListPropertyChanged) + Q_PROPERTY (QList<QString> stringListProperty READ stringListProperty WRITE setStringListProperty NOTIFY stringListPropertyChanged) + Q_PROPERTY (QList<QUrl> urlListProperty READ urlListProperty WRITE setUrlListProperty NOTIFY urlListPropertyChanged) + Q_PROPERTY (QStringList qstringListProperty READ qstringListProperty WRITE setQStringListProperty NOTIFY qstringListPropertyChanged) + + Q_PROPERTY (QList<QPoint> pointListProperty READ pointListProperty WRITE setPointListProperty NOTIFY pointListPropertyChanged) + Q_PROPERTY (QList<QVariant> variantListProperty READ variantListProperty WRITE setVariantListProperty NOTIFY variantListPropertyChanged) + +public: + MySequenceConversionObject() + { + m_intList << 1 << 2 << 3 << 4; + m_intList2 << 1 << 2 << 3 << 4; + m_qrealList << 1.1 << 2.2 << 3.3 << 4.4; + m_boolList << true << false << true << false; + m_stringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth"); + m_urlList << QUrl("http://www.example1.com") << QUrl("http://www.example2.com") << QUrl("http://www.example3.com"); + m_qstringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth"); + + m_pointList << QPoint(1, 2) << QPoint(3, 4) << QPoint(5, 6); + m_variantList << QVariant(QLatin1String("one")) << QVariant(true) << QVariant(3); + } + + ~MySequenceConversionObject() {} + + QList<int> intListProperty() const { return m_intList; } + void setIntListProperty(const QList<int> &list) { m_intList = list; emit intListPropertyChanged(); } + QList<int> intListProperty2() const { return m_intList2; } + void setIntListProperty2(const QList<int> &list) { m_intList2 = list; emit intListProperty2Changed(); } + QList<qreal> qrealListProperty() const { return m_qrealList; } + void setQrealListProperty(const QList<qreal> &list) { m_qrealList = list; emit qrealListPropertyChanged(); } + QList<bool> boolListProperty() const { return m_boolList; } + void setBoolListProperty(const QList<bool> &list) { m_boolList = list; emit boolListPropertyChanged(); } + QList<QString> stringListProperty() const { return m_stringList; } + void setStringListProperty(const QList<QString> &list) { m_stringList = list; emit stringListPropertyChanged(); } + QList<QUrl> urlListProperty() const { return m_urlList; } + void setUrlListProperty(const QList<QUrl> &list) { m_urlList = list; emit urlListPropertyChanged(); } + QStringList qstringListProperty() const { return m_qstringList; } + void setQStringListProperty(const QStringList &list) { m_qstringList = list; emit qstringListPropertyChanged(); } + QList<QPoint> pointListProperty() const { return m_pointList; } + void setPointListProperty(const QList<QPoint> &list) { m_pointList = list; emit pointListPropertyChanged(); } + QList<QVariant> variantListProperty() const { return m_variantList; } + void setVariantListProperty(const QList<QVariant> &list) { m_variantList = list; emit variantListPropertyChanged(); } + + // now for "copy resource" sequences: + Q_INVOKABLE QList<int> generateIntSequence() const { QList<int> retn; retn << 1 << 2 << 3; return retn; } + Q_INVOKABLE QList<qreal> generateQrealSequence() const { QList<qreal> retn; retn << 1.1 << 2.2 << 3.3; return retn; } + Q_INVOKABLE QList<bool> generateBoolSequence() const { QList<bool> retn; retn << true << false << true; return retn; } + Q_INVOKABLE QList<QString> generateStringSequence() const { QList<QString> retn; retn << "one" << "two" << "three"; return retn; } + Q_INVOKABLE QList<QUrl> generateUrlSequence() const { QList<QUrl> retn; retn << QUrl("http://www.example1.com") << QUrl("http://www.example2.com") << QUrl("http://www.example3.com"); return retn; } + Q_INVOKABLE QStringList generateQStringSequence() const { QStringList retn; retn << "one" << "two" << "three"; return retn; } + + // "reference resource" underlying qobject deletion test: + Q_INVOKABLE MySequenceConversionObject *generateTestObject() const { return new MySequenceConversionObject; } + Q_INVOKABLE void deleteTestObject(QObject *object) const { delete object; } + +signals: + void intListPropertyChanged(); + void intListProperty2Changed(); + void qrealListPropertyChanged(); + void boolListPropertyChanged(); + void stringListPropertyChanged(); + void urlListPropertyChanged(); + void qstringListPropertyChanged(); + void pointListPropertyChanged(); + void variantListPropertyChanged(); + +private: + QList<int> m_intList; + QList<int> m_intList2; + QList<qreal> m_qrealList; + QList<bool> m_boolList; + QList<QString> m_stringList; + QList<QUrl> m_urlList; + QStringList m_qstringList; + + QList<QPoint> m_pointList; // not a supported sequence type + QList<QVariant> m_variantList; // not a supported sequence type, but QVariantList support is hardcoded. +}; + +class MyDeleteObject : public QObject +{ + Q_OBJECT + Q_PROPERTY(QObject *nestedObject READ nestedObject NOTIFY nestedObjectChanged); + Q_PROPERTY(int deleteNestedObject READ deleteNestedObject NOTIFY deleteNestedObjectChanged); + +public: + MyDeleteObject() : m_nestedObject(new MyQmlObject) {} + + QObject *nestedObject() const { return m_nestedObject; } + int deleteNestedObject() { delete m_nestedObject; m_nestedObject = 0; return 1; } + +signals: + void nestedObjectChanged(); + void deleteNestedObjectChanged(); + +private: + MyQmlObject *m_nestedObject; +}; + void registerTypes(); #endif // TESTTYPES_H diff --git a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp index 40072c9e60..492ed739b2 100644 --- a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp +++ b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp @@ -51,6 +51,7 @@ #include <private/qdeclarativeengine_p.h> #include <private/qv8gccallback_p.h> #include <private/qdeclarativevmemetaobject_p.h> +#include <private/qv4compiler_p.h> #include "testtypes.h" #include "testhttpserver.h" #include "../shared/util.h" @@ -169,6 +170,13 @@ private slots: void booleanConversion(); void handleReferenceManagement(); void stringArg(); + void readonlyDeclaration(); + void sequenceConversionRead(); + void sequenceConversionWrite(); + void sequenceConversionArray(); + void sequenceConversionThreads(); + void sequenceConversionBindings(); + void sequenceConversionCopy(); void bug1(); void bug2(); @@ -195,6 +203,7 @@ private slots: void nonscriptable(); void deleteLater(); void in(); + void typeOf(); void sharedAttachedObject(); void objectName(); void writeRemovesBinding(); @@ -207,11 +216,13 @@ private slots: void include(); void signalHandlers(); void doubleEvaluate(); - + void forInLoop(); + void nonNotifyable(); + void deleteWhileBindingRunning(); void callQtInvokables(); void invokableObjectArg(); void invokableObjectRet(); - + void qtbug_20344(); void revisionErrors(); void revision(); @@ -1579,7 +1590,8 @@ void tst_qdeclarativeecmascript::shutdownErrors() void tst_qdeclarativeecmascript::compositePropertyType() { QDeclarativeComponent component(&engine, TEST_FILE("compositePropertyType.qml")); - QTest::ignoreMessage(QtDebugMsg, "hello world"); + QString messageFormat = QString(QLatin1String("hello world (%1:%2)")).arg(TEST_FILE("compositePropertyType.qml").toString()).arg(7); + QTest::ignoreMessage(QtDebugMsg, qPrintable(messageFormat)); QObject *object = qobject_cast<QObject *>(component.create()); delete object; } @@ -4034,6 +4046,248 @@ void tst_qdeclarativeecmascript::stringArg() delete object; } +void tst_qdeclarativeecmascript::readonlyDeclaration() +{ + QDeclarativeComponent component(&engine, TEST_FILE("readonlyDeclaration.qml")); + + QObject *object = component.create(); + QVERIFY(object != 0); + + QCOMPARE(object->property("test").toBool(), true); + + delete object; +} + +Q_DECLARE_METATYPE(QList<int>) +Q_DECLARE_METATYPE(QList<qreal>) +Q_DECLARE_METATYPE(QList<bool>) +Q_DECLARE_METATYPE(QList<QString>) +Q_DECLARE_METATYPE(QList<QUrl>) +void tst_qdeclarativeecmascript::sequenceConversionRead() +{ + { + QUrl qmlFile = TEST_FILE("sequenceConversion.read.qml"); + QDeclarativeComponent component(&engine, qmlFile); + QObject *object = component.create(); + QVERIFY(object != 0); + MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco"); + QVERIFY(seq != 0); + + QMetaObject::invokeMethod(object, "readSequences"); + QList<int> intList; intList << 1 << 2 << 3 << 4; + QCOMPARE(object->property("intListLength").toInt(), intList.length()); + QCOMPARE(object->property("intList").value<QList<int> >(), intList); + QList<qreal> qrealList; qrealList << 1.1 << 2.2 << 3.3 << 4.4; + QCOMPARE(object->property("qrealListLength").toInt(), qrealList.length()); + QCOMPARE(object->property("qrealList").value<QList<qreal> >(), qrealList); + QList<bool> boolList; boolList << true << false << true << false; + QCOMPARE(object->property("boolListLength").toInt(), boolList.length()); + QCOMPARE(object->property("boolList").value<QList<bool> >(), boolList); + QList<QString> stringList; stringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth"); + QCOMPARE(object->property("stringListLength").toInt(), stringList.length()); + QCOMPARE(object->property("stringList").value<QList<QString> >(), stringList); + QList<QUrl> urlList; urlList << QUrl("http://www.example1.com") << QUrl("http://www.example2.com") << QUrl("http://www.example3.com"); + QCOMPARE(object->property("urlListLength").toInt(), urlList.length()); + QCOMPARE(object->property("urlList").value<QList<QUrl> >(), urlList); + QStringList qstringList; qstringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth"); + QCOMPARE(object->property("qstringListLength").toInt(), qstringList.length()); + QCOMPARE(object->property("qstringList").value<QStringList>(), qstringList); + + QMetaObject::invokeMethod(object, "readSequenceElements"); + QCOMPARE(object->property("intVal").toInt(), 2); + QCOMPARE(object->property("qrealVal").toReal(), 2.2); + QCOMPARE(object->property("boolVal").toBool(), false); + QCOMPARE(object->property("stringVal").toString(), QString(QLatin1String("second"))); + QCOMPARE(object->property("urlVal").toUrl(), QUrl("http://www.example2.com")); + QCOMPARE(object->property("qstringVal").toString(), QString(QLatin1String("second"))); + + QMetaObject::invokeMethod(object, "enumerateSequenceElements"); + QCOMPARE(object->property("enumerationMatches").toBool(), true); + + intList.clear(); intList << 1 << 2 << 3 << 4 << 5; // set by the enumerateSequenceElements test. + QDeclarativeProperty seqProp(seq, "intListProperty"); + QCOMPARE(seqProp.read().value<QList<int> >(), intList); + QDeclarativeProperty seqProp2(seq, "intListProperty", &engine); + QCOMPARE(seqProp2.read().value<QList<int> >(), intList); + + QMetaObject::invokeMethod(object, "testReferenceDeletion"); + QCOMPARE(object->property("referenceDeletion").toBool(), true); + + delete object; + } + + { + QUrl qmlFile = TEST_FILE("sequenceConversion.read.error.qml"); + QDeclarativeComponent component(&engine, qmlFile); + QObject *object = component.create(); + QVERIFY(object != 0); + MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco"); + QVERIFY(seq != 0); + + // we haven't registered QList<QPoint> as a sequence type. + QString warningOne = QLatin1String("QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'"); + QString warningTwo = qmlFile.toString() + QLatin1String(":18: TypeError: Cannot read property 'length' of undefined"); + QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData()); + QTest::ignoreMessage(QtWarningMsg, warningTwo.toAscii().constData()); + + QMetaObject::invokeMethod(object, "performTest"); + + // QList<QPoint> has not been registered as a sequence type. + QCOMPARE(object->property("pointListLength").toInt(), 0); + QVERIFY(!object->property("pointList").isValid()); + QTest::ignoreMessage(QtWarningMsg, "QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'"); + QDeclarativeProperty seqProp(seq, "pointListProperty", &engine); + QVERIFY(!seqProp.read().isValid()); // not a valid/known sequence type + + delete object; + } +} + +void tst_qdeclarativeecmascript::sequenceConversionWrite() +{ + { + QUrl qmlFile = TEST_FILE("sequenceConversion.write.qml"); + QDeclarativeComponent component(&engine, qmlFile); + QObject *object = component.create(); + QVERIFY(object != 0); + MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco"); + QVERIFY(seq != 0); + + QMetaObject::invokeMethod(object, "writeSequences"); + QCOMPARE(object->property("success").toBool(), true); + + QMetaObject::invokeMethod(object, "writeSequenceElements"); + QCOMPARE(object->property("success").toBool(), true); + + QMetaObject::invokeMethod(object, "writeOtherElements"); + QCOMPARE(object->property("success").toBool(), true); + + QMetaObject::invokeMethod(object, "testReferenceDeletion"); + QCOMPARE(object->property("referenceDeletion").toBool(), true); + + delete object; + } + + { + QUrl qmlFile = TEST_FILE("sequenceConversion.write.error.qml"); + QDeclarativeComponent component(&engine, qmlFile); + QObject *object = component.create(); + QVERIFY(object != 0); + MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco"); + QVERIFY(seq != 0); + + // we haven't registered QList<QPoint> as a sequence type, so writing shouldn't work. + QString warningOne = qmlFile.toString() + QLatin1String(":16: Error: Cannot assign QVariantList to void"); + QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData()); + + QMetaObject::invokeMethod(object, "performTest"); + + QList<QPoint> pointList; pointList << QPoint(1, 2) << QPoint(3, 4) << QPoint(5, 6); // original values, shouldn't have changed + QCOMPARE(seq->pointListProperty(), pointList); + + delete object; + } +} + +void tst_qdeclarativeecmascript::sequenceConversionArray() +{ + // ensure that in JS the returned sequences act just like normal JS Arrays. + QUrl qmlFile = TEST_FILE("sequenceConversion.array.qml"); + QDeclarativeComponent component(&engine, qmlFile); + QObject *object = component.create(); + QVERIFY(object != 0); + //QMetaObject::invokeMethod(object, "indexedAccess"); + //QVERIFY(object->property("success").toBool()); + //QMetaObject::invokeMethod(object, "arrayOperations"); + //QVERIFY(object->property("success").toBool()); + QMetaObject::invokeMethod(object, "testEqualitySemantics"); + QVERIFY(object->property("success").toBool()); + //QMetaObject::invokeMethod(object, "testReferenceDeletion"); + //QCOMPARE(object->property("referenceDeletion").toBool(), true); + delete object; +} + +void tst_qdeclarativeecmascript::sequenceConversionThreads() +{ + // ensure that sequence conversion operations work correctly in a worker thread + // and that serialisation between the main and worker thread succeeds. + QUrl qmlFile = TEST_FILE("sequenceConversion.threads.qml"); + QDeclarativeComponent component(&engine, qmlFile); + QObject *object = component.create(); + QVERIFY(object != 0); + + QMetaObject::invokeMethod(object, "testIntSequence"); + QTRY_VERIFY(object->property("finished").toBool()); + QVERIFY(object->property("success").toBool()); + + QMetaObject::invokeMethod(object, "testQrealSequence"); + QTRY_VERIFY(object->property("finished").toBool()); + QVERIFY(object->property("success").toBool()); + + QMetaObject::invokeMethod(object, "testBoolSequence"); + QTRY_VERIFY(object->property("finished").toBool()); + QVERIFY(object->property("success").toBool()); + + QMetaObject::invokeMethod(object, "testStringSequence"); + QTRY_VERIFY(object->property("finished").toBool()); + QVERIFY(object->property("success").toBool()); + + QMetaObject::invokeMethod(object, "testQStringSequence"); + QTRY_VERIFY(object->property("finished").toBool()); + QVERIFY(object->property("success").toBool()); + + QMetaObject::invokeMethod(object, "testUrlSequence"); + QTRY_VERIFY(object->property("finished").toBool()); + QVERIFY(object->property("success").toBool()); + + QMetaObject::invokeMethod(object, "testVariantSequence"); + QTRY_VERIFY(object->property("finished").toBool()); + QVERIFY(object->property("success").toBool()); + + delete object; +} + +void tst_qdeclarativeecmascript::sequenceConversionBindings() +{ + { + QUrl qmlFile = TEST_FILE("sequenceConversion.bindings.qml"); + QDeclarativeComponent component(&engine, qmlFile); + QObject *object = component.create(); + QVERIFY(object != 0); + QList<int> intList; intList << 1 << 2 << 3 << 12 << 7; + QCOMPARE(object->property("boundSequence").value<QList<int> >(), intList); + QCOMPARE(object->property("boundElement").toInt(), intList.at(3)); + QList<int> intListTwo; intListTwo << 1 << 2 << 3 << 12 << 14; + QCOMPARE(object->property("boundSequenceTwo").value<QList<int> >(), intListTwo); + delete object; + } + + { + QUrl qmlFile = TEST_FILE("sequenceConversion.bindings.error.qml"); + QString warning = QString(QLatin1String("%1:17: Unable to assign QList<int> to QList<bool>")).arg(qmlFile.toString()); + QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData()); + QDeclarativeComponent component(&engine, qmlFile); + QObject *object = component.create(); + QVERIFY(object != 0); + delete object; + } +} + +void tst_qdeclarativeecmascript::sequenceConversionCopy() +{ + QUrl qmlFile = TEST_FILE("sequenceConversion.copy.qml"); + QDeclarativeComponent component(&engine, qmlFile); + QObject *object = component.create(); + QVERIFY(object != 0); + QMetaObject::invokeMethod(object, "testCopySequences"); + QCOMPARE(object->property("success").toBool(), true); + QMetaObject::invokeMethod(object, "readSequenceCopyElements"); + QCOMPARE(object->property("success").toBool(), true); + QMetaObject::invokeMethod(object, "testEqualitySemantics"); + QCOMPARE(object->property("success").toBool(), true); + delete object; +} + // Test that assigning a null object works // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4 void tst_qdeclarativeecmascript::nullObjectBinding() @@ -4109,7 +4363,8 @@ void tst_qdeclarativeecmascript::qtbug_9792() MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context)); QVERIFY(object != 0); - QTest::ignoreMessage(QtDebugMsg, "Hello world!"); + QString message = QString(QLatin1String("Hello world! (%1:%2)")).arg(TEST_FILE("qtbug_9792.qml").toString()).arg(4); + QTest::ignoreMessage(QtDebugMsg, qPrintable(message)); object->basicSignal(); delete context; @@ -4511,6 +4766,25 @@ void tst_qdeclarativeecmascript::in() delete o; } +void tst_qdeclarativeecmascript::typeOf() +{ + QDeclarativeComponent component(&engine, TEST_FILE("typeOf.qml")); + QObject *o = component.create(); + QVERIFY(o != 0); + QEXPECT_FAIL("", "QTBUG-21864", Abort); + QCOMPARE(o->property("test1").toString(), QLatin1String("undefined")); + QCOMPARE(o->property("test2").toString(), QLatin1String("object")); + QCOMPARE(o->property("test3").toString(), QLatin1String("number")); + QCOMPARE(o->property("test4").toString(), QLatin1String("string")); + QCOMPARE(o->property("test5").toString(), QLatin1String("function")); + QCOMPARE(o->property("test6").toString(), QLatin1String("object")); + QCOMPARE(o->property("test7").toString(), QLatin1String("undefined")); + QCOMPARE(o->property("test8").toString(), QLatin1String("boolean")); + QCOMPARE(o->property("test9").toString(), QLatin1String("object")); + + delete o; +} + void tst_qdeclarativeecmascript::sharedAttachedObject() { QDeclarativeComponent component(&engine, TEST_FILE("sharedAttachedObject.qml")); @@ -4642,6 +4916,19 @@ void tst_qdeclarativeecmascript::aliasToCompositeElement() delete object; } +void tst_qdeclarativeecmascript::qtbug_20344() +{ + QDeclarativeComponent component(&engine, TEST_FILE("qtbug_20344.qml")); + + QString warning = component.url().toString() + ":5: Error: Exception thrown from within QObject slot"; + QTest::ignoreMessage(QtWarningMsg, qPrintable(warning)); + + QObject *object = component.create(); + QVERIFY(object != 0); + + delete object; +} + void tst_qdeclarativeecmascript::revisionErrors() { { @@ -4780,6 +5067,67 @@ void tst_qdeclarativeecmascript::doubleEvaluate() delete object; } +static QStringList messages; +static void captureMsgHandler(QtMsgType, const char *msg) +{ + messages.append(QLatin1String(msg)); +} + +void tst_qdeclarativeecmascript::nonNotifyable() +{ + QV4Compiler::enableV4(false); + QDeclarativeComponent component(&engine, TEST_FILE("nonNotifyable.qml")); + QV4Compiler::enableV4(true); + + QtMsgHandler old = qInstallMsgHandler(captureMsgHandler); + messages.clear(); + QObject *object = component.create(); + qInstallMsgHandler(old); + + QVERIFY(object != 0); + + QString expected1 = QLatin1String("QDeclarativeExpression: Expression ") + + component.url().toString() + + QLatin1String(":5 depends on non-NOTIFYable properties:"); + QString expected2 = QLatin1String(" ") + + QLatin1String(object->metaObject()->className()) + + QLatin1String("::value"); + + QCOMPARE(messages.length(), 2); + QCOMPARE(messages.at(0), expected1); + QCOMPARE(messages.at(1), expected2); + + delete object; +} + +void tst_qdeclarativeecmascript::forInLoop() +{ + QDeclarativeComponent component(&engine, TEST_FILE("forInLoop.qml")); + QObject *object = component.create(); + QVERIFY(object != 0); + + QMetaObject::invokeMethod(object, "listProperty"); + + QStringList r = object->property("listResult").toString().split("|", QString::SkipEmptyParts); + QCOMPARE(r.size(), 3); + QCOMPARE(r[0],QLatin1String("0=obj1")); + QCOMPARE(r[1],QLatin1String("1=obj2")); + QCOMPARE(r[2],QLatin1String("2=obj3")); + + //TODO: should test for in loop for other objects (such as QObjects) as well. + + delete object; +} + +// An object the binding depends on is deleted while the binding is still running +void tst_qdeclarativeecmascript::deleteWhileBindingRunning() +{ + QDeclarativeComponent component(&engine, TEST_FILE("deleteWhileBindingRunning.qml")); + QObject *object = component.create(); + QVERIFY(object != 0); + delete object; +} + QTEST_MAIN(tst_qdeclarativeecmascript) #include "tst_qdeclarativeecmascript.moc" diff --git a/tests/auto/declarative/qdeclarativeexpression/tst_qdeclarativeexpression.cpp b/tests/auto/declarative/qdeclarativeexpression/tst_qdeclarativeexpression.cpp index a05c06f23f..a65045b48f 100644 --- a/tests/auto/declarative/qdeclarativeexpression/tst_qdeclarativeexpression.cpp +++ b/tests/auto/declarative/qdeclarativeexpression/tst_qdeclarativeexpression.cpp @@ -54,6 +54,7 @@ public: private slots: void scriptString(); + void syntaxError(); }; class TestObject : public QObject @@ -106,6 +107,15 @@ void tst_qdeclarativeexpression::scriptString() QCOMPARE(error.line(), 8); } +// QTBUG-21310 - crash test +void tst_qdeclarativeexpression::syntaxError() +{ + QDeclarativeEngine engine; + QDeclarativeExpression expression(engine.rootContext(), 0, "asd asd"); + QVariant v = expression.evaluate(); + QCOMPARE(v, QVariant()); +} + QTEST_MAIN(tst_qdeclarativeexpression) #include "tst_qdeclarativeexpression.moc" diff --git a/tests/auto/declarative/qdeclarativefontloader/data/qtbug-20268.qml b/tests/auto/declarative/qdeclarativefontloader/data/qtbug-20268.qml new file mode 100644 index 0000000000..0eafdfa17b --- /dev/null +++ b/tests/auto/declarative/qdeclarativefontloader/data/qtbug-20268.qml @@ -0,0 +1,27 @@ +import QtQuick 2.0 + +Rectangle { + id: test + property variant fontloader: fontloaderelement + height: 100; width: 100 + property bool usename: false + property int statenum: 1 + property alias name: fontloaderelement.name + property alias source: fontloaderelement.source + property alias status: fontloaderelement.status + + FontLoader { + id: fontloaderelement + } + + states: [ + State { name: "start"; when: !usename + PropertyChanges { target: fontloaderelement; source: "tarzeau_ocr_a.ttf" } + }, + State { name: "changefont"; when: usename + PropertyChanges { target: fontloaderelement; name: "Tahoma" } + } + ] + + Text { id: textelement; text: fontloaderelement.name; color: "black" } +} diff --git a/tests/auto/declarative/qdeclarativefontloader/tst_qdeclarativefontloader.cpp b/tests/auto/declarative/qdeclarativefontloader/tst_qdeclarativefontloader.cpp index 67a040dcf2..9831ac1087 100644 --- a/tests/auto/declarative/qdeclarativefontloader/tst_qdeclarativefontloader.cpp +++ b/tests/auto/declarative/qdeclarativefontloader/tst_qdeclarativefontloader.cpp @@ -46,6 +46,8 @@ #include <QtDeclarative/private/qdeclarativefontloader_p.h> #include "../shared/util.h" #include "../../declarative/shared/testhttpserver.h" +#include <QQuickView> +#include <QQuickItem> #define SERVER_PORT 14448 @@ -65,6 +67,7 @@ private slots: void redirWebFont(); void failWebFont(); void changeFont(); + void changeFontSourceViaState(); private: QDeclarativeEngine engine; @@ -220,6 +223,26 @@ void tst_qdeclarativefontloader::changeFont() QTRY_COMPARE(fontObject->name(), QString("Daniel")); } +void tst_qdeclarativefontloader::changeFontSourceViaState() +{ + QQuickView canvas(QUrl::fromLocalFile(TESTDATA("qtbug-20268.qml"))); + canvas.show(); + canvas.requestActivateWindow(); + QTest::qWaitForWindowShown(&canvas); + QTRY_COMPARE(&canvas, qGuiApp->focusWindow()); + + QDeclarativeFontLoader *fontObject = qobject_cast<QDeclarativeFontLoader*>(qvariant_cast<QObject *>(canvas.rootObject()->property("fontloader"))); + QVERIFY(fontObject != 0); + QTRY_VERIFY(fontObject->status() == QDeclarativeFontLoader::Ready); + QVERIFY(fontObject->source() != QUrl("")); + QTRY_COMPARE(fontObject->name(), QString("OCRA")); + + canvas.rootObject()->setProperty("usename", true); + QEXPECT_FAIL("", "QTBUG-20268", Abort); + QTRY_VERIFY(fontObject->status() == QDeclarativeFontLoader::Ready); + QCOMPARE(canvas.rootObject()->property("name").toString(), QString("Tahoma")); +} + QTEST_MAIN(tst_qdeclarativefontloader) #include "tst_qdeclarativefontloader.moc" diff --git a/tests/auto/declarative/qdeclarativeincubator/data/chainInCompletion.qml b/tests/auto/declarative/qdeclarativeincubator/data/chainInCompletion.qml new file mode 100644 index 0000000000..e79fed356a --- /dev/null +++ b/tests/auto/declarative/qdeclarativeincubator/data/chainInCompletion.qml @@ -0,0 +1,5 @@ +import Qt.test 1.0 + +SelfRegistering { + property variant a: CompletionCallback {} +} diff --git a/tests/auto/declarative/qdeclarativeincubator/testtypes.cpp b/tests/auto/declarative/qdeclarativeincubator/testtypes.cpp index 99d2cb1005..6d6fb38daf 100644 --- a/tests/auto/declarative/qdeclarativeincubator/testtypes.cpp +++ b/tests/auto/declarative/qdeclarativeincubator/testtypes.cpp @@ -101,9 +101,37 @@ void CallbackRegisteringType::registerCallback(callback c, void *d) m_data = d; } +CompletionCallbackType::callback CompletionCallbackType::m_callback = 0; +void *CompletionCallbackType::m_data = 0; +CompletionCallbackType::CompletionCallbackType() +{ +} + +void CompletionCallbackType::classBegin() +{ +} + +void CompletionCallbackType::componentComplete() +{ + if (m_callback) m_callback(this, m_data); +} + +void CompletionCallbackType::clearCallback() +{ + m_callback = 0; + m_data = 0; +} + +void CompletionCallbackType::registerCallback(callback c, void *d) +{ + m_callback = c; + m_data = d; +} + void registerTypes() { qmlRegisterType<SelfRegisteringType>("Qt.test", 1,0, "SelfRegistering"); qmlRegisterType<CompletionRegisteringType>("Qt.test", 1,0, "CompletionRegistering"); qmlRegisterType<CallbackRegisteringType>("Qt.test", 1,0, "CallbackRegistering"); + qmlRegisterType<CompletionCallbackType>("Qt.test", 1,0, "CompletionCallback"); } diff --git a/tests/auto/declarative/qdeclarativeincubator/testtypes.h b/tests/auto/declarative/qdeclarativeincubator/testtypes.h index 6e732548b2..8d9968de3c 100644 --- a/tests/auto/declarative/qdeclarativeincubator/testtypes.h +++ b/tests/auto/declarative/qdeclarativeincubator/testtypes.h @@ -100,6 +100,24 @@ private: static CompletionRegisteringType *m_me; }; +class CompletionCallbackType : public QObject, public QDeclarativeParserStatus +{ +Q_OBJECT +public: + CompletionCallbackType(); + + virtual void classBegin(); + virtual void componentComplete(); + + typedef void (*callback)(CompletionCallbackType *, void *); + static void clearCallback(); + static void registerCallback(callback, void *); + +private: + static callback m_callback; + static void *m_data; +}; + void registerTypes(); #endif // TESTTYPES_H diff --git a/tests/auto/declarative/qdeclarativeincubator/tst_qdeclarativeincubator.cpp b/tests/auto/declarative/qdeclarativeincubator/tst_qdeclarativeincubator.cpp index 684cd35613..54ca622753 100644 --- a/tests/auto/declarative/qdeclarativeincubator/tst_qdeclarativeincubator.cpp +++ b/tests/auto/declarative/qdeclarativeincubator/tst_qdeclarativeincubator.cpp @@ -83,6 +83,7 @@ private slots: void asynchronousIfNested(); void nestedComponent(); void chainedAsynchronousIfNested(); + void chainedAsynchronousIfNestedOnCompleted(); void selfDelete(); private: @@ -773,6 +774,134 @@ void tst_qdeclarativeincubator::chainedAsynchronousIfNested() QVERIFY(incubator2.isReady()); } +// Checks that new AsynchronousIfNested incubators can be correctly chained if started in +// componentCompleted(). +void tst_qdeclarativeincubator::chainedAsynchronousIfNestedOnCompleted() +{ + SelfRegisteringType::clearMe(); + + QDeclarativeComponent component(&engine, TEST_FILE("chainInCompletion.qml")); + QVERIFY(component.isReady()); + + QDeclarativeComponent c1(&engine, TEST_FILE("chainedAsynchronousIfNested.qml")); + QVERIFY(c1.isReady()); + + struct MyIncubator : public QDeclarativeIncubator { + MyIncubator(MyIncubator *next, QDeclarativeComponent *component, QDeclarativeContext *ctxt) + : QDeclarativeIncubator(AsynchronousIfNested), next(next), component(component), ctxt(ctxt) {} + + protected: + virtual void statusChanged(Status s) { + if (s == Ready && next) { + component->create(*next, 0, ctxt); + } + } + + private: + MyIncubator *next; + QDeclarativeComponent *component; + QDeclarativeContext *ctxt; + }; + + struct CallbackData { + CallbackData(QDeclarativeComponent *c, MyIncubator *i, QDeclarativeContext *ct) + : component(c), incubator(i), ctxt(ct) {} + QDeclarativeComponent *component; + MyIncubator *incubator; + QDeclarativeContext *ctxt; + static void callback(CompletionCallbackType *o, void *data) { + CallbackData *d = (CallbackData *)data; + d->component->create(*d->incubator, 0, d->ctxt); + } + }; + + QDeclarativeIncubator incubator(QDeclarativeIncubator::Asynchronous); + component.create(incubator); + + QVERIFY(incubator.isLoading()); + QVERIFY(SelfRegisteringType::me() == 0); + + while (SelfRegisteringType::me() == 0 && incubator.isLoading()) { + bool b = false; + controller.incubateWhile(&b); + } + + QVERIFY(SelfRegisteringType::me() != 0); + QVERIFY(incubator.isLoading()); + + MyIncubator incubator3(0, &c1, qmlContext(SelfRegisteringType::me())); + MyIncubator incubator2(&incubator3, &c1, qmlContext(SelfRegisteringType::me())); + MyIncubator incubator1(&incubator2, &c1, qmlContext(SelfRegisteringType::me())); + + // start incubator1 in componentComplete + CallbackData cd(&c1, &incubator1, qmlContext(SelfRegisteringType::me())); + CompletionCallbackType::registerCallback(&CallbackData::callback, &cd); + + while (!incubator1.isLoading()) { + QVERIFY(incubator.isLoading()); + QVERIFY(incubator2.isNull()); + QVERIFY(incubator3.isNull()); + + bool b = false; + controller.incubateWhile(&b); + } + + QVERIFY(incubator.isLoading()); + QVERIFY(incubator1.isLoading()); + QVERIFY(incubator2.isNull()); + QVERIFY(incubator3.isNull()); + + while (incubator1.isLoading()) { + QVERIFY(incubator.isLoading()); + QVERIFY(incubator1.isLoading()); + QVERIFY(incubator2.isNull()); + QVERIFY(incubator3.isNull()); + + bool b = false; + controller.incubateWhile(&b); + } + + QVERIFY(incubator.isLoading()); + QVERIFY(incubator1.isReady()); + QVERIFY(incubator2.isLoading()); + QVERIFY(incubator3.isNull()); + + while (incubator2.isLoading()) { + QVERIFY(incubator.isLoading()); + QVERIFY(incubator1.isReady()); + QVERIFY(incubator2.isLoading()); + QVERIFY(incubator3.isNull()); + + bool b = false; + controller.incubateWhile(&b); + } + + QVERIFY(incubator.isLoading()); + QVERIFY(incubator1.isReady()); + QVERIFY(incubator2.isReady()); + QVERIFY(incubator3.isLoading()); + + while (incubator3.isLoading()) { + QVERIFY(incubator.isLoading()); + QVERIFY(incubator1.isReady()); + QVERIFY(incubator2.isReady()); + QVERIFY(incubator3.isLoading()); + + bool b = false; + controller.incubateWhile(&b); + } + + { + bool b = true; + controller.incubateWhile(&b); + } + + QVERIFY(incubator.isReady()); + QVERIFY(incubator1.isReady()); + QVERIFY(incubator2.isReady()); + QVERIFY(incubator3.isReady()); +} + void tst_qdeclarativeincubator::selfDelete() { struct MyIncubator : public QDeclarativeIncubator { diff --git a/tests/auto/declarative/qdeclarativelanguage/data/ReadOnlyType.qml b/tests/auto/declarative/qdeclarativelanguage/data/ReadOnlyType.qml new file mode 100644 index 0000000000..456ac762fc --- /dev/null +++ b/tests/auto/declarative/qdeclarativelanguage/data/ReadOnlyType.qml @@ -0,0 +1,5 @@ +import QtQuick 2.0 + +QtObject { + readonly property int readOnlyProperty: 19 +} diff --git a/tests/auto/declarative/qdeclarativelanguage/data/property.5.errors.txt b/tests/auto/declarative/qdeclarativelanguage/data/property.5.errors.txt deleted file mode 100644 index 32a8dc11e1..0000000000 --- a/tests/auto/declarative/qdeclarativelanguage/data/property.5.errors.txt +++ /dev/null @@ -1 +0,0 @@ -4:5:Readonly not yet supported diff --git a/tests/auto/declarative/qdeclarativelanguage/data/property.5.qml b/tests/auto/declarative/qdeclarativelanguage/data/property.5.qml deleted file mode 100644 index a1401d2fdc..0000000000 --- a/tests/auto/declarative/qdeclarativelanguage/data/property.5.qml +++ /dev/null @@ -1,6 +0,0 @@ -import QtQuick 2.0 - -QtObject { - readonly property int a: value -} - diff --git a/tests/auto/declarative/qdeclarativelanguage/data/readOnly.5.errors.txt b/tests/auto/declarative/qdeclarativelanguage/data/readOnly.5.errors.txt index baf47667bc..e71ae4447c 100644 --- a/tests/auto/declarative/qdeclarativelanguage/data/readOnly.5.errors.txt +++ b/tests/auto/declarative/qdeclarativelanguage/data/readOnly.5.errors.txt @@ -1 +1 @@ -3:27:Invalid property assignment: "readOnlyEnumProperty" is a read-only property +2:23:Invalid property assignment: "readOnlyProperty" is a read-only property diff --git a/tests/auto/declarative/qdeclarativelanguage/data/readOnly.5.qml b/tests/auto/declarative/qdeclarativelanguage/data/readOnly.5.qml index 422d13d8d0..d80b27a1e3 100644 --- a/tests/auto/declarative/qdeclarativelanguage/data/readOnly.5.qml +++ b/tests/auto/declarative/qdeclarativelanguage/data/readOnly.5.qml @@ -1,4 +1,3 @@ -import Test 1.0 -MyTypeObject { - readOnlyEnumProperty: MyTypeObject.EnumValue1 +ReadOnlyType { + readOnlyProperty: 13 } diff --git a/tests/auto/declarative/qdeclarativelanguage/data/readonly.qml b/tests/auto/declarative/qdeclarativelanguage/data/readonly.qml new file mode 100644 index 0000000000..493a9ad502 --- /dev/null +++ b/tests/auto/declarative/qdeclarativelanguage/data/readonly.qml @@ -0,0 +1,17 @@ +import Test 1.0 + +MyQmlObject { + property int testData: 9 + property alias testData2: myObject.test1 + + readonly property int test1: 10 + readonly property int test2: testData + 9 + readonly property alias test3: myObject.test1 + + + property variant dummy: MyQmlObject { + id: myObject + property int test1: 13 + } +} + diff --git a/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp b/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp index 538ebbb1a3..a3fb5f0917 100644 --- a/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp +++ b/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp @@ -156,6 +156,7 @@ private slots: void inlineAssignmentsOverrideBindings(); void nestedComponentRoots(); void registrationOrder(); + void readonly(); void basicRemote_data(); void basicRemote(); @@ -364,7 +365,6 @@ void tst_qdeclarativelanguage::errors_data() QTest::newRow("property.2") << "property.2.qml" << "property.2.errors.txt" << false; QTest::newRow("property.3") << "property.3.qml" << "property.3.errors.txt" << false; QTest::newRow("property.4") << "property.4.qml" << "property.4.errors.txt" << false; - QTest::newRow("property.5") << "property.5.qml" << "property.5.errors.txt" << false; QTest::newRow("property.6") << "property.6.qml" << "property.6.errors.txt" << false; QTest::newRow("property.7") << "property.7.qml" << "property.7.errors.txt" << false; @@ -850,7 +850,8 @@ void tst_qdeclarativelanguage::dynamicObjectProperties() // Tests the declaration of dynamic signals and slots void tst_qdeclarativelanguage::dynamicSignalsAndSlots() { - QTest::ignoreMessage(QtDebugMsg, "1921"); + QString message = QString(QLatin1String("1921 (%1:%2)")).arg(TEST_FILE("dynamicSignalsAndSlots.qml").toString()).arg(9); + QTest::ignoreMessage(QtDebugMsg, qPrintable(message)); QDeclarativeComponent component(&engine, TEST_FILE("dynamicSignalsAndSlots.qml")); VERIFY_ERRORS(0); @@ -1288,9 +1289,10 @@ void tst_qdeclarativelanguage::onCompleted() { QDeclarativeComponent component(&engine, TEST_FILE("onCompleted.qml")); VERIFY_ERRORS(0); - QTest::ignoreMessage(QtDebugMsg, "Completed 6 10"); - QTest::ignoreMessage(QtDebugMsg, "Completed 6 10"); - QTest::ignoreMessage(QtDebugMsg, "Completed 10 11"); + QString formatMessage = QString(QLatin1String("%1 (%2:%3)")); + QTest::ignoreMessage(QtDebugMsg, formatMessage.arg(QLatin1String("Completed 6 10")).arg(TEST_FILE("onCompleted.qml").toString()).arg(8).toLatin1()); + QTest::ignoreMessage(QtDebugMsg, formatMessage.arg(QLatin1String("Completed 6 10")).arg(TEST_FILE("onCompleted.qml").toString()).arg(14).toLatin1()); + QTest::ignoreMessage(QtDebugMsg, formatMessage.arg(QLatin1String("Completed 10 11")).arg(TEST_FILE("OnCompletedType.qml").toString()).arg(7).toLatin1()); QObject *object = component.create(); QVERIFY(object != 0); } @@ -1302,10 +1304,10 @@ void tst_qdeclarativelanguage::onDestruction() VERIFY_ERRORS(0); QObject *object = component.create(); QVERIFY(object != 0); - - QTest::ignoreMessage(QtDebugMsg, "Destruction 6 10"); - QTest::ignoreMessage(QtDebugMsg, "Destruction 6 10"); - QTest::ignoreMessage(QtDebugMsg, "Destruction 10 11"); + QString formatMessage = QString(QLatin1String("%1 (%2:%3)")); + QTest::ignoreMessage(QtDebugMsg, formatMessage.arg(QLatin1String("Destruction 6 10")).arg(TEST_FILE("onDestruction.qml").toString()).arg(8).toLatin1()); + QTest::ignoreMessage(QtDebugMsg, formatMessage.arg(QLatin1String("Destruction 6 10")).arg(TEST_FILE("onDestruction.qml").toString()).arg(14).toLatin1()); + QTest::ignoreMessage(QtDebugMsg, formatMessage.arg(QLatin1String("Destruction 10 11")).arg(TEST_FILE("OnDestructionType.qml").toString()).arg(7).toLatin1()); delete object; } @@ -2142,6 +2144,40 @@ void tst_qdeclarativelanguage::registrationOrder() delete o; } +void tst_qdeclarativelanguage::readonly() +{ + QDeclarativeComponent component(&engine, TEST_FILE("readonly.qml")); + + QObject *o = component.create(); + QVERIFY(o != 0); + + QCOMPARE(o->property("test1").toInt(), 10); + QCOMPARE(o->property("test2").toInt(), 18); + QCOMPARE(o->property("test3").toInt(), 13); + + o->setProperty("testData", 13); + + QCOMPARE(o->property("test1").toInt(), 10); + QCOMPARE(o->property("test2").toInt(), 22); + QCOMPARE(o->property("test3").toInt(), 13); + + o->setProperty("testData2", 2); + + QCOMPARE(o->property("test1").toInt(), 10); + QCOMPARE(o->property("test2").toInt(), 22); + QCOMPARE(o->property("test3").toInt(), 2); + + o->setProperty("test1", 11); + o->setProperty("test2", 11); + o->setProperty("test3", 11); + + QCOMPARE(o->property("test1").toInt(), 10); + QCOMPARE(o->property("test2").toInt(), 22); + QCOMPARE(o->property("test3").toInt(), 2); + + delete o; +} + // QTBUG-18268 void tst_qdeclarativelanguage::remoteLoadCrash() { diff --git a/tests/auto/declarative/qdeclarativelistcompositor/tst_qdeclarativelistcompositor.cpp b/tests/auto/declarative/qdeclarativelistcompositor/tst_qdeclarativelistcompositor.cpp index 67bced6da8..425f35cc08 100644 --- a/tests/auto/declarative/qdeclarativelistcompositor/tst_qdeclarativelistcompositor.cpp +++ b/tests/auto/declarative/qdeclarativelistcompositor/tst_qdeclarativelistcompositor.cpp @@ -146,6 +146,10 @@ class tst_qdeclarativelistcompositor : public QObject } private slots: + void find_data(); + void find(); + void findInsertPosition_data(); + void findInsertPosition(); void insert(); void clearFlags_data(); void clearFlags(); @@ -164,6 +168,131 @@ private slots: void listItemsChanged(); }; +void tst_qdeclarativelistcompositor::find_data() +{ + QTest::addColumn<RangeList>("ranges"); + QTest::addColumn<C::Group>("startGroup"); + QTest::addColumn<int>("startIndex"); + QTest::addColumn<C::Group>("group"); + QTest::addColumn<int>("index"); + QTest::addColumn<int>("selectionIndex"); + QTest::addColumn<int>("visibleIndex"); + QTest::addColumn<int>("defaultIndex"); + QTest::addColumn<int>("cacheIndex"); + QTest::addColumn<int>("rangeFlags"); + QTest::addColumn<int>("rangeIndex"); + + int listA; void *a = &listA; + + QTest::newRow("Start") + << (RangeList() + << Range(a, 0, 1, int(C::PrependFlag | SelectionFlag | C::DefaultFlag | C::CacheFlag)) + << Range(a, 1, 1, int(C::AppendFlag | C::PrependFlag | C::CacheFlag)) + << Range(0, 0, 1, int(VisibleFlag| C::CacheFlag))) + << C::Cache << 2 + << Selection << 0 + << 0 << 0 << 0 << 0 + << int(C::PrependFlag | SelectionFlag | C::DefaultFlag | C::CacheFlag) << 0; +} + +void tst_qdeclarativelistcompositor::find() +{ + QFETCH(RangeList, ranges); + QFETCH(C::Group, startGroup); + QFETCH(int, startIndex); + QFETCH(C::Group, group); + QFETCH(int, index); + QFETCH(int, cacheIndex); + QFETCH(int, defaultIndex); + QFETCH(int, visibleIndex); + QFETCH(int, selectionIndex); + QFETCH(int, rangeFlags); + QFETCH(int, rangeIndex); + + QDeclarativeListCompositor compositor; + compositor.setGroupCount(4); + compositor.setDefaultGroups(VisibleFlag | C::DefaultFlag); + + foreach (const Range &range, ranges) + compositor.append(range.list, range.index, range.count, range.flags); + + compositor.find(startGroup, startIndex); + + QDeclarativeListCompositor::iterator it = compositor.find(group, index); + QCOMPARE(it.index[C::Cache], cacheIndex); + QCOMPARE(it.index[C::Default], defaultIndex); + QCOMPARE(it.index[Visible], visibleIndex); + QCOMPARE(it.index[Selection], selectionIndex); + QCOMPARE(it->flags, rangeFlags); + QCOMPARE(it->index, rangeIndex); +} + +void tst_qdeclarativelistcompositor::findInsertPosition_data() +{ + QTest::addColumn<RangeList>("ranges"); + QTest::addColumn<C::Group>("startGroup"); + QTest::addColumn<int>("startIndex"); + QTest::addColumn<C::Group>("group"); + QTest::addColumn<int>("index"); + QTest::addColumn<int>("selectionIndex"); + QTest::addColumn<int>("visibleIndex"); + QTest::addColumn<int>("defaultIndex"); + QTest::addColumn<int>("cacheIndex"); + QTest::addColumn<int>("rangeFlags"); + QTest::addColumn<int>("rangeIndex"); + + int listA; void *a = &listA; + + QTest::newRow("Start") + << (RangeList() + << Range(a, 0, 1, int(C::PrependFlag | SelectionFlag | C::DefaultFlag | C::CacheFlag)) + << Range(a, 1, 1, int(C::AppendFlag | C::PrependFlag | C::CacheFlag)) + << Range(0, 0, 1, int(VisibleFlag| C::CacheFlag))) + << C::Cache << 2 + << Selection << 0 + << 0 << 0 << 0 << 0 + << int(C::PrependFlag | SelectionFlag | C::DefaultFlag | C::CacheFlag) << 0; + QTest::newRow("1") + << (RangeList() + << Range(a, 0, 1, int(C::PrependFlag | SelectionFlag | C::DefaultFlag | C::CacheFlag)) + << Range(a, 1, 1, int(C::AppendFlag | C::PrependFlag | C::CacheFlag)) + << Range(0, 0, 1, int(VisibleFlag| C::CacheFlag))) + << C::Cache << 2 + << Selection << 1 + << 1 << 0 << 1 << 1 + << int(C::AppendFlag | C::PrependFlag | C::CacheFlag) << 1; +} + +void tst_qdeclarativelistcompositor::findInsertPosition() +{ + QFETCH(RangeList, ranges); + QFETCH(C::Group, startGroup); + QFETCH(int, startIndex); + QFETCH(C::Group, group); + QFETCH(int, index); + QFETCH(int, cacheIndex); + QFETCH(int, defaultIndex); + QFETCH(int, visibleIndex); + QFETCH(int, selectionIndex); + QFETCH(int, rangeFlags); + QFETCH(int, rangeIndex); + + QDeclarativeListCompositor compositor; + compositor.setGroupCount(4); + compositor.setDefaultGroups(VisibleFlag | C::DefaultFlag); + + foreach (const Range &range, ranges) + compositor.append(range.list, range.index, range.count, range.flags); + + QDeclarativeListCompositor::insert_iterator it = compositor.findInsertPosition(group, index); + QCOMPARE(it.index[C::Cache], cacheIndex); + QCOMPARE(it.index[C::Default], defaultIndex); + QCOMPARE(it.index[Visible], visibleIndex); + QCOMPARE(it.index[Selection], selectionIndex); + QCOMPARE(it->flags, rangeFlags); + QCOMPARE(it->index, rangeIndex); +} + void tst_qdeclarativelistcompositor::insert() { QDeclarativeListCompositor compositor; @@ -547,6 +676,27 @@ void tst_qdeclarativelistcompositor::setFlags_data() << IndexArray(defaultIndexes) << ListArray(defaultLists) << IndexArray(visibleIndexes) << ListArray(visibleLists) << IndexArray(selectionIndexes) << ListArray(selectionLists); + } { static const int cacheIndexes[] = {0,1,2,3,4,5,6,7,8,9,10,11}; + static const void *cacheLists[] = {a,a,a,a,a,a,a,a,a,a, a, a}; + static const int defaultIndexes[] = {0,1,2,3,4,5,6,7,8,9,10,11}; + static const void *defaultLists[] = {a,a,a,a,a,a,a,a,a,a, a, a}; + static const int visibleIndexes[] = {0,1,3,4,5,6,7,8,9,10,11}; + static const void *visibleLists[] = {a,a,a,a,a,a,a,a,a, a, a}; + static const int selectionIndexes[] = {2,6,7,8,9}; + static const void *selectionLists[] = {a,a,a,a,a}; + QTest::newRow("Existing flag, sparse selection") + << (RangeList() + << Range(a, 0, 2, C::PrependFlag | VisibleFlag | C::DefaultFlag | C::CacheFlag) + << Range(a, 2, 1, C::PrependFlag | SelectionFlag | C::DefaultFlag | C::CacheFlag) + << Range(a, 3, 3, C::PrependFlag | VisibleFlag | C::DefaultFlag | C::CacheFlag) + << Range(a, 6, 4, C::PrependFlag | SelectionFlag | VisibleFlag | C::DefaultFlag | C::CacheFlag) + << Range(a,10, 2, C::AppendFlag | C::PrependFlag | VisibleFlag | C::DefaultFlag | C::CacheFlag)) + << C::Cache << 3 << 1 << int(VisibleFlag) + << InsertList() + << IndexArray(cacheIndexes) << ListArray(cacheLists) + << IndexArray(defaultIndexes) << ListArray(defaultLists) + << IndexArray(visibleIndexes) << ListArray(visibleLists) + << IndexArray(selectionIndexes) << ListArray(selectionLists); } } @@ -756,6 +906,35 @@ void tst_qdeclarativelistcompositor::move_data() << IndexArray(defaultIndexes) << ListArray(defaultLists) << IndexArray() << ListArray() << IndexArray() << ListArray(); + } { static const int cacheIndexes[] = {8,9,10,4,11,0,1,2,3,5,6,7}; + static const void *cacheLists[] = {a,a, a,a, a,a,a,a,a,a,a,a}; + static const int defaultIndexes[] = {8,9,10,4,11,0,1,2,3,5,6,7}; + static const void *defaultLists[] = {a,a, a,a, a,a,a,a,a,a,a,a}; + static const int visibleIndexes[] = {8,9,10,4,11,0,1,2,3,5,6,7}; + static const void *visibleLists[] = {a,a, a,a, a,a,a,a,a,a,a,a}; + QTest::newRow("3, 4, 5") + << (RangeList() + << Range(a, 8, 4, VisibleFlag | C::DefaultFlag | C::CacheFlag) + << Range(a, 0, 2, C::PrependFlag | VisibleFlag | C::DefaultFlag | C::CacheFlag) + << Range(a, 2, 1, C::PrependFlag) + << Range(a, 2, 1, VisibleFlag | C::DefaultFlag | C::CacheFlag) + << Range(a, 3, 5, C::PrependFlag | VisibleFlag | C::DefaultFlag | C::CacheFlag) + << Range(a, 8, 4, C::AppendFlag | C::PrependFlag)) + << C::Default << 3 << C::Default << 4 << 5 + << (RemoveList() + << Remove(0, 3, 3, 3, 1, VisibleFlag | C::DefaultFlag | C::CacheFlag, 0) + << Remove(0, 3, 3, 3, 2, VisibleFlag | C::DefaultFlag | C::CacheFlag, 1) + << Remove(0, 3, 3, 3, 1, VisibleFlag | C::DefaultFlag | C::CacheFlag, 2) + << Remove(0, 3, 3, 3, 1, VisibleFlag | C::DefaultFlag | C::CacheFlag, 3)) + << (InsertList() + << Insert(0, 4, 4, 4, 1, VisibleFlag | C::DefaultFlag | C::CacheFlag, 0) + << Insert(0, 5, 5, 5, 2, VisibleFlag | C::DefaultFlag | C::CacheFlag, 1) + << Insert(0, 7, 7, 7, 1, VisibleFlag | C::DefaultFlag | C::CacheFlag, 2) + << Insert(0, 8, 8, 8, 1, VisibleFlag | C::DefaultFlag | C::CacheFlag, 3)) + << IndexArray(cacheIndexes) << ListArray(cacheLists) + << IndexArray(defaultIndexes) << ListArray(defaultLists) + << IndexArray(visibleIndexes) << ListArray(visibleLists) + << IndexArray() << ListArray(); } } @@ -955,6 +1134,21 @@ void tst_qdeclarativelistcompositor::listItemsInserted_data() << IndexArray(defaultIndexes) << IndexArray(visibleIndexes) << IndexArray(); + } { static const int cacheIndexes[] = {/*A*/0,1,2,3,4}; + static const int defaultIndexes[] = {/*A*/0,1,2,3,4,5,6}; + static const int visibleIndexes[] = {/*A*/0,1,2,3,4,5,6}; + QTest::newRow("Consecutive appends") + << (RangeList() + << Range(a, 0, 5, C::PrependFlag | VisibleFlag | C::DefaultFlag | C::CacheFlag) + << Range(a, 5, 1, C::PrependFlag | VisibleFlag | C::DefaultFlag) + << Range(a, 6, 0, C::AppendFlag | VisibleFlag | C::PrependFlag | C::DefaultFlag | C::CacheFlag)) + << a << 6 << 1 + << (InsertList() + << Insert(0, 6, 6, 5, 1, VisibleFlag | C::DefaultFlag)) + << IndexArray(cacheIndexes) + << IndexArray(defaultIndexes) + << IndexArray(visibleIndexes) + << IndexArray(); } } @@ -1067,6 +1261,30 @@ void tst_qdeclarativelistcompositor::listItemsRemoved_data() << IndexArray(defaultIndexes) << IndexArray() << IndexArray(); + } { static const int cacheIndexes[] = {/*A*/-1,-1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1}; + static const int defaultIndexes[] = {/*A*/0,1,2,3,4,5,6}; + QTest::newRow("Sparse remove") + << (RangeList() + << Range(a, 0, 2, C::CacheFlag) + << Range(a, 0, 1, C::DefaultFlag | C::CacheFlag) + << Range(a, 0, 1, C::CacheFlag) + << Range(a, 1, 5, C::DefaultFlag | C::CacheFlag) + << Range(a, 0, 1, C::CacheFlag) + << Range(a, 6, 2, C::DefaultFlag | C::CacheFlag) + << Range(a, 0, 1, C::CacheFlag) + << Range(a, 8, 3, C::DefaultFlag | C::CacheFlag) + << Range(a, 0, 1, C::CacheFlag) + << Range(a, 11, 1, C::DefaultFlag | C::CacheFlag) + << Range(a, 12, 5, C::DefaultFlag)) + << a << 1 << 10 + << (RemoveList() + << Remove(0, 0, 1, 4, 5, C::DefaultFlag | C::CacheFlag) + << Remove(0, 0, 1,10, 2, C::DefaultFlag | C::CacheFlag) + << Remove(0, 0, 1,13, 3, C::DefaultFlag | C::CacheFlag)) + << IndexArray(cacheIndexes) + << IndexArray(defaultIndexes) + << IndexArray() + << IndexArray(); } } @@ -1205,6 +1423,24 @@ void tst_qdeclarativelistcompositor::listItemsMoved_data() << IndexArray(defaultIndexes) << IndexArray() << IndexArray(); + } { static const int cacheIndexes[] = {/*A*/0,1,5,6,7,8,9,10,11,12}; + static const int defaultIndexes[] = {/*A*/0,1,2,3,4,5,6,7,8,9,10,11,12}; + QTest::newRow("Move merge tail") + << (RangeList() + << Range(a, 0, 10, C::PrependFlag | C::DefaultFlag | C::CacheFlag) + << Range(a, 10, 3, C::PrependFlag | C::DefaultFlag) + << Range(a, 13, 0, C::AppendFlag | C::PrependFlag | C::DefaultFlag | C::CacheFlag)) + << a << 8 << 0 << 5 + << (RemoveList() + << Remove(0, 0, 8, 8, 2, C::DefaultFlag | C::CacheFlag, 0) + << Remove(0, 0, 8, 8, 3, C::DefaultFlag, 1)) + << (InsertList() + << Insert(0, 0, 0, 0, 2, C::DefaultFlag | C::CacheFlag, 0) + << Insert(0, 0, 2, 2, 3, C::DefaultFlag, 1)) + << IndexArray(cacheIndexes) + << IndexArray(defaultIndexes) + << IndexArray() + << IndexArray(); } } diff --git a/tests/auto/declarative/qdeclarativelistmodel/data/workerremoveelement.js b/tests/auto/declarative/qdeclarativelistmodel/data/workerremoveelement.js new file mode 100644 index 0000000000..cb9dfa66aa --- /dev/null +++ b/tests/auto/declarative/qdeclarativelistmodel/data/workerremoveelement.js @@ -0,0 +1,8 @@ +WorkerScript.onMessage = function(msg) { + if (msg.action == 'removeItem') { + msg.model.remove(0); + } else if (msg.action == 'dosync') { + msg.model.sync(); + } + WorkerScript.sendMessage({'done': true}) +} diff --git a/tests/auto/declarative/qdeclarativelistmodel/data/workerremoveelement.qml b/tests/auto/declarative/qdeclarativelistmodel/data/workerremoveelement.qml new file mode 100644 index 0000000000..e2361acf6b --- /dev/null +++ b/tests/auto/declarative/qdeclarativelistmodel/data/workerremoveelement.qml @@ -0,0 +1,33 @@ +import QtQuick 2.0 + +Item { + id: item + property variant model + property bool done: false + + WorkerScript { + id: worker + source: "workerremoveelement.js" + onMessage: { + item.done = true + } + } + + function addItem() { + model.append({ 'data': 1 }); + + var element = model.get(0); + } + + function removeItemViaWorker() { + done = false + var msg = { 'action': 'removeItem', 'model': model } + worker.sendMessage(msg); + } + + function doSync() { + done = false + var msg = { 'action': 'dosync', 'model': model } + worker.sendMessage(msg); + } +} diff --git a/tests/auto/declarative/qdeclarativelistmodel/data/workerremovelist.js b/tests/auto/declarative/qdeclarativelistmodel/data/workerremovelist.js new file mode 100644 index 0000000000..f63dd68839 --- /dev/null +++ b/tests/auto/declarative/qdeclarativelistmodel/data/workerremovelist.js @@ -0,0 +1,9 @@ +WorkerScript.onMessage = function(msg) { + if (msg.action == 'removeList') { + msg.model.remove(0); + } else if (msg.action == 'dosync') { + msg.model.sync(); + } + WorkerScript.sendMessage({'done': true}) +} + diff --git a/tests/auto/declarative/qdeclarativelistmodel/data/workerremovelist.qml b/tests/auto/declarative/qdeclarativelistmodel/data/workerremovelist.qml new file mode 100644 index 0000000000..bdb5e024d8 --- /dev/null +++ b/tests/auto/declarative/qdeclarativelistmodel/data/workerremovelist.qml @@ -0,0 +1,33 @@ +import QtQuick 2.0 + +Item { + id: item + property variant model + property bool done: false + + WorkerScript { + id: worker + source: "workerremovelist.js" + onMessage: { + item.done = true + } + } + + function addList() { + model.append({ 'data': [ { 'subData': 1 } ] }); + + var element = model.get(0); + } + + function removeListViaWorker() { + done = false + var msg = { 'action': 'removeList', 'model': model } + worker.sendMessage(msg); + } + + function doSync() { + done = false + var msg = { 'action': 'dosync', 'model': model } + worker.sendMessage(msg); + } +} diff --git a/tests/auto/declarative/qdeclarativelistmodel/data/workersync.js b/tests/auto/declarative/qdeclarativelistmodel/data/workersync.js new file mode 100644 index 0000000000..9b8d8fa7f3 --- /dev/null +++ b/tests/auto/declarative/qdeclarativelistmodel/data/workersync.js @@ -0,0 +1,8 @@ +WorkerScript.onMessage = function(msg) { + if (msg.action == 'addItem') { + msg.model.get(0).level0.append({ 'level1': 33 }); + } else if (msg.action == 'dosync') { + msg.model.sync(); + } + WorkerScript.sendMessage({'done': true}) +} diff --git a/tests/auto/declarative/qdeclarativelistmodel/data/workersync.qml b/tests/auto/declarative/qdeclarativelistmodel/data/workersync.qml new file mode 100644 index 0000000000..c21cd43e7e --- /dev/null +++ b/tests/auto/declarative/qdeclarativelistmodel/data/workersync.qml @@ -0,0 +1,32 @@ +import QtQuick 2.0 + +Item { + id: item + property variant model + property bool done: false + + WorkerScript { + id: worker + source: "workersync.js" + onMessage: { + item.done = true + } + } + + function addItem0() { + model.append({ 'level0': [ { 'level1': 29 } ] }); + model.append({ 'level0': [ { 'level1': 37 } ] }); + } + + function addItemViaWorker() { + done = false + var msg = { 'action': 'addItem', 'model': model } + worker.sendMessage(msg); + } + + function doSync() { + done = false + var msg = { 'action': 'dosync', 'model': model } + worker.sendMessage(msg); + } +} diff --git a/tests/auto/declarative/qdeclarativelistmodel/qdeclarativelistmodel.pro b/tests/auto/declarative/qdeclarativelistmodel/qdeclarativelistmodel.pro index 1586e68281..fc8a3178ae 100644 --- a/tests/auto/declarative/qdeclarativelistmodel/qdeclarativelistmodel.pro +++ b/tests/auto/declarative/qdeclarativelistmodel/qdeclarativelistmodel.pro @@ -4,7 +4,9 @@ macx:CONFIG -= app_bundle SOURCES += tst_qdeclarativelistmodel.cpp -DEFINES += SRCDIR=\\\"$$PWD\\\" +testDataFiles.files = data +testDataFiles.path = . +DEPLOYMENT += testDataFiles CONFIG += parallel_test diff --git a/tests/auto/declarative/qdeclarativelistmodel/tst_qdeclarativelistmodel.cpp b/tests/auto/declarative/qdeclarativelistmodel/tst_qdeclarativelistmodel.cpp index bc6c99102e..e5e12092e3 100644 --- a/tests/auto/declarative/qdeclarativelistmodel/tst_qdeclarativelistmodel.cpp +++ b/tests/auto/declarative/qdeclarativelistmodel/tst_qdeclarativelistmodel.cpp @@ -51,9 +51,22 @@ #include <QtCore/qtranslator.h> #include <QSignalSpy> +#include "../shared/util.h" + Q_DECLARE_METATYPE(QList<int>) Q_DECLARE_METATYPE(QList<QVariantHash>) +#define RUNEVAL(object, string) \ + QVERIFY(QMetaObject::invokeMethod(object, "runEval", Q_ARG(QVariant, QString(string)))); + +inline QVariant runexpr(QDeclarativeEngine *engine, const QString &str) +{ + QDeclarativeExpression expr(engine->rootContext(), 0, str); + return expr.evaluate(); +} + +#define RUNEXPR(string) runexpr(&engine, QString(string)) + class tst_qdeclarativelistmodel : public QObject { Q_OBJECT @@ -65,6 +78,8 @@ private: QQuickItem *createWorkerTest(QDeclarativeEngine *eng, QDeclarativeComponent *component, QDeclarativeListModel *model); void waitForWorker(QQuickItem *item); + static bool compareVariantList(const QVariantList &testList, QVariant object); + private slots: void static_types(); void static_types_data(); @@ -78,16 +93,12 @@ private slots: void dynamic_worker(); void dynamic_worker_sync_data(); void dynamic_worker_sync(); - void convertNestedToFlat_fail(); - void convertNestedToFlat_fail_data(); - void convertNestedToFlat_ok(); - void convertNestedToFlat_ok_data(); void enumerate(); void error_data(); void error(); void syncError(); - void set(); void get(); + void set(); void get_data(); void get_worker(); void get_worker_data(); @@ -101,8 +112,64 @@ private slots: void property_changes_worker_data(); void clear(); void signal_handlers(); + void worker_sync(); + void worker_remove_element(); + void worker_remove_list(); }; +bool tst_qdeclarativelistmodel::compareVariantList(const QVariantList &testList, QVariant object) +{ + bool allOk = true; + + QDeclarativeListModel *model = qobject_cast<QDeclarativeListModel *>(object.value<QObject *>()); + if (model == 0) + return false; + + if (model->count() != testList.count()) + return false; + + for (int i=0 ; i < testList.count() ; ++i) { + const QVariant &testVariant = testList.at(i); + if (testVariant.type() != QVariant::Map) + return false; + const QVariantMap &map = testVariant.toMap(); + + const QList<int> &roles = model->roles(); + + QVariantMap::const_iterator it = map.begin(); + QVariantMap::const_iterator end = map.end(); + + while (it != end) { + const QString &testKey = it.key(); + const QVariant &testData = it.value(); + + int roleIndex = -1; + for (int j=0 ; j < roles.count() ; ++j) { + if (model->toString(roles[j]).compare(testKey) == 0) { + roleIndex = j; + break; + } + } + + if (roleIndex == -1) + return false; + + const QVariant &modelData = model->data(i, roleIndex); + + if (testData.type() == QVariant::List) { + const QVariantList &subList = testData.toList(); + allOk = allOk && compareVariantList(subList, modelData); + } else { + allOk = allOk && (testData == modelData); + } + + ++it; + } + } + + return allOk; +} + int tst_qdeclarativelistmodel::roleFromName(const QDeclarativeListModel *model, const QString &roleName) { QList<int> roles = model->roles(); @@ -118,7 +185,7 @@ QQuickItem *tst_qdeclarativelistmodel::createWorkerTest(QDeclarativeEngine *eng, QQuickItem *item = qobject_cast<QQuickItem*>(component->create()); QDeclarativeEngine::setContextForObject(model, eng->rootContext()); if (item) - item->setProperty("model", qVariantFromValue(model)); + item->setProperty("model", qVariantFromValue(model)); return item; } @@ -141,43 +208,66 @@ void tst_qdeclarativelistmodel::static_types_data() { QTest::addColumn<QString>("qml"); QTest::addColumn<QVariant>("value"); + QTest::addColumn<QString>("error"); QTest::newRow("string") << "ListElement { foo: \"bar\" }" - << QVariant(QString("bar")); + << QVariant(QString("bar")) + << QString(); QTest::newRow("real") << "ListElement { foo: 10.5 }" - << QVariant(10.5); + << QVariant(10.5) + << QString(); QTest::newRow("real0") << "ListElement { foo: 0 }" - << QVariant(double(0)); + << QVariant(double(0)) + << QString(); QTest::newRow("bool") << "ListElement { foo: false }" - << QVariant(false); + << QVariant(false) + << QString(); QTest::newRow("bool") << "ListElement { foo: true }" - << QVariant(true); + << QVariant(true) + << QString(); QTest::newRow("enum") << "ListElement { foo: Text.AlignHCenter }" - << QVariant(double(QQuickText::AlignHCenter)); + << QVariant(double(QQuickText::AlignHCenter)) + << QString(); QTest::newRow("Qt enum") << "ListElement { foo: Qt.AlignBottom }" - << QVariant(double(Qt::AlignBottom)); + << QVariant(double(Qt::AlignBottom)) + << QString(); + + QTest::newRow("role error") + << "ListElement { foo: 1 } ListElement { foo: 'string' }" + << QVariant() + << QString("<Unknown File>: Can't assign to existing role 'foo' of different type [String -> Number]"); + + QTest::newRow("list type error") + << "ListElement { foo: 1 } ListElement { foo: ListElement { bar: 1 } }" + << QVariant() + << QString("<Unknown File>: Can't assign to existing role 'foo' of different type [List -> Number]"); } void tst_qdeclarativelistmodel::static_types() { QFETCH(QString, qml); QFETCH(QVariant, value); + QFETCH(QString, error); qml = "import QtQuick 2.0\nItem { property variant test: model.get(0).foo; ListModel { id: model; " + qml + " } }"; + if (!error.isEmpty()) { + QTest::ignoreMessage(QtWarningMsg, error.toLatin1()); + } + QDeclarativeEngine engine; QDeclarativeComponent component(&engine); component.setData(qml.toUtf8(), @@ -188,10 +278,12 @@ void tst_qdeclarativelistmodel::static_types() QObject *obj = component.create(); QVERIFY(obj != 0); - QVariant actual = obj->property("test"); + if (error.isEmpty()) { + QVariant actual = obj->property("test"); - QCOMPARE(actual, value); - QCOMPARE(actual.toString(), value.toString()); + QCOMPARE(actual, value); + QCOMPARE(actual.toString(), value.toString()); + } delete obj; } @@ -270,11 +362,11 @@ void tst_qdeclarativelistmodel::static_nestedElements() QFETCH(int, elementCount); QStringList elements; - for (int i=0; i<elementCount; i++) + for (int i=0; i<elementCount; i++) elements.append("ListElement { a: 1; b: 2 }"); QString elementsStr = elements.join(",\n") + "\n"; - QString componentStr = + QString componentStr = "import QtQuick 2.0\n" "Item {\n" " property variant count: model.get(0).attributes.count\n" @@ -283,7 +375,7 @@ void tst_qdeclarativelistmodel::static_nestedElements() " ListElement {\n" " attributes: [\n"; componentStr += elementsStr.toUtf8().constData(); - componentStr += + componentStr += " ]\n" " }\n" " }\n" @@ -320,7 +412,6 @@ void tst_qdeclarativelistmodel::dynamic_data() QTest::addColumn<QString>("warning"); // Simple flat model - QTest::newRow("count") << "count" << 0 << ""; QTest::newRow("get1") << "{get(0) === undefined}" << 1 << ""; @@ -336,7 +427,8 @@ void tst_qdeclarativelistmodel::dynamic_data() QTest::newRow("append3a") << "{append({'foo':123});append({'foo':456});get(0).foo}" << 123 << ""; QTest::newRow("append3b") << "{append({'foo':123});append({'foo':456});get(1).foo}" << 456 << ""; QTest::newRow("append4a") << "{append(123)}" << 0 << "<Unknown File>: QML ListModel: append: value is not an object"; - QTest::newRow("append4b") << "{append([1,2,3])}" << 0 << "<Unknown File>: QML ListModel: append: value is not an object"; + QTest::newRow("append4b") << "{append([{'foo':123},{'foo':456},{'foo':789}]);count}" << 3 << ""; + QTest::newRow("append4c") << "{append([{'foo':123},{'foo':456},{'foo':789}]);get(1).foo}" << 456 << ""; QTest::newRow("clear1") << "{append({'foo':456});clear();count}" << 0 << ""; QTest::newRow("clear2") << "{append({'foo':123});append({'foo':456});clear();count}" << 0 << ""; @@ -361,7 +453,8 @@ void tst_qdeclarativelistmodel::dynamic_data() QTest::newRow("insert3e") << "{append({'foo':123});insert(0,{'foo':456});get(1).foo}" << 123 << ""; QTest::newRow("insert4") << "{append({'foo':123});insert(-1,{'foo':456});count}" << 1 << "<Unknown File>: QML ListModel: insert: index -1 out of range"; QTest::newRow("insert5a") << "{insert(0,123)}" << 0 << "<Unknown File>: QML ListModel: insert: value is not an object"; - QTest::newRow("insert5b") << "{insert(0,[1,2,3])}" << 0 << "<Unknown File>: QML ListModel: insert: value is not an object"; + QTest::newRow("insert5b") << "{insert(0,[{'foo':11},{'foo':22},{'foo':33}]);count}" << 3 << ""; + QTest::newRow("insert5c") << "{insert(0,[{'foo':11},{'foo':22},{'foo':33}]);get(2).foo}" << 33 << ""; QTest::newRow("set1") << "{append({'foo':123});set(0,{'foo':456});count}" << 1 << ""; QTest::newRow("set2") << "{append({'foo':123});set(0,{'foo':456});get(0).foo}" << 456 << ""; @@ -396,8 +489,38 @@ void tst_qdeclarativelistmodel::dynamic_data() QTest::newRow("move3c") << "{append({'foo':123});append({'foo':456});append({'foo':789});move(1,0,-1);count}" << 3 << "<Unknown File>: QML ListModel: move: out of range"; QTest::newRow("move3d") << "{append({'foo':123});append({'foo':456});append({'foo':789});move(0,3,1);count}" << 3 << "<Unknown File>: QML ListModel: move: out of range"; - // Nested models + QTest::newRow("large1") << "{append({'a':1,'b':2,'c':3,'d':4,'e':5,'f':6,'g':7,'h':8});get(0).h}" << 8 << ""; + + QTest::newRow("datatypes1") << "{append({'a':1});append({'a':'string'});}" << 0 << "<Unknown File>: Can't assign to existing role 'a' of different type [String -> Number]"; + + QTest::newRow("null") << "{append({'a':null});}" << 0 << ""; + QTest::newRow("setNull") << "{append({'a':1});set(0, {'a':null});}" << 0 << ""; + QTest::newRow("setString") << "{append({'a':'hello'});set(0, {'a':'world'});get(0).a == 'world'}" << 1 << ""; + QTest::newRow("setInt") << "{append({'a':5});set(0, {'a':10});get(0).a}" << 10 << ""; + QTest::newRow("setNumber") << "{append({'a':6});set(0, {'a':5.5});get(0).a < 5.6}" << 1 << ""; + QTest::newRow("badType0") << "{append({'a':'hello'});set(0, {'a':1});}" << 0 << "<Unknown File>: Can't assign to existing role 'a' of different type [Number -> String]"; + QTest::newRow("invalidInsert0") << "{insert(0);}" << 0 << "<Unknown File>: QML ListModel: insert: value is not an object"; + QTest::newRow("invalidAppend0") << "{append();}" << 0 << "<Unknown File>: QML ListModel: append: value is not an object"; + QTest::newRow("invalidInsert1") << "{insert(0, 34);}" << 0 << "<Unknown File>: QML ListModel: insert: value is not an object"; + QTest::newRow("invalidAppend1") << "{append(37);}" << 0 << "<Unknown File>: QML ListModel: append: value is not an object"; + + // QObjects + QTest::newRow("qobject0") << "{append({'a':dummyItem0});}" << 0 << ""; + QTest::newRow("qobject1") << "{append({'a':dummyItem0});set(0,{'a':dummyItem1});get(0).a == dummyItem1;}" << 1 << ""; + QTest::newRow("qobject2") << "{append({'a':dummyItem0});get(0).a == dummyItem0;}" << 1 << ""; + QTest::newRow("qobject3") << "{append({'a':dummyItem0});append({'b':1});}" << 0 << ""; + + // JS objects + QTest::newRow("js1") << "{append({'foo':{'prop':1}});count}" << 1 << ""; + QTest::newRow("js2") << "{append({'foo':{'prop':27}});get(0).foo.prop}" << 27 << ""; + QTest::newRow("js3") << "{append({'foo':{'prop':27}});append({'bar':1});count}" << 2 << ""; + QTest::newRow("js4") << "{append({'foo':{'prop':27}});append({'bar':1});set(0, {'foo':{'prop':28}});get(0).foo.prop}" << 28 << ""; + QTest::newRow("js5") << "{append({'foo':{'prop':27}});append({'bar':1});set(1, {'foo':{'prop':33}});get(1).foo.prop}" << 33 << ""; + QTest::newRow("js6") << "{append({'foo':{'prop':27}});clear();count}" << 0 << ""; + QTest::newRow("js7") << "{append({'foo':{'prop':27}});set(0, {'foo':null});count}" << 1 << ""; + QTest::newRow("js8") << "{append({'foo':{'prop':27}});set(0, {'foo':{'prop2':31}});get(0).foo.prop2}" << 31 << ""; + // Nested models QTest::newRow("nested-append1") << "{append({'foo':123,'bars':[{'a':1},{'a':2},{'a':3}]});count}" << 1 << ""; QTest::newRow("nested-append2") << "{append({'foo':123,'bars':[{'a':1},{'a':2},{'a':3}]});get(0).bars.get(1).a}" << 2 << ""; QTest::newRow("nested-append3") << "{append({'foo':123,'bars':[{'a':1},{'a':2},{'a':3}]});get(0).bars.append({'a':4});get(0).bars.get(3).a}" << 4 << ""; @@ -415,10 +538,13 @@ void tst_qdeclarativelistmodel::dynamic() QFETCH(int, result); QFETCH(QString, warning); + QQuickItem dummyItem0, dummyItem1; QDeclarativeEngine engine; QDeclarativeListModel model; QDeclarativeEngine::setContextForObject(&model,engine.rootContext()); engine.rootContext()->setContextObject(&model); + engine.rootContext()->setContextProperty("dummyItem0", QVariant::fromValue(&dummyItem0)); + engine.rootContext()->setContextProperty("dummyItem1", QVariant::fromValue(&dummyItem1)); QDeclarativeExpression e(engine.rootContext(), &model, script); if (!warning.isEmpty()) QTest::ignoreMessage(QtWarningMsg, warning.toLatin1()); @@ -446,16 +572,15 @@ void tst_qdeclarativelistmodel::dynamic_worker() QFETCH(int, result); QFETCH(QString, warning); - if (QByteArray(QTest::currentDataTag()).startsWith("nested")) + if (QByteArray(QTest::currentDataTag()).startsWith("qobject")) return; - // This is same as dynamic() except it applies the test to a ListModel called - // from a WorkerScript (i.e. testing the internal FlatListModel that is created - // by the WorkerListModelAgent) + // This is same as dynamic() except it applies the test to a ListModel called + // from a WorkerScript. QDeclarativeListModel model; QDeclarativeEngine eng; - QDeclarativeComponent component(&eng, QUrl::fromLocalFile(SRCDIR "/data/model.qml")); + QDeclarativeComponent component(&eng, QUrl::fromLocalFile(TESTDATA("model.qml"))); QQuickItem *item = createWorkerTest(&eng, &component, &model); QVERIFY(item != 0); @@ -495,13 +620,16 @@ void tst_qdeclarativelistmodel::dynamic_worker_sync() QFETCH(int, result); QFETCH(QString, warning); + if (QByteArray(QTest::currentDataTag()).startsWith("qobject")) + return; + // This is the same as dynamic_worker() except that it executes a set of list operations // from the worker script, calls sync(), and tests the changes are reflected in the // list in the main thread - + QDeclarativeListModel model; QDeclarativeEngine eng; - QDeclarativeComponent component(&eng, QUrl::fromLocalFile(SRCDIR "/data/model.qml")); + QDeclarativeComponent component(&eng, QUrl::fromLocalFile(TESTDATA("model.qml"))); QQuickItem *item = createWorkerTest(&eng, &component, &model); QVERIFY(item != 0); @@ -518,139 +646,55 @@ void tst_qdeclarativelistmodel::dynamic_worker_sync() // execute a set of commands on the worker list model, then check the // changes are reflected in the list model in the main thread - if (QByteArray(QTest::currentDataTag()).startsWith("nested")) - QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML ListModel: Cannot add list-type data when modifying or after modification from a worker script"); - - if (QByteArray(QTest::currentDataTag()).startsWith("nested-set")) - QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML ListModel: Cannot add list-type data when modifying or after modification from a worker script"); - - QVERIFY(QMetaObject::invokeMethod(item, "evalExpressionViaWorker", + QVERIFY(QMetaObject::invokeMethod(item, "evalExpressionViaWorker", Q_ARG(QVariant, operations.mid(0, operations.length()-1)))); waitForWorker(item); QDeclarativeExpression e(eng.rootContext(), &model, operations.last().toString()); - if (!QByteArray(QTest::currentDataTag()).startsWith("nested")) - QCOMPARE(e.evaluate().toInt(), result); + QCOMPARE(e.evaluate().toInt(), result); delete item; qApp->processEvents(); } -#define RUNEVAL(object, string) \ - QVERIFY(QMetaObject::invokeMethod(object, "runEval", Q_ARG(QVariant, QString(string)))); - -inline QVariant runexpr(QDeclarativeEngine *engine, const QString &str) -{ - QDeclarativeExpression expr(engine->rootContext(), 0, str); - return expr.evaluate(); -} - -#define RUNEXPR(string) runexpr(&engine, QString(string)) - -void tst_qdeclarativelistmodel::convertNestedToFlat_fail() -{ - // If a model has nested data, it cannot be used at all from a worker script - - QFETCH(QString, script); - - QDeclarativeListModel model; - QDeclarativeEngine eng; - QDeclarativeComponent component(&eng, QUrl::fromLocalFile(SRCDIR "/data/model.qml")); - QQuickItem *item = createWorkerTest(&eng, &component, &model); - QVERIFY(item != 0); - - RUNEVAL(item, "model.append({foo: 123})"); - RUNEVAL(item, "model.append({foo: [{}, {}]})"); - - QCOMPARE(model.count(), 2); - - QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML ListModel: List contains list-type data and cannot be used from a worker script"); - QVERIFY(QMetaObject::invokeMethod(item, "evalExpressionViaWorker", Q_ARG(QVariant, script))); - waitForWorker(item); - - QCOMPARE(model.count(), 2); - - delete item; - qApp->processEvents(); -} - -void tst_qdeclarativelistmodel::convertNestedToFlat_fail_data() -{ - QTest::addColumn<QString>("script"); - - QTest::newRow("clear") << "clear()"; - QTest::newRow("remove") << "remove(0)"; - QTest::newRow("append") << "append({'x':1})"; - QTest::newRow("insert") << "insert(0, {'x':1})"; - QTest::newRow("set") << "set(0, {'foo':1})"; - QTest::newRow("setProperty") << "setProperty(0, 'foo', 1})"; - QTest::newRow("move") << "move(0, 1, 1})"; - QTest::newRow("get") << "get(0)"; -} - -void tst_qdeclarativelistmodel::convertNestedToFlat_ok() - +void tst_qdeclarativelistmodel::enumerate() { - // If a model only has plain data, it can be modified from a worker script. However, - // once the model is used from a worker script, it no longer accepts nested data - - QFETCH(QString, script); - - QDeclarativeListModel model; QDeclarativeEngine eng; - QDeclarativeComponent component(&eng, QUrl::fromLocalFile(SRCDIR "/data/model.qml")); - QQuickItem *item = createWorkerTest(&eng, &component, &model); + QDeclarativeComponent component(&eng, QUrl::fromLocalFile(TESTDATA("enumerate.qml"))); + QVERIFY(!component.isError()); + QQuickItem *item = qobject_cast<QQuickItem*>(component.create()); QVERIFY(item != 0); - RUNEVAL(item, "model.append({foo: 123})"); - - QCOMPARE(model.count(), 1); - - QVERIFY(QMetaObject::invokeMethod(item, "evalExpressionViaWorker", Q_ARG(QVariant, script))); - waitForWorker(item); - - // can still add plain data - int count = model.count(); - - RUNEVAL(item, "model.append({foo: 123})"); - - QCOMPARE(model.count(), count+1); + QLatin1String expectedStrings[] = { + QLatin1String("val1=1Y"), + QLatin1String("val2=2Y"), + QLatin1String("val3=strY"), + QLatin1String("val4=falseN"), + QLatin1String("val5=trueY") + }; - const char *warning = "<Unknown File>: QML ListModel: Cannot add list-type data when modifying or after modification from a worker script"; + int expectedStringCount = sizeof(expectedStrings) / sizeof(expectedStrings[0]); - QTest::ignoreMessage(QtWarningMsg, warning); - RUNEVAL(item, "model.append({foo: [{}, {}]})"); - - QTest::ignoreMessage(QtWarningMsg, warning); - RUNEVAL(item, "model.insert(0, {foo: [{}, {}]})"); + QStringList r = item->property("result").toString().split(":"); - QTest::ignoreMessage(QtWarningMsg, warning); - RUNEVAL(item, "model.set(0, {foo: [{}, {}]})"); + int matchCount = 0; + for (int i=0 ; i < expectedStringCount ; ++i) { + const QLatin1String &expectedString = expectedStrings[i]; - QCOMPARE(model.count(), count+1); + QStringList::const_iterator it = r.begin(); + QStringList::const_iterator end = r.end(); - delete item; - qApp->processEvents(); -} + while (it != end) { + if (it->compare(expectedString) == 0) { + ++matchCount; + break; + } + ++it; + } + } -void tst_qdeclarativelistmodel::convertNestedToFlat_ok_data() -{ - convertNestedToFlat_fail_data(); -} + QVERIFY(matchCount == expectedStringCount); -void tst_qdeclarativelistmodel::enumerate() -{ - QDeclarativeEngine eng; - QDeclarativeComponent component(&eng, QUrl::fromLocalFile(SRCDIR "/data/enumerate.qml")); - QVERIFY(!component.isError()); - QQuickItem *item = qobject_cast<QQuickItem*>(component.create()); - QVERIFY(item != 0); - QStringList r = item->property("result").toString().split(":"); - QCOMPARE(r[0],QLatin1String("val1=1Y")); - QCOMPARE(r[1],QLatin1String("val2=2Y")); - QCOMPARE(r[2],QLatin1String("val3=strY")); - QCOMPARE(r[3],QLatin1String("val4=falseN")); - QCOMPARE(r[4],QLatin1String("val5=trueY")); delete item; } @@ -752,11 +796,15 @@ void tst_qdeclarativelistmodel::set() RUNEXPR("model.set(0, {test:true})"); QCOMPARE(RUNEXPR("model.get(0).test").toBool(), true); // triggers creation of model cache - QCOMPARE(model.data(0, model.roles()[0]), qVariantFromValue(true)); + QCOMPARE(model.data(0, model.roles()[0]), qVariantFromValue(true)); RUNEXPR("model.set(0, {test:false})"); QCOMPARE(RUNEXPR("model.get(0).test").toBool(), false); // tests model cache is updated - QCOMPARE(model.data(0, model.roles()[0]), qVariantFromValue(false)); + QCOMPARE(model.data(0, model.roles()[0]), qVariantFromValue(false)); + + QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: Can't create role for unsupported data type"); + QVariant invalidData = QColor(); + model.setProperty(0, "test", invalidData); } /* @@ -773,21 +821,31 @@ void tst_qdeclarativelistmodel::get() QDeclarativeComponent component(&engine); component.setData( "import QtQuick 2.0\n" - "ListModel { \n" - "ListElement { roleA: 100 }\n" - "ListElement { roleA: 200; roleB: 400 } \n" - "ListElement { roleA: 200; roleB: 400 } \n" - "}", QUrl()); + "ListModel {}\n", QUrl()); QDeclarativeListModel *model = qobject_cast<QDeclarativeListModel*>(component.create()); - int role = roleFromName(model, roleName); - QVERIFY(role >= 0); + engine.rootContext()->setContextProperty("model", model); + + RUNEXPR("model.append({roleA: 100})"); + RUNEXPR("model.append({roleA: 200, roleB: 400})"); + RUNEXPR("model.append({roleA: 200, roleB: 400})"); + RUNEXPR("model.append({roleC: {} })"); + RUNEXPR("model.append({roleD: [ { a:1, b:2 }, { c: 3 } ] })"); QSignalSpy spy(model, SIGNAL(itemsChanged(int, int, QList<int>))); QDeclarativeExpression expr(engine.rootContext(), model, expression); expr.evaluate(); QVERIFY(!expr.hasError()); - QCOMPARE(model->data(index, role), roleValue); + int role = roleFromName(model, roleName); + QVERIFY(role >= 0); + + if (roleValue.type() == QVariant::List) { + const QVariantList &list = roleValue.toList(); + QVERIFY(compareVariantList(list, model->data(index, role))); + } else { + QCOMPARE(model->data(index, role), roleValue); + } + QCOMPARE(spy.count(), 1); QList<QVariant> spyResult = spy.takeFirst(); @@ -805,19 +863,16 @@ void tst_qdeclarativelistmodel::get_data() QTest::addColumn<QString>("roleName"); QTest::addColumn<QVariant>("roleValue"); - QTest::newRow("simple value") << "get(0).roleA = 500" << 0 << "roleA" << QVariant(500); - QTest::newRow("simple value 2") << "get(1).roleB = 500" << 1 << "roleB" << QVariant(500); + QTest::newRow("simple value") << "get(0).roleA = 500" << 0 << "roleA" << QVariant(500); + QTest::newRow("simple value 2") << "get(1).roleB = 500" << 1 << "roleB" << QVariant(500); QVariantMap map; - map["zzz"] = 123; - QTest::newRow("object value") << "get(1).roleB = {'zzz':123}" << 1 << "roleB" << QVariant::fromValue(map); - QVariantList list; map.clear(); map["a"] = 50; map["b"] = 500; list << map; map.clear(); map["c"] = 1000; list << map; - QTest::newRow("list of objects") << "get(2).roleB = [{'a': 50, 'b': 500}, {'c': 1000}]" << 2 << "roleB" << QVariant::fromValue(list); + QTest::newRow("list of objects") << "get(2).roleD = [{'a': 50, 'b': 500}, {'c': 1000}]" << 2 << "roleD" << QVariant::fromValue(list); } void tst_qdeclarativelistmodel::get_worker() @@ -829,7 +884,7 @@ void tst_qdeclarativelistmodel::get_worker() QDeclarativeListModel model; QDeclarativeEngine eng; - QDeclarativeComponent component(&eng, QUrl::fromLocalFile(SRCDIR "/data/model.qml")); + QDeclarativeComponent component(&eng, QUrl::fromLocalFile(TESTDATA("model.qml"))); QQuickItem *item = createWorkerTest(&eng, &component, &model); QVERIFY(item != 0); @@ -837,13 +892,12 @@ void tst_qdeclarativelistmodel::get_worker() RUNEVAL(item, "model.append({roleA: 100})"); RUNEVAL(item, "model.append({roleA: 200, roleB: 400})"); RUNEVAL(item, "model.append({roleA: 200, roleB: 400})"); + RUNEVAL(item, "model.append({roleC: {} })"); + RUNEVAL(item, "model.append({roleD: [ { a:1, b:2 }, { c: 3 } ] })"); int role = roleFromName(&model, roleName); QVERIFY(role >= 0); - const char *warning = "<Unknown File>: QML ListModel: Cannot add list-type data when modifying or after modification from a worker script"; - if (roleValue.type() == QVariant::List || roleValue.type() == QVariant::Map) - QTest::ignoreMessage(QtWarningMsg, warning); QSignalSpy spy(&model, SIGNAL(itemsChanged(int, int, QList<int>))); // in the worker thread, change the model data and call sync() @@ -852,18 +906,19 @@ void tst_qdeclarativelistmodel::get_worker() waitForWorker(item); // see if we receive the model changes in the main thread's model - if (roleValue.type() == QVariant::List || roleValue.type() == QVariant::Map) { - QVERIFY(model.data(index, role) != roleValue); - QCOMPARE(spy.count(), 0); + if (roleValue.type() == QVariant::List) { + const QVariantList &list = roleValue.toList(); + QVERIFY(compareVariantList(list, model.data(index, role))); } else { QCOMPARE(model.data(index, role), roleValue); - QCOMPARE(spy.count(), 1); - - QList<QVariant> spyResult = spy.takeFirst(); - QCOMPARE(spyResult.at(0).toInt(), index); - QCOMPARE(spyResult.at(1).toInt(), 1); // only 1 item is modified at a time - QVERIFY(spyResult.at(2).value<QList<int> >().contains(role)); } + + QCOMPARE(spy.count(), 1); + + QList<QVariant> spyResult = spy.takeFirst(); + QCOMPARE(spyResult.at(0).toInt(), index); + QCOMPARE(spyResult.at(1).toInt(), 1); // only 1 item is modified at a time + QVERIFY(spyResult.at(2).value<QList<int> >().contains(role)); } void tst_qdeclarativelistmodel::get_worker_data() @@ -881,39 +936,48 @@ void tst_qdeclarativelistmodel::get_nested() QFETCH(QString, roleName); QFETCH(QVariant, roleValue); - QDeclarativeEngine eng; - QDeclarativeComponent component(&eng); + if (roleValue.type() == QVariant::Map) + return; + + QDeclarativeEngine engine; + QDeclarativeComponent component(&engine); component.setData( "import QtQuick 2.0\n" - "ListModel { \n" - "ListElement {\n" - "listRoleA: [\n" - "ListElement { roleA: 100 },\n" - "ListElement { roleA: 200; roleB: 400 },\n" - "ListElement { roleA: 200; roleB: 400 } \n" - "]\n" - "}\n" - "ListElement {\n" - "listRoleA: [\n" - "ListElement { roleA: 100 },\n" - "ListElement { roleA: 200; roleB: 400 },\n" - "ListElement { roleA: 200; roleB: 400 } \n" - "]\n" - "listRoleB: [\n" - "ListElement { roleA: 100 },\n" - "ListElement { roleA: 200; roleB: 400 },\n" - "ListElement { roleA: 200; roleB: 400 } \n" - "]\n" - "listRoleC: [\n" - "ListElement { roleA: 100 },\n" - "ListElement { roleA: 200; roleB: 400 },\n" - "ListElement { roleA: 200; roleB: 400 } \n" - "]\n" - "}\n" - "}", QUrl()); + "ListModel {}", QUrl()); QDeclarativeListModel *model = qobject_cast<QDeclarativeListModel*>(component.create()); QVERIFY(component.errorString().isEmpty()); QDeclarativeListModel *childModel; + engine.rootContext()->setContextProperty("model", model); + + RUNEXPR("model.append({ listRoleA: [\n" + "{ roleA: 100 },\n" + "{ roleA: 200, roleB: 400 },\n" + "{ roleA: 200, roleB: 400 }, \n" + "{ roleC: {} }, \n" + "{ roleD: [ { a: 1, b:2 }, { c: 3 } ] } \n" + "] })\n"); + + RUNEXPR("model.append({ listRoleA: [\n" + "{ roleA: 100 },\n" + "{ roleA: 200, roleB: 400 },\n" + "{ roleA: 200, roleB: 400 }, \n" + "{ roleC: {} }, \n" + "{ roleD: [ { a: 1, b:2 }, { c: 3 } ] } \n" + "],\n" + "listRoleB: [\n" + "{ roleA: 100 },\n" + "{ roleA: 200, roleB: 400 },\n" + "{ roleA: 200, roleB: 400 }, \n" + "{ roleC: {} }, \n" + "{ roleD: [ { a: 1, b:2 }, { c: 3 } ] } \n" + "],\n" + "listRoleC: [\n" + "{ roleA: 100 },\n" + "{ roleA: 200, roleB: 400 },\n" + "{ roleA: 200, roleB: 400 }, \n" + "{ roleC: {} }, \n" + "{ roleD: [ { a: 1, b:2 }, { c: 3 } ] } \n" + "] })\n"); // Test setting the inner list data for: // get(0).listRoleA @@ -937,7 +1001,7 @@ void tst_qdeclarativelistmodel::get_nested() QVERIFY(childModel); QString extendedExpression = QString("get(%1).%2.%3").arg(outerListIndex).arg(outerListRoleName).arg(expression); - QDeclarativeExpression expr(eng.rootContext(), model, extendedExpression); + QDeclarativeExpression expr(engine.rootContext(), model, extendedExpression); QSignalSpy spy(childModel, SIGNAL(itemsChanged(int, int, QList<int>))); expr.evaluate(); @@ -945,7 +1009,11 @@ void tst_qdeclarativelistmodel::get_nested() int role = roleFromName(childModel, roleName); QVERIFY(role >= 0); - QCOMPARE(childModel->data(index, role), roleValue); + if (roleValue.type() == QVariant::List) { + QVERIFY(compareVariantList(roleValue.toList(), childModel->data(index, role))); + } else { + QCOMPARE(childModel->data(index, role), roleValue); + } QCOMPARE(spy.count(), 1); QList<QVariant> spyResult = spy.takeFirst(); @@ -966,7 +1034,7 @@ void tst_qdeclarativelistmodel::get_nested_data() void tst_qdeclarativelistmodel::crash_model_with_multiple_roles() { QDeclarativeEngine eng; - QDeclarativeComponent component(&eng, QUrl::fromLocalFile(SRCDIR "/data/multipleroles.qml")); + QDeclarativeComponent component(&eng, QUrl::fromLocalFile(TESTDATA("multipleroles.qml"))); QObject *rootItem = component.create(); QVERIFY(component.errorString().isEmpty()); QVERIFY(rootItem != 0); @@ -983,7 +1051,7 @@ void tst_qdeclarativelistmodel::crash_model_with_multiple_roles() void tst_qdeclarativelistmodel::set_model_cache() { QDeclarativeEngine eng; - QDeclarativeComponent component(&eng, QUrl::fromLocalFile(SRCDIR "/data/setmodelcachelist.qml")); + QDeclarativeComponent component(&eng, QUrl::fromLocalFile(TESTDATA("setmodelcachelist.qml"))); QObject *model = component.create(); QVERIFY2(component.errorString().isEmpty(), QTest::toString(component.errorString())); QVERIFY(model != 0); @@ -1017,6 +1085,7 @@ void tst_qdeclarativelistmodel::property_changes() "target: model.get(" + QString::number(listIndex) + ")\n" + signalHandler + " gotSignal = true\n" "}\n"; + QDeclarativeComponent component(&engine); component.setData(qml.toUtf8(), QUrl::fromLocalFile("")); engine.rootContext()->setContextProperty("model", &model); @@ -1117,10 +1186,6 @@ void tst_qdeclarativelistmodel::property_changes_data() void tst_qdeclarativelistmodel::property_changes_worker() { - // nested models are not supported when WorkerScript is involved - if (QByteArray(QTest::currentDataTag()).startsWith("nested-")) - return; - QFETCH(QString, script_setup); QFETCH(QString, script_change); QFETCH(QString, roleName); @@ -1129,7 +1194,7 @@ void tst_qdeclarativelistmodel::property_changes_worker() QDeclarativeListModel model; QDeclarativeEngine engine; - QDeclarativeComponent component(&engine, QUrl::fromLocalFile(SRCDIR "/data/model.qml")); + QDeclarativeComponent component(&engine, QUrl::fromLocalFile(TESTDATA("model.qml"))); QVERIFY2(component.errorString().isEmpty(), component.errorString().toUtf8()); QQuickItem *item = createWorkerTest(&engine, &component, &model); QVERIFY(item != 0); @@ -1199,7 +1264,7 @@ void tst_qdeclarativelistmodel::clear() void tst_qdeclarativelistmodel::signal_handlers() { QDeclarativeEngine eng; - QDeclarativeComponent component(&eng, QUrl::fromLocalFile(SRCDIR "/data/signalhandlers.qml")); + QDeclarativeComponent component(&eng, QUrl::fromLocalFile(TESTDATA("signalhandlers.qml"))); QObject *model = component.create(); QVERIFY2(component.errorString().isEmpty(), QTest::toString(component.errorString())); QVERIFY(model != 0); @@ -1208,6 +1273,129 @@ void tst_qdeclarativelistmodel::signal_handlers() delete model; } +void tst_qdeclarativelistmodel::worker_sync() +{ + QDeclarativeListModel model; + QDeclarativeEngine eng; + QDeclarativeComponent component(&eng, QUrl::fromLocalFile(TESTDATA("workersync.qml"))); + QQuickItem *item = createWorkerTest(&eng, &component, &model); + QVERIFY(item != 0); + + QVERIFY(model.count() == 0); + + QVERIFY(QMetaObject::invokeMethod(item, "addItem0")); + + QVERIFY(model.count() == 2); + QVariant childData = model.data(0, 0); + QDeclarativeListModel *childModel = qobject_cast<QDeclarativeListModel *>(childData.value<QObject *>()); + QVERIFY(childModel); + QVERIFY(childModel->count() == 1); + + QSignalSpy spyModelInserted(&model, SIGNAL(itemsInserted(int,int))); + QSignalSpy spyChildInserted(childModel, SIGNAL(itemsInserted(int,int))); + + QVERIFY(QMetaObject::invokeMethod(item, "addItemViaWorker")); + waitForWorker(item); + + QVERIFY(model.count() == 2); + QVERIFY(childModel->count() == 1); + QVERIFY(spyModelInserted.count() == 0); + QVERIFY(spyChildInserted.count() == 0); + + QVERIFY(QMetaObject::invokeMethod(item, "doSync")); + waitForWorker(item); + + QVERIFY(model.count() == 2); + QVERIFY(childModel->count() == 2); + QVERIFY(spyModelInserted.count() == 0); + QVERIFY(spyChildInserted.count() == 1); + + QVERIFY(QMetaObject::invokeMethod(item, "addItemViaWorker")); + waitForWorker(item); + + QVERIFY(model.count() == 2); + QVERIFY(childModel->count() == 2); + QVERIFY(spyModelInserted.count() == 0); + QVERIFY(spyChildInserted.count() == 1); + + QVERIFY(QMetaObject::invokeMethod(item, "doSync")); + waitForWorker(item); + + QVERIFY(model.count() == 2); + QVERIFY(childModel->count() == 3); + QVERIFY(spyModelInserted.count() == 0); + QVERIFY(spyChildInserted.count() == 2); + + delete item; + qApp->processEvents(); +} + +void tst_qdeclarativelistmodel::worker_remove_element() +{ + QDeclarativeListModel model; + QDeclarativeEngine eng; + QDeclarativeComponent component(&eng, QUrl::fromLocalFile(TESTDATA("workerremoveelement.qml"))); + QQuickItem *item = createWorkerTest(&eng, &component, &model); + QVERIFY(item != 0); + + QSignalSpy spyModelRemoved(&model, SIGNAL(itemsRemoved(int,int))); + + QVERIFY(model.count() == 0); + QVERIFY(spyModelRemoved.count() == 0); + + QVERIFY(QMetaObject::invokeMethod(item, "addItem")); + + QVERIFY(model.count() == 1); + + QVERIFY(QMetaObject::invokeMethod(item, "removeItemViaWorker")); + waitForWorker(item); + + QVERIFY(model.count() == 1); + QVERIFY(spyModelRemoved.count() == 0); + + QVERIFY(QMetaObject::invokeMethod(item, "doSync")); + waitForWorker(item); + + QVERIFY(model.count() == 0); + QVERIFY(spyModelRemoved.count() == 1); + + delete item; + qApp->processEvents(); +} + +void tst_qdeclarativelistmodel::worker_remove_list() +{ + QDeclarativeListModel model; + QDeclarativeEngine eng; + QDeclarativeComponent component(&eng, QUrl::fromLocalFile(TESTDATA("workerremovelist.qml"))); + QQuickItem *item = createWorkerTest(&eng, &component, &model); + QVERIFY(item != 0); + + QSignalSpy spyModelRemoved(&model, SIGNAL(itemsRemoved(int,int))); + + QVERIFY(model.count() == 0); + QVERIFY(spyModelRemoved.count() == 0); + + QVERIFY(QMetaObject::invokeMethod(item, "addList")); + + QVERIFY(model.count() == 1); + + QVERIFY(QMetaObject::invokeMethod(item, "removeListViaWorker")); + waitForWorker(item); + + QVERIFY(model.count() == 1); + QVERIFY(spyModelRemoved.count() == 0); + + QVERIFY(QMetaObject::invokeMethod(item, "doSync")); + waitForWorker(item); + + QVERIFY(model.count() == 0); + QVERIFY(spyModelRemoved.count() == 1); + + delete item; + qApp->processEvents(); +} + QTEST_MAIN(tst_qdeclarativelistmodel) #include "tst_qdeclarativelistmodel.moc" diff --git a/tests/auto/declarative/qdeclarativemetatype/tst_qdeclarativemetatype.cpp b/tests/auto/declarative/qdeclarativemetatype/tst_qdeclarativemetatype.cpp index a85e73ed57..ce8b3357fa 100644 --- a/tests/auto/declarative/qdeclarativemetatype/tst_qdeclarativemetatype.cpp +++ b/tests/auto/declarative/qdeclarativemetatype/tst_qdeclarativemetatype.cpp @@ -202,17 +202,6 @@ void tst_qdeclarativemetatype::copy() QT_COPY_TEST(QPalette, QPalette(Qt::green)); { - QPixmap icon(100, 100); - - QIcon v = QIcon(icon); QIcon v2 = QIcon(icon); - QEXPECT_FAIL("", "QTBUG-21629 - copy() test function failure.", Abort); - QVERIFY(QDeclarativeMetaType::copy(QMetaType::QIcon, &v, 0)); - QVERIFY(v.isNull() == QIcon().isNull()); - QVERIFY(QDeclarativeMetaType::copy(QMetaType::QIcon , &v, &v2)); - QVERIFY(v.isNull() == QIcon(icon).isNull()); - } - - { QImage v = QImage(100, 100, QImage::Format_RGB32); QImage v2 = QImage(100, 100, QImage::Format_RGB32); QVERIFY(QDeclarativeMetaType::copy(QMetaType::QImage, &v, 0)); @@ -240,7 +229,6 @@ void tst_qdeclarativemetatype::copy() QVERIFY(v.shape() == QCursor(Qt::SizeFDiagCursor).shape()); } - QT_COPY_TEST(QSizePolicy, QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Maximum)); QT_COPY_TEST(QKeySequence, QKeySequence("Ctrl+O")); QT_COPY_TEST(QPen, QPen(Qt::red)); QT_COPY_TEST(QTextLength, QTextLength(QTextLength::FixedLength, 10.2)); diff --git a/tests/auto/declarative/qdeclarativeqt/data/consoleLog.qml b/tests/auto/declarative/qdeclarativeqt/data/consoleLog.qml index 4c581cf245..afb758a21f 100644 --- a/tests/auto/declarative/qdeclarativeqt/data/consoleLog.qml +++ b/tests/auto/declarative/qdeclarativeqt/data/consoleLog.qml @@ -1,8 +1,30 @@ import QtQuick 2.0 QtObject { + id: root Component.onCompleted: { + var a = [1, 2] + var b = {a: "hello", d: 1 } + var c + var d = 12 + var e = function() { return 5;} + var f = true + var g = {toString: function() { throw new Error('toString'); }} + + console.log("completed", "ok") console.log("completed ok") + console.debug("completed ok") + console.warn("completed ok") + console.error("completed ok") + console.log(a) + console.log(b) + console.log(c) + console.log(d) + console.log(e) + console.log(f) + console.log(root) + console.log(g) + console.log(exception) //This has to be at the end } } diff --git a/tests/auto/declarative/qdeclarativeqt/data/resolvedUrl.qml b/tests/auto/declarative/qdeclarativeqt/data/resolvedUrl.qml new file mode 100644 index 0000000000..06ef48b82b --- /dev/null +++ b/tests/auto/declarative/qdeclarativeqt/data/resolvedUrl.qml @@ -0,0 +1,13 @@ +import QtQuick 2.0 + +QtObject { + property string result + property bool isString: false + + Component.onCompleted: { + var a = Qt.resolvedUrl("resolvedUrl.qml"); + result = a; + isString = (typeof a) == "string" + } +} + diff --git a/tests/auto/declarative/qdeclarativeqt/tst_qdeclarativeqt.cpp b/tests/auto/declarative/qdeclarativeqt/tst_qdeclarativeqt.cpp index b4ac2dfc66..c550ac2f5b 100644 --- a/tests/auto/declarative/qdeclarativeqt/tst_qdeclarativeqt.cpp +++ b/tests/auto/declarative/qdeclarativeqt/tst_qdeclarativeqt.cpp @@ -89,6 +89,7 @@ private slots: void atob(); void fontFamilies(); void quit(); + void resolvedUrl(); private: QDeclarativeEngine engine; @@ -436,8 +437,8 @@ void tst_qdeclarativeqt::createQmlObject() QString warning3 = component.url().toString()+ ":11: Error: Qt.createQmlObject(): failed to create object: \n " + TEST_FILE("main.qml").toString() + ":4:1: Duplicate property name"; QString warning4 = component.url().toString()+ ":9: Error: Qt.createQmlObject(): Missing parent object"; QString warning5 = component.url().toString()+ ":8: Error: Qt.createQmlObject(): Invalid arguments"; - QString warning6 = "RunTimeError: Qt.createQmlObject(): failed to create object: \n " + TEST_FILE("inline").toString() + ":3: Cannot assign object type QObject with no default method"; - + QString messageFormat = QString(QLatin1String("%1 (%2:%3)")); + QString warning6 = messageFormat.arg("RunTimeError: Qt.createQmlObject(): failed to create object: \n " + TEST_FILE("inline").toString() + ":3: Cannot assign object type QObject with no default method").arg(TEST_FILE("createQmlObject.qml").toString()).arg(23); QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1)); QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2)); QTest::ignoreMessage(QtWarningMsg, qPrintable(warning3)); @@ -460,9 +461,34 @@ void tst_qdeclarativeqt::createQmlObject() void tst_qdeclarativeqt::consoleLog() { - QTest::ignoreMessage(QtDebugMsg, "completed ok"); - QTest::ignoreMessage(QtDebugMsg, "completed ok"); - QDeclarativeComponent component(&engine, TEST_FILE("consoleLog.qml")); + int startLineNumber = 15; + QUrl testFileUrl = TEST_FILE("consoleLog.qml"); + QString testString = QString(QLatin1String("completed ok (%1:%2)")).arg(testFileUrl.toString()); + QTest::ignoreMessage(QtDebugMsg, qPrintable(testString.arg(startLineNumber++))); + QTest::ignoreMessage(QtDebugMsg, qPrintable(testString.arg(startLineNumber++))); + QTest::ignoreMessage(QtDebugMsg, qPrintable(testString.arg(startLineNumber++))); + QTest::ignoreMessage(QtWarningMsg, qPrintable(testString.arg(startLineNumber++))); + QTest::ignoreMessage(QtCriticalMsg, qPrintable(testString.arg(startLineNumber++))); + + QString testArray = QString(QLatin1String("[1,2] (%1:%2)")).arg(testFileUrl.toString()); + QTest::ignoreMessage(QtDebugMsg, qPrintable(testArray.arg(startLineNumber++))); + QString testObject = QString(QLatin1String("Object (%1:%2)")).arg(testFileUrl.toString()); + QTest::ignoreMessage(QtDebugMsg, qPrintable(testObject.arg(startLineNumber++))); + QString testUndefined = QString(QLatin1String("undefined (%1:%2)")).arg(testFileUrl.toString()); + QTest::ignoreMessage(QtDebugMsg, qPrintable(testUndefined.arg(startLineNumber++))); + QString testNumber = QString(QLatin1String("12 (%1:%2)")).arg(testFileUrl.toString()); + QTest::ignoreMessage(QtDebugMsg, qPrintable(testNumber.arg(startLineNumber++))); + QString testFunction = QString(QLatin1String("function () { return 5;} (%1:%2)")).arg(testFileUrl.toString()); + QTest::ignoreMessage(QtDebugMsg, qPrintable(testFunction.arg(startLineNumber++))); + QString testBoolean = QString(QLatin1String("true (%1:%2)")).arg(testFileUrl.toString()); + QTest::ignoreMessage(QtDebugMsg, qPrintable(testBoolean.arg(startLineNumber++))); + QTest::ignoreMessage(QtDebugMsg, qPrintable(testObject.arg(startLineNumber++))); + QTest::ignoreMessage(QtDebugMsg, qPrintable(testObject.arg(startLineNumber++))); + + QString testException = QString(QLatin1String("%1:%2: ReferenceError: Can't find variable: exception")).arg(testFileUrl.toString()); + QTest::ignoreMessage(QtWarningMsg, qPrintable(testException.arg(startLineNumber++))); + + QDeclarativeComponent component(&engine, testFileUrl); QObject *object = component.create(); QVERIFY(object != 0); delete object; @@ -727,6 +753,19 @@ void tst_qdeclarativeqt::quit() delete object; } +void tst_qdeclarativeqt::resolvedUrl() +{ + QDeclarativeComponent component(&engine, TEST_FILE("resolvedUrl.qml")); + + QObject *object = component.create(); + QVERIFY(object != 0); + + QCOMPARE(object->property("result").toString(), component.url().toString()); + QCOMPARE(object->property("isString").toBool(), true); + + delete object; +} + QTEST_MAIN(tst_qdeclarativeqt) #include "tst_qdeclarativeqt.moc" diff --git a/tests/auto/declarative/qdeclarativestates/data/signalOverrideCrash3.qml b/tests/auto/declarative/qdeclarativestates/data/signalOverrideCrash3.qml new file mode 100644 index 0000000000..98d4c57219 --- /dev/null +++ b/tests/auto/declarative/qdeclarativestates/data/signalOverrideCrash3.qml @@ -0,0 +1,27 @@ +import QtQuick 2.0 + +Rectangle { + id: myRect + width: 400 + height: 400 + + onHeightChanged: console.log("base state") + + states: [ + State { + name: "state1" + PropertyChanges { + target: myRect + onHeightChanged: console.log("state1") + color: "green" + } + }, + State { + name: "state2"; + PropertyChanges { + target: myRect + onHeightChanged: console.log("state2") + color: "red" + } + }] +} diff --git a/tests/auto/declarative/qdeclarativestates/tst_qdeclarativestates.cpp b/tests/auto/declarative/qdeclarativestates/tst_qdeclarativestates.cpp index f6ab6526aa..5c9760aba3 100644 --- a/tests/auto/declarative/qdeclarativestates/tst_qdeclarativestates.cpp +++ b/tests/auto/declarative/qdeclarativestates/tst_qdeclarativestates.cpp @@ -111,6 +111,7 @@ private slots: void signalOverride(); void signalOverrideCrash(); void signalOverrideCrash2(); + void signalOverrideCrash3(); void parentChange(); void parentChangeErrors(); void anchorChanges(); @@ -519,6 +520,22 @@ void tst_qdeclarativestates::signalOverrideCrash2() delete rect; } +void tst_qdeclarativestates::signalOverrideCrash3() +{ + QDeclarativeEngine engine; + + QDeclarativeComponent rectComponent(&engine, TESTDATA("signalOverrideCrash3.qml")); + QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create()); + QVERIFY(rect != 0); + + QQuickItemPrivate::get(rect)->setState("state1"); + QQuickItemPrivate::get(rect)->setState(""); + QQuickItemPrivate::get(rect)->setState("state2"); + QQuickItemPrivate::get(rect)->setState(""); + + delete rect; +} + void tst_qdeclarativestates::parentChange() { QDeclarativeEngine engine; @@ -1211,8 +1228,9 @@ void tst_qdeclarativestates::tempState() QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create()); QVERIFY(rect != 0); QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); - QTest::ignoreMessage(QtDebugMsg, "entering placed"); - QTest::ignoreMessage(QtDebugMsg, "entering idle"); + QString messageFormat = QString(QLatin1String("%1 (file://%2:%3)")); + QTest::ignoreMessage(QtDebugMsg, messageFormat.arg(QLatin1String("entering placed")).arg(TESTDATA("legalTempState.qml")).arg(11).toLatin1()); + QTest::ignoreMessage(QtDebugMsg, messageFormat.arg(QLatin1String("entering idle")).arg(TESTDATA("legalTempState.qml")).arg(15).toLatin1()); rectPrivate->setState("placed"); QCOMPARE(rectPrivate->state(), QLatin1String("idle")); } diff --git a/tests/auto/declarative/qdeclarativevaluetypes/tst_qdeclarativevaluetypes.cpp b/tests/auto/declarative/qdeclarativevaluetypes/tst_qdeclarativevaluetypes.cpp index db0e05bcf2..b9a249fa92 100644 --- a/tests/auto/declarative/qdeclarativevaluetypes/tst_qdeclarativevaluetypes.cpp +++ b/tests/auto/declarative/qdeclarativevaluetypes/tst_qdeclarativevaluetypes.cpp @@ -1059,8 +1059,9 @@ void tst_qdeclarativevaluetypes::bindingConflict() // doesn't crash void tst_qdeclarativevaluetypes::deletedObject() { + QString messageFormat = QString(QLatin1String("%1 (%2:%3)")); QDeclarativeComponent component(&engine, TEST_FILE("deletedObject.qml")); - QTest::ignoreMessage(QtDebugMsg, "Test: 2"); + QTest::ignoreMessage(QtDebugMsg, messageFormat.arg(QLatin1String("Test: 2")).arg(TEST_FILE("deletedObject.js").toString()).arg(6).toLatin1()); MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create()); QVERIFY(object != 0); @@ -1068,7 +1069,7 @@ void tst_qdeclarativevaluetypes::deletedObject() QVERIFY(dObject != 0); delete dObject; - QTest::ignoreMessage(QtDebugMsg, "Test: undefined"); + QTest::ignoreMessage(QtDebugMsg, messageFormat.arg(QLatin1String("Test: undefined")).arg(TEST_FILE("deletedObject.js").toString()).arg(11).toLatin1()); object->emitRunScript(); delete object; diff --git a/tests/auto/declarative/qdeclarativeworkerscript/data/externalObjectWorker.qml b/tests/auto/declarative/qdeclarativeworkerscript/data/externalObjectWorker.qml new file mode 100644 index 0000000000..1dae608b50 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeworkerscript/data/externalObjectWorker.qml @@ -0,0 +1,14 @@ +import QtQuick 2.0 + +Item { + id: root + + function testExternalObject() { + worker.sendMessage(Qt.vector3d(1,2,3)); + } + + WorkerScript { + id: worker + source: "script.js" + } +} diff --git a/tests/auto/declarative/qdeclarativeworkerscript/tst_qdeclarativeworkerscript.cpp b/tests/auto/declarative/qdeclarativeworkerscript/tst_qdeclarativeworkerscript.cpp index bb7921c8e3..eb3413ec10 100644 --- a/tests/auto/declarative/qdeclarativeworkerscript/tst_qdeclarativeworkerscript.cpp +++ b/tests/auto/declarative/qdeclarativeworkerscript/tst_qdeclarativeworkerscript.cpp @@ -69,6 +69,7 @@ private slots: void messaging_data(); void messaging_sendQObjectList(); void messaging_sendJsObject(); + void messaging_sendExternalObject(); void script_with_pragma(); void script_included(); void scriptError_onLoad(); @@ -200,6 +201,16 @@ void tst_QDeclarativeWorkerScript::messaging_sendJsObject() delete worker; } +void tst_QDeclarativeWorkerScript::messaging_sendExternalObject() +{ + QDeclarativeComponent component(&m_engine, TESTDATA("externalObjectWorker.qml")); + QObject *obj = component.create(); + QVERIFY(obj); + QMetaObject::invokeMethod(obj, "testExternalObject"); + QTest::qWait(100); // shouldn't crash. + delete obj; +} + void tst_QDeclarativeWorkerScript::script_with_pragma() { QVariant value(100); diff --git a/tests/auto/declarative/qjsengine/tst_qjsengine.cpp b/tests/auto/declarative/qjsengine/tst_qjsengine.cpp index f83a1b3efd..8517850c5b 100644 --- a/tests/auto/declarative/qjsengine/tst_qjsengine.cpp +++ b/tests/auto/declarative/qjsengine/tst_qjsengine.cpp @@ -929,13 +929,11 @@ void tst_QJSEngine::jsParseDate() } // Date.parse() should be able to parse the output of Date().toString() -#ifndef Q_WS_WIN // TODO: Test and remove this since 169701 has been fixed { QJSValue ret = eng.evaluate("var x = new Date(); var s = x.toString(); s == new Date(Date.parse(s)).toString()"); QVERIFY(ret.isBoolean()); QCOMPARE(ret.toBoolean(), true); } -#endif } void tst_QJSEngine::newQObject() @@ -1073,7 +1071,7 @@ void tst_QJSEngine::newQObject_promoteObject() void tst_QJSEngine::newQObject_sameQObject() { #if 0 // ###FIXME: No QObjectWrapOptions API - QSKIP("This test stongly relay on strictlyEquals feature that would change in near future"); + QSKIP("This test strongly relies on strictlyEquals feature that would change in near future"); QScriptEngine eng; // calling newQObject() several times with same object for (int x = 0; x < 2; ++x) { @@ -2170,7 +2168,6 @@ void tst_QJSEngine::evaluate() ret = eng.evaluate(code, /*fileName =*/QString(), lineNumber); else ret = eng.evaluate(code); - QEXPECT_FAIL("/a/gimp", "v8 ignore invalid flags", Abort); QCOMPARE(eng.hasUncaughtException(), expectHadError); #if 0 // ###FIXME: No support for the line number of an uncaught exception QEXPECT_FAIL("f()", "SyntaxError do not report line number", Continue); diff --git a/tests/auto/declarative/qmlplugindump/tst_qmlplugindump.cpp b/tests/auto/declarative/qmlplugindump/tst_qmlplugindump.cpp index 234d4bc04c..57e3abb72c 100644 --- a/tests/auto/declarative/qmlplugindump/tst_qmlplugindump.cpp +++ b/tests/auto/declarative/qmlplugindump/tst_qmlplugindump.cpp @@ -66,10 +66,16 @@ tst_qmlplugindump::tst_qmlplugindump() void tst_qmlplugindump::initTestCase() { - qmlplugindumpPath = QLibraryInfo::location(QLibraryInfo::BinariesPath) + QLatin1String("/qmlplugindump"); -#ifdef Q_OS_WIN - qmlplugindumpPath += QLatin1String(".exe"); + qmlplugindumpPath = QLibraryInfo::location(QLibraryInfo::BinariesPath); + +#if defined(Q_OS_MAC) + qmlplugindumpPath += QLatin1String("/qmlplugindump.app/Contents/MacOS/qmlplugindump"); +#elif defined(Q_OS_WIN) + qmlplugindumpPath += QLatin1String("/qmlplugindump.exe"); +#else + qmlplugindumpPath += QLatin1String("/qmlplugindump"); #endif + if (!QFileInfo(qmlplugindumpPath).exists()) { QString message = QString::fromLatin1("qmlplugindump executable not found (looked for %0)") .arg(qmlplugindumpPath); diff --git a/tests/auto/declarative/qquickanchors/data/anchors.qml b/tests/auto/declarative/qquickanchors/data/anchors.qml new file mode 100644 index 0000000000..4be49a3468 --- /dev/null +++ b/tests/auto/declarative/qquickanchors/data/anchors.qml @@ -0,0 +1,162 @@ +import QtQuick 2.0 + +Rectangle { + color: "white" + width: 240 + height: 320 + Rectangle { id: masterRect; objectName: "masterRect"; x: 26; width: 96; height: 20; color: "red" } + Rectangle { + id: rect1; objectName: "rect1" + y: 20; width: 10; height: 10 + anchors.left: masterRect.left + } + Rectangle { + id: rect2; objectName: "rect2" + y: 20; width: 10; height: 10 + anchors.left: masterRect.right + } + Rectangle { + id: rect3; objectName: "rect3" + y: 20; width: 10; height: 10 + anchors.left: masterRect.horizontalCenter + } + Rectangle { + id: rect4; objectName: "rect4" + y: 30; width: 10; height: 10 + anchors.right: masterRect.left + } + Rectangle { + id: rect5; objectName: "rect5" + y: 30; width: 10; height: 10 + anchors.right: masterRect.right + } + Rectangle { + id: rect6; objectName: "rect6" + y: 30; width: 10; height: 10 + anchors.right: masterRect.horizontalCenter + } + Rectangle { + id: rect7; objectName: "rect7" + y: 50; width: 10; height: 10 + anchors.left: parent.left + } + Rectangle { + id: rect8; objectName: "rect8" + y: 50; width: 10; height: 10 + anchors.left: parent.right + } + Rectangle { + id: rect9; objectName: "rect9" + y: 50; width: 10; height: 10 + anchors.left: parent.horizontalCenter + } + Rectangle { + id: rect10; objectName: "rect10" + y: 60; width: 10; height: 10 + anchors.right: parent.left + } + Rectangle { + id: rect11; objectName: "rect11" + y: 60; width: 10; height: 10 + anchors.right: parent.right + } + Rectangle { + id: rect12; objectName: "rect12" + y: 60; width: 10; height: 10 + anchors.right: parent.horizontalCenter + } + Rectangle { + id: rect13; objectName: "rect13" + x: 200; width: 10; height: 10 + anchors.top: masterRect.bottom + } + Rectangle { + id: rect14; objectName: "rect14" + width: 10; height: 10; color: "steelblue" + anchors.verticalCenter: parent.verticalCenter + } + Rectangle { + id: rect15; objectName: "rect15" + y: 200; height: 10 + anchors.left: masterRect.left + anchors.right: masterRect.right + } + Rectangle { + id: rect16; objectName: "rect16" + y: 220; height: 10 + anchors.left: masterRect.left + anchors.horizontalCenter: masterRect.right + } + Rectangle { + id: rect17; objectName: "rect17" + y: 240; height: 10 + anchors.right: masterRect.right + anchors.horizontalCenter: masterRect.left + } + Rectangle { + id: rect18; objectName: "rect18" + x: 180; width: 10 + anchors.top: masterRect.bottom + anchors.bottom: rect12.top + } + Rectangle { + id: rect19; objectName: "rect19" + y: 70; width: 10; height: 10 + anchors.horizontalCenter: parent.horizontalCenter + } + Rectangle { + id: rect20; objectName: "rect20" + y: 70; width: 10; height: 10 + anchors.horizontalCenter: parent.right + } + Rectangle { + id: rect21; objectName: "rect21" + y: 70; width: 10; height: 10 + anchors.horizontalCenter: parent.left + } + Rectangle { + id: rect22; objectName: "rect22" + width: 10; height: 10 + anchors.centerIn: masterRect + } + Rectangle { + id: rect23; objectName: "rect23" + anchors.left: masterRect.left + anchors.leftMargin: 5 + anchors.right: masterRect.right + anchors.rightMargin: 5 + anchors.top: masterRect.top + anchors.topMargin: 5 + anchors.bottom: masterRect.bottom + anchors.bottomMargin: 5 + } + Rectangle { + id: rect24; objectName: "rect24" + width: 10; height: 10 + anchors.horizontalCenter: masterRect.left + anchors.horizontalCenterOffset: width/2 + } + Rectangle { + id: rect25; objectName: "rect25" + width: 10; height: 10 + anchors.verticalCenter: rect12.top + anchors.verticalCenterOffset: height/2 + } + Rectangle { + id: rect26; objectName: "rect26" + width: 10; height: 10 + anchors.baseline: masterRect.top + anchors.baselineOffset: height/2 + } + Text { + id: text1; objectName: "text1" + y: 200; + text: "Hello" + } + Text { + id: text2; objectName: "text2" + anchors.baseline: text1.baseline + anchors.left: text1.right + text: "World" + } +} diff --git a/tests/auto/declarative/qquickanchors/data/centerin.qml b/tests/auto/declarative/qquickanchors/data/centerin.qml new file mode 100644 index 0000000000..e5f64f1e47 --- /dev/null +++ b/tests/auto/declarative/qquickanchors/data/centerin.qml @@ -0,0 +1,12 @@ +import QtQuick 2.0 + +Rectangle { + width: 200; height: 200 + Rectangle { + objectName: "centered" + width: 50; height: 50; color: "blue" + anchors.centerIn: parent; + anchors.verticalCenterOffset: 30 + anchors.horizontalCenterOffset: 10 + } +} diff --git a/tests/auto/declarative/qquickanchors/data/centerinRotation.qml b/tests/auto/declarative/qquickanchors/data/centerinRotation.qml new file mode 100644 index 0000000000..933a25c100 --- /dev/null +++ b/tests/auto/declarative/qquickanchors/data/centerinRotation.qml @@ -0,0 +1,17 @@ +import QtQuick 2.0 + +Rectangle { + width: 200; height: 200 + Rectangle { + objectName: "outer" + rotation: 90 + width: 101; height: 101; color: "blue" + anchors.centerIn: parent; + + Rectangle { + objectName: "inner" + width: 50; height: 50; color: "blue" + anchors.centerIn: parent; + } + } +} diff --git a/tests/auto/declarative/qquickanchors/data/crash1.qml b/tests/auto/declarative/qquickanchors/data/crash1.qml new file mode 100644 index 0000000000..98dd6cfa41 --- /dev/null +++ b/tests/auto/declarative/qquickanchors/data/crash1.qml @@ -0,0 +1,11 @@ +import QtQuick 2.0 + +Column { + Text { + text: "foo" + anchors.fill: parent + } + Text { + text: "bar" + } +} diff --git a/tests/auto/declarative/qquickanchors/data/fill.qml b/tests/auto/declarative/qquickanchors/data/fill.qml new file mode 100644 index 0000000000..08db199d7b --- /dev/null +++ b/tests/auto/declarative/qquickanchors/data/fill.qml @@ -0,0 +1,14 @@ +import QtQuick 2.0 + +Rectangle { + width: 200; height: 200 + Rectangle { + objectName: "filler" + width: 50; height: 50; color: "blue" + anchors.fill: parent; + anchors.leftMargin: 10; + anchors.rightMargin: 20; + anchors.topMargin: 30; + anchors.bottomMargin: 40; + } +} diff --git a/tests/auto/declarative/qquickanchors/data/hvCenter.qml b/tests/auto/declarative/qquickanchors/data/hvCenter.qml new file mode 100644 index 0000000000..6763f8eb75 --- /dev/null +++ b/tests/auto/declarative/qquickanchors/data/hvCenter.qml @@ -0,0 +1,11 @@ +import QtQuick 2.0 + +Rectangle { + width: 77; height: 95 + Rectangle { + objectName: "centered" + width: 57; height: 57; color: "blue" + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + } +} diff --git a/tests/auto/declarative/qquickanchors/data/loop1.qml b/tests/auto/declarative/qquickanchors/data/loop1.qml new file mode 100644 index 0000000000..342b2af052 --- /dev/null +++ b/tests/auto/declarative/qquickanchors/data/loop1.qml @@ -0,0 +1,8 @@ +import QtQuick 2.0 + +Rectangle { + id: rect + width: 120; height: 200; color: "white" + Text { id: text1; anchors.right: text2.right; text: "Hello" } + Text { id: text2; anchors.right: text1.right; anchors.rightMargin: 10; text: "World" } +} diff --git a/tests/auto/declarative/qquickanchors/data/loop2.qml b/tests/auto/declarative/qquickanchors/data/loop2.qml new file mode 100644 index 0000000000..e1875be025 --- /dev/null +++ b/tests/auto/declarative/qquickanchors/data/loop2.qml @@ -0,0 +1,20 @@ +import QtQuick 2.0 + +Rectangle { + id: container; + width: 600; + height: 600; + + Image { + id: image1 + source: "http://labs.trolltech.com/blogs/wp-content/uploads/2009/03/3311388091_ac2a257feb.jpg" + anchors.right: image2.left + } + + Image { + id: image2 + source: "http://labs.trolltech.com/blogs/wp-content/uploads/2009/03/oslo_groupphoto.jpg" + anchors.left: image1.right + anchors.leftMargin: 20 + } +} diff --git a/tests/auto/declarative/qquickanchors/data/margins.qml b/tests/auto/declarative/qquickanchors/data/margins.qml new file mode 100644 index 0000000000..9403f65a61 --- /dev/null +++ b/tests/auto/declarative/qquickanchors/data/margins.qml @@ -0,0 +1,13 @@ +import QtQuick 2.0 + +Rectangle { + width: 200; height: 200 + Rectangle { + objectName: "filler" + width: 50; height: 50; color: "blue" + anchors.fill: parent; + anchors.margins: 10 + anchors.leftMargin: 5 + anchors.topMargin: 6 + } +} diff --git a/tests/auto/declarative/qquickanchors/qquickanchors.pro b/tests/auto/declarative/qquickanchors/qquickanchors.pro new file mode 100644 index 0000000000..0d085d367d --- /dev/null +++ b/tests/auto/declarative/qquickanchors/qquickanchors.pro @@ -0,0 +1,12 @@ +TARGET = tst_qquickanchors +CONFIG += testcase +SOURCES += tst_qquickanchors.cpp +macx:CONFIG -= app_bundle + +testDataFiles.files = data +testDataFiles.path = . +DEPLOYMENT += testDataFiles + +CONFIG += parallel_test + +QT += core-private gui-private declarative-private v8-private testlib diff --git a/tests/auto/declarative/qquickanchors/tst_qquickanchors.cpp b/tests/auto/declarative/qquickanchors/tst_qquickanchors.cpp new file mode 100644 index 0000000000..cfdab7f14c --- /dev/null +++ b/tests/auto/declarative/qquickanchors/tst_qquickanchors.cpp @@ -0,0 +1,693 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include <qtest.h> +#include <QSignalSpy> +#include <private/qquickitem_p.h> +#include <QtDeclarative/qdeclarativeengine.h> +#include <QtDeclarative/qdeclarativecomponent.h> +#include <QtDeclarative/qquickview.h> +#include <QtDeclarative/private/qquickrectangle_p.h> +#include <QtDeclarative/private/qquicktext_p.h> +#include <QtDeclarative/private/qquickanchors_p_p.h> +#include <QtDeclarative/private/qquickitem_p.h> +#include "../shared/util.h" + +Q_DECLARE_METATYPE(QQuickAnchors::Anchor) +Q_DECLARE_METATYPE(QQuickAnchorLine::AnchorLine) + +class tst_qquickanchors : public QObject +{ + Q_OBJECT +public: + tst_qquickanchors() {} + +private slots: + void basicAnchors(); + void basicAnchorsRTL(); + void loops(); + void illegalSets(); + void illegalSets_data(); + void reset(); + void reset_data(); + void resetConvenience(); + void nullItem(); + void nullItem_data(); + void crash1(); + void centerIn(); + void centerInRTL(); + void centerInRotation(); + void hvCenter(); + void hvCenterRTL(); + void fill(); + void fillRTL(); + void margins(); + void marginsRTL(); +}; + +/* + Find an item with the specified objectName. +*/ +template<typename T> +T *findItem(QQuickItem *parent, const QString &objectName) +{ + if (!parent) + return 0; + + const QMetaObject &mo = T::staticMetaObject; + //qDebug() << parent->QQuickItem::children().count() << "children"; + for (int i = 0; i < parent->childItems().count(); ++i) { + QQuickItem *item = qobject_cast<QQuickItem*>(parent->childItems().at(i)); + if (!item) + continue; + //qDebug() << "try" << item; + if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) + return static_cast<T*>(item); + item = findItem<T>(item, objectName); + if (item) + return static_cast<T*>(item); + } + + return 0; +} + +void tst_qquickanchors::basicAnchors() +{ + QQuickView *view = new QQuickView; + view->setSource(QUrl::fromLocalFile(TESTDATA("anchors.qml"))); + + qApp->processEvents(); + + //sibling horizontal + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect1"))->x(), 26.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect2"))->x(), 122.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect3"))->x(), 74.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect4"))->x(), 16.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect5"))->x(), 112.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect6"))->x(), 64.0); + + //parent horizontal + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect7"))->x(), 0.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect8"))->x(), 240.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect9"))->x(), 120.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect10"))->x(), -10.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect11"))->x(), 230.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect12"))->x(), 110.0); + + //vertical + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect13"))->y(), 20.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect14"))->y(), 155.0); + + //stretch + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect15"))->x(), 26.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect15"))->width(), 96.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect16"))->x(), 26.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect16"))->width(), 192.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect17"))->x(), -70.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect17"))->width(), 192.0); + + //vertical stretch + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect18"))->y(), 20.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect18"))->height(), 40.0); + + //more parent horizontal + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect19"))->x(), 115.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect20"))->x(), 235.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect21"))->x(), -5.0); + + //centerIn + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect22"))->x(), 69.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect22"))->y(), 5.0); + + //margins + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect23"))->x(), 31.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect23"))->y(), 5.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect23"))->width(), 86.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect23"))->height(), 10.0); + + // offsets + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect24"))->x(), 26.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect25"))->y(), 60.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect26"))->y(), 5.0); + + //baseline + QQuickText *text1 = findItem<QQuickText>(view->rootObject(), QLatin1String("text1")); + QQuickText *text2 = findItem<QQuickText>(view->rootObject(), QLatin1String("text2")); + QCOMPARE(text1->y(), text2->y()); + + delete view; +} + +QQuickItem* childItem(QQuickItem *parentItem, const char * itemString) { + return findItem<QQuickItem>(parentItem, QLatin1String(itemString)); +} + +qreal offsetMasterRTL(QQuickItem *rootItem, const char * itemString) { + QQuickItem* masterItem = findItem<QQuickItem>(rootItem, QLatin1String("masterRect")); + return masterItem->width()+2*masterItem->x()-findItem<QQuickItem>(rootItem, QLatin1String(itemString))->width(); +} + +qreal offsetParentRTL(QQuickItem *rootItem, const char * itemString) { + return rootItem->width()+2*rootItem->x()-findItem<QQuickItem>(rootItem, QLatin1String(itemString))->width(); +} + +void mirrorAnchors(QQuickItem *item) { + QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); + itemPrivate->setLayoutMirror(true); +} + +void tst_qquickanchors::basicAnchorsRTL() +{ + QQuickView *view = new QQuickView; + view->setSource(QUrl::fromLocalFile(TESTDATA("anchors.qml"))); + + qApp->processEvents(); + + QQuickItem* rootItem = qobject_cast<QQuickItem*>(view->rootObject()); + foreach (QObject *child, rootItem->children()) { + bool mirrored = QQuickItemPrivate::get(qobject_cast<QQuickItem*>(child))->anchors()->property("mirrored").toBool(); + QCOMPARE(mirrored, false); + } + + foreach (QObject *child, rootItem->children()) + mirrorAnchors(qobject_cast<QQuickItem*>(child)); + + foreach (QObject *child, rootItem->children()) { + bool mirrored = QQuickItemPrivate::get(qobject_cast<QQuickItem*>(child))->anchors()->property("mirrored").toBool(); + QCOMPARE(mirrored, true); + } + + //sibling horizontal + QCOMPARE(childItem(rootItem, "rect1")->x(), offsetMasterRTL(rootItem, "rect1")-26.0); + QCOMPARE(childItem(rootItem, "rect2")->x(), offsetMasterRTL(rootItem, "rect2")-122.0); + QCOMPARE(childItem(rootItem, "rect3")->x(), offsetMasterRTL(rootItem, "rect3")-74.0); + QCOMPARE(childItem(rootItem, "rect4")->x(), offsetMasterRTL(rootItem, "rect4")-16.0); + QCOMPARE(childItem(rootItem, "rect5")->x(), offsetMasterRTL(rootItem, "rect5")-112.0); + QCOMPARE(childItem(rootItem, "rect6")->x(), offsetMasterRTL(rootItem, "rect6")-64.0); + + //parent horizontal + QCOMPARE(childItem(rootItem, "rect7")->x(), offsetParentRTL(rootItem, "rect7")-0.0); + QCOMPARE(childItem(rootItem, "rect8")->x(), offsetParentRTL(rootItem, "rect8")-240.0); + QCOMPARE(childItem(rootItem, "rect9")->x(), offsetParentRTL(rootItem, "rect9")-120.0); + QCOMPARE(childItem(rootItem, "rect10")->x(), offsetParentRTL(rootItem, "rect10")+10.0); + QCOMPARE(childItem(rootItem, "rect11")->x(), offsetParentRTL(rootItem, "rect11")-230.0); + QCOMPARE(childItem(rootItem, "rect12")->x(), offsetParentRTL(rootItem, "rect12")-110.0); + + //vertical + QCOMPARE(childItem(rootItem, "rect13")->y(), 20.0); + QCOMPARE(childItem(rootItem, "rect14")->y(), 155.0); + + //stretch + QCOMPARE(childItem(rootItem, "rect15")->x(), offsetMasterRTL(rootItem, "rect15")-26.0); + QCOMPARE(childItem(rootItem, "rect15")->width(), 96.0); + QCOMPARE(childItem(rootItem, "rect16")->x(), offsetMasterRTL(rootItem, "rect16")-26.0); + QCOMPARE(childItem(rootItem, "rect16")->width(), 192.0); + QCOMPARE(childItem(rootItem, "rect17")->x(), offsetMasterRTL(rootItem, "rect17")+70.0); + QCOMPARE(childItem(rootItem, "rect17")->width(), 192.0); + + //vertical stretch + QCOMPARE(childItem(rootItem, "rect18")->y(), 20.0); + QCOMPARE(childItem(rootItem, "rect18")->height(), 40.0); + + //more parent horizontal + QCOMPARE(childItem(rootItem, "rect19")->x(), offsetParentRTL(rootItem, "rect19")-115.0); + QCOMPARE(childItem(rootItem, "rect20")->x(), offsetParentRTL(rootItem, "rect20")-235.0); + QCOMPARE(childItem(rootItem, "rect21")->x(), offsetParentRTL(rootItem, "rect21")+5.0); + + //centerIn + QCOMPARE(childItem(rootItem, "rect22")->x(), offsetMasterRTL(rootItem, "rect22")-69.0); + QCOMPARE(childItem(rootItem, "rect22")->y(), 5.0); + + //margins + QCOMPARE(childItem(rootItem, "rect23")->x(), offsetMasterRTL(rootItem, "rect23")-31.0); + QCOMPARE(childItem(rootItem, "rect23")->y(), 5.0); + QCOMPARE(childItem(rootItem, "rect23")->width(), 86.0); + QCOMPARE(childItem(rootItem, "rect23")->height(), 10.0); + + // offsets + QCOMPARE(childItem(rootItem, "rect24")->x(), offsetMasterRTL(rootItem, "rect24")-26.0); + QCOMPARE(childItem(rootItem, "rect25")->y(), 60.0); + QCOMPARE(childItem(rootItem, "rect26")->y(), 5.0); + + //baseline + QQuickText *text1 = findItem<QQuickText>(rootItem, QLatin1String("text1")); + QQuickText *text2 = findItem<QQuickText>(rootItem, QLatin1String("text2")); + QCOMPARE(text1->y(), text2->y()); + + delete view; +} + +// mostly testing that we don't crash +void tst_qquickanchors::loops() +{ + { + QUrl source(QUrl::fromLocalFile(TESTDATA("loop1.qml"))); + + QString expect = source.toString() + ":6:5: QML Text: Possible anchor loop detected on horizontal anchor."; + QTest::ignoreMessage(QtWarningMsg, expect.toLatin1()); + QTest::ignoreMessage(QtWarningMsg, expect.toLatin1()); + QTest::ignoreMessage(QtWarningMsg, expect.toLatin1()); + + QQuickView *view = new QQuickView; + view->setSource(source); + qApp->processEvents(); + + delete view; + } + + { + QUrl source(QUrl::fromLocalFile(TESTDATA("loop2.qml"))); + + QString expect = source.toString() + ":8:3: QML Image: Possible anchor loop detected on horizontal anchor."; + QTest::ignoreMessage(QtWarningMsg, expect.toLatin1()); + + QQuickView *view = new QQuickView; + view->setSource(source); + qApp->processEvents(); + + delete view; + } +} + +void tst_qquickanchors::illegalSets() +{ + QFETCH(QString, qml); + QFETCH(QString, warning); + + QTest::ignoreMessage(QtWarningMsg, warning.toLatin1()); + + QDeclarativeEngine engine; + QDeclarativeComponent component(&engine); + component.setData(QByteArray("import QtQuick 1.0\n" + qml.toUtf8()), QUrl::fromLocalFile("")); + if (!component.isReady()) + qWarning() << "Test errors:" << component.errors(); + QVERIFY(component.isReady()); + QObject *o = component.create(); + delete o; +} + +void tst_qquickanchors::illegalSets_data() +{ + QTest::addColumn<QString>("qml"); + QTest::addColumn<QString>("warning"); + + QTest::newRow("H - too many anchors") + << "Rectangle { id: rect; Rectangle { anchors.left: rect.left; anchors.right: rect.right; anchors.horizontalCenter: rect.horizontalCenter } }" + << "file::2:23: QML Rectangle: Cannot specify left, right, and hcenter anchors."; + + foreach (const QString &side, QStringList() << "left" << "right") { + QTest::newRow("H - anchor to V") + << QString("Rectangle { Rectangle { anchors.%1: parent.top } }").arg(side) + << "file::2:13: QML Rectangle: Cannot anchor a horizontal edge to a vertical edge."; + + QTest::newRow("H - anchor to non parent/sibling") + << QString("Rectangle { Item { Rectangle { id: rect } } Rectangle { anchors.%1: rect.%1 } }").arg(side) + << "file::2:45: QML Rectangle: Cannot anchor to an item that isn't a parent or sibling."; + + QTest::newRow("H - anchor to self") + << QString("Rectangle { id: rect; anchors.%1: rect.%1 }").arg(side) + << "file::2:1: QML Rectangle: Cannot anchor item to self."; + } + + + QTest::newRow("V - too many anchors") + << "Rectangle { id: rect; Rectangle { anchors.top: rect.top; anchors.bottom: rect.bottom; anchors.verticalCenter: rect.verticalCenter } }" + << "file::2:23: QML Rectangle: Cannot specify top, bottom, and vcenter anchors."; + + QTest::newRow("V - too many anchors with baseline") + << "Rectangle { Text { id: text1; text: \"Hello\" } Text { anchors.baseline: text1.baseline; anchors.top: text1.top; } }" + << "file::2:47: QML Text: Baseline anchor cannot be used in conjunction with top, bottom, or vcenter anchors."; + + foreach (const QString &side, QStringList() << "top" << "bottom" << "baseline") { + + QTest::newRow("V - anchor to H") + << QString("Rectangle { Rectangle { anchors.%1: parent.left } }").arg(side) + << "file::2:13: QML Rectangle: Cannot anchor a vertical edge to a horizontal edge."; + + QTest::newRow("V - anchor to non parent/sibling") + << QString("Rectangle { Item { Rectangle { id: rect } } Rectangle { anchors.%1: rect.%1 } }").arg(side) + << "file::2:45: QML Rectangle: Cannot anchor to an item that isn't a parent or sibling."; + + QTest::newRow("V - anchor to self") + << QString("Rectangle { id: rect; anchors.%1: rect.%1 }").arg(side) + << "file::2:1: QML Rectangle: Cannot anchor item to self."; + } + + + QTest::newRow("centerIn - anchor to non parent/sibling") + << "Rectangle { Item { Rectangle { id: rect } } Rectangle { anchors.centerIn: rect} }" + << "file::2:45: QML Rectangle: Cannot anchor to an item that isn't a parent or sibling."; + + + QTest::newRow("fill - anchor to non parent/sibling") + << "Rectangle { Item { Rectangle { id: rect } } Rectangle { anchors.fill: rect} }" + << "file::2:45: QML Rectangle: Cannot anchor to an item that isn't a parent or sibling."; +} + +void tst_qquickanchors::reset() +{ + QFETCH(QString, side); + QFETCH(QQuickAnchorLine::AnchorLine, anchorLine); + QFETCH(QQuickAnchors::Anchor, usedAnchor); + + QQuickItem *baseItem = new QQuickItem; + + QQuickAnchorLine anchor; + anchor.item = baseItem; + anchor.anchorLine = anchorLine; + + QQuickItem *item = new QQuickItem; + QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); + + const QMetaObject *meta = itemPrivate->anchors()->metaObject(); + QMetaProperty p = meta->property(meta->indexOfProperty(side.toUtf8().constData())); + + QVERIFY(p.write(itemPrivate->anchors(), qVariantFromValue(anchor))); + QCOMPARE(itemPrivate->anchors()->usedAnchors().testFlag(usedAnchor), true); + + QVERIFY(p.reset(itemPrivate->anchors())); + QCOMPARE(itemPrivate->anchors()->usedAnchors().testFlag(usedAnchor), false); + + delete item; + delete baseItem; +} + +void tst_qquickanchors::reset_data() +{ + QTest::addColumn<QString>("side"); + QTest::addColumn<QQuickAnchorLine::AnchorLine>("anchorLine"); + QTest::addColumn<QQuickAnchors::Anchor>("usedAnchor"); + + QTest::newRow("left") << "left" << QQuickAnchorLine::Left << QQuickAnchors::LeftAnchor; + QTest::newRow("top") << "top" << QQuickAnchorLine::Top << QQuickAnchors::TopAnchor; + QTest::newRow("right") << "right" << QQuickAnchorLine::Right << QQuickAnchors::RightAnchor; + QTest::newRow("bottom") << "bottom" << QQuickAnchorLine::Bottom << QQuickAnchors::BottomAnchor; + + QTest::newRow("hcenter") << "horizontalCenter" << QQuickAnchorLine::HCenter << QQuickAnchors::HCenterAnchor; + QTest::newRow("vcenter") << "verticalCenter" << QQuickAnchorLine::VCenter << QQuickAnchors::VCenterAnchor; + QTest::newRow("baseline") << "baseline" << QQuickAnchorLine::Baseline << QQuickAnchors::BaselineAnchor; +} + +void tst_qquickanchors::resetConvenience() +{ + QQuickItem *baseItem = new QQuickItem; + QQuickItem *item = new QQuickItem; + QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); + + //fill + itemPrivate->anchors()->setFill(baseItem); + QVERIFY(itemPrivate->anchors()->fill() == baseItem); + itemPrivate->anchors()->resetFill(); + QVERIFY(itemPrivate->anchors()->fill() == 0); + + //centerIn + itemPrivate->anchors()->setCenterIn(baseItem); + QVERIFY(itemPrivate->anchors()->centerIn() == baseItem); + itemPrivate->anchors()->resetCenterIn(); + QVERIFY(itemPrivate->anchors()->centerIn() == 0); + + delete item; + delete baseItem; +} + +void tst_qquickanchors::nullItem() +{ + QFETCH(QString, side); + + QQuickAnchorLine anchor; + QQuickItem *item = new QQuickItem; + QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); + + const QMetaObject *meta = itemPrivate->anchors()->metaObject(); + QMetaProperty p = meta->property(meta->indexOfProperty(side.toUtf8().constData())); + + QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML Item: Cannot anchor to a null item."); + QVERIFY(p.write(itemPrivate->anchors(), qVariantFromValue(anchor))); + + delete item; +} + +void tst_qquickanchors::nullItem_data() +{ + QTest::addColumn<QString>("side"); + + QTest::newRow("left") << "left"; + QTest::newRow("top") << "top"; + QTest::newRow("right") << "right"; + QTest::newRow("bottom") << "bottom"; + + QTest::newRow("hcenter") << "horizontalCenter"; + QTest::newRow("vcenter") << "verticalCenter"; + QTest::newRow("baseline") << "baseline"; +} + +//QTBUG-5428 +void tst_qquickanchors::crash1() +{ + QUrl source(QUrl::fromLocalFile(TESTDATA("crash1.qml"))); + + QString expect = source.toString() + ":3:1: QML Column: Cannot specify top, bottom, verticalCenter, fill or centerIn anchors for items inside Column"; + + QTest::ignoreMessage(QtWarningMsg, expect.toLatin1()); + + QQuickView *view = new QQuickView(source); + qApp->processEvents(); + + delete view; +} + +void tst_qquickanchors::fill() +{ + QQuickView *view = new QQuickView(QUrl::fromLocalFile(TESTDATA("fill.qml"))); + + qApp->processEvents(); + QQuickRectangle* rect = findItem<QQuickRectangle>(view->rootObject(), QLatin1String("filler")); + QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); + QCOMPARE(rect->x(), 0.0 + 10.0); + QCOMPARE(rect->y(), 0.0 + 30.0); + QCOMPARE(rect->width(), 200.0 - 10.0 - 20.0); + QCOMPARE(rect->height(), 200.0 - 30.0 - 40.0); + //Alter Offsets (tests QTBUG-6631) + rectPrivate->anchors()->setLeftMargin(20.0); + rectPrivate->anchors()->setRightMargin(0.0); + rectPrivate->anchors()->setBottomMargin(0.0); + rectPrivate->anchors()->setTopMargin(10.0); + QCOMPARE(rect->x(), 0.0 + 20.0); + QCOMPARE(rect->y(), 0.0 + 10.0); + QCOMPARE(rect->width(), 200.0 - 20.0); + QCOMPARE(rect->height(), 200.0 - 10.0); + + delete view; +} + +void tst_qquickanchors::fillRTL() +{ + QQuickView *view = new QQuickView(QUrl::fromLocalFile(TESTDATA("fill.qml"))); + + qApp->processEvents(); + QQuickRectangle* rect = findItem<QQuickRectangle>(view->rootObject(), QLatin1String("filler")); + QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); + mirrorAnchors(rect); + + QCOMPARE(rect->x(), 0.0 + 20.0); + QCOMPARE(rect->y(), 0.0 + 30.0); + QCOMPARE(rect->width(), 200.0 - 10.0 - 20.0); + QCOMPARE(rect->height(), 200.0 - 30.0 - 40.0); + //Alter Offsets (tests QTBUG-6631) + rectPrivate->anchors()->setLeftMargin(20.0); + rectPrivate->anchors()->setRightMargin(0.0); + rectPrivate->anchors()->setBottomMargin(0.0); + rectPrivate->anchors()->setTopMargin(10.0); + QCOMPARE(rect->x(), 0.0 + 0.0); + QCOMPARE(rect->y(), 0.0 + 10.0); + QCOMPARE(rect->width(), 200.0 - 20.0); + QCOMPARE(rect->height(), 200.0 - 10.0); + + delete view; +} + +void tst_qquickanchors::centerIn() +{ + QQuickView *view = new QQuickView(QUrl::fromLocalFile(TESTDATA("centerin.qml"))); + + qApp->processEvents(); + QQuickRectangle* rect = findItem<QQuickRectangle>(view->rootObject(), QLatin1String("centered")); + QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); + + QCOMPARE(rect->x(), 75.0 + 10); + QCOMPARE(rect->y(), 75.0 + 30); + //Alter Offsets (tests QTBUG-6631) + rectPrivate->anchors()->setHorizontalCenterOffset(-20.0); + rectPrivate->anchors()->setVerticalCenterOffset(-10.0); + QCOMPARE(rect->x(), 75.0 - 20.0); + QCOMPARE(rect->y(), 75.0 - 10.0); + + delete view; +} + +void tst_qquickanchors::centerInRTL() +{ + QQuickView *view = new QQuickView(QUrl::fromLocalFile(TESTDATA("centerin.qml"))); + + qApp->processEvents(); + QQuickRectangle* rect = findItem<QQuickRectangle>(view->rootObject(), QLatin1String("centered")); + QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); + mirrorAnchors(rect); + + QCOMPARE(rect->x(), 75.0 - 10); + QCOMPARE(rect->y(), 75.0 + 30); + //Alter Offsets (tests QTBUG-6631) + rectPrivate->anchors()->setHorizontalCenterOffset(-20.0); + rectPrivate->anchors()->setVerticalCenterOffset(-10.0); + QCOMPARE(rect->x(), 75.0 + 20.0); + QCOMPARE(rect->y(), 75.0 - 10.0); + + delete view; +} + +//QTBUG-12441 +void tst_qquickanchors::centerInRotation() +{ + QQuickView *view = new QQuickView(QUrl::fromLocalFile(TESTDATA("centerinRotation.qml"))); + + qApp->processEvents(); + QQuickRectangle* outer = findItem<QQuickRectangle>(view->rootObject(), QLatin1String("outer")); + QQuickRectangle* inner = findItem<QQuickRectangle>(view->rootObject(), QLatin1String("inner")); + + QEXPECT_FAIL("", "QTBUG-12441", Abort); + QCOMPARE(outer->x(), qreal(49.5)); + QCOMPARE(outer->y(), qreal(49.5)); + QCOMPARE(inner->x(), qreal(25.5)); + QCOMPARE(inner->y(), qreal(25.5)); + + delete view; +} + +void tst_qquickanchors::hvCenter() +{ + QQuickView *view = new QQuickView(QUrl::fromLocalFile(TESTDATA("hvCenter.qml"))); + + qApp->processEvents(); + QQuickRectangle* rect = findItem<QQuickRectangle>(view->rootObject(), QLatin1String("centered")); + QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); + + // test QTBUG-10999 + QCOMPARE(rect->x(), 10.0); + QCOMPARE(rect->y(), 19.0); + + rectPrivate->anchors()->setHorizontalCenterOffset(-5.0); + rectPrivate->anchors()->setVerticalCenterOffset(5.0); + QCOMPARE(rect->x(), 10.0 - 5.0); + QCOMPARE(rect->y(), 19.0 + 5.0); + + delete view; +} + +void tst_qquickanchors::hvCenterRTL() +{ + QQuickView *view = new QQuickView(QUrl::fromLocalFile(TESTDATA("hvCenter.qml"))); + + qApp->processEvents(); + QQuickRectangle* rect = findItem<QQuickRectangle>(view->rootObject(), QLatin1String("centered")); + QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); + mirrorAnchors(rect); + + // test QTBUG-10999 + QCOMPARE(rect->x(), 10.0); + QCOMPARE(rect->y(), 19.0); + + rectPrivate->anchors()->setHorizontalCenterOffset(-5.0); + rectPrivate->anchors()->setVerticalCenterOffset(5.0); + QCOMPARE(rect->x(), 10.0 + 5.0); + QCOMPARE(rect->y(), 19.0 + 5.0); + + delete view; +} +void tst_qquickanchors::margins() +{ + QQuickView *view = new QQuickView(QUrl::fromLocalFile(TESTDATA("margins.qml"))); + + qApp->processEvents(); + QQuickRectangle* rect = findItem<QQuickRectangle>(view->rootObject(), QLatin1String("filler")); + QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); + QCOMPARE(rect->x(), 5.0); + QCOMPARE(rect->y(), 6.0); + QCOMPARE(rect->width(), 200.0 - 5.0 - 10.0); + QCOMPARE(rect->height(), 200.0 - 6.0 - 10.0); + + rectPrivate->anchors()->setTopMargin(0.0); + rectPrivate->anchors()->setMargins(20.0); + + QCOMPARE(rect->x(), 5.0); + QCOMPARE(rect->y(), 20.0); + QCOMPARE(rect->width(), 200.0 - 5.0 - 20.0); + QCOMPARE(rect->height(), 200.0 - 20.0 - 20.0); + + delete view; +} + +void tst_qquickanchors::marginsRTL() +{ + QQuickView *view = new QQuickView(QUrl::fromLocalFile(TESTDATA("margins.qml"))); + + QQuickRectangle* rect = findItem<QQuickRectangle>(view->rootObject(), QLatin1String("filler")); + QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); + mirrorAnchors(rect); + + QCOMPARE(rect->x(), 10.0); + QCOMPARE(rect->y(), 6.0); + QCOMPARE(rect->width(), 200.0 - 5.0 - 10.0); + QCOMPARE(rect->height(), 200.0 - 6.0 - 10.0); + + rectPrivate->anchors()->setTopMargin(0.0); + rectPrivate->anchors()->setMargins(20.0); + + QCOMPARE(rect->x(), 20.0); + QCOMPARE(rect->y(), 20.0); + QCOMPARE(rect->width(), 200.0 - 5.0 - 20.0); + QCOMPARE(rect->height(), 200.0 - 20.0 - 20.0); + + delete view; +} + + +QTEST_MAIN(tst_qquickanchors) + +#include "tst_qquickanchors.moc" diff --git a/tests/auto/declarative/qquickcanvas/tst_qquickcanvas.cpp b/tests/auto/declarative/qquickcanvas/tst_qquickcanvas.cpp index d2b691d461..640b4b4f40 100644 --- a/tests/auto/declarative/qquickcanvas/tst_qquickcanvas.cpp +++ b/tests/auto/declarative/qquickcanvas/tst_qquickcanvas.cpp @@ -153,8 +153,9 @@ protected: mousePressId = ++mousePressNum; } - bool childMouseEventFilter(QQuickItem *, QEvent *) { - mousePressId = ++mousePressNum; + bool childMouseEventFilter(QQuickItem *, QEvent *event) { + if (event->type() == QEvent::MouseButtonPress) + mousePressId = ++mousePressNum; return false; } diff --git a/tests/auto/declarative/qquickflickable/tst_qquickflickable.cpp b/tests/auto/declarative/qquickflickable/tst_qquickflickable.cpp index 2f155e298e..a02db06616 100644 --- a/tests/auto/declarative/qquickflickable/tst_qquickflickable.cpp +++ b/tests/auto/declarative/qquickflickable/tst_qquickflickable.cpp @@ -533,7 +533,7 @@ void tst_qquickflickable::disabled() void tst_qquickflickable::flickVelocity() { -#ifdef Q_WS_MAC +#ifdef Q_OS_MAC QSKIP("Producing flicks on Mac CI impossible due to timing problems"); #endif diff --git a/tests/auto/declarative/qquickfocusscope/tst_qquickfocusscope.cpp b/tests/auto/declarative/qquickfocusscope/tst_qquickfocusscope.cpp index ffb9660262..d0149ed1d6 100644 --- a/tests/auto/declarative/qquickfocusscope/tst_qquickfocusscope.cpp +++ b/tests/auto/declarative/qquickfocusscope/tst_qquickfocusscope.cpp @@ -557,6 +557,7 @@ void tst_qquickfocusscope::canvasFocus() QSignalSpy scope2ActiveFocusSpy(scope2, SIGNAL(activeFocusChanged(bool))); QSignalSpy item2ActiveFocusSpy(item2, SIGNAL(activeFocusChanged(bool))); + QEXPECT_FAIL("", "QTBUG-22415", Abort); QCOMPARE(rootItem->hasFocus(), false); QCOMPARE(rootItem->hasActiveFocus(), false); QCOMPARE(scope1->hasFocus(), true); @@ -585,6 +586,7 @@ void tst_qquickfocusscope::canvasFocus() QCOMPARE(scope2->hasActiveFocus(), false); QCOMPARE(item2->hasFocus(), false); QCOMPARE(item2->hasActiveFocus(), false); + QCOMPARE(rootFocusSpy.count(), 1); QCOMPARE(rootActiveFocusSpy.count(), 1); QCOMPARE(scope1FocusSpy.count(), 0); @@ -605,6 +607,7 @@ void tst_qquickfocusscope::canvasFocus() QCOMPARE(scope1->hasActiveFocus(), false); QCOMPARE(item1->hasFocus(), true); QCOMPARE(item1->hasActiveFocus(), false); + QCOMPARE(rootFocusSpy.count(), 2); QCOMPARE(rootActiveFocusSpy.count(), 2); QCOMPARE(scope1FocusSpy.count(), 0); @@ -612,6 +615,7 @@ void tst_qquickfocusscope::canvasFocus() QCOMPARE(item1FocusSpy.count(), 0); QCOMPARE(item1ActiveFocusSpy.count(), 2); + // canvas does not have focus, so item2 will not get active focus item2->forceActiveFocus(); diff --git a/tests/auto/declarative/qquickgridview/tst_qquickgridview.cpp b/tests/auto/declarative/qquickgridview/tst_qquickgridview.cpp index 5f3842a660..a190d878ad 100644 --- a/tests/auto/declarative/qquickgridview/tst_qquickgridview.cpp +++ b/tests/auto/declarative/qquickgridview/tst_qquickgridview.cpp @@ -72,6 +72,8 @@ private slots: void inserted_more(); void inserted_more_data(); void removed(); + void addOrRemoveBeforeVisible(); + void addOrRemoveBeforeVisible_data(); void clear(); void moved(); void moved_data(); @@ -740,6 +742,91 @@ void tst_QQuickGridView::removed() delete canvas; } +void tst_QQuickGridView::addOrRemoveBeforeVisible() +{ + // QTBUG-21588: ensure re-layout is done on grid after adding or removing + // items from before the visible area + + QFETCH(bool, doAdd); + QFETCH(qreal, newTopContentY); + + QQuickView *canvas = createView(); + canvas->show(); + + TestModel model; + for (int i = 0; i < 30; i++) + model.addItem("Item" + QString::number(i), ""); + + QDeclarativeContext *ctxt = canvas->rootContext(); + ctxt->setContextProperty("testModel", &model); + ctxt->setContextProperty("testRightToLeft", QVariant(false)); + ctxt->setContextProperty("testTopToBottom", QVariant(false)); + canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml"))); + + QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid"); + QTRY_VERIFY(gridview != 0); + QQuickItem *contentItem = gridview->contentItem(); + QTRY_VERIFY(contentItem != 0); + + QQuickText *name = findItem<QQuickText>(contentItem, "textName", 0); + QTRY_COMPARE(name->text(), QString("Item0")); + + gridview->setCurrentIndex(0); + qApp->processEvents(); + + // scroll down until item 0 is no longer drawn + // (bug not triggered if we just move using content y, since that doesn't + // refill and change the visible items) + gridview->setCurrentIndex(24); + qApp->processEvents(); + + QTRY_COMPARE(gridview->currentIndex(), 24); + QTRY_COMPARE(gridview->contentY(), 220.0); + + QTest::qWait(100); // wait for refill to complete + QTRY_VERIFY(!findItem<QQuickItem>(contentItem, "wrapper", 0)); // 0 shouldn't be visible + + if (doAdd) { + model.insertItem(0, "New Item", "New Item number"); + QTRY_COMPARE(gridview->count(), 31); + } else { + model.removeItem(0); + QTRY_COMPARE(gridview->count(), 29); + } + + // scroll back up and item 0 should be gone + gridview->setCurrentIndex(0); + qApp->processEvents(); + QTRY_COMPARE(gridview->currentIndex(), 0); + QTRY_COMPARE(gridview->contentY(), newTopContentY); + + name = findItem<QQuickText>(contentItem, "textName", 0); + if (doAdd) + QCOMPARE(name->text(), QString("New Item")); + else + QCOMPARE(name->text(), QString("Item1")); + + // Confirm items positioned correctly + int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count(); + for (int i = 0; i < model.count() && i < itemCount; ++i) { + QTRY_VERIFY(findItem<QQuickItem>(contentItem, "wrapper", i)); + QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i); + QTRY_VERIFY(item->x() == (i%3)*80); + QTRY_VERIFY(item->y() == (i/3)*60 + newTopContentY); + } + + delete canvas; +} + +void tst_QQuickGridView::addOrRemoveBeforeVisible_data() +{ + QTest::addColumn<bool>("doAdd"); + QTest::addColumn<qreal>("newTopContentY"); + + QTest::newRow("add") << true << -60.0; + QTest::newRow("remove") << false << 0.0; +} + void tst_QQuickGridView::clear() { QQuickView *canvas = createView(); @@ -2356,18 +2443,17 @@ void tst_QQuickGridView::enforceRange_rightToLeft() QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid"); QTRY_VERIFY(gridview != 0); - QTRY_COMPARE(gridview->preferredHighlightBegin(), 100.0); - QTRY_COMPARE(gridview->preferredHighlightEnd(), 100.0); - QTRY_COMPARE(gridview->highlightRangeMode(), QQuickGridView::StrictlyEnforceRange); + QCOMPARE(gridview->preferredHighlightBegin(), 100.0); + QCOMPARE(gridview->preferredHighlightEnd(), 100.0); + QCOMPARE(gridview->highlightRangeMode(), QQuickGridView::StrictlyEnforceRange); QQuickItem *contentItem = gridview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QVERIFY(contentItem != 0); // view should be positioned at the top of the range. QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", 0); - QTRY_VERIFY(item); - QEXPECT_FAIL("", "QTBUG-22162", Abort); - QTRY_COMPARE(gridview->contentX(), -100.); + QVERIFY(item); + QTRY_COMPARE(gridview->contentX(), -140.); QTRY_COMPARE(gridview->contentY(), 0.0); QQuickText *name = findItem<QQuickText>(contentItem, "textName", 0); @@ -2378,11 +2464,11 @@ void tst_QQuickGridView::enforceRange_rightToLeft() QTRY_COMPARE(number->text(), model.number(0)); // Check currentIndex is updated when contentItem moves - gridview->setContentX(-200); + gridview->setContentX(-240); QTRY_COMPARE(gridview->currentIndex(), 3); gridview->setCurrentIndex(7); - QTRY_COMPARE(gridview->contentX(), -300.); + QTRY_COMPARE(gridview->contentX(), -340.); QTRY_COMPARE(gridview->contentY(), 0.0); TestModel model2; diff --git a/tests/auto/declarative/qquickitem/tst_qquickitem.cpp b/tests/auto/declarative/qquickitem/tst_qquickitem.cpp index 35346c8236..a5f908ce86 100644 --- a/tests/auto/declarative/qquickitem/tst_qquickitem.cpp +++ b/tests/auto/declarative/qquickitem/tst_qquickitem.cpp @@ -137,11 +137,6 @@ private: w->show(); w->requestActivateWindow(); qApp->processEvents(); - -#ifdef Q_WS_X11 - // to be safe and avoid failing setFocus with window managers - qt_x11_wait_for_window_manager(w); -#endif } }; diff --git a/tests/auto/declarative/qquickitem2/qquickitem2.pro b/tests/auto/declarative/qquickitem2/qquickitem2.pro index 47b31d98e9..2fe1eb1e3a 100644 --- a/tests/auto/declarative/qquickitem2/qquickitem2.pro +++ b/tests/auto/declarative/qquickitem2/qquickitem2.pro @@ -1,5 +1,5 @@ CONFIG += testcase -TARGET = tst_qquickitem +TARGET = tst_qquickitem2 macx:CONFIG -= app_bundle SOURCES += tst_qquickitem.cpp diff --git a/tests/auto/declarative/qquickmultipointtoucharea/data/inFlickable.qml b/tests/auto/declarative/qquickmultipointtoucharea/data/inFlickable.qml new file mode 100644 index 0000000000..53a2bf87f9 --- /dev/null +++ b/tests/auto/declarative/qquickmultipointtoucharea/data/inFlickable.qml @@ -0,0 +1,25 @@ +import QtQuick 2.0 + +Flickable { + width: 240 + height: 320 + + contentWidth: width + contentHeight: height * 2 + + MultiPointTouchArea { + anchors.fill: parent + minimumTouchPoints: 2 + maximumTouchPoints: 2 + onGestureStarted: { + if ((Math.abs(point2.x - point2.startX) > gesture.dragThreshold/2) && (Math.abs(point1.x - point1.startX) > gesture.dragThreshold/2)) { + gesture.grab() + } + } + touchPoints: [ + TouchPoint { id: point1; objectName: "point1" }, + TouchPoint { id: point2; objectName: "point2" } + ] + } +} + diff --git a/tests/auto/declarative/qquickmultipointtoucharea/data/nested.qml b/tests/auto/declarative/qquickmultipointtoucharea/data/nested.qml new file mode 100644 index 0000000000..37b8820aa0 --- /dev/null +++ b/tests/auto/declarative/qquickmultipointtoucharea/data/nested.qml @@ -0,0 +1,27 @@ +import QtQuick 2.0 + +MultiPointTouchArea { + width: 240 + height: 320 + + property bool grabInnerArea: true + + minimumTouchPoints: 2 + maximumTouchPoints: 3 + touchPoints: [ + TouchPoint { objectName: "point11" }, + TouchPoint { objectName: "point12" } + ] + + MultiPointTouchArea { + anchors.fill: parent + minimumTouchPoints: 3 + maximumTouchPoints: 3 + onGestureStarted: if (grabInnerArea) gesture.grab() + touchPoints: [ + TouchPoint { objectName: "point21" }, + TouchPoint { objectName: "point22" }, + TouchPoint { objectName: "point23" } + ] + } +} diff --git a/tests/auto/declarative/qquickmultipointtoucharea/data/nonOverlapping.qml b/tests/auto/declarative/qquickmultipointtoucharea/data/nonOverlapping.qml new file mode 100644 index 0000000000..039607e26c --- /dev/null +++ b/tests/auto/declarative/qquickmultipointtoucharea/data/nonOverlapping.qml @@ -0,0 +1,32 @@ +import QtQuick 2.0 + +Rectangle { + width: 240 + height: 320 + + MultiPointTouchArea { + width: parent.width + height: 160 + minimumTouchPoints: 2 + maximumTouchPoints: 2 + onGestureStarted: gesture.grab() + touchPoints: [ + TouchPoint { objectName: "point11" }, + TouchPoint { objectName: "point12" } + ] + } + + MultiPointTouchArea { + width: parent.width + height: 160 + y: 160 + minimumTouchPoints: 3 + maximumTouchPoints: 3 + onGestureStarted: gesture.grab() + touchPoints: [ + TouchPoint { objectName: "point21" }, + TouchPoint { objectName: "point22" }, + TouchPoint { objectName: "point23" } + ] + } +} diff --git a/tests/auto/declarative/qquickmultipointtoucharea/data/properties.qml b/tests/auto/declarative/qquickmultipointtoucharea/data/properties.qml new file mode 100644 index 0000000000..98ef1a9cbe --- /dev/null +++ b/tests/auto/declarative/qquickmultipointtoucharea/data/properties.qml @@ -0,0 +1,15 @@ +import QtQuick 2.0 + +MultiPointTouchArea { + width: 240 + height: 320 + + minimumTouchPoints: 2 + maximumTouchPoints: 4 + touchPoints: [ + TouchPoint {}, + TouchPoint {}, + TouchPoint {}, + TouchPoint {} + ] +} diff --git a/tests/auto/declarative/qquickmultipointtoucharea/data/signalTest.qml b/tests/auto/declarative/qquickmultipointtoucharea/data/signalTest.qml new file mode 100644 index 0000000000..3a6aa86a1c --- /dev/null +++ b/tests/auto/declarative/qquickmultipointtoucharea/data/signalTest.qml @@ -0,0 +1,25 @@ +import QtQuick 2.0 + +MultiPointTouchArea { + width: 240 + height: 320 + + function clearCounts() { + touchPointPressCount = 0; + touchPointUpdateCount = 0; + touchPointReleaseCount = 0; + touchCount = 0; + } + + property int touchPointPressCount: 0 + property int touchPointUpdateCount: 0 + property int touchPointReleaseCount: 0 + property int touchCount: 0 + + maximumTouchPoints: 5 + + onTouchPointsPressed: { touchPointPressCount = touchPoints.length } + onTouchPointsUpdated: { touchPointUpdateCount = touchPoints.length } + onTouchPointsReleased: { touchPointReleaseCount = touchPoints.length } + onTouchUpdated: { touchCount = touchPoints.length } +} diff --git a/tests/auto/declarative/qquickmultipointtoucharea/qquickmultipointtoucharea.pro b/tests/auto/declarative/qquickmultipointtoucharea/qquickmultipointtoucharea.pro new file mode 100644 index 0000000000..8be4b1f1fd --- /dev/null +++ b/tests/auto/declarative/qquickmultipointtoucharea/qquickmultipointtoucharea.pro @@ -0,0 +1,11 @@ +TARGET = tst_qquickmultipointtoucharea +CONFIG += testcase +macx:CONFIG -= app_bundle + +SOURCES += tst_qquickmultipointtoucharea.cpp + +importFiles.files = data +importFiles.path = . +DEPLOYMENT += importFiles + +QT += core-private gui-private declarative-private testlib diff --git a/tests/auto/declarative/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp b/tests/auto/declarative/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp new file mode 100644 index 0000000000..9acef50645 --- /dev/null +++ b/tests/auto/declarative/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp @@ -0,0 +1,586 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> +#include <QtTest/QSignalSpy> +#include <private/qquickmultipointtoucharea_p.h> +#include <private/qquickflickable_p.h> +#include <QtDeclarative/qquickview.h> + +class tst_QQuickMultiPointTouchArea: public QObject +{ + Q_OBJECT +private slots: + void initTestCase() {} + void cleanupTestCase() {} + + void properties(); + void signalTest(); + void nonOverlapping(); + void nested(); + void inFlickable(); + +private: + QQuickView *createAndShowView(const QString &file); +}; + +void tst_QQuickMultiPointTouchArea::properties() +{ + QQuickView *canvas = createAndShowView("properties.qml"); + QVERIFY(canvas->rootObject() != 0); + + QQuickMultiPointTouchArea *area = qobject_cast<QQuickMultiPointTouchArea *>(canvas->rootObject()); + QVERIFY(area != 0); + + QCOMPARE(area->minimumTouchPoints(), 2); + QCOMPARE(area->maximumTouchPoints(), 4); + + QDeclarativeListReference ref(area, "touchPoints"); + QCOMPARE(ref.count(), 4); + + delete canvas; +} + +void tst_QQuickMultiPointTouchArea::signalTest() +{ + QQuickView *canvas = createAndShowView("signalTest.qml"); + QVERIFY(canvas->rootObject() != 0); + + QQuickMultiPointTouchArea *area = qobject_cast<QQuickMultiPointTouchArea *>(canvas->rootObject()); + QVERIFY(area != 0); + + QPoint p1(20,100); + QPoint p2(40,100); + QPoint p3(60,100); + QPoint p4(80,100); + QPoint p5(100,100); + + QTest::QTouchEventSequence sequence = QTest::touchEvent(canvas); + + sequence.press(0, p1).press(1, p2).commit(); + + QCOMPARE(area->property("touchPointPressCount").toInt(), 2); + QCOMPARE(area->property("touchPointUpdateCount").toInt(), 0); + QCOMPARE(area->property("touchPointReleaseCount").toInt(), 0); + QCOMPARE(area->property("touchCount").toInt(), 2); + QMetaObject::invokeMethod(area, "clearCounts"); + + sequence.stationary(0).stationary(1).press(2, p3).commit(); + + QCOMPARE(area->property("touchPointPressCount").toInt(), 1); + QCOMPARE(area->property("touchPointUpdateCount").toInt(), 0); + QCOMPARE(area->property("touchPointReleaseCount").toInt(), 0); + QCOMPARE(area->property("touchCount").toInt(), 3); + QMetaObject::invokeMethod(area, "clearCounts"); + + p1 -= QPoint(10,10); + p2 += QPoint(10,10); + sequence.move(0, p1).move(1, p2).stationary(2).commit(); + + QCOMPARE(area->property("touchPointPressCount").toInt(), 0); + QCOMPARE(area->property("touchPointUpdateCount").toInt(), 2); + QCOMPARE(area->property("touchPointReleaseCount").toInt(), 0); + QCOMPARE(area->property("touchCount").toInt(), 3); + QMetaObject::invokeMethod(area, "clearCounts"); + + p3 += QPoint(10,10); + sequence.release(0, p1).release(1, p2) + .move(2, p3).press(3, p4).press(4, p5).commit(); + + QCOMPARE(area->property("touchPointPressCount").toInt(), 2); + QCOMPARE(area->property("touchPointUpdateCount").toInt(), 1); + QCOMPARE(area->property("touchPointReleaseCount").toInt(), 2); + QCOMPARE(area->property("touchCount").toInt(), 3); + QMetaObject::invokeMethod(area, "clearCounts"); + + sequence.release(2, p3).release(3, p4).release(4, p5).commit(); + + QCOMPARE(area->property("touchPointPressCount").toInt(), 0); + QCOMPARE(area->property("touchPointUpdateCount").toInt(), 0); + QCOMPARE(area->property("touchPointReleaseCount").toInt(), 3); + QCOMPARE(area->property("touchCount").toInt(), 0); + QMetaObject::invokeMethod(area, "clearCounts"); + + delete canvas; +} + +void tst_QQuickMultiPointTouchArea::nonOverlapping() +{ + QQuickView *canvas = createAndShowView("nonOverlapping.qml"); + QVERIFY(canvas->rootObject() != 0); + + QQuickTouchPoint *point11 = canvas->rootObject()->findChild<QQuickTouchPoint*>("point11"); + QQuickTouchPoint *point12 = canvas->rootObject()->findChild<QQuickTouchPoint*>("point12"); + QQuickTouchPoint *point21 = canvas->rootObject()->findChild<QQuickTouchPoint*>("point21"); + QQuickTouchPoint *point22 = canvas->rootObject()->findChild<QQuickTouchPoint*>("point22"); + QQuickTouchPoint *point23 = canvas->rootObject()->findChild<QQuickTouchPoint*>("point23"); + + QCOMPARE(point11->isValid(), false); + QCOMPARE(point12->isValid(), false); + QCOMPARE(point21->isValid(), false); + QCOMPARE(point22->isValid(), false); + QCOMPARE(point23->isValid(), false); + + QPoint p1(20,100); + QPoint p2(40,100); + QPoint p3(60,180); + QPoint p4(80,180); + QPoint p5(100,180); + + QTest::QTouchEventSequence sequence = QTest::touchEvent(canvas); + + sequence.press(0, p1).commit(); + + QCOMPARE(point11->isValid(), false); + QCOMPARE(point12->isValid(), false); + QCOMPARE(point21->isValid(), false); + QCOMPARE(point22->isValid(), false); + QCOMPARE(point23->isValid(), false); + + sequence.stationary(0).press(1, p2).commit(); + + QCOMPARE(point11->isValid(), true); + QCOMPARE(point12->isValid(), true); + QCOMPARE(point21->isValid(), false); + QCOMPARE(point22->isValid(), false); + QCOMPARE(point23->isValid(), false); + + QCOMPARE(point11->x(), qreal(20)); QCOMPARE(point11->y(), qreal(100)); + QCOMPARE(point12->x(), qreal(40)); QCOMPARE(point12->y(), qreal(100)); + + p1 += QPoint(0,10); + p2 += QPoint(5,0); + sequence.move(0, p1).move(1, p2).commit(); + + QCOMPARE(point11->isValid(), true); + QCOMPARE(point12->isValid(), true); + QCOMPARE(point21->isValid(), false); + QCOMPARE(point22->isValid(), false); + QCOMPARE(point23->isValid(), false); + + QCOMPARE(point11->x(), qreal(20)); QCOMPARE(point11->y(), qreal(110)); + QCOMPARE(point12->x(), qreal(45)); QCOMPARE(point12->y(), qreal(100)); + + sequence.stationary(0).stationary(1).press(2, p3).commit(); + + QCOMPARE(point11->isValid(), true); + QCOMPARE(point12->isValid(), true); + QCOMPARE(point21->isValid(), false); + QCOMPARE(point22->isValid(), false); + QCOMPARE(point23->isValid(), false); + + sequence.stationary(0).stationary(1).stationary(2).press(3, p4).press(4, p5).commit(); + + QCOMPARE(point11->isValid(), true); + QCOMPARE(point12->isValid(), true); + QCOMPARE(point21->isValid(), true); + QCOMPARE(point22->isValid(), true); + QCOMPARE(point23->isValid(), true); + + QCOMPARE(point11->x(), qreal(20)); QCOMPARE(point11->y(), qreal(110)); + QCOMPARE(point12->x(), qreal(45)); QCOMPARE(point12->y(), qreal(100)); + QCOMPARE(point21->x(), qreal(60)); QCOMPARE(point21->y(), qreal(20)); + QCOMPARE(point22->x(), qreal(80)); QCOMPARE(point22->y(), qreal(20)); + QCOMPARE(point23->x(), qreal(100)); QCOMPARE(point23->y(), qreal(20)); + + p1 += QPoint(4,10); + p2 += QPoint(17,17); + p3 += QPoint(3,0); + p4 += QPoint(1,-1); + p5 += QPoint(-7,10); + sequence.move(0, p1).move(1, p2).move(2, p3).move(3, p4).move(4, p5).commit(); + + QCOMPARE(point11->isValid(), true); + QCOMPARE(point12->isValid(), true); + QCOMPARE(point21->isValid(), true); + QCOMPARE(point22->isValid(), true); + QCOMPARE(point23->isValid(), true); + + QCOMPARE(point11->x(), qreal(24)); QCOMPARE(point11->y(), qreal(120)); + QCOMPARE(point12->x(), qreal(62)); QCOMPARE(point12->y(), qreal(117)); + QCOMPARE(point21->x(), qreal(63)); QCOMPARE(point21->y(), qreal(20)); + QCOMPARE(point22->x(), qreal(81)); QCOMPARE(point22->y(), qreal(19)); + QCOMPARE(point23->x(), qreal(93)); QCOMPARE(point23->y(), qreal(30)); + + sequence.release(0, p1).release(1, p2).release(2, p3).release(3, p4).release(4, p5).commit(); + + //points remain valid immediately after release + QCOMPARE(point11->isValid(), true); + QCOMPARE(point12->isValid(), true); + QCOMPARE(point21->isValid(), true); + QCOMPARE(point22->isValid(), true); + QCOMPARE(point23->isValid(), true); + + delete canvas; +} + +void tst_QQuickMultiPointTouchArea::nested() +{ + QQuickView *canvas = createAndShowView("nested.qml"); + QVERIFY(canvas->rootObject() != 0); + + QQuickTouchPoint *point11 = canvas->rootObject()->findChild<QQuickTouchPoint*>("point11"); + QQuickTouchPoint *point12 = canvas->rootObject()->findChild<QQuickTouchPoint*>("point12"); + QQuickTouchPoint *point21 = canvas->rootObject()->findChild<QQuickTouchPoint*>("point21"); + QQuickTouchPoint *point22 = canvas->rootObject()->findChild<QQuickTouchPoint*>("point22"); + QQuickTouchPoint *point23 = canvas->rootObject()->findChild<QQuickTouchPoint*>("point23"); + + QCOMPARE(point11->isValid(), false); + QCOMPARE(point12->isValid(), false); + QCOMPARE(point21->isValid(), false); + QCOMPARE(point22->isValid(), false); + QCOMPARE(point23->isValid(), false); + + QPoint p1(20,100); + QPoint p2(40,100); + QPoint p3(60,180); + + QTest::QTouchEventSequence sequence = QTest::touchEvent(canvas); + + sequence.press(0, p1).commit(); + + QCOMPARE(point11->isValid(), false); + QCOMPARE(point12->isValid(), false); + QCOMPARE(point21->isValid(), false); + QCOMPARE(point22->isValid(), false); + QCOMPARE(point23->isValid(), false); + + sequence.stationary(0).press(1, p2).commit(); + + QCOMPARE(point11->isValid(), true); + QCOMPARE(point12->isValid(), true); + QCOMPARE(point21->isValid(), false); + QCOMPARE(point22->isValid(), false); + QCOMPARE(point23->isValid(), false); + + QCOMPARE(point11->x(), qreal(20)); QCOMPARE(point11->y(), qreal(100)); + QCOMPARE(point12->x(), qreal(40)); QCOMPARE(point12->y(), qreal(100)); + + p1 += QPoint(0,10); + p2 += QPoint(5,0); + sequence.move(0, p1).move(1, p2).commit(); + + QCOMPARE(point11->isValid(), true); + QCOMPARE(point12->isValid(), true); + QCOMPARE(point21->isValid(), false); + QCOMPARE(point22->isValid(), false); + QCOMPARE(point23->isValid(), false); + + QCOMPARE(point11->x(), qreal(20)); QCOMPARE(point11->y(), qreal(110)); + QCOMPARE(point12->x(), qreal(45)); QCOMPARE(point12->y(), qreal(100)); + + sequence.stationary(0).stationary(1).press(2, p3).commit(); + + QCOMPARE(point11->isValid(), true); + QCOMPARE(point12->isValid(), true); + QCOMPARE(point21->isValid(), true); + QCOMPARE(point22->isValid(), true); + QCOMPARE(point23->isValid(), true); + + //point11 should be same as point21, point12 same as point22 + QCOMPARE(point11->x(), qreal(20)); QCOMPARE(point11->y(), qreal(110)); + QCOMPARE(point12->x(), qreal(45)); QCOMPARE(point12->y(), qreal(100)); + QCOMPARE(point21->x(), qreal(20)); QCOMPARE(point21->y(), qreal(110)); + QCOMPARE(point22->x(), qreal(45)); QCOMPARE(point22->y(), qreal(100)); + QCOMPARE(point23->x(), qreal(60)); QCOMPARE(point23->y(), qreal(180)); + + sequence.stationary(0).stationary(1).stationary(2).press(3, QPoint(80,180)).press(4, QPoint(100,180)).commit(); + + QCOMPARE(point11->isValid(), true); + QCOMPARE(point12->isValid(), true); + QCOMPARE(point21->isValid(), true); + QCOMPARE(point22->isValid(), true); + QCOMPARE(point23->isValid(), true); + + //new touch points should be ignored (have no impact on our existing touch points) + QCOMPARE(point11->x(), qreal(20)); QCOMPARE(point11->y(), qreal(110)); + QCOMPARE(point12->x(), qreal(45)); QCOMPARE(point12->y(), qreal(100)); + QCOMPARE(point21->x(), qreal(20)); QCOMPARE(point21->y(), qreal(110)); + QCOMPARE(point22->x(), qreal(45)); QCOMPARE(point22->y(), qreal(100)); + QCOMPARE(point23->x(), qreal(60)); QCOMPARE(point23->y(), qreal(180)); + + sequence.stationary(0).stationary(1).stationary(2).release(3, QPoint(80,180)).release(4, QPoint(100,180)).commit(); + + p1 += QPoint(4,10); + p2 += QPoint(17,17); + p3 += QPoint(3,0); + sequence.move(0, p1).move(1, p2).move(2, p3).commit(); + + QCOMPARE(point11->isValid(), true); + QCOMPARE(point12->isValid(), true); + QCOMPARE(point21->isValid(), true); + QCOMPARE(point22->isValid(), true); + QCOMPARE(point23->isValid(), true); + + QCOMPARE(point21->x(), qreal(24)); QCOMPARE(point21->y(), qreal(120)); + QCOMPARE(point22->x(), qreal(62)); QCOMPARE(point22->y(), qreal(117)); + QCOMPARE(point21->x(), qreal(24)); QCOMPARE(point21->y(), qreal(120)); + QCOMPARE(point22->x(), qreal(62)); QCOMPARE(point22->y(), qreal(117)); + QCOMPARE(point23->x(), qreal(63)); QCOMPARE(point23->y(), qreal(180)); + + p1 += QPoint(4,10); + p2 += QPoint(17,17); + p3 += QPoint(3,0); + sequence.move(0, p1).move(1, p2).move(2, p3).commit(); + + QCOMPARE(point11->isValid(), false); + QCOMPARE(point12->isValid(), false); + QCOMPARE(point21->isValid(), true); + QCOMPARE(point22->isValid(), true); + QCOMPARE(point23->isValid(), true); + + //first two remain the same (touches now grabbed by inner touch area) + QCOMPARE(point11->x(), qreal(24)); QCOMPARE(point11->y(), qreal(120)); + QCOMPARE(point12->x(), qreal(62)); QCOMPARE(point12->y(), qreal(117)); + QCOMPARE(point21->x(), qreal(28)); QCOMPARE(point21->y(), qreal(130)); + QCOMPARE(point22->x(), qreal(79)); QCOMPARE(point22->y(), qreal(134)); + QCOMPARE(point23->x(), qreal(66)); QCOMPARE(point23->y(), qreal(180)); + + sequence.release(0, p1).release(1, p2).release(2, p3).commit(); + + sequence.press(0, p1).commit(); + + QCOMPARE(point11->isValid(), false); + QCOMPARE(point12->isValid(), false); + QCOMPARE(point21->isValid(), false); + QCOMPARE(point22->isValid(), false); + QCOMPARE(point23->isValid(), false); + + sequence.release(0, p1).commit(); + + //test with grabbing turned off + canvas->rootObject()->setProperty("grabInnerArea", false); + + sequence.press(0, p1).press(1, p2).press(2, p3).commit(); + + QCOMPARE(point11->isValid(), true); + QCOMPARE(point12->isValid(), true); + QCOMPARE(point21->isValid(), true); + QCOMPARE(point22->isValid(), true); + QCOMPARE(point23->isValid(), true); + + p1 -= QPoint(4,10); + p2 -= QPoint(17,17); + p3 -= QPoint(3,0); + sequence.move(0, p1).move(1, p2).move(2, p3).commit(); + + QCOMPARE(point11->isValid(), true); + QCOMPARE(point12->isValid(), true); + QCOMPARE(point21->isValid(), true); + QCOMPARE(point22->isValid(), true); + QCOMPARE(point23->isValid(), true); + + QCOMPARE(point21->x(), qreal(24)); QCOMPARE(point21->y(), qreal(120)); + QCOMPARE(point22->x(), qreal(62)); QCOMPARE(point22->y(), qreal(117)); + QCOMPARE(point21->x(), qreal(24)); QCOMPARE(point21->y(), qreal(120)); + QCOMPARE(point22->x(), qreal(62)); QCOMPARE(point22->y(), qreal(117)); + QCOMPARE(point23->x(), qreal(63)); QCOMPARE(point23->y(), qreal(180)); + + p1 -= QPoint(4,10); + p2 -= QPoint(17,17); + p3 -= QPoint(3,0); + sequence.move(0, p1).move(1, p2).move(2, p3).commit(); + + QCOMPARE(point11->isValid(), true); + QCOMPARE(point12->isValid(), true); + QCOMPARE(point21->isValid(), true); + QCOMPARE(point22->isValid(), true); + QCOMPARE(point23->isValid(), true); + + //all change (touches not grabbed by inner touch area) + QCOMPARE(point11->x(), qreal(20)); QCOMPARE(point11->y(), qreal(110)); + QCOMPARE(point12->x(), qreal(45)); QCOMPARE(point12->y(), qreal(100)); + QCOMPARE(point21->x(), qreal(20)); QCOMPARE(point21->y(), qreal(110)); + QCOMPARE(point22->x(), qreal(45)); QCOMPARE(point22->y(), qreal(100)); + QCOMPARE(point23->x(), qreal(60)); QCOMPARE(point23->y(), qreal(180)); + + sequence.release(0, p1).release(1, p2).release(2, p3).commit(); + + delete canvas; +} + +void tst_QQuickMultiPointTouchArea::inFlickable() +{ + QQuickView *canvas = createAndShowView("inFlickable.qml"); + QVERIFY(canvas->rootObject() != 0); + + QQuickFlickable *flickable = qobject_cast<QQuickFlickable *>(canvas->rootObject()); + QVERIFY(flickable != 0); + + QQuickTouchPoint *point11 = canvas->rootObject()->findChild<QQuickTouchPoint*>("point1"); + QQuickTouchPoint *point12 = canvas->rootObject()->findChild<QQuickTouchPoint*>("point2"); + + QCOMPARE(point11->isValid(), false); + QCOMPARE(point12->isValid(), false); + + QPoint p1(20,100); + QPoint p2(40,100); + + //moving one point vertically + QTest::touchEvent(canvas).press(0, p1); + QTest::mousePress(canvas, Qt::LeftButton, 0, p1); + + p1 += QPoint(0,15); + QTest::touchEvent(canvas).move(0, p1); + QTest::mouseMove(canvas, p1); + + p1 += QPoint(0,15); + QTest::touchEvent(canvas).move(0, p1); + QTest::mouseMove(canvas, p1); + + p1 += QPoint(0,15); + QTest::touchEvent(canvas).move(0, p1); + QTest::mouseMove(canvas, p1); + + p1 += QPoint(0,15); + QTest::touchEvent(canvas).move(0, p1); + QTest::mouseMove(canvas, p1); + + QVERIFY(flickable->contentY() < 0); + QCOMPARE(point11->isValid(), false); + QCOMPARE(point12->isValid(), false); + + QTest::touchEvent(canvas).release(0, p1); + QTest::mouseRelease(canvas,Qt::LeftButton, 0, p1); + QTest::qWait(50); + + QTRY_VERIFY(!flickable->isMoving()); + + //moving two points vertically + p1 = QPoint(20,100); + QTest::touchEvent(canvas).press(0, p1).press(1, p2); + QTest::mousePress(canvas, Qt::LeftButton, 0, p1); + + QCOMPARE(point11->isValid(), true); + QCOMPARE(point12->isValid(), true); + + p1 += QPoint(0,15); p2 += QPoint(0,15); + QTest::touchEvent(canvas).move(0, p1).move(1, p2); + QTest::mouseMove(canvas, p1); + + p1 += QPoint(0,15); p2 += QPoint(0,15); + QTest::touchEvent(canvas).move(0, p1).move(1, p2); + QTest::mouseMove(canvas, p1); + + p1 += QPoint(0,15); p2 += QPoint(0,15); + QTest::touchEvent(canvas).move(0, p1).move(1, p2); + QTest::mouseMove(canvas, p1); + + p1 += QPoint(0,15); p2 += QPoint(0,15); + QTest::touchEvent(canvas).move(0, p1).move(1, p2); + QTest::mouseMove(canvas, p1); + + QVERIFY(flickable->contentY() < 0); + QCOMPARE(point11->isValid(), false); + QCOMPARE(point12->isValid(), false); + + QTest::touchEvent(canvas).release(0, p1).release(1, p2); + QTest::mouseRelease(canvas,Qt::LeftButton, 0, p1); + QTest::qWait(50); + + QTRY_VERIFY(!flickable->isMoving()); + + //moving two points horizontally, then one point vertically + p1 = QPoint(20,100); + p2 = QPoint(40,100); + QTest::touchEvent(canvas).press(0, p1).press(1, p2); + QTest::mousePress(canvas, Qt::LeftButton, 0, p1); + + QCOMPARE(point11->isValid(), true); + QCOMPARE(point12->isValid(), true); + + p1 += QPoint(15,0); p2 += QPoint(15,0); + QTest::touchEvent(canvas).move(0, p1).move(1, p2); + QTest::mouseMove(canvas, p1); + + p1 += QPoint(15,0); p2 += QPoint(15,0); + QTest::touchEvent(canvas).move(0, p1).move(1, p2); + QTest::mouseMove(canvas, p1); + + p1 += QPoint(15,0); p2 += QPoint(15,0); + QTest::touchEvent(canvas).move(0, p1).move(1, p2); + QTest::mouseMove(canvas, p1); + + p1 += QPoint(15,0); p2 += QPoint(15,0); + QTest::touchEvent(canvas).move(0, p1).move(1, p2); + QTest::mouseMove(canvas, p1); + + p1 += QPoint(0,15); p2 += QPoint(0,15); + QTest::touchEvent(canvas).move(0, p1).move(1, p2); + QTest::mouseMove(canvas, p1); + + p1 += QPoint(0,15); p2 += QPoint(0,15); + QTest::touchEvent(canvas).move(0, p1).move(1, p2); + QTest::mouseMove(canvas, p1); + + p1 += QPoint(0,15); p2 += QPoint(0,15); + QTest::touchEvent(canvas).move(0, p1).move(1, p2); + QTest::mouseMove(canvas, p1); + + p1 += QPoint(0,15); p2 += QPoint(0,15); + QTest::touchEvent(canvas).move(0, p1).move(1, p2); + QTest::mouseMove(canvas, p1); + + QVERIFY(flickable->contentY() == 0); + QCOMPARE(point11->isValid(), true); + QCOMPARE(point12->isValid(), true); + + QTest::touchEvent(canvas).release(0, p1).release(1, p2); + QTest::mouseRelease(canvas,Qt::LeftButton, 0, p1); + QTest::qWait(50); + + delete canvas; +} + +QQuickView *tst_QQuickMultiPointTouchArea::createAndShowView(const QString &file) +{ + QQuickView *canvas = new QQuickView(0); + canvas->setSource(QUrl::fromLocalFile(QCoreApplication::applicationDirPath() + QLatin1String("/data/") + file)); + canvas->show(); + canvas->requestActivateWindow(); + QTest::qWaitForWindowShown(canvas); + + return canvas; +} + +QTEST_MAIN(tst_QQuickMultiPointTouchArea) + +#include "tst_qquickmultipointtoucharea.moc" diff --git a/tests/auto/declarative/qquickpathview/data/pathline.qml b/tests/auto/declarative/qquickpathview/data/pathline.qml new file mode 100644 index 0000000000..4c1c785bce --- /dev/null +++ b/tests/auto/declarative/qquickpathview/data/pathline.qml @@ -0,0 +1,48 @@ +import QtQuick 2.0 + +Rectangle { + id: app + width: 360 + height: 360 + + PathView { + id: pathView + objectName: "view" + x: (app.width-pathView.width)/2 + y: 100 + width: 240 + height: 100 + + model: testModel + + Rectangle { + anchors.fill: parent + color: "white" + border.color: "black" + } + preferredHighlightBegin: 0.5 + preferredHighlightEnd: 0.5 + + delegate: Rectangle { + objectName: "wrapper" + width: 100 + height: 100 + color: PathView.isCurrentItem ? "red" : "yellow" + Text { + text: index + anchors.centerIn: parent + } + z: (PathView.isCurrentItem?1:0) + } + path: Path { + id: path + startX: -100+pathView.width/2 + startY: pathView.height/2 + PathLine { + id: line + x: 100+pathView.width/2 + y: pathView.height/2 + } + } + } +} diff --git a/tests/auto/declarative/qquickpathview/tst_qquickpathview.cpp b/tests/auto/declarative/qquickpathview/tst_qquickpathview.cpp index dc85f590e9..5e434b0259 100644 --- a/tests/auto/declarative/qquickpathview/tst_qquickpathview.cpp +++ b/tests/auto/declarative/qquickpathview/tst_qquickpathview.cpp @@ -111,6 +111,7 @@ private slots: void changePreferredHighlight(); void missingPercent(); void creationContext(); + void currentOffsetOnInsertion(); private: QQuickView *createView(); @@ -240,6 +241,8 @@ void tst_QQuickPathView::initValues() QCOMPARE(obj->dragMargin(), 0.); QCOMPARE(obj->count(), 0); QCOMPARE(obj->pathItemCount(), -1); + + delete obj; } void tst_QQuickPathView::items() @@ -303,6 +306,8 @@ void tst_QQuickPathView::pathview2() QCOMPARE(obj->dragMargin(), 0.); QCOMPARE(obj->count(), 8); QCOMPARE(obj->pathItemCount(), 10); + + delete obj; } void tst_QQuickPathView::pathview3() @@ -321,6 +326,8 @@ void tst_QQuickPathView::pathview3() QCOMPARE(obj->dragMargin(), 24.); QCOMPARE(obj->count(), 8); QCOMPARE(obj->pathItemCount(), 4); + + delete obj; } void tst_QQuickPathView::path() @@ -366,6 +373,8 @@ void tst_QQuickPathView::path() QCOMPARE(cubic->control1Y(), 90.); QCOMPARE(cubic->control2X(), 210.); QCOMPARE(cubic->control2Y(), 90.); + + delete obj; } void tst_QQuickPathView::dataModel() @@ -1081,6 +1090,86 @@ void tst_QQuickPathView::creationContext() QCOMPARE(item->property("text").toString(), QString("Hello!")); } +// QTBUG-21320 +void tst_QQuickPathView::currentOffsetOnInsertion() +{ + QQuickView *canvas = createView(); + canvas->show(); + + TestModel model; + + QDeclarativeContext *ctxt = canvas->rootContext(); + ctxt->setContextProperty("testModel", &model); + + canvas->setSource(QUrl::fromLocalFile(TESTDATA("pathline.qml"))); + qApp->processEvents(); + + QQuickPathView *pathview = findItem<QQuickPathView>(canvas->rootObject(), "view"); + QVERIFY(pathview != 0); + + pathview->setPreferredHighlightBegin(0.5); + pathview->setPreferredHighlightEnd(0.5); + + QCOMPARE(pathview->count(), model.count()); + + model.addItem("item0", "0"); + + QCOMPARE(pathview->count(), model.count()); + + QQuickRectangle *item = 0; + QTRY_VERIFY(item = findItem<QQuickRectangle>(pathview, "wrapper", 0)); + + QDeclarativePath *path = qobject_cast<QDeclarativePath*>(pathview->path()); + QVERIFY(path); + + QPointF start = path->pointAt(0.5); + start = QPointF(qRound(start.x()), qRound(start.y())); + QPointF offset;//Center of item is at point, but pos is from corner + offset.setX(item->width()/2); + offset.setY(item->height()/2); + QCOMPARE(item->pos() + offset, start); + + QSignalSpy currentIndexSpy(pathview, SIGNAL(currentIndexChanged())); + + // insert an item at the beginning + model.insertItem(0, "item1", "1"); + qApp->processEvents(); + + QCOMPARE(currentIndexSpy.count(), 1); + + // currentIndex is now 1 + QVERIFY(item = findItem<QQuickRectangle>(pathview, "wrapper", 1)); + + // verify that current item (item 1) is still at offset 0.5 + QCOMPARE(item->pos() + offset, start); + + // insert another item at the beginning + model.insertItem(0, "item2", "2"); + qApp->processEvents(); + + QCOMPARE(currentIndexSpy.count(), 2); + + // currentIndex is now 2 + QVERIFY(item = findItem<QQuickRectangle>(pathview, "wrapper", 2)); + + // verify that current item (item 2) is still at offset 0.5 + QCOMPARE(item->pos() + offset, start); + + // verify that remove before current maintains current item + model.removeItem(0); + qApp->processEvents(); + + QCOMPARE(currentIndexSpy.count(), 3); + + // currentIndex is now 1 + QVERIFY(item = findItem<QQuickRectangle>(pathview, "wrapper", 1)); + + // verify that current item (item 1) is still at offset 0.5 + QCOMPARE(item->pos() + offset, start); + + delete canvas; +} + QQuickView *tst_QQuickPathView::createView() { QQuickView *canvas = new QQuickView(0); diff --git a/tests/auto/declarative/qquickpositioners/tst_qquickpositioners.cpp b/tests/auto/declarative/qquickpositioners/tst_qquickpositioners.cpp index 1d3ccabbf5..f50b5a5b49 100644 --- a/tests/auto/declarative/qquickpositioners/tst_qquickpositioners.cpp +++ b/tests/auto/declarative/qquickpositioners/tst_qquickpositioners.cpp @@ -267,8 +267,8 @@ void tst_qquickpositioners::test_horizontal_animated() QTRY_COMPARE(row->height(), 50.0); QTest::qWait(0);//Let the animation start - QCOMPARE(two->x(), -100.0); - QCOMPARE(three->x(), 50.0); + QVERIFY(two->x() >= -100.0 && two->x() < 50.0); + QVERIFY(three->x() >= 50.0 && three->x() < 100.0); QTRY_COMPARE(two->x(), 50.0); QTRY_COMPARE(three->x(), 100.0); @@ -323,8 +323,8 @@ void tst_qquickpositioners::test_horizontal_animated_rightToLeft() QTRY_COMPARE(row->height(), 50.0); QTest::qWait(0);//Let the animation start - QCOMPARE(one->x(), 50.0); - QCOMPARE(two->x(), -100.0); + QVERIFY(one->x() >= 50.0 && one->x() < 100); + QVERIFY(two->x() >= -100.0 && two->x() < 50.0); QTRY_COMPARE(one->x(), 100.0); QTRY_COMPARE(two->x(), 50.0); @@ -361,13 +361,11 @@ void tst_qquickpositioners::test_horizontal_animated_disabled() //Add 'two' two->setVisible(true); QCOMPARE(two->isVisible(), true); - qApp->processEvents(); - QCOMPARE(row->width(), 150.0); - QCOMPARE(row->height(), 50.0); + QTRY_COMPARE(row->width(), 150.0); + QTRY_COMPARE(row->height(), 50.0); - qApp->processEvents(); - QCOMPARE(two->x(), 50.0); - QCOMPARE(three->x(), 100.0); + QTRY_COMPARE(two->x(), 50.0); + QTRY_COMPARE(three->x(), 100.0); delete canvas; } @@ -468,8 +466,8 @@ void tst_qquickpositioners::test_vertical_animated() QTRY_COMPARE(column->height(), 150.0); QTRY_COMPARE(column->width(), 50.0); QTest::qWait(0);//Let the animation start - QCOMPARE(two->y(), -100.0); - QCOMPARE(three->y(), 50.0); + QVERIFY(two->y() >= -100.0 && two->y() < 50.0); + QVERIFY(three->y() >= 50.0 && three->y() < 100.0); QTRY_COMPARE(two->y(), 50.0); QTRY_COMPARE(three->y(), 100.0); diff --git a/tests/auto/declarative/qquickspriteimage/data/basic.qml b/tests/auto/declarative/qquickspriteimage/data/basic.qml new file mode 100644 index 0000000000..1fcdfd99c3 --- /dev/null +++ b/tests/auto/declarative/qquickspriteimage/data/basic.qml @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Rectangle { + color: "black" + width: 320 + height: 320 + + SpriteImage { + objectName: "sprite" + sprites: Sprite { + name: "happy" + source: "squarefacesprite.png" + frames: 6 + duration: 120 + } + width: 160 + height: 160 + } +} diff --git a/tests/auto/declarative/qquickspriteimage/data/squarefacesprite.png b/tests/auto/declarative/qquickspriteimage/data/squarefacesprite.png Binary files differnew file mode 100644 index 0000000000..f9a5d5fcce --- /dev/null +++ b/tests/auto/declarative/qquickspriteimage/data/squarefacesprite.png diff --git a/tests/auto/declarative/qquickspriteimage/qquickspriteimage.pro b/tests/auto/declarative/qquickspriteimage/qquickspriteimage.pro new file mode 100644 index 0000000000..db5c45da8a --- /dev/null +++ b/tests/auto/declarative/qquickspriteimage/qquickspriteimage.pro @@ -0,0 +1,12 @@ +CONFIG += testcase +TARGET = tst_qquickspriteimage +SOURCES += tst_qquickspriteimage.cpp +macx:CONFIG -= app_bundle + +testDataFiles.files = data +testDataFiles.path = . +DEPLOYMENT += testDataFiles + +CONFIG += parallel_test + +QT += core-private gui-private declarative-private network testlib diff --git a/tests/auto/declarative/qquickspriteimage/tst_qquickspriteimage.cpp b/tests/auto/declarative/qquickspriteimage/tst_qquickspriteimage.cpp new file mode 100644 index 0000000000..1b8c58b873 --- /dev/null +++ b/tests/auto/declarative/qquickspriteimage/tst_qquickspriteimage.cpp @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include <QtTest/QtTest> +#include "../shared/util.h" +#include <qquickview.h> +#include <private/qquickspriteimage_p.h> + +class tst_qquickspriteimage : public QObject +{ + Q_OBJECT +public: + tst_qquickspriteimage(){} + +private slots: + void test_properties(); +}; + +void tst_qquickspriteimage::test_properties() +{ + QQuickView *canvas = new QQuickView(0); + + canvas->setSource(QUrl::fromLocalFile(TESTDATA("basic.qml"))); + canvas->show(); + QTest::qWaitForWindowShown(canvas); + + QVERIFY(canvas->rootObject()); + QQuickSpriteImage* sprite = canvas->rootObject()->findChild<QQuickSpriteImage*>("sprite"); + QVERIFY(sprite); + + QVERIFY(sprite->running()); + QVERIFY(sprite->interpolate()); + + sprite->setRunning(false); + QVERIFY(!sprite->running()); + sprite->setInterpolate(false); + QVERIFY(!sprite->interpolate()); + + delete canvas; +} + +QTEST_MAIN(tst_qquickspriteimage) + +#include "tst_qquickspriteimage.moc" diff --git a/tests/auto/declarative/qquicktext/tst_qquicktext.cpp b/tests/auto/declarative/qquicktext/tst_qquicktext.cpp index 3a08dd208d..8ac3a078bc 100644 --- a/tests/auto/declarative/qquicktext/tst_qquicktext.cpp +++ b/tests/auto/declarative/qquicktext/tst_qquicktext.cpp @@ -520,15 +520,7 @@ void tst_qquicktext::alignments() QFETCH(int, vAlign); QFETCH(QString, expectfile); -#ifdef Q_WS_X11 - // Font-specific, but not likely platform-specific, so only test on one platform - QFont fn; - fn.setRawName("-misc-fixed-medium-r-*-*-8-*-*-*-*-*-*-*"); - QApplication::setFont(fn); -#endif - QQuickView *canvas = createView(TESTDATA("alignments.qml")); - canvas->show(); canvas->requestActivateWindow(); QTest::qWait(50); @@ -545,14 +537,9 @@ void tst_qquicktext::alignments() canvas->render(&p); QImage expect(expectfile); - -#ifdef Q_WS_X11 - // Font-specific, but not likely platform-specific, so only test on one platform if (QApplicationPrivate::graphics_system_name == "raster" || QApplicationPrivate::graphics_system_name == "") { QCOMPARE(actual,expect); } -#endif - delete canvas; #endif } diff --git a/tests/auto/declarative/qquicktextedit/tst_qquicktextedit.cpp b/tests/auto/declarative/qquicktextedit/tst_qquicktextedit.cpp index 86c33a64d8..693619f638 100644 --- a/tests/auto/declarative/qquicktextedit/tst_qquicktextedit.cpp +++ b/tests/auto/declarative/qquicktextedit/tst_qquicktextedit.cpp @@ -63,7 +63,7 @@ #include <private/qtextcontrol_p.h> #include "../shared/util.h" -#ifdef Q_WS_MAC +#ifdef Q_OS_MAC #include <Carbon/Carbon.h> #endif @@ -151,8 +151,7 @@ private slots: void testQtQuick11Attributes(); void testQtQuick11Attributes_data(); - void preeditMicroFocus(); - void inputContextMouseHandler(); + void preeditCursorRectangle(); void inputMethodComposing(); void cursorRectangleSize(); @@ -573,12 +572,15 @@ void tst_qquicktextedit::hAlign_RightToLeft() QTRY_COMPARE(&canvas, qGuiApp->focusWindow()); textEdit->setText(QString()); - { QInputMethodEvent ev(rtlText, QList<QInputMethodEvent::Attribute>()); QGuiApplication::sendEvent(&canvas, &ev); } - QEXPECT_FAIL("", "QTBUG-21691", Abort); + { QInputMethodEvent ev(rtlText, QList<QInputMethodEvent::Attribute>()); QGuiApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &ev); } QCOMPARE(textEdit->hAlign(), QQuickTextEdit::AlignRight); - { QInputMethodEvent ev("Hello world!", QList<QInputMethodEvent::Attribute>()); QGuiApplication::sendEvent(&canvas, &ev); } + { QInputMethodEvent ev("Hello world!", QList<QInputMethodEvent::Attribute>()); QGuiApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &ev); } QCOMPARE(textEdit->hAlign(), QQuickTextEdit::AlignLeft); + // Clear pre-edit text. TextEdit should maybe do this itself on setText, but that may be + // redundant as an actual input method may take care of it. + { QInputMethodEvent ev; QGuiApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &ev); } + #ifndef Q_OS_MAC // QTBUG-18040 // empty text with implicit alignment follows the system locale-based // keyboard input direction from QGuiApplication::keyboardInputDirection @@ -1402,8 +1404,6 @@ void tst_qquicktextedit::mouseSelection() QTest::mouseClick(&canvas, Qt::LeftButton, Qt::NoModifier, p1); QTest::mouseClick(&canvas, Qt::LeftButton, Qt::ShiftModifier, p2); QTest::qWait(50); - if (!selectedText.isEmpty()) - QEXPECT_FAIL("", "QTBUG-21743", Continue); QTRY_COMPARE(textEditObject->selectedText(), selectedText); } @@ -1525,36 +1525,28 @@ void tst_qquicktextedit::positionAt() const int y1 = fm.height() * 3 / 2; int pos = texteditObject->positionAt(texteditObject->width()/2, y0); - int width = 0; + int widthBegin = 0; + int widthEnd = 0; if (!qmlDisableDistanceField()) { - QTextLayout layout(texteditObject->text().left(pos)); + QTextLayout layout(texteditObject->text()); - { - QTextOption option; - option.setUseDesignMetrics(true); - layout.setTextOption(option); - } + QTextOption option; + option.setUseDesignMetrics(true); + layout.setTextOption(option); layout.beginLayout(); QTextLine line = layout.createLine(); layout.endLayout(); - width = ceil(line.horizontalAdvance()); - + widthBegin = floor(line.cursorToX(pos - 1)); + widthEnd = ceil(line.cursorToX(pos + 1)); } else { - width = fm.width(texteditObject->text().left(pos)); + widthBegin = fm.width(texteditObject->text().left(pos - 1)); + widthEnd = fm.width(texteditObject->text().left(pos + 1)); } - - int diff = abs(int(width-texteditObject->width()/2)); - - QEXPECT_FAIL("", "QTBUG-21689", Abort); - // some tollerance for different fonts. -#ifdef Q_OS_LINUX - QVERIFY(diff < 2); -#else - QVERIFY(diff < 5); -#endif + QVERIFY(widthBegin <= texteditObject->width() / 2); + QVERIFY(widthEnd >= texteditObject->width() / 2); const qreal x0 = texteditObject->positionToRectangle(pos).x(); const qreal x1 = texteditObject->positionToRectangle(pos + 1).x(); @@ -1564,7 +1556,7 @@ void tst_qquicktextedit::positionAt() texteditObject->setCursorPosition(0); QInputMethodEvent inputEvent(preeditText, QList<QInputMethodEvent::Attribute>()); - QGuiApplication::sendEvent(&canvas, &inputEvent); + QGuiApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &inputEvent); // Check all points within the preedit text return the same position. QCOMPARE(texteditObject->positionAt(0, y0), 0); @@ -1780,7 +1772,7 @@ void tst_qquicktextedit::navigation() void tst_qquicktextedit::copyAndPaste() { #ifndef QT_NO_CLIPBOARD -#ifdef Q_WS_MAC +#ifdef Q_OS_MAC { PasteboardRef pasteboard; OSStatus status = PasteboardCreate(0, &pasteboard); @@ -1909,55 +1901,6 @@ void tst_qquicktextedit::simulateKey(QQuickView *view, int key, Qt::KeyboardModi QGuiApplication::sendEvent(view, &release); } - -#ifndef QTBUG_21691 -class MyInputContext : public QInputContext -{ -public: - MyInputContext() : updateReceived(false), eventType(QEvent::None) {} - ~MyInputContext() {} - - QString identifierName() { return QString(); } - QString language() { return QString(); } - - void reset() {} - - bool isComposing() const { return false; } - - void update() { updateReceived = true; } - - void sendPreeditText(const QString &text, int cursor) - { - QList<QInputMethodEvent::Attribute> attributes; - attributes.append(QInputMethodEvent::Attribute( - QInputMethodEvent::Cursor, cursor, text.length(), QVariant())); - - QInputMethodEvent event(text, attributes); - sendEvent(event); - } - - void mouseHandler(int x, QMouseEvent *event) - { - cursor = x; - eventType = event->type(); - eventPosition = event->pos(); - eventGlobalPosition = event->globalPos(); - eventButton = event->button(); - eventButtons = event->buttons(); - eventModifiers = event->modifiers(); - } - - bool updateReceived; - int cursor; - QEvent::Type eventType; - QPoint eventPosition; - QPoint eventGlobalPosition; - Qt::MouseButton eventButton; - Qt::MouseButtons eventButtons; - Qt::KeyboardModifiers eventModifiers; -}; -#endif - void tst_qquicktextedit::textInput() { QQuickView view(QUrl::fromLocalFile(TESTDATA("inputMethodEvent.qml"))); @@ -1972,8 +1915,7 @@ void tst_qquicktextedit::textInput() // test that input method event is committed QInputMethodEvent event; event.setCommitString( "Hello world!", 0, 0); - QGuiApplication::sendEvent(&view, &event); - QEXPECT_FAIL("", "QTBUG-21689", Abort); + QGuiApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &event); QCOMPARE(edit->text(), QString("Hello world!")); // QTBUG-12339 @@ -2179,12 +2121,8 @@ void tst_qquicktextedit::testQtQuick11Attributes_data() << ":1 \"TextEdit.onLinkActivated\" is not available in QtQuick 1.0.\n"; } -void tst_qquicktextedit::preeditMicroFocus() +void tst_qquicktextedit::preeditCursorRectangle() { -#ifdef QTBUG_21691 - QEXPECT_FAIL("", QTBUG_21691_MESSAGE, Abort); - QVERIFY(false); -#else QString preeditText = "super"; QQuickView view(QUrl::fromLocalFile(TESTDATA("inputMethodEvent.qml"))); @@ -2196,173 +2134,52 @@ void tst_qquicktextedit::preeditMicroFocus() QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(view.rootObject()); QVERIFY(edit); - QSignalSpy cursorRectangleSpy(edit, SIGNAL(cursorRectangleChanged())); + QSignalSpy editSpy(edit, SIGNAL(cursorRectangleChanged())); + QSignalSpy panelSpy(qGuiApp->inputPanel(), SIGNAL(cursorRectangleChanged())); QRect currentRect; - QRect previousRect = edit->inputMethodQuery(Qt::ImCursorRectangle).toRect(); + + QInputMethodQueryEvent query(Qt::ImCursorRectangle); + QCoreApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &query); + QRect previousRect = query.value(Qt::ImCursorRectangle).toRect(); // Verify that the micro focus rect is positioned the same for position 0 as // it would be if there was no preedit text. - ic.updateReceived = false; - ic.sendPreeditText(preeditText, 0); - currentRect = edit->inputMethodQuery(Qt::ImCursorRectangle).toRect(); + QInputMethodEvent imEvent(preeditText, QList<QInputMethodEvent::Attribute>() + << QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, 0, preeditText.length(), QVariant())); + QCoreApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &imEvent); + QCoreApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &query); + currentRect = query.value(Qt::ImCursorRectangle).toRect(); QCOMPARE(currentRect, previousRect); -#if defined(Q_WS_X11) || defined(Q_WS_QWS) - QCOMPARE(ic.updateReceived, false); // The cursor position hasn't changed. -#endif - QCOMPARE(cursorRectangleSpy.count(), 0); + QCOMPARE(editSpy.count(), 0); + QCOMPARE(panelSpy.count(), 0); // Verify that the micro focus rect moves to the left as the cursor position // is incremented. for (int i = 1; i <= 5; ++i) { - ic.updateReceived = false; - ic.sendPreeditText(preeditText, i); - currentRect = edit->inputMethodQuery(Qt::ImCursorRectangle).toRect(); + QInputMethodEvent imEvent(preeditText, QList<QInputMethodEvent::Attribute>() + << QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, i, preeditText.length(), QVariant())); + QCoreApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &imEvent); + QCoreApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &query); + currentRect = query.value(Qt::ImCursorRectangle).toRect(); QVERIFY(previousRect.left() < currentRect.left()); -#if defined(Q_WS_X11) || defined(Q_WS_QWS) - QCOMPARE(ic.updateReceived, true); -#endif - QVERIFY(cursorRectangleSpy.count() > 0); - cursorRectangleSpy.clear(); + QVERIFY(editSpy.count() > 0); editSpy.clear(); + QVERIFY(panelSpy.count() > 0); panelSpy.clear(); previousRect = currentRect; } // Verify that if there is no preedit cursor then the micro focus rect is the // same as it would be if it were positioned at the end of the preedit text. - ic.sendPreeditText(preeditText, 0); - ic.updateReceived = false; - ic.sendEvent(QInputMethodEvent(preeditText, QList<QInputMethodEvent::Attribute>())); - currentRect = edit->inputMethodQuery(Qt::ImCursorRectangle).toRect(); + QCoreApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &imEvent); + editSpy.clear(); + panelSpy.clear(); + { QInputMethodEvent imEvent(preeditText, QList<QInputMethodEvent::Attribute>()); + QCoreApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &imEvent); } + QCoreApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &query); + currentRect = query.value(Qt::ImCursorRectangle).toRect(); QCOMPARE(currentRect, previousRect); -#if defined(Q_WS_X11) || defined(Q_WS_QWS) - QCOMPARE(ic.updateReceived, true); -#endif - QVERIFY(cursorRectangleSpy.count() > 0); -#endif -} - -void tst_qquicktextedit::inputContextMouseHandler() -{ - -#ifdef QTBUG_21691 - QEXPECT_FAIL("", QTBUG_21691_MESSAGE, Abort); - QVERIFY(false); -#else - QString text = "supercalifragisiticexpialidocious!"; - - QQuickView view(QUrl::fromLocalFile(TESTDATA("inputContext.qml"))); - MyInputContext ic; - // QQuickCanvas won't set the Qt::WA_InputMethodEnabled flag unless a suitable item has focus - // and QWidget won't allow an input context to be set when the flag is not set. - view.setAttribute(Qt::WA_InputMethodEnabled, true); - view.setInputContext(&ic); - view.setAttribute(Qt::WA_InputMethodEnabled, false); - view.show(); - view.requestActivateWindow(); - QTest::qWaitForWindowShown(&view); - - QTRY_COMPARE(&view, qGuiApp->focusWindow()); - QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(view.rootObject()); - QVERIFY(edit); - edit->setCursorPosition(12); - - QFontMetricsF fm(edit->font()); - const qreal y = fm.height() / 2; - - QPoint position2 = edit->mapToScene(QPointF(fm.width(text.mid(0, 2)), y)).toPoint(); - QPoint position8 = edit->mapToScene(QPointF(fm.width(text.mid(0, 8)), y)).toPoint(); - QPoint position20 = edit->mapToScene(QPointF(fm.width(text.mid(0, 20)), y)).toPoint(); - QPoint position27 = edit->mapToScene(QPointF(fm.width(text.mid(0, 27)), y)).toPoint(); - QPoint globalPosition2 = view.mapToGlobal(position2); - QPoint globalposition8 = view.mapToGlobal(position8); - QPoint globalposition20 = view.mapToGlobal(position20); - QPoint globalposition27 = view.mapToGlobal(position27); - - ic.sendEvent(QInputMethodEvent(text.mid(12), QList<QInputMethodEvent::Attribute>())); - - QTest::mouseDClick(&view, Qt::LeftButton, Qt::NoModifier, position2); - QCOMPARE(ic.eventType, QEvent::MouseButtonDblClick); - QCOMPARE(ic.eventPosition, position2); - QCOMPARE(ic.eventGlobalPosition, globalPosition2); - QCOMPARE(ic.eventButton, Qt::LeftButton); - QCOMPARE(ic.eventModifiers, Qt::NoModifier); - QVERIFY(ic.cursor < 0); - ic.eventType = QEvent::None; - - QTest::mousePress(&view, Qt::LeftButton, Qt::NoModifier, position2); - QCOMPARE(ic.eventType, QEvent::MouseButtonPress); - QCOMPARE(ic.eventPosition, position2); - QCOMPARE(ic.eventGlobalPosition, globalPosition2); - QCOMPARE(ic.eventButton, Qt::LeftButton); - QCOMPARE(ic.eventModifiers, Qt::NoModifier); - QVERIFY(ic.cursor < 0); - ic.eventType = QEvent::None; - - { QMouseEvent mv(QEvent::MouseMove, position8, globalposition8, Qt::LeftButton, Qt::LeftButton,Qt::NoModifier); - QGuiApplication::sendEvent(&view, &mv); } - QCOMPARE(ic.eventType, QEvent::None); - - { QMouseEvent mv(QEvent::MouseMove, position27, globalposition27, Qt::LeftButton, Qt::LeftButton,Qt::NoModifier); - QGuiApplication::sendEvent(&view, &mv); } - QCOMPARE(ic.eventType, QEvent::MouseMove); - QCOMPARE(ic.eventPosition, position27); - QCOMPARE(ic.eventGlobalPosition, globalposition27); - QCOMPARE(ic.eventButton, Qt::LeftButton); - QCOMPARE(ic.eventModifiers, Qt::NoModifier); - QVERIFY(ic.cursor >= 14 && ic.cursor <= 16); // 15 is expected but some platforms may be off by one. - ic.eventType = QEvent::None; - - QTest::mouseRelease(&view, Qt::LeftButton, Qt::NoModifier, position27); - QCOMPARE(ic.eventType, QEvent::MouseButtonRelease); - QCOMPARE(ic.eventPosition, position27); - QCOMPARE(ic.eventGlobalPosition, globalposition27); - QCOMPARE(ic.eventButton, Qt::LeftButton); - QCOMPARE(ic.eventModifiers, Qt::NoModifier); - QVERIFY(ic.cursor >= 14 && ic.cursor <= 16); - ic.eventType = QEvent::None; - - // And in the other direction. - QTest::mouseDClick(&view, Qt::LeftButton, Qt::ControlModifier, position27); - QCOMPARE(ic.eventType, QEvent::MouseButtonDblClick); - QCOMPARE(ic.eventPosition, position27); - QCOMPARE(ic.eventGlobalPosition, globalposition27); - QCOMPARE(ic.eventButton, Qt::LeftButton); - QCOMPARE(ic.eventModifiers, Qt::ControlModifier); - QVERIFY(ic.cursor >= 14 && ic.cursor <= 16); - ic.eventType = QEvent::None; - - QTest::mousePress(&view, Qt::RightButton, Qt::ControlModifier, position27); - QCOMPARE(ic.eventType, QEvent::MouseButtonPress); - QCOMPARE(ic.eventPosition, position27); - QCOMPARE(ic.eventGlobalPosition, globalposition27); - QCOMPARE(ic.eventButton, Qt::RightButton); - QCOMPARE(ic.eventModifiers, Qt::ControlModifier); - QVERIFY(ic.cursor >= 14 && ic.cursor <= 16); - ic.eventType = QEvent::None; - - { QMouseEvent mv(QEvent::MouseMove, position20, globalposition20, Qt::RightButton, Qt::RightButton,Qt::ControlModifier); - QGuiApplication::sendEvent(&view, &mv); } - QCOMPARE(ic.eventType, QEvent::MouseMove); - QCOMPARE(ic.eventPosition, position20); - QCOMPARE(ic.eventGlobalPosition, globalposition20); - QCOMPARE(ic.eventButton, Qt::RightButton); - QCOMPARE(ic.eventModifiers, Qt::ControlModifier); - QVERIFY(ic.cursor >= 7 && ic.cursor <= 9); - ic.eventType = QEvent::None; - - { QMouseEvent mv(QEvent::MouseMove, position2, globalPosition2, Qt::RightButton, Qt::RightButton,Qt::ControlModifier); - QGuiApplication::sendEvent(&view, &mv); } - QCOMPARE(ic.eventType, QEvent::None); - - QTest::mouseRelease(&view, Qt::RightButton, Qt::ControlModifier, position2); - QCOMPARE(ic.eventType, QEvent::MouseButtonRelease); - QCOMPARE(ic.eventPosition, position2); - QCOMPARE(ic.eventGlobalPosition, globalPosition2); - QCOMPARE(ic.eventButton, Qt::RightButton); - QCOMPARE(ic.eventModifiers, Qt::ControlModifier); - QVERIFY(ic.cursor < 0); - ic.eventType = QEvent::None; -#endif + QVERIFY(editSpy.count() > 0); + QVERIFY(panelSpy.count() > 0); } void tst_qquicktextedit::inputMethodComposing() diff --git a/tests/auto/declarative/qquicktextinput/tst_qquicktextinput.cpp b/tests/auto/declarative/qquicktextinput/tst_qquicktextinput.cpp index 23224d0452..bf29f88ff1 100644 --- a/tests/auto/declarative/qquicktextinput/tst_qquicktextinput.cpp +++ b/tests/auto/declarative/qquicktextinput/tst_qquicktextinput.cpp @@ -56,6 +56,10 @@ #include <QtOpenGL/QGLShaderProgram> #include <math.h> +#ifdef Q_OS_MAC +#include <Carbon/Carbon.h> +#endif + #include "qplatformdefs.h" Q_DECLARE_METATYPE(QQuickTextInput::SelectionMode) @@ -142,8 +146,7 @@ private slots: void testQtQuick11Attributes_data(); void preeditAutoScroll(); - void preeditMicroFocus(); - void inputContextMouseHandler(); + void preeditCursorRectangle(); void inputMethodComposing(); void cursorRectangleSize(); @@ -1158,15 +1161,20 @@ void tst_qquicktextinput::horizontalAlignment_RightToLeft() // If there is no commited text, the preedit text should determine the alignment. textInput->setText(QString()); - { QInputMethodEvent ev(rtlText, QList<QInputMethodEvent::Attribute>()); QGuiApplication::sendEvent(&canvas, &ev); } - QEXPECT_FAIL("", "QTBUG-21691", Continue); + { QInputMethodEvent ev(rtlText, QList<QInputMethodEvent::Attribute>()); QGuiApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &ev); } QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignRight); - { QInputMethodEvent ev("Hello world!", QList<QInputMethodEvent::Attribute>()); QGuiApplication::sendEvent(&canvas, &ev); } + { QInputMethodEvent ev("Hello world!", QList<QInputMethodEvent::Attribute>()); QGuiApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &ev); } QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignLeft); -#ifndef Q_OS_MAC // QTBUG-18040 + // Clear pre-edit text. TextInput should maybe do this itself on setText, but that may be + // redundant as an actual input method may take care of it. + { QInputMethodEvent ev; QGuiApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &ev); } + +#ifdef Q_OS_MAC // empty text with implicit alignment follows the system locale-based // keyboard input direction from QGuiApplication::keyboardInputDirection + QEXPECT_FAIL("", "QTBUG-18040", Abort); +#endif textInput->setText(""); QCOMPARE(textInput->hAlign(), QGuiApplication::keyboardInputDirection() == Qt::LeftToRight ? QQuickTextInput::AlignLeft : QQuickTextInput::AlignRight); @@ -1177,10 +1185,11 @@ void tst_qquicktextinput::horizontalAlignment_RightToLeft() textInput->setHAlign(QQuickTextInput::AlignRight); QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignRight); QVERIFY(-textInputPrivate->hscroll > canvas.width()/2); -#endif -#ifndef Q_OS_MAC // QTBUG-18040 - // alignment of TextInput with no text set to it + +#ifdef Q_OS_MAC + QEXPECT_FAIL("", "QTBUG-18040", Abort); // alignment of TextInput with no text set to it +#endif QString componentStr = "import QtQuick 2.0\nTextInput {}"; QDeclarativeComponent textComponent(&engine); textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); @@ -1188,7 +1197,6 @@ void tst_qquicktextinput::horizontalAlignment_RightToLeft() QCOMPARE(textObject->hAlign(), QGuiApplication::keyboardInputDirection() == Qt::LeftToRight ? QQuickTextInput::AlignLeft : QQuickTextInput::AlignRight); delete textObject; -#endif } void tst_qquicktextinput::positionAt() @@ -1207,52 +1215,30 @@ void tst_qquicktextinput::positionAt() int pos = textinputObject->positionAt(textinputObject->width()/2); int textWidth = 0; - int textLeftWidth = 0; + int textLeftWidthBegin = 0; + int textLeftWidthEnd = 0; if (!qmlDisableDistanceField()) { - { - QTextLayout layout(textinputObject->text().left(pos)); + QTextLayout layout(textinputObject->text()); - { - QTextOption option; - option.setUseDesignMetrics(true); - layout.setTextOption(option); - } - - layout.beginLayout(); - QTextLine line = layout.createLine(); - layout.endLayout(); + QTextOption option; + option.setUseDesignMetrics(true); + layout.setTextOption(option); - textLeftWidth = ceil(line.horizontalAdvance()); - } - { - QTextLayout layout(textinputObject->text()); + layout.beginLayout(); + QTextLine line = layout.createLine(); + layout.endLayout(); - { - QTextOption option; - option.setUseDesignMetrics(true); - layout.setTextOption(option); - } - - layout.beginLayout(); - QTextLine line = layout.createLine(); - layout.endLayout(); - - textWidth = ceil(line.horizontalAdvance()); - } + textLeftWidthBegin = floor(line.cursorToX(pos - 1)); + textLeftWidthEnd = ceil(line.cursorToX(pos + 1)); + textWidth = floor(line.horizontalAdvance()); } else { textWidth = fm.width(textinputObject->text()); - textLeftWidth = fm.width(textinputObject->text().left(pos)); + textLeftWidthBegin = fm.width(textinputObject->text().left(pos - 1)); + textLeftWidthEnd = fm.width(textinputObject->text().left(pos + 1)); } - int diff = abs(textWidth - (textLeftWidth+textinputObject->width()/2)); - - // some tollerance for different fonts. - QEXPECT_FAIL("", "QTBUG-21689", Abort); -#ifdef Q_OS_LINUX - QVERIFY(diff < 2); -#else - QVERIFY(diff < 5); -#endif + QVERIFY(textLeftWidthBegin <= textWidth - textinputObject->width() / 2); + QVERIFY(textLeftWidthEnd >= textWidth - textinputObject->width() / 2); int x = textinputObject->positionToRectangle(pos + 1).x() - 1; QCOMPARE(textinputObject->positionAt(x, QQuickTextInput::CursorBetweenCharacters), pos + 1); @@ -1263,33 +1249,25 @@ void tst_qquicktextinput::positionAt() pos = textinputObject->positionAt(textinputObject->width()/2); if (!qmlDisableDistanceField()) { - { - QTextLayout layout(textinputObject->text().left(pos)); + QTextLayout layout(textinputObject->text()); - { - QTextOption option; - option.setUseDesignMetrics(true); - layout.setTextOption(option); - } + QTextOption option; + option.setUseDesignMetrics(true); + layout.setTextOption(option); - layout.beginLayout(); - QTextLine line = layout.createLine(); - layout.endLayout(); + layout.beginLayout(); + QTextLine line = layout.createLine(); + layout.endLayout(); - textLeftWidth = ceil(line.horizontalAdvance()); - } + textLeftWidthBegin = floor(line.cursorToX(pos - 1)); + textLeftWidthEnd = ceil(line.cursorToX(pos + 1)); } else { - textLeftWidth = fm.width(textinputObject->text().left(pos)); + textLeftWidthBegin = fm.width(textinputObject->text().left(pos - 1)); + textLeftWidthEnd = fm.width(textinputObject->text().left(pos + 1)); } - diff = abs(int(textLeftWidth-textinputObject->width()/2)); - - // some tollerance for different fonts. -#ifdef Q_OS_LINUX - QVERIFY(diff < 2); -#else - QVERIFY(diff < 5); -#endif + QVERIFY(textLeftWidthBegin <= textinputObject->width() / 2); + QVERIFY(textLeftWidthEnd >= textinputObject->width() / 2); x = textinputObject->positionToRectangle(pos + 1).x() - 1; QCOMPARE(textinputObject->positionAt(x, QQuickTextInput::CursorBetweenCharacters), pos + 1); @@ -1303,7 +1281,7 @@ void tst_qquicktextinput::positionAt() textinputObject->setCursorPosition(0); QInputMethodEvent inputEvent(preeditText, QList<QInputMethodEvent::Attribute>()); - QGuiApplication::sendEvent(&canvas, &inputEvent); + QGuiApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &inputEvent); // Check all points within the preedit text return the same position. QCOMPARE(textinputObject->positionAt(0), 0); @@ -1495,25 +1473,24 @@ void tst_qquicktextinput::inputMethods() // test that input method event is committed QInputMethodEvent event; event.setCommitString( "My ", -12, 0); - QGuiApplication::sendEvent(&canvas, &event); - QEXPECT_FAIL("", QTBUG_21691_MESSAGE, Abort); + QGuiApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &event); QCOMPARE(input->text(), QString("My Hello world!")); input->setCursorPosition(2); event.setCommitString("Your", -2, 2); - QGuiApplication::sendEvent(&canvas, &event); + QGuiApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &event); QCOMPARE(input->text(), QString("Your Hello world!")); QCOMPARE(input->cursorPosition(), 4); input->setCursorPosition(7); event.setCommitString("Goodbye", -2, 5); - QGuiApplication::sendEvent(&canvas, &event); + QGuiApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &event); QCOMPARE(input->text(), QString("Your Goodbye world!")); QCOMPARE(input->cursorPosition(), 12); input->setCursorPosition(8); event.setCommitString("Our", -8, 4); - QGuiApplication::sendEvent(&canvas, &event); + QGuiApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &event); QCOMPARE(input->text(), QString("Our Goodbye world!")); QCOMPARE(input->cursorPosition(), 7); } @@ -1602,7 +1579,7 @@ void tst_qquicktextinput::navigation_RTL() void tst_qquicktextinput::copyAndPaste() { #ifndef QT_NO_CLIPBOARD -#ifdef Q_WS_MAC +#ifdef Q_OS_MAC { PasteboardRef pasteboard; OSStatus status = PasteboardCreate(0, &pasteboard); @@ -2265,66 +2242,69 @@ void tst_qquicktextinput::testQtQuick11Attributes_data() << ""; } +static void sendPreeditText(const QString &text, int cursor) +{ + QInputMethodEvent event(text, QList<QInputMethodEvent::Attribute>() + << QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, cursor, text.length(), QVariant())); + QCoreApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &event); +} + void tst_qquicktextinput::preeditAutoScroll() { -#ifdef QTBUG_21691 - QEXPECT_FAIL("", QTBUG_21691_MESSAGE, Abort); - QVERIFY(false); -#else QString preeditText = "califragisiticexpialidocious!"; QQuickView view(QUrl::fromLocalFile(TESTDATA("preeditAutoScroll.qml"))); - MyInputContext ic; - // QQuickCanvas won't set the Qt::WA_InputMethodEnabled flag unless a suitable item has active focus - // and QWidget won't allow an input context to be set when the flag is not set. - view.setAttribute(Qt::WA_InputMethodEnabled, true); - view.setInputContext(&ic); - view.setAttribute(Qt::WA_InputMethodEnabled, false); view.show(); view.requestActivateWindow(); QTest::qWaitForWindowShown(&view); QTRY_COMPARE(&view, qGuiApp->focusWindow()); QQuickTextInput *input = qobject_cast<QQuickTextInput *>(view.rootObject()); QVERIFY(input); + QVERIFY(input->hasActiveFocus()); + + input->setWidth(input->implicitWidth()); QSignalSpy cursorRectangleSpy(input, SIGNAL(cursorRectangleChanged())); int cursorRectangleChanges = 0; - QFontMetricsF fm(input->font()); - input->setWidth(fm.width(input->text())); - // test the text is scrolled so the preedit is visible. - ic.sendPreeditText(preeditText.mid(0, 3), 1); + sendPreeditText(preeditText.mid(0, 3), 1); QVERIFY(input->positionAt(0) != 0); QVERIFY(input->cursorRectangle().left() < input->boundingRect().width()); QCOMPARE(cursorRectangleSpy.count(), ++cursorRectangleChanges); // test the text is scrolled back when the preedit is removed. - ic.sendEvent(QInputMethodEvent()); + QInputMethodEvent imEvent; + QCoreApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &imEvent); QCOMPARE(input->positionAt(0), 0); QCOMPARE(input->positionAt(input->width()), 5); QCOMPARE(cursorRectangleSpy.count(), ++cursorRectangleChanges); - // some tolerance for different fonts. -#ifdef Q_OS_LINUX - const int error = 2; -#else - const int error = 5; -#endif + QTextLayout layout(preeditText); + if (!qmlDisableDistanceField()) { + QTextOption option; + option.setUseDesignMetrics(true); + layout.setTextOption(option); + } + layout.beginLayout(); + QTextLine line = layout.createLine(); + layout.endLayout(); // test if the preedit is larger than the text input that the // character preceding the cursor is still visible. qreal x = input->positionToRectangle(0).x(); for (int i = 0; i < 3; ++i) { - ic.sendPreeditText(preeditText, i + 1); - QVERIFY(input->cursorRectangle().right() >= fm.width(preeditText.at(i)) - error); + sendPreeditText(preeditText, i + 1); + int width = ceil(line.cursorToX(i, QTextLine::Trailing)) - floor(line.cursorToX(i)); + QVERIFY(input->cursorRectangle().right() >= width - 3); QVERIFY(input->positionToRectangle(0).x() < x); QCOMPARE(cursorRectangleSpy.count(), ++cursorRectangleChanges); x = input->positionToRectangle(0).x(); } for (int i = 1; i >= 0; --i) { - ic.sendPreeditText(preeditText, i + 1); - QVERIFY(input->cursorRectangle().right() >= fm.width(preeditText.at(i)) - error); + sendPreeditText(preeditText, i + 1); + int width = ceil(line.cursorToX(i, QTextLine::Trailing)) - floor(line.cursorToX(i)); + QVERIFY(input->cursorRectangle().right() >= width - 3); QVERIFY(input->positionToRectangle(0).x() > x); QCOMPARE(cursorRectangleSpy.count(), ++cursorRectangleChanges); x = input->positionToRectangle(0).x(); @@ -2332,45 +2312,34 @@ void tst_qquicktextinput::preeditAutoScroll() // Test incrementing the preedit cursor doesn't cause further // scrolling when right most text is visible. - ic.sendPreeditText(preeditText, preeditText.length() - 3); + sendPreeditText(preeditText, preeditText.length() - 3); QCOMPARE(cursorRectangleSpy.count(), ++cursorRectangleChanges); x = input->positionToRectangle(0).x(); for (int i = 2; i >= 0; --i) { - ic.sendPreeditText(preeditText, preeditText.length() - i); + sendPreeditText(preeditText, preeditText.length() - i); QCOMPARE(input->positionToRectangle(0).x(), x); QCOMPARE(cursorRectangleSpy.count(), ++cursorRectangleChanges); } for (int i = 1; i < 3; ++i) { - ic.sendPreeditText(preeditText, preeditText.length() - i); + sendPreeditText(preeditText, preeditText.length() - i); QCOMPARE(input->positionToRectangle(0).x(), x); QCOMPARE(cursorRectangleSpy.count(), ++cursorRectangleChanges); } // Test disabling auto scroll. - ic.sendEvent(QInputMethodEvent()); + QCoreApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &imEvent); input->setAutoScroll(false); - ic.sendPreeditText(preeditText.mid(0, 3), 1); + sendPreeditText(preeditText.mid(0, 3), 1); QCOMPARE(input->positionAt(0), 0); QCOMPARE(input->positionAt(input->width()), 5); -#endif } -void tst_qquicktextinput::preeditMicroFocus() +void tst_qquicktextinput::preeditCursorRectangle() { -#ifdef QTBUG_21691 - QEXPECT_FAIL("", QTBUG_21691_MESSAGE, Abort); - QVERIFY(false); -#else QString preeditText = "super"; QQuickView view(QUrl::fromLocalFile(TESTDATA("inputMethodEvent.qml"))); - MyInputContext ic; - // QQuickCanvas won't set the Qt::WA_InputMethodEnabled flag unless a suitable item has active focus - // and QWidget won't allow an input context to be set when the flag is not set. - view.setAttribute(Qt::WA_InputMethodEnabled, true); - view.setInputContext(&ic); - view.setAttribute(Qt::WA_InputMethodEnabled, false); view.show(); view.requestActivateWindow(); QTest::qWaitForWindowShown(&view); @@ -2379,163 +2348,43 @@ void tst_qquicktextinput::preeditMicroFocus() QVERIFY(input); QRect currentRect; - QRect previousRect = input->inputMethodQuery(Qt::ImCursorRectangle).toRect(); + + QInputMethodQueryEvent query(Qt::ImCursorRectangle); + QCoreApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &query); + QRect previousRect = query.value(Qt::ImCursorRectangle).toRect(); // Verify that the micro focus rect is positioned the same for position 0 as // it would be if there was no preedit text. - ic.updateReceived = false; - ic.sendPreeditText(preeditText, 0); - currentRect = input->inputMethodQuery(Qt::ImCursorRectangle).toRect(); + sendPreeditText(preeditText, 0); + QCoreApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &query); + currentRect = query.value(Qt::ImCursorRectangle).toRect(); QCOMPARE(currentRect, previousRect); -#if defined(Q_WS_X11) || defined(Q_WS_QWS) - QCOMPARE(ic.updateReceived, true); -#endif + + QSignalSpy inputSpy(input, SIGNAL(cursorRectangleChanged())); + QSignalSpy panelSpy(qGuiApp->inputPanel(), SIGNAL(cursorRectangleChanged())); // Verify that the micro focus rect moves to the left as the cursor position // is incremented. for (int i = 1; i <= 5; ++i) { - ic.updateReceived = false; - ic.sendPreeditText(preeditText, i); - currentRect = input->inputMethodQuery(Qt::ImCursorRectangle).toRect(); + sendPreeditText(preeditText, i); + QCoreApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &query); + currentRect = query.value(Qt::ImCursorRectangle).toRect(); QVERIFY(previousRect.left() < currentRect.left()); -#if defined(Q_WS_X11) || defined(Q_WS_QWS) - QCOMPARE(ic.updateReceived, true); -#endif + QVERIFY(inputSpy.count() > 0); inputSpy.clear(); + QVERIFY(panelSpy.count() > 0); panelSpy.clear(); previousRect = currentRect; } // Verify that if there is no preedit cursor then the micro focus rect is the // same as it would be if it were positioned at the end of the preedit text. - ic.sendPreeditText(preeditText, 0); - ic.updateReceived = false; - ic.sendEvent(QInputMethodEvent(preeditText, QList<QInputMethodEvent::Attribute>())); - currentRect = input->inputMethodQuery(Qt::ImCursorRectangle).toRect(); + sendPreeditText(preeditText, 0); + QInputMethodEvent imEvent(preeditText, QList<QInputMethodEvent::Attribute>()); + QCoreApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &imEvent); + QCoreApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &query); + currentRect = query.value(Qt::ImCursorRectangle).toRect(); QCOMPARE(currentRect, previousRect); -#if defined(Q_WS_X11) || defined(Q_WS_QWS) - QCOMPARE(ic.updateReceived, true); -#endif -#endif -} - -void tst_qquicktextinput::inputContextMouseHandler() -{ -#ifdef QTBUG_21691 - QEXPECT_FAIL("", QTBUG_21691_MESSAGE, Abort); - QVERIFY(false); -#else - QString text = "supercalifragisiticexpialidocious!"; - - QQuickView view(QUrl::fromLocalFile(TESTDATA("inputContext.qml"))); - MyInputContext ic; - // QQuickCanvas won't set the Qt::WA_InputMethodEnabled flag unless a suitable item has active focus - // and QWidget won't allow an input context to be set when the flag is not set. - view.setAttribute(Qt::WA_InputMethodEnabled, true); - view.setInputContext(&ic); - view.setAttribute(Qt::WA_InputMethodEnabled, false); - view.show(); - view.requestActivateWindow(); - QTest::qWaitForWindowShown(&view); - QTRY_COMPARE(&view, qGuiApp->focusWindow()); - QQuickTextInput *input = qobject_cast<QQuickTextInput *>(view.rootObject()); - QVERIFY(input); - - QFontMetricsF fm(input->font()); - const qreal y = fm.height() / 2; - - QPoint position2 = input->mapToScene(QPointF(fm.width(text.mid(0, 2)), y)).toPoint(); - QPoint position8 = input->mapToScene(QPointF(fm.width(text.mid(0, 8)), y)).toPoint(); - QPoint position20 = input->mapToScene(QPointF(fm.width(text.mid(0, 20)), y)).toPoint(); - QPoint position27 = input->mapToScene(QPointF(fm.width(text.mid(0, 27)), y)).toPoint(); - QPoint globalPosition2 = view.mapToGlobal(position2); - QPoint globalposition8 = view.mapToGlobal(position8); - QPoint globalposition20 = view.mapToGlobal(position20); - QPoint globalposition27 = view.mapToGlobal(position27); - - ic.sendEvent(QInputMethodEvent(text.mid(12), QList<QInputMethodEvent::Attribute>())); - - QTest::mouseDClick(&view, Qt::LeftButton, Qt::NoModifier, position2); - QCOMPARE(ic.eventType, QEvent::MouseButtonDblClick); - QCOMPARE(ic.eventPosition, position2); - QCOMPARE(ic.eventGlobalPosition, globalPosition2); - QCOMPARE(ic.eventButton, Qt::LeftButton); - QCOMPARE(ic.eventModifiers, Qt::NoModifier); - QVERIFY(ic.cursor < 0); - ic.eventType = QEvent::None; - - QTest::mousePress(&view, Qt::LeftButton, Qt::NoModifier, position2); - QCOMPARE(ic.eventType, QEvent::MouseButtonPress); - QCOMPARE(ic.eventPosition, position2); - QCOMPARE(ic.eventGlobalPosition, globalPosition2); - QCOMPARE(ic.eventButton, Qt::LeftButton); - QCOMPARE(ic.eventModifiers, Qt::NoModifier); - QVERIFY(ic.cursor < 0); - ic.eventType = QEvent::None; - - { QMouseEvent mv(QEvent::MouseMove, position8, globalposition8, Qt::LeftButton, Qt::LeftButton,Qt::NoModifier); - QGuiApplication::sendEvent(&view, &mv); } - QCOMPARE(ic.eventType, QEvent::None); - - { QMouseEvent mv(QEvent::MouseMove, position27, globalposition27, Qt::LeftButton, Qt::LeftButton,Qt::NoModifier); - QGuiApplication::sendEvent(&view, &mv); } - QCOMPARE(ic.eventType, QEvent::MouseMove); - QCOMPARE(ic.eventPosition, position27); - QCOMPARE(ic.eventGlobalPosition, globalposition27); - QCOMPARE(ic.eventButton, Qt::LeftButton); - QCOMPARE(ic.eventModifiers, Qt::NoModifier); - QVERIFY(ic.cursor >= 14 && ic.cursor <= 16); // 15 is expected but some platforms may be off by one. - ic.eventType = QEvent::None; - - QTest::mouseRelease(&view, Qt::LeftButton, Qt::NoModifier, position27); - QCOMPARE(ic.eventType, QEvent::MouseButtonRelease); - QCOMPARE(ic.eventPosition, position27); - QCOMPARE(ic.eventGlobalPosition, globalposition27); - QCOMPARE(ic.eventButton, Qt::LeftButton); - QCOMPARE(ic.eventModifiers, Qt::NoModifier); - QVERIFY(ic.cursor >= 14 && ic.cursor <= 16); - ic.eventType = QEvent::None; - - // And in the other direction. - QTest::mouseDClick(&view, Qt::LeftButton, Qt::ControlModifier, position27); - QCOMPARE(ic.eventType, QEvent::MouseButtonDblClick); - QCOMPARE(ic.eventPosition, position27); - QCOMPARE(ic.eventGlobalPosition, globalposition27); - QCOMPARE(ic.eventButton, Qt::LeftButton); - QCOMPARE(ic.eventModifiers, Qt::ControlModifier); - QVERIFY(ic.cursor >= 14 && ic.cursor <= 16); - ic.eventType = QEvent::None; - - QTest::mousePress(&view, Qt::RightButton, Qt::ControlModifier, position27); - QCOMPARE(ic.eventType, QEvent::MouseButtonPress); - QCOMPARE(ic.eventPosition, position27); - QCOMPARE(ic.eventGlobalPosition, globalposition27); - QCOMPARE(ic.eventButton, Qt::RightButton); - QCOMPARE(ic.eventModifiers, Qt::ControlModifier); - QVERIFY(ic.cursor >= 14 && ic.cursor <= 16); - ic.eventType = QEvent::None; - - { QMouseEvent mv(QEvent::MouseMove, position20, globalposition20, Qt::RightButton, Qt::RightButton,Qt::ControlModifier); - QGuiApplication::sendEvent(&view, &mv); } - QCOMPARE(ic.eventType, QEvent::MouseMove); - QCOMPARE(ic.eventPosition, position20); - QCOMPARE(ic.eventGlobalPosition, globalposition20); - QCOMPARE(ic.eventButton, Qt::RightButton); - QCOMPARE(ic.eventModifiers, Qt::ControlModifier); - QVERIFY(ic.cursor >= 7 && ic.cursor <= 9); - ic.eventType = QEvent::None; - - { QMouseEvent mv(QEvent::MouseMove, position2, globalPosition2, Qt::RightButton, Qt::RightButton,Qt::ControlModifier); - QGuiApplication::sendEvent(&view, &mv); } - QCOMPARE(ic.eventType, QEvent::None); - - QTest::mouseRelease(&view, Qt::RightButton, Qt::ControlModifier, position2); - QCOMPARE(ic.eventType, QEvent::MouseButtonRelease); - QCOMPARE(ic.eventPosition, position2); - QCOMPARE(ic.eventGlobalPosition, globalPosition2); - QCOMPARE(ic.eventButton, Qt::RightButton); - QCOMPARE(ic.eventModifiers, Qt::ControlModifier); - QVERIFY(ic.cursor < 0); - ic.eventType = QEvent::None; -#endif + QVERIFY(inputSpy.count() > 0); + QVERIFY(panelSpy.count() > 0); } void tst_qquicktextinput::inputMethodComposing() diff --git a/tests/auto/declarative/qquickview/tst_qquickview.cpp b/tests/auto/declarative/qquickview/tst_qquickview.cpp index a2334d2e58..fc480b5fca 100644 --- a/tests/auto/declarative/qquickview/tst_qquickview.cpp +++ b/tests/auto/declarative/qquickview/tst_qquickview.cpp @@ -89,9 +89,8 @@ void tst_QQuickView::resizemodeitem() // size update from view canvas->resize(QSize(80,100)); - QTest::qWait(50); - QCOMPARE(item->width(), 80.0); + QTRY_COMPARE(item->width(), 80.0); QCOMPARE(item->height(), 100.0); QCOMPARE(canvas->size(), QSize(80, 100)); QCOMPARE(canvas->size(), canvas->sizeHint()); @@ -177,7 +176,6 @@ void tst_QQuickView::resizemodeitem() QTest::qWait(50); // initial size from root object - QEXPECT_FAIL("", "QTBUG-22019", Abort); QCOMPARE(item->width(), 300.0); QCOMPARE(item->height(), 300.0); QCOMPARE(canvas->size(), QSize(300, 300)); diff --git a/tests/auto/declarative/qquickvisualdatamodel/data/create.qml b/tests/auto/declarative/qquickvisualdatamodel/data/create.qml index 36ea3baf76..3475a0dace 100644 --- a/tests/auto/declarative/qquickvisualdatamodel/data/create.qml +++ b/tests/auto/declarative/qquickvisualdatamodel/data/create.qml @@ -7,6 +7,8 @@ ListView { model: VisualDataModel { id: visualModel + persistedItems.includeByDefault: true + model: myModel delegate: Item { id: delegate @@ -16,6 +18,7 @@ ListView { property bool destroyed: false + Component.onDestruction: destroyed = true } } diff --git a/tests/auto/declarative/qquickvisualdatamodel/data/datalist-package.qml b/tests/auto/declarative/qquickvisualdatamodel/data/datalist-package.qml new file mode 100644 index 0000000000..ae3bd81d91 --- /dev/null +++ b/tests/auto/declarative/qquickvisualdatamodel/data/datalist-package.qml @@ -0,0 +1,20 @@ +import QtQuick 2.0 + +ListView { + width: 100 + height: 100 + model: visualModel.parts.package + VisualDataModel { + id: visualModel + objectName: "visualModel" + model: myModel + delegate: Package { + Rectangle { + height: 25 + width: 100 + Package.name: "package" + Text { objectName: "display"; text: display } + } + } + } +} diff --git a/tests/auto/declarative/qquickvisualdatamodel/data/groups-invalid.qml b/tests/auto/declarative/qquickvisualdatamodel/data/groups-invalid.qml new file mode 100644 index 0000000000..70c6f9f995 --- /dev/null +++ b/tests/auto/declarative/qquickvisualdatamodel/data/groups-invalid.qml @@ -0,0 +1,14 @@ +import QtQuick 2.0 + +VisualDataModel { + id: visualModel + + objectName: "visualModel" + + groups: [ + VisualDataGroup { id: visibleItems; objectName: "visibleItems"; name: "visible"; includeByDefault: true }, + VisualDataGroup { id: selectedItems; objectName: "selectedItems"; name: "selected" }, + VisualDataGroup { id: unnamed; objectName: "unnamed" }, + VisualDataGroup { id: capitalised; objectName: "capitalised"; name: "Capitalised" } + ] +} diff --git a/tests/auto/declarative/qquickvisualdatamodel/data/groups-package.qml b/tests/auto/declarative/qquickvisualdatamodel/data/groups-package.qml new file mode 100644 index 0000000000..ea5ad5d3bd --- /dev/null +++ b/tests/auto/declarative/qquickvisualdatamodel/data/groups-package.qml @@ -0,0 +1,52 @@ +import QtQuick 2.0 + +ListView { + width: 100 + height: 100 + + function contains(array, value) { + for (var i = 0; i < array.length; ++i) + if (array[i] == value) + return true + return false + } + model: visualModel.parts.package + + VisualDataModel { + id: visualModel + + objectName: "visualModel" + + groups: [ + VisualDataGroup { id: visibleItems; objectName: "visibleItems"; name: "visible"; includeByDefault: true }, + VisualDataGroup { id: selectedItems; objectName: "selectedItems"; name: "selected" } + ] + + model: myModel + delegate: Package { + id: delegate + + property variant test1: name + property variant test2: index + property variant test3: VisualDataModel.itemsIndex + property variant test4: VisualDataModel.inItems + property variant test5: VisualDataModel.visibleIndex + property variant test6: VisualDataModel.inVisible + property variant test7: VisualDataModel.selectedIndex + property variant test8: VisualDataModel.inSelected + property variant test9: VisualDataModel.groups + + function hide() { VisualDataModel.inVisible = false } + function select() { VisualDataModel.inSelected = true } + + Item { + Package.name: "package" + + objectName: "delegate" + width: 100 + height: 2 + } + } + } + +} diff --git a/tests/auto/declarative/qquickvisualdatamodel/data/groups.qml b/tests/auto/declarative/qquickvisualdatamodel/data/groups.qml index a24e223bc5..7502dd2502 100644 --- a/tests/auto/declarative/qquickvisualdatamodel/data/groups.qml +++ b/tests/auto/declarative/qquickvisualdatamodel/data/groups.qml @@ -11,7 +11,12 @@ ListView { return false } - model: VisualDataModel { + model: visualModel + VisualDataModel { + id: visualModel + + objectName: "visualModel" + groups: [ VisualDataGroup { id: visibleItems; objectName: "visibleItems"; name: "visible"; includeByDefault: true }, VisualDataGroup { id: selectedItems; objectName: "selectedItems"; name: "selected" } @@ -20,6 +25,7 @@ ListView { model: myModel delegate: Item { id: delegate + objectName: "delegate" width: 100 height: 2 diff --git a/tests/auto/declarative/qquickvisualdatamodel/data/onChanged.qml b/tests/auto/declarative/qquickvisualdatamodel/data/onChanged.qml new file mode 100644 index 0000000000..71dc7d72d7 --- /dev/null +++ b/tests/auto/declarative/qquickvisualdatamodel/data/onChanged.qml @@ -0,0 +1,87 @@ +import QtQuick 2.0 + +VisualDataModel { + id: vm + + property var inserted + property var removed + + Component.onCompleted: { + vm.inserted = [] + vm.removed = [] + vi.inserted = [] + vi.removed = [] + si.inserted = [] + si.removed = [] + } + + function verify(changes, indexes, counts, moveIds) { + if (changes.length != indexes.length + || changes.length != counts.length + || changes.length != moveIds.length) { + console.log("invalid length", changes.length, indexes.length, counts.length, moveIds.length) + return false + } + + var valid = true; + for (var i = 0; i < changes.length; ++i) { + if (changes[i].index != indexes[i]) { + console.log(i, "incorrect index. actual:", changes[i].index, "expected:", indexes[i]) + valid = false; + } + if (changes[i].count != counts[i]) { + console.log(i, "incorrect count. actual:", changes[i].count, "expected:", counts[i]) + valid = false; + } + if (changes[i].moveId != moveIds[i]) { + console.log(i, "incorrect moveId. actual:", changes[i].moveId, "expected:", moveIds[i]) + valid = false; + } + } + return valid + } + + groups: [ + VisualDataGroup { + id: vi; + + property var inserted + property var removed + + name: "visible" + includeByDefault: true + + onChanged: { + vi.inserted = inserted + vi.removed = removed + } + }, + VisualDataGroup { + id: si; + + property var inserted + property var removed + + name: "selected" + onChanged: { + si.inserted = inserted + si.removed = removed + } + } + ] + + model: ListModel { + id: listModel + ListElement { number: "one" } + ListElement { number: "two" } + ListElement { number: "three" } + ListElement { number: "four" } + } + + delegate: Item {} + + items.onChanged: { + vm.inserted = inserted + vm.removed = removed + } +} diff --git a/tests/auto/declarative/qquickvisualdatamodel/tst_qquickvisualdatamodel.cpp b/tests/auto/declarative/qquickvisualdatamodel/tst_qquickvisualdatamodel.cpp index aba760db91..706c20fa15 100644 --- a/tests/auto/declarative/qquickvisualdatamodel/tst_qquickvisualdatamodel.cpp +++ b/tests/auto/declarative/qquickvisualdatamodel/tst_qquickvisualdatamodel.cpp @@ -122,18 +122,27 @@ private slots: void initTestCase(); void cleanupTestCase(); void rootIndex(); + void updateLayout_data(); void updateLayout(); + void childChanged_data(); void childChanged(); void objectListModel(); void singleRole(); void modelProperties(); + void noDelegate_data(); void noDelegate(); void qaimRowsMoved(); void qaimRowsMoved_data(); + void remove_data(); void remove(); + void move_data(); void move(); + void groups_data(); void groups(); + void invalidGroups(); void get(); + void onChanged_data(); + void onChanged(); void create(); private: @@ -262,8 +271,18 @@ void tst_qquickvisualdatamodel::rootIndex() delete obj; } +void tst_qquickvisualdatamodel::updateLayout_data() +{ + QTest::addColumn<QUrl>("source"); + + QTest::newRow("item delegate") << QUrl::fromLocalFile(TESTDATA("datalist.qml")); + QTest::newRow("package delegate") << QUrl::fromLocalFile(TESTDATA("datalist-package.qml")); +} + void tst_qquickvisualdatamodel::updateLayout() { + QFETCH(QUrl, source); + QQuickView view; QStandardItemModel model; @@ -271,7 +290,7 @@ void tst_qquickvisualdatamodel::updateLayout() view.rootContext()->setContextProperty("myModel", &model); - view.setSource(QUrl::fromLocalFile(TESTDATA("datalist.qml"))); + view.setSource(source); QQuickListView *listview = qobject_cast<QQuickListView*>(view.rootObject()); QVERIFY(listview != 0); @@ -302,8 +321,18 @@ void tst_qquickvisualdatamodel::updateLayout() QCOMPARE(name->text(), QString("Row 1 Item")); } +void tst_qquickvisualdatamodel::childChanged_data() +{ + QTest::addColumn<QUrl>("source"); + + QTest::newRow("item delegate") << QUrl::fromLocalFile(TESTDATA("datalist.qml")); + QTest::newRow("package delegate") << QUrl::fromLocalFile(TESTDATA("datalist-package.qml")); +} + void tst_qquickvisualdatamodel::childChanged() { + QFETCH(QUrl, source); + QQuickView view; QStandardItemModel model; @@ -311,7 +340,7 @@ void tst_qquickvisualdatamodel::childChanged() view.rootContext()->setContextProperty("myModel", &model); - view.setSource(QUrl::fromLocalFile(TESTDATA("datalist.qml"))); + view.setSource(source); QQuickListView *listview = qobject_cast<QQuickListView*>(view.rootObject()); QVERIFY(listview != 0); @@ -567,8 +596,18 @@ void tst_qquickvisualdatamodel::modelProperties() //### should also test QStringList and QVariantList } +void tst_qquickvisualdatamodel::noDelegate_data() +{ + QTest::addColumn<QUrl>("source"); + + QTest::newRow("item delegate") << QUrl::fromLocalFile(TESTDATA("datalist.qml")); + QTest::newRow("package delegate") << QUrl::fromLocalFile(TESTDATA("datalist-package.qml")); +} + void tst_qquickvisualdatamodel::noDelegate() { + QFETCH(QUrl, source); + QQuickView view; QStandardItemModel model; @@ -576,7 +615,7 @@ void tst_qquickvisualdatamodel::noDelegate() view.rootContext()->setContextProperty("myModel", &model); - view.setSource(QUrl::fromLocalFile(TESTDATA("datalist.qml"))); + view.setSource(source); QQuickListView *listview = qobject_cast<QQuickListView*>(view.rootObject()); QVERIFY(listview != 0); @@ -669,6 +708,19 @@ void tst_qquickvisualdatamodel::qaimRowsMoved_data() << 10 << 1 << 5; } +void tst_qquickvisualdatamodel::remove_data() +{ + QTest::addColumn<QUrl>("source"); + QTest::addColumn<QString>("package delegate"); + + QTest::newRow("item delegate") + << QUrl::fromLocalFile(TESTDATA("groups.qml")) + << QString(); + QTest::newRow("package") + << QUrl::fromLocalFile(TESTDATA("groups-package.qml")) + << QString("package."); +} + void tst_qquickvisualdatamodel::remove() { QQuickView view; @@ -766,6 +818,19 @@ void tst_qquickvisualdatamodel::remove() } } +void tst_qquickvisualdatamodel::move_data() +{ + QTest::addColumn<QUrl>("source"); + QTest::addColumn<QString>("package delegate"); + + QTest::newRow("item delegate") + << QUrl::fromLocalFile(TESTDATA("groups.qml")) + << QString(); + QTest::newRow("package") + << QUrl::fromLocalFile(TESTDATA("groups-package.qml")) + << QString("package."); +} + void tst_qquickvisualdatamodel::move() { QQuickView view; @@ -906,6 +971,18 @@ void tst_qquickvisualdatamodel::move() } } +void tst_qquickvisualdatamodel::groups_data() +{ + QTest::addColumn<QUrl>("source"); + QTest::addColumn<QString>("part"); + + QTest::newRow("item delegate") + << QUrl::fromLocalFile(TESTDATA("groups.qml")) + << QString(); + QTest::newRow("package") + << QUrl::fromLocalFile(TESTDATA("groups-package.qml")) + << QString("visualModel.parts.package."); +} template <int N> void tst_qquickvisualdatamodel::groups_verify( const SingleRoleModel &model, @@ -921,17 +998,17 @@ template <int N> void tst_qquickvisualdatamodel::groups_verify( for (int i = 0; i < N; ++i) { QQuickItem *delegate = findItem<QQuickItem>(contentItem, "delegate", mIndex[i]); QVERIFY(delegate); - QCOMPARE(delegate->property("test1").toString(), model.list.at(mIndex[i])); - QCOMPARE(delegate->property("test2").toInt() , mIndex[i]); - QCOMPARE(delegate->property("test3").toInt() , iIndex[i]); - QCOMPARE(delegate->property("test4").toBool(), true); - QCOMPARE(delegate->property("test5").toInt() , vIndex[i]); - QCOMPARE(delegate->property("test6").toBool(), vMember[i]); - QCOMPARE(delegate->property("test7").toInt() , sIndex[i]); - QCOMPARE(delegate->property("test8").toBool(), sMember[i]); - QCOMPARE(delegate->property("test9").toStringList().contains("items") , QBool(true)); - QCOMPARE(delegate->property("test9").toStringList().contains("visible") , QBool(vMember[i])); - QCOMPARE(delegate->property("test9").toStringList().contains("selected"), QBool(sMember[i])); + QCOMPARE(evaluate<QString>(delegate, "test1"), model.list.at(mIndex[i])); + QCOMPARE(evaluate<int>(delegate, "test2") , mIndex[i]); + QCOMPARE(evaluate<int>(delegate, "test3") , iIndex[i]); + QCOMPARE(evaluate<bool>(delegate, "test4"), true); + QCOMPARE(evaluate<int>(delegate, "test5") , vIndex[i]); + QCOMPARE(evaluate<bool>(delegate, "test6"), vMember[i]); + QCOMPARE(evaluate<int>(delegate, "test7") , sIndex[i]); + QCOMPARE(evaluate<bool>(delegate, "test8"), sMember[i]); + QCOMPARE(evaluate<QStringList>(delegate, "test9").contains("items") , QBool(true)); + QCOMPARE(evaluate<QStringList>(delegate, "test9").contains("visible") , QBool(vMember[i])); + QCOMPARE(evaluate<QStringList>(delegate, "test9").contains("selected"), QBool(sMember[i])); } failed = false; } @@ -943,6 +1020,9 @@ template <int N> void tst_qquickvisualdatamodel::groups_verify( void tst_qquickvisualdatamodel::groups() { + QFETCH(QUrl, source); + QFETCH(QString, part); + QQuickView view; SingleRoleModel model; @@ -963,7 +1043,7 @@ void tst_qquickvisualdatamodel::groups() QDeclarativeContext *ctxt = view.rootContext(); ctxt->setContextProperty("myModel", &model); - view.setSource(QUrl::fromLocalFile(TESTDATA("groups.qml"))); + view.setSource(source); QQuickListView *listview = qobject_cast<QQuickListView*>(view.rootObject()); QVERIFY(listview != 0); @@ -971,13 +1051,13 @@ void tst_qquickvisualdatamodel::groups() QQuickItem *contentItem = listview->contentItem(); QVERIFY(contentItem != 0); - QQuickVisualDataModel *visualModel = qobject_cast<QQuickVisualDataModel *>(qvariant_cast<QObject *>(listview->model())); + QQuickVisualDataModel *visualModel = listview->findChild<QQuickVisualDataModel *>("visualModel"); QVERIFY(visualModel); - QQuickVisualDataGroup *visibleItems = visualModel->findChild<QQuickVisualDataGroup *>("visibleItems"); + QQuickVisualDataGroup *visibleItems = listview->findChild<QQuickVisualDataGroup *>("visibleItems"); QVERIFY(visibleItems); - QQuickVisualDataGroup *selectedItems = visualModel->findChild<QQuickVisualDataGroup *>("selectedItems"); + QQuickVisualDataGroup *selectedItems = listview->findChild<QQuickVisualDataGroup *>("selectedItems"); QVERIFY(selectedItems); const bool f = false; @@ -1130,23 +1210,26 @@ void tst_qquickvisualdatamodel::groups() QCOMPARE(visibleItems->count(), 9); QCOMPARE(selectedItems->count(), 2); } { - evaluate<void>(visualModel, "filterOnGroup = \"visible\""); + evaluate<void>(visualModel, part + "filterOnGroup = \"visible\""); QCOMPARE(listview->count(), 9); QCOMPARE(visualModel->items()->count(), 12); QCOMPARE(visibleItems->count(), 9); QCOMPARE(selectedItems->count(), 2); + QCOMPARE(evaluate<QString>(visualModel, part + "filterOnGroup"), QString("visible")); } { - evaluate<void>(visualModel, "filterOnGroup = \"selected\""); + evaluate<void>(visualModel, part + "filterOnGroup = \"selected\""); QCOMPARE(listview->count(), 2); QCOMPARE(visualModel->items()->count(), 12); QCOMPARE(visibleItems->count(), 9); QCOMPARE(selectedItems->count(), 2); + QCOMPARE(evaluate<QString>(visualModel, part + "filterOnGroup"), QString("selected")); } { - evaluate<void>(visualModel, "filterOnGroup = \"items\""); + evaluate<void>(visualModel, part + "filterOnGroup = undefined"); QCOMPARE(listview->count(), 12); QCOMPARE(visualModel->items()->count(), 12); QCOMPARE(visibleItems->count(), 9); QCOMPARE(selectedItems->count(), 2); + QCOMPARE(evaluate<QString>(visualModel, part + "filterOnGroup"), QString("items")); } { QQuickItem *delegate = findItem<QQuickItem>(contentItem, "delegate", 5); QVERIFY(delegate); @@ -1410,6 +1493,144 @@ void tst_qquickvisualdatamodel::get() } } +void tst_qquickvisualdatamodel::invalidGroups() +{ + QUrl source = QUrl::fromLocalFile(TESTDATA("groups-invalid.qml")); + QTest::ignoreMessage(QtWarningMsg, (source.toString() + ":12:9: QML VisualDataGroup: " + QQuickVisualDataGroup::tr("Group names must start with a lower case letter")).toUtf8()); + + QDeclarativeComponent component(&engine, source); + QScopedPointer<QObject> object(component.create()); + QVERIFY(object); + + QCOMPARE(evaluate<int>(object.data(), "groups.length"), 4); + QCOMPARE(evaluate<QString>(object.data(), "groups[0].name"), QString("items")); + QCOMPARE(evaluate<QString>(object.data(), "groups[1].name"), QString("persistedItems")); + QCOMPARE(evaluate<QString>(object.data(), "groups[2].name"), QString("visible")); + QCOMPARE(evaluate<QString>(object.data(), "groups[3].name"), QString("selected")); +} + +void tst_qquickvisualdatamodel::onChanged_data() +{ + QTest::addColumn<QString>("expression"); + QTest::addColumn<QStringList>("tests"); + + QTest::newRow("item appended") + << QString("listModel.append({\"number\": \"five\"})") + << (QStringList() + << "verify(vm.removed, [], [], [])" + << "verify(vm.inserted, [4], [1], [undefined])" + << "verify(vi.removed, [], [], [])" + << "verify(vi.inserted, [4], [1], [undefined])" + << "verify(si.removed, [], [], [])" + << "verify(si.inserted, [], [], [])"); + QTest::newRow("item prepended") + << QString("listModel.insert(0, {\"number\": \"five\"})") + << (QStringList() + << "verify(vm.removed, [], [], [])" + << "verify(vm.inserted, [0], [1], [undefined])" + << "verify(vi.removed, [], [], [])" + << "verify(vi.inserted, [0], [1], [undefined])" + << "verify(si.removed, [], [], [])" + << "verify(si.inserted, [], [], [])"); + QTest::newRow("item inserted") + << QString("listModel.insert(2, {\"number\": \"five\"})") + << (QStringList() + << "verify(vm.removed, [], [], [])" + << "verify(vm.inserted, [2], [1], [undefined])" + << "verify(vi.removed, [], [], [])" + << "verify(vi.inserted, [2], [1], [undefined])" + << "verify(si.removed, [], [], [])" + << "verify(si.inserted, [], [], [])"); + + QTest::newRow("item removed tail") + << QString("listModel.remove(3)") + << (QStringList() + << "verify(vm.removed, [3], [1], [undefined])" + << "verify(vm.inserted, [], [], [])" + << "verify(vi.removed, [3], [1], [undefined])" + << "verify(vi.inserted, [], [], [])" + << "verify(si.removed, [], [], [])" + << "verify(si.inserted, [], [], [])"); + QTest::newRow("item removed head") + << QString("listModel.remove(0)") + << (QStringList() + << "verify(vm.removed, [0], [1], [undefined])" + << "verify(vm.inserted, [], [], [])" + << "verify(vi.removed, [0], [1], [undefined])" + << "verify(vi.inserted, [], [], [])" + << "verify(si.removed, [], [], [])" + << "verify(si.inserted, [], [], [])"); + QTest::newRow("item removed middle") + << QString("listModel.remove(1)") + << (QStringList() + << "verify(vm.removed, [1], [1], [undefined])" + << "verify(vm.inserted, [], [], [])" + << "verify(vi.removed, [1], [1], [undefined])" + << "verify(vi.inserted, [], [], [])" + << "verify(si.removed, [], [], [])" + << "verify(si.inserted, [], [], [])"); + + + QTest::newRow("item moved from tail") + << QString("listModel.move(3, 0, 1)") + << (QStringList() + << "verify(vm.removed, [3], [1], [vm.inserted[0].moveId])" + << "verify(vm.inserted, [0], [1], [vm.removed[0].moveId])" + << "verify(vi.removed, [3], [1], [vi.inserted[0].moveId])" + << "verify(vi.inserted, [0], [1], [vi.removed[0].moveId])" + << "verify(si.removed, [], [], [])" + << "verify(si.inserted, [], [], [])"); + QTest::newRow("item moved from head") + << QString("listModel.move(0, 2, 2)") + << (QStringList() + << "verify(vm.removed, [0], [2], [vm.inserted[0].moveId])" + << "verify(vm.inserted, [2], [2], [vm.removed[0].moveId])" + << "verify(vi.removed, [0], [2], [vi.inserted[0].moveId])" + << "verify(vi.inserted, [2], [2], [vi.removed[0].moveId])" + << "verify(si.removed, [], [], [])" + << "verify(si.inserted, [], [], [])"); + + QTest::newRow("groups changed") + << QString("items.setGroups(1, 2, [\"items\", \"selected\"])") + << (QStringList() + << "verify(vm.inserted, [], [], [])" + << "verify(vm.removed, [], [], [])" + << "verify(vi.removed, [1], [2], [undefined])" + << "verify(vi.inserted, [], [], [])" + << "verify(si.removed, [], [], [])" + << "verify(si.inserted, [0], [2], [undefined])"); + + QTest::newRow("multiple removes") + << QString("{ vi.remove(1, 1); " + "vi.removeGroups(0, 2, \"items\") }") + << (QStringList() + << "verify(vm.removed, [0, 1], [1, 1], [undefined, undefined])" + << "verify(vm.inserted, [], [], [])" + << "verify(vi.removed, [1], [1], [undefined])" + << "verify(vi.inserted, [], [], [])" + << "verify(si.removed, [], [], [])" + << "verify(si.inserted, [], [], [])"); +} + +void tst_qquickvisualdatamodel::onChanged() +{ + QFETCH(QString, expression); + QFETCH(QStringList, tests); + + QDeclarativeComponent component(&engine, QUrl::fromLocalFile(TESTDATA("onChanged.qml"))); + QScopedPointer<QObject> object(component.create()); + QVERIFY(object); + + evaluate<void>(object.data(), expression); + + foreach (const QString &test, tests) { + bool passed = evaluate<bool>(object.data(), test); + if (!passed) + qWarning() << test; + QVERIFY(passed); + } +} + void tst_qquickvisualdatamodel::create() { QQuickView view; @@ -1455,8 +1676,20 @@ void tst_qquickvisualdatamodel::create() QQuickItem *delegate; + // persistedItems.includeByDefault is true, so all items belong to persistedItems initially. + QVERIFY(delegate = findItem<QQuickItem>(contentItem, "delegate", 1)); + QCOMPARE(evaluate<bool>(delegate, "VisualDataModel.inPersistedItems"), true); + + // changing include by default doesn't remove persistance. + evaluate<void>(visualModel, "persistedItems.includeByDefault = false"); + QCOMPARE(evaluate<bool>(delegate, "VisualDataModel.inPersistedItems"), true); + + // removing from persistedItems does. + evaluate<void>(visualModel, "persistedItems.remove(0, 20)"); + QCOMPARE(listview->count(), 20); + QCOMPARE(evaluate<bool>(delegate, "VisualDataModel.inPersistedItems"), false); + // Request an item instantiated by the view. - QVERIFY(findItem<QQuickItem>(contentItem, "delegate", 1)); QVERIFY(delegate = qobject_cast<QQuickItem *>(evaluate<QObject *>(visualModel, "items.create(1)"))); QCOMPARE(delegate, findItem<QQuickItem>(contentItem, "delegate", 1)); QCOMPARE(evaluate<bool>(delegate, "VisualDataModel.inPersistedItems"), true); diff --git a/tests/auto/declarative/v4/data/qtbug_21883.qml b/tests/auto/declarative/v4/data/qtbug_21883.qml new file mode 100644 index 0000000000..a51f97c944 --- /dev/null +++ b/tests/auto/declarative/v4/data/qtbug_21883.qml @@ -0,0 +1,5 @@ +import Qt.v4 1.0 + +Result { + property Result dummy: Result +} diff --git a/tests/auto/declarative/v4/tst_v4.cpp b/tests/auto/declarative/v4/tst_v4.cpp index 0b6b2c24f7..20d739f4b5 100644 --- a/tests/auto/declarative/v4/tst_v4.cpp +++ b/tests/auto/declarative/v4/tst_v4.cpp @@ -77,6 +77,7 @@ private slots: void qtscript_data(); void nestedObjectAccess(); void subscriptionsInConditionalExpressions(); + void qtbug_21883(); private: QDeclarativeEngine engine; @@ -239,6 +240,19 @@ void tst_v4::subscriptionsInConditionalExpressions() delete o; } +// Crash test +void tst_v4::qtbug_21883() +{ + QDeclarativeComponent component(&engine, TEST_FILE("qtbug_21883.qml")); + + QString warning = component.url().toString() + ":4: Unable to assign null to ResultObject*"; + QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); + + QObject *o = component.create(); + QVERIFY(o != 0); + delete o; +} + QTEST_MAIN(tst_v4) #include "tst_v4.moc" diff --git a/tests/auto/headersclean/tst_headersclean.cpp b/tests/auto/headersclean/tst_headersclean.cpp index 60bb799076..9aa7f1d693 100644 --- a/tests/auto/headersclean/tst_headersclean.cpp +++ b/tests/auto/headersclean/tst_headersclean.cpp @@ -49,6 +49,7 @@ #include <QtCore/QtCore> #include <QtTest/QtTest> +#include <QtDeclarative/QtDeclarative> class tst_HeadersClean: public QObject { diff --git a/tests/auto/particles/qquickage/tst_qquickage.cpp b/tests/auto/particles/qquickage/tst_qquickage.cpp index 73db409de3..b787a73ef7 100644 --- a/tests/auto/particles/qquickage/tst_qquickage.cpp +++ b/tests/auto/particles/qquickage/tst_qquickage.cpp @@ -68,7 +68,7 @@ void tst_qquickage::test_kill() QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); ensureAnimTime(600, system->m_animation); - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused @@ -84,6 +84,7 @@ void tst_qquickage::test_kill() QCOMPARE(d->endSize, 32.f); QVERIFY(d->t <= ((qreal)system->timeInt/1000.0) - 0.5f + EPSILON); } + delete view; } void tst_qquickage::test_jump() @@ -92,14 +93,14 @@ void tst_qquickage::test_jump() QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); ensureAnimTime(600, system->m_animation); - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused - //Allow for a small variance because jump is trying to simulate off wall time - extremelyFuzzyCompare(d->x, -100.f, 5.0f); - extremelyFuzzyCompare(d->y, -100.f, 5.0f); + //Allow for variance because jump is trying to simulate off wall time and things have emitted 'continuously' before first affect + QVERIFY(d->x <= -50.f); + QVERIFY(d->y <= -50.f); QCOMPARE(d->vx, 500.f); QCOMPARE(d->vy, 500.f); QCOMPARE(d->ax, 0.f); @@ -109,6 +110,7 @@ void tst_qquickage::test_jump() QCOMPARE(d->endSize, 32.f); QVERIFY(d->t <= ((qreal)system->timeInt/1000.0) - 0.4f + EPSILON); } + delete view; } void tst_qquickage::test_onceOff() @@ -117,7 +119,7 @@ void tst_qquickage::test_onceOff() QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); ensureAnimTime(600, system->m_animation); - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused @@ -133,6 +135,7 @@ void tst_qquickage::test_onceOff() QCOMPARE(d->endSize, 32.f); QVERIFY(d->t <= ((qreal)system->timeInt/1000.0) - 0.4f + EPSILON); } + delete view; } void tst_qquickage::test_sustained() @@ -142,7 +145,7 @@ void tst_qquickage::test_sustained() ensureAnimTime(600, system->m_animation); //TODO: Ensure some particles have lived to 0.4s point despite unified timer - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused @@ -158,6 +161,7 @@ void tst_qquickage::test_sustained() QCOMPARE(d->endSize, 32.f); QVERIFY(myFuzzyCompare(d->t, ((qreal)system->timeInt/1000.0) - 0.4f)); } + delete view; } QTEST_MAIN(tst_qquickage); diff --git a/tests/auto/particles/qquickangleddirection/tst_qquickangleddirection.cpp b/tests/auto/particles/qquickangleddirection/tst_qquickangleddirection.cpp index d21753e8a0..4e3fda3d03 100644 --- a/tests/auto/particles/qquickangleddirection/tst_qquickangleddirection.cpp +++ b/tests/auto/particles/qquickangleddirection/tst_qquickangleddirection.cpp @@ -66,7 +66,7 @@ void tst_qquickangleddirection::test_basic() QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); ensureAnimTime(600, system->m_animation); - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused @@ -85,6 +85,7 @@ void tst_qquickangleddirection::test_basic() QCOMPARE(d->endSize, 32.f); QVERIFY(myFuzzyLEQ(d->t, ((qreal)system->timeInt/1000.0))); } + delete view; } QTEST_MAIN(tst_qquickangleddirection); diff --git a/tests/auto/particles/qquickcumulativedirection/tst_qquickcumulativedirection.cpp b/tests/auto/particles/qquickcumulativedirection/tst_qquickcumulativedirection.cpp index 052578f3a8..22c2d5efa0 100644 --- a/tests/auto/particles/qquickcumulativedirection/tst_qquickcumulativedirection.cpp +++ b/tests/auto/particles/qquickcumulativedirection/tst_qquickcumulativedirection.cpp @@ -65,7 +65,7 @@ void tst_qquickcumulativedirection::test_basic() QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); ensureAnimTime(600, system->m_animation); - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused @@ -81,6 +81,7 @@ void tst_qquickcumulativedirection::test_basic() QCOMPARE(d->endSize, 32.f); QVERIFY(myFuzzyLEQ(d->t, ((qreal)system->timeInt/1000.0))); } + delete view; } QTEST_MAIN(tst_qquickcumulativedirection); diff --git a/tests/auto/particles/qquickcustomaffector/data/basic.qml b/tests/auto/particles/qquickcustomaffector/data/basic.qml index 7371698026..253c566c66 100644 --- a/tests/auto/particles/qquickcustomaffector/data/basic.qml +++ b/tests/auto/particles/qquickcustomaffector/data/basic.qml @@ -54,6 +54,7 @@ Rectangle { ImageParticle { source: "../../shared/star.png" + rotation: 90 } Emitter{ @@ -75,6 +76,12 @@ Rectangle { particles[i].initialAY = 100; particles[i].startSize = 100; particles[i].endSize = 100; + particles[i].autoRotate = true; + particles[i].update = true; + particles[i].red = 0; + particles[i].green = 1.0; + particles[i].blue = 0; + particles[i].alpha = 0; } } } diff --git a/tests/auto/particles/qquickcustomaffector/tst_qquickcustomaffector.cpp b/tests/auto/particles/qquickcustomaffector/tst_qquickcustomaffector.cpp index 77b1d09763..c33895e9ad 100644 --- a/tests/auto/particles/qquickcustomaffector/tst_qquickcustomaffector.cpp +++ b/tests/auto/particles/qquickcustomaffector/tst_qquickcustomaffector.cpp @@ -66,10 +66,13 @@ void tst_qquickcustomaffector::test_basic() QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); ensureAnimTime(600, system->m_animation); - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused + //in CI the whole simulation often happens at once, so dead particles end up missing out + if (!d->stillAlive()) + continue; //parameters no longer get set once you die QCOMPARE(d->x, 100.f); QCOMPARE(d->y, 100.f); @@ -80,8 +83,14 @@ void tst_qquickcustomaffector::test_basic() QCOMPARE(d->lifeSpan, 0.5f); QCOMPARE(d->size, 100.f); QCOMPARE(d->endSize, 100.f); + QCOMPARE(d->autoRotate, 1.f); + QCOMPARE(d->color.r, (uchar)0); + QCOMPARE(d->color.g, (uchar)255); + QCOMPARE(d->color.b, (uchar)0); + QCOMPARE(d->color.a, (uchar)0); QVERIFY(myFuzzyLEQ(d->t, ((qreal)system->timeInt/1000.0))); } + delete view; } void tst_qquickcustomaffector::test_move() @@ -90,7 +99,7 @@ void tst_qquickcustomaffector::test_move() QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); ensureAnimTime(600, system->m_animation); - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused @@ -108,6 +117,7 @@ void tst_qquickcustomaffector::test_move() QCOMPARE(d->endSize, 32.f); QVERIFY(myFuzzyLEQ(d->t, ((qreal)system->timeInt/1000.0))); } + delete view; } QTEST_MAIN(tst_qquickcustomaffector); diff --git a/tests/auto/particles/qquickcustomparticle/tst_qquickcustomparticle.cpp b/tests/auto/particles/qquickcustomparticle/tst_qquickcustomparticle.cpp index 3c73fad3f3..60977b2f49 100644 --- a/tests/auto/particles/qquickcustomparticle/tst_qquickcustomparticle.cpp +++ b/tests/auto/particles/qquickcustomparticle/tst_qquickcustomparticle.cpp @@ -67,7 +67,7 @@ void tst_qquickcustomparticle::test_basic() ensureAnimTime(600, system->m_animation); bool oneNonZero = false; - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused @@ -86,6 +86,7 @@ void tst_qquickcustomparticle::test_basic() if (d->r != 0.0 ) oneNonZero = true; } + delete view; QVERIFY(oneNonZero);//Zero is a valid value, but it also needs to be set to a random number } diff --git a/tests/auto/particles/qquickellipseextruder/tst_qquickellipseextruder.cpp b/tests/auto/particles/qquickellipseextruder/tst_qquickellipseextruder.cpp index 7f412c8521..683eb49ed7 100644 --- a/tests/auto/particles/qquickellipseextruder/tst_qquickellipseextruder.cpp +++ b/tests/auto/particles/qquickellipseextruder/tst_qquickellipseextruder.cpp @@ -82,7 +82,7 @@ void tst_qquickellipseextruder::test_basic() ensureAnimTime(600, system->m_animation); //Filled - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused @@ -97,6 +97,7 @@ void tst_qquickellipseextruder::test_basic() QCOMPARE(d->endSize, 32.f); QVERIFY(myFuzzyLEQ(d->t, ((qreal)system->timeInt/1000.0))); } + //Just border QCOMPARE(system->groupData[1]->size(), 500); foreach (QQuickParticleData *d, system->groupData[1]->data) { @@ -113,6 +114,7 @@ void tst_qquickellipseextruder::test_basic() QCOMPARE(d->endSize, 32.f); QVERIFY(myFuzzyLEQ(d->t, ((qreal)system->timeInt/1000.0))); } + delete view; } QTEST_MAIN(tst_qquickellipseextruder); diff --git a/tests/auto/particles/qquickfriction/tst_qquickfriction.cpp b/tests/auto/particles/qquickfriction/tst_qquickfriction.cpp index aca4ea2330..bea3e18d27 100644 --- a/tests/auto/particles/qquickfriction/tst_qquickfriction.cpp +++ b/tests/auto/particles/qquickfriction/tst_qquickfriction.cpp @@ -67,7 +67,7 @@ void tst_qquickfriction::test_basic() ensureAnimTime(600, system->m_animation); //Default is just slowed a little - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused @@ -101,6 +101,7 @@ void tst_qquickfriction::test_basic() QCOMPARE(d->endSize, 32.f); QVERIFY(myFuzzyLEQ(d->t, ((qreal)system->timeInt/1000.0))); } + delete view; } void tst_qquickfriction::test_threshold() @@ -110,7 +111,7 @@ void tst_qquickfriction::test_threshold() ensureAnimTime(600, system->m_animation); //Speed capped at 50, but it might take a frame or two to get there - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1.0f) continue; //Particle data unused @@ -127,6 +128,7 @@ void tst_qquickfriction::test_threshold() QCOMPARE(d->endSize, 32.f); QVERIFY(myFuzzyLEQ(d->t, ((qreal)system->timeInt/1000.0))); } + delete view; } QTEST_MAIN(tst_qquickfriction); diff --git a/tests/auto/particles/qquickgravity/tst_qquickgravity.cpp b/tests/auto/particles/qquickgravity/tst_qquickgravity.cpp index 5613591171..bc8cca8522 100644 --- a/tests/auto/particles/qquickgravity/tst_qquickgravity.cpp +++ b/tests/auto/particles/qquickgravity/tst_qquickgravity.cpp @@ -65,18 +65,21 @@ void tst_qquickgravity::test_basic() QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); ensureAnimTime(600, system->m_animation); - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); + float mag = 707.10678f; foreach (QQuickParticleData *d, system->groupData[0]->data) { - if (d->t == -1) - continue; //Particle data unused + if (d->t == -1 || !d->stillAlive()) + continue; //Particle data unused or dead - QCOMPARE(d->ax, 707.10678f); - QCOMPARE(d->ay, 707.10678f); + float t = ((qreal)system->timeInt/1000.0) - d->t; + QVERIFY(extremelyFuzzyCompare(d->vx, t*mag, 20.0f)); + QVERIFY(extremelyFuzzyCompare(d->vy, t*mag, 20.0f)); QCOMPARE(d->lifeSpan, 0.5f); QCOMPARE(d->size, 32.f); QCOMPARE(d->endSize, 32.f); QVERIFY(myFuzzyLEQ(d->t, ((qreal)system->timeInt/1000.0))); } + delete view; } QTEST_MAIN(tst_qquickgravity); diff --git a/tests/auto/particles/qquickgroupgoal/data/basic.qml b/tests/auto/particles/qquickgroupgoal/data/basic.qml new file mode 100644 index 0000000000..4b27cd4ac9 --- /dev/null +++ b/tests/auto/particles/qquickgroupgoal/data/basic.qml @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQuick.Particles 2.0 + +Rectangle { + color: "black" + width: 320 + height: 320 + + ParticleSystem { + id: sys + objectName: "system" + anchors.fill: parent + + ImageParticle { + source: "../../shared/star.png" + } + + GroupGoal { + groups: ["notdefault"] + goalState: "" + jump: true + } + + Emitter { + //0,0 position + group: "notdefault" + size: 32 + emitRate: 1000 + lifeSpan: 500 + } + } +} diff --git a/tests/auto/particles/qquickgroupgoal/qquickgroupgoal.pro b/tests/auto/particles/qquickgroupgoal/qquickgroupgoal.pro new file mode 100644 index 0000000000..8e7d5ae021 --- /dev/null +++ b/tests/auto/particles/qquickgroupgoal/qquickgroupgoal.pro @@ -0,0 +1,11 @@ +CONFIG += testcase +TARGET = tst_qquickgroupgoal +SOURCES += tst_qquickgroupgoal.cpp +macx:CONFIG -= app_bundle + +testDataFiles.files = data +testDataFiles.path = . +DEPLOYMENT += testDataFiles + +QT += core-private gui-private v8-private declarative-private opengl-private testlib + diff --git a/tests/auto/particles/qquickgroupgoal/tst_qquickgroupgoal.cpp b/tests/auto/particles/qquickgroupgoal/tst_qquickgroupgoal.cpp new file mode 100644 index 0000000000..92f30d903f --- /dev/null +++ b/tests/auto/particles/qquickgroupgoal/tst_qquickgroupgoal.cpp @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> +#include "../shared/particlestestsshared.h" +#include <private/qquickparticlesystem_p.h> +#include <private/qabstractanimation_p.h> + +class tst_qquickgroupgoal : public QObject +{ + Q_OBJECT +public: + tst_qquickgroupgoal(); + +private slots: + void test_instantTransition(); +}; + +tst_qquickgroupgoal::tst_qquickgroupgoal() +{ + QUnifiedTimer::instance()->setConsistentTiming(true); +} + +void tst_qquickgroupgoal::test_instantTransition() +{ + //Note: Does not go through sprite engine + QQuickView* view = createView(QCoreApplication::applicationDirPath() + "/data/basic.qml", 600); + QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); + ensureAnimTime(600, system->m_animation); + + QVERIFY(system->groupData[0]->size() <= 500 && system->groupData[0]->size() >= 450); + foreach (QQuickParticleData *d, system->groupData[0]->data) { + if (d->t == -1) + continue; //Particle data unused + + QCOMPARE(d->x, 0.f); + QCOMPARE(d->y, 0.f); + QCOMPARE(d->vx, 0.f); + QCOMPARE(d->vy, 0.f); + QCOMPARE(d->ax, 0.f); + QCOMPARE(d->ay, 0.f); + QCOMPARE(d->lifeSpan, 0.5f); + QCOMPARE(d->size, 32.f); + QCOMPARE(d->endSize, 32.f); + QVERIFY(myFuzzyLEQ(d->t, ((qreal)system->timeInt/1000.0))); + } + delete view; +} + +QTEST_MAIN(tst_qquickgroupgoal); + +#include "tst_qquickgroupgoal.moc" diff --git a/tests/auto/particles/qquickimageparticle/qquickimageparticle.pro b/tests/auto/particles/qquickimageparticle/qquickimageparticle.pro index c05ecdfb09..14d28fd43d 100644 --- a/tests/auto/particles/qquickimageparticle/qquickimageparticle.pro +++ b/tests/auto/particles/qquickimageparticle/qquickimageparticle.pro @@ -8,4 +8,3 @@ testDataFiles.path = . DEPLOYMENT += testDataFiles QT += core-private gui-private v8-private declarative-private opengl-private testlib - diff --git a/tests/auto/particles/qquickimageparticle/tst_qquickimageparticle.cpp b/tests/auto/particles/qquickimageparticle/tst_qquickimageparticle.cpp index e56de35137..27b386dcd5 100644 --- a/tests/auto/particles/qquickimageparticle/tst_qquickimageparticle.cpp +++ b/tests/auto/particles/qquickimageparticle/tst_qquickimageparticle.cpp @@ -71,7 +71,7 @@ void tst_qquickimageparticle::test_basic() QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); ensureAnimTime(600, system->m_animation); - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused @@ -105,6 +105,7 @@ void tst_qquickimageparticle::test_basic() QCOMPARE(d->frameCount, 1.0f); QCOMPARE(d->animT, -1.0f); } + delete view; } @@ -114,7 +115,7 @@ void tst_qquickimageparticle::test_colored() QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); ensureAnimTime(600, system->m_animation); - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused @@ -148,6 +149,7 @@ void tst_qquickimageparticle::test_colored() QCOMPARE(d->frameCount, 1.0f); QCOMPARE(d->animT, -1.0f); } + delete view; } @@ -157,7 +159,7 @@ void tst_qquickimageparticle::test_deformed() QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); ensureAnimTime(600, system->m_animation); - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused @@ -191,6 +193,7 @@ void tst_qquickimageparticle::test_deformed() QCOMPARE(d->frameCount, 1.0f); QCOMPARE(d->animT, -1.0f); } + delete view; } @@ -200,7 +203,7 @@ void tst_qquickimageparticle::test_tabled() QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); ensureAnimTime(600, system->m_animation); - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused @@ -235,6 +238,7 @@ void tst_qquickimageparticle::test_tabled() QCOMPARE(d->animT, -1.0f); //TODO: This performance level doesn't alter particleData, but goes straight to shaders. Find something to test } + delete view; } @@ -244,7 +248,7 @@ void tst_qquickimageparticle::test_sprite() QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); ensureAnimTime(600, system->m_animation); - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused @@ -278,6 +282,7 @@ void tst_qquickimageparticle::test_sprite() QCOMPARE(d->animWidth, 31.0f); QCOMPARE(d->animHeight, 30.0f); } + delete view; } QTEST_MAIN(tst_qquickimageparticle); diff --git a/tests/auto/particles/qquickitemparticle/qquickitemparticle.pro b/tests/auto/particles/qquickitemparticle/qquickitemparticle.pro index dc006d2ba1..8e8eadd463 100644 --- a/tests/auto/particles/qquickitemparticle/qquickitemparticle.pro +++ b/tests/auto/particles/qquickitemparticle/qquickitemparticle.pro @@ -7,5 +7,7 @@ testDataFiles.files = data testDataFiles.path = . DEPLOYMENT += testDataFiles +CONFIG += insignificant_test #temporary + QT += core-private gui-private v8-private declarative-private opengl-private testlib diff --git a/tests/auto/particles/qquickitemparticle/tst_qquickitemparticle.cpp b/tests/auto/particles/qquickitemparticle/tst_qquickitemparticle.cpp index 40197ec619..6cfb6c5562 100644 --- a/tests/auto/particles/qquickitemparticle/tst_qquickitemparticle.cpp +++ b/tests/auto/particles/qquickitemparticle/tst_qquickitemparticle.cpp @@ -66,7 +66,7 @@ void tst_qquickitemparticle::test_basic() QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); ensureAnimTime(600, system->m_animation); - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused @@ -88,6 +88,7 @@ void tst_qquickitemparticle::test_basic() QVERIFY(d->delegate); QVERIFY(qobject_cast<QQuickImage*>(d->delegate)); } + delete view; } QTEST_MAIN(tst_qquickitemparticle); diff --git a/tests/auto/particles/qquicklineextruder/tst_qquicklineextruder.cpp b/tests/auto/particles/qquicklineextruder/tst_qquicklineextruder.cpp index ff45a9e92c..69d87acf44 100644 --- a/tests/auto/particles/qquicklineextruder/tst_qquicklineextruder.cpp +++ b/tests/auto/particles/qquicklineextruder/tst_qquicklineextruder.cpp @@ -65,7 +65,7 @@ void tst_qquicklineextruder::test_basic() QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); ensureAnimTime(600, system->m_animation); - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused @@ -96,6 +96,7 @@ void tst_qquicklineextruder::test_basic() QCOMPARE(d->endSize, 32.f); QVERIFY(myFuzzyLEQ(d->t, ((qreal)system->timeInt/1000.0))); } + delete view; } QTEST_MAIN(tst_qquicklineextruder); diff --git a/tests/auto/particles/qquickmaskextruder/tst_qquickmaskextruder.cpp b/tests/auto/particles/qquickmaskextruder/tst_qquickmaskextruder.cpp index b2a178fa1c..c13a776586 100644 --- a/tests/auto/particles/qquickmaskextruder/tst_qquickmaskextruder.cpp +++ b/tests/auto/particles/qquickmaskextruder/tst_qquickmaskextruder.cpp @@ -65,7 +65,7 @@ void tst_qquickmaskextruder::test_basic() QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); ensureAnimTime(600, system->m_animation); - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused @@ -81,6 +81,7 @@ void tst_qquickmaskextruder::test_basic() QCOMPARE(d->endSize, 32.f); QVERIFY(myFuzzyLEQ(d->t, ((qreal)system->timeInt/1000.0))); } + delete view; } QTEST_MAIN(tst_qquickmaskextruder); diff --git a/tests/auto/particles/qquickparticlegroup/tst_qquickparticlegroup.cpp b/tests/auto/particles/qquickparticlegroup/tst_qquickparticlegroup.cpp index c3b155aa68..2548d879d0 100644 --- a/tests/auto/particles/qquickparticlegroup/tst_qquickparticlegroup.cpp +++ b/tests/auto/particles/qquickparticlegroup/tst_qquickparticlegroup.cpp @@ -82,6 +82,7 @@ void tst_qquickparticlegroup::test_instantTransition() QCOMPARE(d->endSize, 32.f); QVERIFY(myFuzzyLEQ(d->t, ((qreal)system->timeInt/1000.0))); } + delete view; } QTEST_MAIN(tst_qquickparticlegroup); diff --git a/tests/auto/particles/qquickparticlesystem/tst_qquickparticlesystem.cpp b/tests/auto/particles/qquickparticlesystem/tst_qquickparticlesystem.cpp index b85c57da0b..f9bb971a82 100644 --- a/tests/auto/particles/qquickparticlesystem/tst_qquickparticlesystem.cpp +++ b/tests/auto/particles/qquickparticlesystem/tst_qquickparticlesystem.cpp @@ -65,7 +65,7 @@ void tst_qquickparticlesystem::test_basic() QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); ensureAnimTime(600, system->m_animation); - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); int stillAlive = 0; foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) @@ -84,6 +84,7 @@ void tst_qquickparticlesystem::test_basic() QCOMPARE(d->endSize, 32.f); QVERIFY(myFuzzyLEQ(d->t, ((qreal)system->timeInt/1000.0))); } + delete view; QVERIFY(extremelyFuzzyCompare(stillAlive, 500, 5));//Small simulation variance is permissible. } diff --git a/tests/auto/particles/qquickpointattractor/tst_qquickpointattractor.cpp b/tests/auto/particles/qquickpointattractor/tst_qquickpointattractor.cpp index 6a64f919c0..e6b1b6e1c8 100644 --- a/tests/auto/particles/qquickpointattractor/tst_qquickpointattractor.cpp +++ b/tests/auto/particles/qquickpointattractor/tst_qquickpointattractor.cpp @@ -65,7 +65,7 @@ void tst_qquickpointattractor::test_basic() QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); ensureAnimTime(600, system->m_animation); - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused @@ -82,6 +82,7 @@ void tst_qquickpointattractor::test_basic() QCOMPARE(d->endSize, 32.f); QVERIFY(myFuzzyLEQ(d->t, ((qreal)system->timeInt/1000.0))); } + delete view; } QTEST_MAIN(tst_qquickpointattractor); diff --git a/tests/auto/particles/qquickpointdirection/tst_qquickpointdirection.cpp b/tests/auto/particles/qquickpointdirection/tst_qquickpointdirection.cpp index 19cc471126..b554ba7226 100644 --- a/tests/auto/particles/qquickpointdirection/tst_qquickpointdirection.cpp +++ b/tests/auto/particles/qquickpointdirection/tst_qquickpointdirection.cpp @@ -65,7 +65,7 @@ void tst_qquickpointdirection::test_basic() QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); ensureAnimTime(600, system->m_animation); - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused @@ -83,6 +83,7 @@ void tst_qquickpointdirection::test_basic() QCOMPARE(d->endSize, 32.f); QVERIFY(myFuzzyLEQ(d->t, ((qreal)system->timeInt/1000.0))); } + delete view; } QTEST_MAIN(tst_qquickpointdirection); diff --git a/tests/auto/particles/qquickrectangleextruder/tst_qquickrectangleextruder.cpp b/tests/auto/particles/qquickrectangleextruder/tst_qquickrectangleextruder.cpp index 6fb2e9cae8..d8c17efdaf 100644 --- a/tests/auto/particles/qquickrectangleextruder/tst_qquickrectangleextruder.cpp +++ b/tests/auto/particles/qquickrectangleextruder/tst_qquickrectangleextruder.cpp @@ -65,7 +65,7 @@ void tst_qquickrectangleextruder::test_basic() QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); ensureAnimTime(600, system->m_animation); - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused @@ -106,6 +106,7 @@ void tst_qquickrectangleextruder::test_basic() QCOMPARE(d->endSize, 32.f); QVERIFY(myFuzzyLEQ(d->t, ((qreal)system->timeInt/1000.0))); } + delete view; } QTEST_MAIN(tst_qquickrectangleextruder); diff --git a/tests/auto/particles/qquickspritegoal/data/basic.qml b/tests/auto/particles/qquickspritegoal/data/basic.qml new file mode 100644 index 0000000000..4c172ef28d --- /dev/null +++ b/tests/auto/particles/qquickspritegoal/data/basic.qml @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQuick.Particles 2.0 + +Rectangle { + color: "black" + width: 320 + height: 320 + + ParticleSystem { + id: sys + objectName: "system" + anchors.fill: parent + + ImageParticle { + sprites: [Sprite { + name: "happy" + source: "../../shared/squarefacesprite.png" + frames: 6 + duration: 120 + }, Sprite { + name: "twoHappy" + source: "../../shared/squarefacesprite.png" + frames: 3 + duration: 240 + }] + } + + SpriteGoal { + goalState: "twoHappy" + jump: true + } + + Emitter { + //0,0 position + size: 32 + emitRate: 1000 + lifeSpan: 500 + } + } +} diff --git a/tests/auto/particles/qquickspritegoal/qquickspritegoal.pro b/tests/auto/particles/qquickspritegoal/qquickspritegoal.pro new file mode 100644 index 0000000000..d335a91537 --- /dev/null +++ b/tests/auto/particles/qquickspritegoal/qquickspritegoal.pro @@ -0,0 +1,11 @@ +CONFIG += testcase +TARGET = tst_qquickspritegoal +SOURCES += tst_qquickspritegoal.cpp +macx:CONFIG -= app_bundle + +testDataFiles.files = data +testDataFiles.path = . +DEPLOYMENT += testDataFiles + +QT += core-private gui-private v8-private declarative-private opengl-private testlib + diff --git a/tests/auto/particles/qquickspritegoal/tst_qquickspritegoal.cpp b/tests/auto/particles/qquickspritegoal/tst_qquickspritegoal.cpp new file mode 100644 index 0000000000..9bb19d207a --- /dev/null +++ b/tests/auto/particles/qquickspritegoal/tst_qquickspritegoal.cpp @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> +#include "../shared/particlestestsshared.h" +#include <private/qquickparticlesystem_p.h> +#include <private/qabstractanimation_p.h> + +class tst_qquickspritegoal : public QObject +{ + Q_OBJECT +public: + tst_qquickspritegoal(); + +private slots: + void test_instantTransition(); +}; + +tst_qquickspritegoal::tst_qquickspritegoal() +{ + QUnifiedTimer::instance()->setConsistentTiming(true); +} + +void tst_qquickspritegoal::test_instantTransition() +{ + QQuickView* view = createView(QCoreApplication::applicationDirPath() + "/data/basic.qml", 600); + QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); + ensureAnimTime(600, system->m_animation); + + QVERIFY(system->groupData[0]->size() <= 500 && system->groupData[0]->size() >= 450); + foreach (QQuickParticleData *d, system->groupData[0]->data) { + if (d->t == -1) + continue; //Particle data unused + + QCOMPARE(d->animIdx, 1.f);//Spawns at 0, affector moves it. + QVERIFY(myFuzzyLEQ(d->t, ((qreal)system->timeInt/1000.0))); + } + delete view; +} + +QTEST_MAIN(tst_qquickspritegoal); + +#include "tst_qquickspritegoal.moc" diff --git a/tests/auto/particles/qquicktargetdirection/tst_qquicktargetdirection.cpp b/tests/auto/particles/qquicktargetdirection/tst_qquicktargetdirection.cpp index 7d83ae8830..789334e175 100644 --- a/tests/auto/particles/qquicktargetdirection/tst_qquicktargetdirection.cpp +++ b/tests/auto/particles/qquicktargetdirection/tst_qquicktargetdirection.cpp @@ -65,7 +65,7 @@ void tst_qquicktargetdirection::test_basic() QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); ensureAnimTime(600, system->m_animation); - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused @@ -81,6 +81,7 @@ void tst_qquicktargetdirection::test_basic() QCOMPARE(d->endSize, 32.f); QVERIFY(myFuzzyLEQ(d->t, ((qreal)system->timeInt/1000.0))); } + delete view; } QTEST_MAIN(tst_qquicktargetdirection); diff --git a/tests/auto/particles/qquicktrailemitter/tst_qquicktrailemitter.cpp b/tests/auto/particles/qquicktrailemitter/tst_qquicktrailemitter.cpp index 6325ca6efe..89463b6362 100644 --- a/tests/auto/particles/qquicktrailemitter/tst_qquicktrailemitter.cpp +++ b/tests/auto/particles/qquicktrailemitter/tst_qquicktrailemitter.cpp @@ -65,7 +65,7 @@ void tst_qquicktrailemitter::test_basic() QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); ensureAnimTime(600, system->m_animation); - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused @@ -98,6 +98,7 @@ void tst_qquicktrailemitter::test_basic() QCOMPARE(d->endSize, 32.f); QVERIFY(myFuzzyLEQ(d->t, ((qreal)system->timeInt/1000.0))); } + delete view; } QTEST_MAIN(tst_qquicktrailemitter); diff --git a/tests/auto/particles/qquickturbulence/tst_qquickturbulence.cpp b/tests/auto/particles/qquickturbulence/tst_qquickturbulence.cpp index 29faec2381..9f4d50c45e 100644 --- a/tests/auto/particles/qquickturbulence/tst_qquickturbulence.cpp +++ b/tests/auto/particles/qquickturbulence/tst_qquickturbulence.cpp @@ -67,7 +67,7 @@ void tst_qquickturbulence::test_basic() //Note that the noise image built-in provides the 'randomness', so this test should be stable so long as it and the size //of the Turbulence item remain the same - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused @@ -79,6 +79,7 @@ void tst_qquickturbulence::test_basic() QCOMPARE(d->endSize, 32.f); QVERIFY(myFuzzyLEQ(d->t, ((qreal)system->timeInt/1000.0))); } + delete view; } QTEST_MAIN(tst_qquickturbulence); diff --git a/tests/auto/particles/qquickwander/tst_qquickwander.cpp b/tests/auto/particles/qquickwander/tst_qquickwander.cpp index 41f09d4993..ac88b582c4 100644 --- a/tests/auto/particles/qquickwander/tst_qquickwander.cpp +++ b/tests/auto/particles/qquickwander/tst_qquickwander.cpp @@ -65,7 +65,7 @@ void tst_qquickwander::test_basic() QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); ensureAnimTime(600, system->m_animation); - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); //Since Wander is random perturbations, the compromise between stability and actual testing is to hope that one of //the 500 was randomly changed from 0.0 in velocity bool vxChanged = false; @@ -85,6 +85,7 @@ void tst_qquickwander::test_basic() if (d->vy != 0.0f) vyChanged = true; } + delete view; QVERIFY(vxChanged); QVERIFY(vyChanged); } diff --git a/tests/auto/qtquick1/examples/examples.pro b/tests/auto/qtquick1/examples/examples.pro index ca4ad04e47..3086ea1413 100644 --- a/tests/auto/qtquick1/examples/examples.pro +++ b/tests/auto/qtquick1/examples/examples.pro @@ -11,4 +11,4 @@ CONFIG += parallel_test QT += core-private gui-private widgets-private declarative-private qtquick1-private testlib -qpa:CONFIG+=insignificant_test # QTBUG-20990, aborts +CONFIG+=insignificant_test # QTBUG-20990, aborts diff --git a/tests/auto/qtquick1/qdeclarativeflipable/qdeclarativeflipable.pro b/tests/auto/qtquick1/qdeclarativeflipable/qdeclarativeflipable.pro index 3b0fd671e1..eefb4d5902 100644 --- a/tests/auto/qtquick1/qdeclarativeflipable/qdeclarativeflipable.pro +++ b/tests/auto/qtquick1/qdeclarativeflipable/qdeclarativeflipable.pro @@ -9,4 +9,4 @@ DEFINES += SRCDIR=\\\"$$PWD\\\" CONFIG += parallel_test QT += core-private gui-private widgets-private v8-private declarative-private qtquick1-private testlib -qpa:contains(QT_CONFIG,xcb):CONFIG+=insignificant_test # QTBUG-21012 fails on exit (X11-specific) +contains(QT_CONFIG,xcb):CONFIG+=insignificant_test # QTBUG-21012 fails on exit (X11-specific) diff --git a/tests/auto/qtquick1/qdeclarativefocusscope/qdeclarativefocusscope.pro b/tests/auto/qtquick1/qdeclarativefocusscope/qdeclarativefocusscope.pro index a42997dc08..67bd8ae6d4 100644 --- a/tests/auto/qtquick1/qdeclarativefocusscope/qdeclarativefocusscope.pro +++ b/tests/auto/qtquick1/qdeclarativefocusscope/qdeclarativefocusscope.pro @@ -6,4 +6,4 @@ macx:CONFIG -= app_bundle DEFINES += SRCDIR=\\\"$$PWD\\\" QT += core-private gui-private widgets-private declarative-private qtquick1-private testlib -qpa:CONFIG+=insignificant_test # QTBUG-21013 unstable +CONFIG+=insignificant_test # QTBUG-21013 unstable diff --git a/tests/auto/qtquick1/qdeclarativeitem/qdeclarativeitem.pro b/tests/auto/qtquick1/qdeclarativeitem/qdeclarativeitem.pro index 31a71a5ab8..8663c69ea4 100644 --- a/tests/auto/qtquick1/qdeclarativeitem/qdeclarativeitem.pro +++ b/tests/auto/qtquick1/qdeclarativeitem/qdeclarativeitem.pro @@ -9,4 +9,4 @@ DEFINES += SRCDIR=\\\"$$PWD\\\" CONFIG += parallel_test QT += core-private gui-private widgets-private v8-private declarative-private qtquick1-private testlib -qpa:contains(QT_CONFIG,xcb):CONFIG+=insignificant_test # QTBUG-21012 fails on exit (X11-specific) +contains(QT_CONFIG,xcb):CONFIG+=insignificant_test # QTBUG-21012 fails on exit (X11-specific) diff --git a/tests/auto/qtquick1/qdeclarativestates/data/signalOverrideCrash3.qml b/tests/auto/qtquick1/qdeclarativestates/data/signalOverrideCrash3.qml new file mode 100644 index 0000000000..ed1f22f39a --- /dev/null +++ b/tests/auto/qtquick1/qdeclarativestates/data/signalOverrideCrash3.qml @@ -0,0 +1,27 @@ +import QtQuick 1.0 + +Rectangle { + id: myRect + width: 400 + height: 400 + + onHeightChanged: console.log("base state") + + states: [ + State { + name: "state1" + PropertyChanges { + target: myRect + onHeightChanged: console.log("state1") + color: "green" + } + }, + State { + name: "state2"; + PropertyChanges { + target: myRect + onHeightChanged: console.log("state2") + color: "red" + } + }] +} diff --git a/tests/auto/qtquick1/qdeclarativestates/tst_qdeclarativestates.cpp b/tests/auto/qtquick1/qdeclarativestates/tst_qdeclarativestates.cpp index 809d9ca65c..ba4177e7ff 100644 --- a/tests/auto/qtquick1/qdeclarativestates/tst_qdeclarativestates.cpp +++ b/tests/auto/qtquick1/qdeclarativestates/tst_qdeclarativestates.cpp @@ -108,6 +108,7 @@ private slots: void signalOverride(); void signalOverrideCrash(); void signalOverrideCrash2(); + void signalOverrideCrash3(); void parentChange(); void parentChangeErrors(); void anchorChanges(); @@ -515,6 +516,22 @@ void tst_qdeclarativestates::signalOverrideCrash2() delete rect; } +void tst_qdeclarativestates::signalOverrideCrash3() +{ + QDeclarativeEngine engine; + + QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/signalOverrideCrash3.qml"); + QDeclarative1Rectangle *rect = qobject_cast<QDeclarative1Rectangle*>(rectComponent.create()); + QVERIFY(rect != 0); + + QDeclarativeItemPrivate::get(rect)->setState("state1"); + QDeclarativeItemPrivate::get(rect)->setState(""); + QDeclarativeItemPrivate::get(rect)->setState("state2"); + QDeclarativeItemPrivate::get(rect)->setState(""); + + delete rect; +} + void tst_qdeclarativestates::parentChange() { QDeclarativeEngine engine; diff --git a/tests/auto/qtquick1/qdeclarativetextedit/tst_qdeclarativetextedit.cpp b/tests/auto/qtquick1/qdeclarativetextedit/tst_qdeclarativetextedit.cpp index 58027bf760..f6af1297bb 100644 --- a/tests/auto/qtquick1/qdeclarativetextedit/tst_qdeclarativetextedit.cpp +++ b/tests/auto/qtquick1/qdeclarativetextedit/tst_qdeclarativetextedit.cpp @@ -1630,10 +1630,8 @@ void tst_qdeclarativetextedit::positionAt() int pos = texteditObject->positionAt(texteditObject->width()/2, y0); int diff = abs(int(fm.width(texteditObject->text().left(pos))-texteditObject->width()/2)); -#ifdef Q_WS_QPA QEXPECT_FAIL("", "QTBUG-21016 fails", Continue); -#endif - // some tollerance for different fonts. + // some tolerance for different fonts. #ifdef Q_OS_LINUX QVERIFY(diff < 2); #else diff --git a/tests/system/sys_elements.qtt b/tests/system/sys_elements.qtt index 296dd83cb8..2ffb83a91a 100644 --- a/tests/system/sys_elements.qtt +++ b/tests/system/sys_elements.qtt @@ -44,79 +44,75 @@ testcase = { pre_existing_elements_data: { - // ElementName: [preconditions,[groups]] - Rectangle: ["",["QtQuick1.0","BAT"]], - Image: ["",["QtQuick1.0","BAT"]], - AnimatedImage: ["",["QtQuick1.0","BAT"]], - BorderImage: ["",["QtQuick1.0","BAT"]], - SystemPalette: ["",["QtQuick1.0","BAT"]], - Text: ["",["QtQuick1.0","BAT"]], - TextInput: ["",["QtQuick1.0","BAT"]], - TextEdit: ["",["QtQuick1.0","BAT"]], - FontLoader: ["",["QtQuick1.0","BAT"]], - Flipable: ["",["QtQuick1.0","BAT"]], - Flickable: ["",["QtQuick1.0","BAT"]], - IntValidator: ["",["QtQuick1.0","BAT"]], - DoubleValidator: ["",["QtQuick1.0","BAT"]], - RegExpValidator: ["",["QtQuick1.0","BAT"]], - Column: ["",["QtQuick1.0","BAT"]], - Row: ["",["QtQuick1.0","BAT"]], - Flow: ["",["QtQuick1.0","BAT"]], - Grid: ["",["QtQuick1.0","BAT"]], - Repeater: ["",["QtQuick1.0","BAT"]], - ListView: ["",["QtQuick1.0","BAT"]], - Keys: ["",["QtQuick1.0","BAT"]], - MouseArea: ["",["QtQuick1.0","BAT"]], - SequentialAnimation: ["",["QtQuick1.0","BAT"]], - ParallelAnimation: ["",["QtQuick1.0","BAT"]], - XmlListModel: ["",["QtQuick1.0","BAT"]], - Scale: ["",["QtQuick1.0","BAT"]] + Rectangle: ["Rectangle"], + Image: ["Image"], + AnimatedImage: ["AnimatedImage"], + BorderImage: ["BorderImage"], + SystemPalette: ["SystemPalette"], + Text: ["Text"], + TextInput: ["TextInput"], + TextEdit: ["TextEdit"], + FontLoader: ["FontLoader"], + Flipable: ["Flipable"], + Flickable: ["Flickable"], + IntValidator: ["IntValidator"], + DoubleValidator: ["DoubleValidator"], + RegExpValidator: ["RegExpValidator"], + Column: ["Column"], + Row: ["Row"], + Flow: ["Flow"], + Grid: ["Grid"], + Repeater: ["Repeater"], + ListView: ["ListView"], + Keys: ["Keys"], + MouseArea: ["MouseArea"], + SequentialAnimation: ["SequentialAnimation"], + ParallelAnimation: ["ParallelAnimation"], + XmlListModel: ["XmlListModel"], + Scale: ["Scale"] }, - pre_existing_elements: function(prec,groups) { + pre_existing_elements: function(name) { // Test Meta-data - testTitle = currentDataTag()+ " Element"; + testTitle = name+ " Element"; testBinary = "qmlscene tests/testapplications/elements/elements.qml"; - testGoal = "Verify the "+currentDataTag()+" element is shown correctly"; - testPreconditions = prec; - testGroups = groups; + testGoal = "Verify the "+name+" element is shown correctly"; + testPreconditions = "None"; + testGroups = "BAT"; // Test Steps prompt(twiki('---+++ ' + testTitle + '<br><br> *Goal:* ' + testGoal + '<br> *Pre-Requisites:* ' + testPreconditions + '<br> *Tested Binary:* ' + testBinary + '<br> - | Select the '+currentDataTag()+' list item | Verify that the '+currentDataTag()+' application is displayed | + | Select the '+name+' list item | Verify that the '+name+' application is displayed | | Follow the instructions in the in-app test | Verify all steps are completed successfully |')); }, new_elements_data: { - // ElementName: [preconditions,[groups]] - ParticleSystem: ["",["QtQuick2.0","BAT"]], - ImageParticle: ["",["QtQuick2.0","BAT"]], - Emitter: ["",["QtQuick2.0","BAT"]], - Affector: ["",["QtQuick2.0","BAT"]], - Shape: ["",["QtQuick2.0","BAT"]], - TrailEmitter: ["",["QtQuick2.0","BAT"]], - Direction: ["",["QtQuick2.0","BAT"]] + ParticleSystem: ["ParticleSystem"], + ImageParticle: ["ImageParticle"], + Emitter: ["Emitter"], + Affector: ["Affector"], + Shape: ["Shape",], + TrailEmitter: ["TrailEmitter"], + Direction: ["Direction"] }, - new_elements: function(prec,groups) { + new_elements: function(name) { // Test Meta-data - testTitle = currentDataTag()+ " Element"; + testTitle = name+ " Element"; testBinary = "qmlscene tests/testapplications/elements/elements.qml"; - testGoal = "Verify the "+currentDataTag()+" element is shown correctly"; - testPreconditions = prec; - testGroups = groups; + testGoal = "Verify the "+name+" element is shown correctly"; + testPreconditions = "None"; + testGroups = "BAT"; // Test Steps prompt(twiki('---+++ ' + testTitle + '<br><br> *Goal:* ' + testGoal + '<br> *Pre-Requisites:* ' + testPreconditions + '<br> *Tested Binary:* ' + testBinary + '<br> - | Select the '+currentDataTag()+' list item | Verify that the '+currentDataTag()+' application is displayed | + | Select the '+name+' list item | Verify that the '+name+' application is displayed | | Follow the instructions in the in-app test | Verify all steps are completed successfully |')); } } - - diff --git a/tests/system/sys_text.qtt b/tests/system/sys_text.qtt new file mode 100644 index 0000000000..0b31688089 --- /dev/null +++ b/tests/system/sys_text.qtt @@ -0,0 +1,145 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//TESTED_COMPONENT=qtdeclarative + +testcase = { + + text_formatting_data: { + // Text type, autotext, plain text, rich text, styled text + BasicText: ["Basic","plain, unformatted red text","plain, unformatted red text","plain, unformatted red text","plain, unformatted red text"], + Rich: ["Rich","bold style","surrounding b,/b tags and no formatting","bold style","bold style"] + }, + + text_formatting: function(texttype,autoformat,plainformat,richformat,styledformat) { + // Test Meta-data + testTitle = "Text Formats"; + testBinary = "qmlscene tests/testapplications/text/text.qml"; + testGoal = "Verify that text shows correctly when displayed in different formats"; + testPreconditions = "None"; + testGroups = "BAT"; + + // Test Steps + prompt(twiki('---+++ ' + testTitle + '<br><br> + *Goal:* ' + testGoal + '<br> + *Pre-Requisites:* ' + testPreconditions + '<br> + *Tested Binary:* ' + testBinary + '<br> + | *Step* | *Verification* | + | Run ' + testBinary + ' | Verify that the Text application is displayed | + | Select Text: '+texttype+', Format: AutoText controls | A single line of text is shown | + | | Qt Quick should be rendered with '+autoformat+' | + | Select the Wrap: Word option | A block of text is shown | + | Select the Format: PlainText option | Qt Quick should be shown with '+plainformat+' | + | Select the Format: RichText option | Qt Quick should be shown with '+richformat+' | + | Select the Format: StyledText option | Qt Quick should be shown with '+styledformat+' |')); + }, + + text_wrapping_data: { + // Text type, No wrap, word wrap, wrap anywhere, auto wrap + Basic: ["Basic", + "two lines, wrapped at the newline (Qt Quick consists...)", + "many lines, with no broken words", + "many lines, words broken at the text boundary", + "many lines, with no broken words"], + Long: ["Long", + "one lone line", + "two lines, wrapped at the - (topboxesand...),", + "many lines, wrapped at the boundary", + "many lines, wrapped at the boundary, and specifically the - in set-top"], + Rich: ["Rich", + "two lines, wrapped at the break (Qt Quick consists...)", + "many lines, with no broken words", + "many lines, words broken at the text boundary", + "many lines, with no broken words"] + }, + + text_wrapping: function(texttype,noWrap,wordWrap,anywhereWrap,autoWrap) { + // Test Meta-data + testTitle = "Wrap Modes"; + testBinary = "qmlscene tests/testapplications/text/text.qml"; + testGoal = "Verify that text wraps correctly with different wrap methods and text formats"; + testPreconditions = "None"; + testGroups = "BAT"; + + // Test Steps + prompt(twiki('---+++ ' + testTitle + '<br><br> + *Goal:* ' + testGoal + '<br> + *Pre-Requisites:* ' + testPreconditions + '<br> + *Tested Binary:* ' + testBinary + '<br> + | *Step* | *Verification* | + | Run ' + testBinary + ' | Verify that the Text application is displayed | + | Select Text: '+texttype+', Format: AutoText controls | Verify '+noWrap+' is displayed | + | Select the Wrap: Word option | Verify '+wordWrap+' is displayed | + | Select the Wrap: Anywhere option | Verify '+anywhereWrap+' is displayed | + | Select the Wrap: Auto option | Verify '+autoWrap+' is displayed |')); + }, + + text_styling_data: { + // Text type + Basic: ["Basic"], + Long: ["Long"], + Rich: ["Rich"] + }, + + text_styling: function(texttype) { + // Test Meta-data + testTitle = "Style Effects"; + testBinary = "qmlscene tests/testapplications/text/text.qml"; + testGoal = "Verify that styling (underline, strikeout etc) works as intended"; + testPreconditions = "None"; + testGroups = "BAT"; + + // Test Steps + prompt(twiki('---+++ ' + testTitle + '<br><br> + *Goal:* ' + testGoal + '<br> + *Pre-Requisites:* ' + testPreconditions + '<br> + *Tested Binary:* ' + testBinary + '<br> + | *Step* | *Verification* | + | Run ' + testBinary + ' | Verify that the Text application is displayed | + | Select Text: '+texttype+', Wrap: WordWrap | Verify the text is displayed, wrapped if necessary | + | Select the U_Line: On option | Verify an underline is drawn under each character | + | Select the Strike: On option | Verify a strikethrough is drawn through each character | + | Select the Style: Outline option | Verify each character is red and has a green outline around it | + | Select the SColor: Blue option | Verify each character is red and has a blue outline around it | + | Select the Style: Raised option | Verify each character is red and has a blue shadow behind and below it | + | Select the Style: Sunken option | Verify each character is red and has a blue shadow behind and above it |')); + } +}
\ No newline at end of file diff --git a/tests/system/sys_textedit.qtt b/tests/system/sys_textedit.qtt new file mode 100644 index 0000000000..632da21a8f --- /dev/null +++ b/tests/system/sys_textedit.qtt @@ -0,0 +1,218 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//TESTED_COMPONENT=qtdeclarative + +testcase = { + + text_formatting_data: { + // Text type, autotext, plain text, rich text, styled text + BasicText: ["Basic","plain, unformatted red text","plain, unformatted red text","plain, unformatted red text","plain, unformatted red text"], + Rich: ["Rich","bold style","surrounding b,/b tags and no formatting","bold style","bold style"] + }, + + text_formatting: function(texttype,autoformat,plainformat,richformat,styledformat) { + // Test Meta-data + testTitle = "Text Formats"; + testBinary = "qmlscene tests/testapplications/text/textedit.qml"; + testGoal = "Verify that text shows correctly when displayed in different formats"; + testPreconditions = "None"; + testGroups = "BAT"; + + // Test Steps + prompt(twiki('---+++ ' + testTitle + '<br><br> + *Goal:* ' + testGoal + '<br> + *Pre-Requisites:* ' + testPreconditions + '<br> + *Tested Binary:* ' + testBinary + '<br> + | *Step* | *Verification* | + | Run ' + testBinary + ' | Verify that the Text application is displayed | + | Select Text: '+texttype+', Format: AutoText controls | A single line of text is shown | + | | Qt Quick should be rendered with '+autoformat+' | + | Select the Wrap: Word option | A block of text is shown | + | Select the Format: PlainText option | Qt Quick should be shown with '+plainformat+' | + | Select the Format: RichText option | Qt Quick should be shown with '+richformat+' | + | Select the Format: StyledText option | Qt Quick should be shown with '+styledformat+' |')); + }, + + text_wrapping_data: { + // Text type, No wrap, word wrap, wrap anywhere, auto wrap + Basic: ["Basic", + "two lines, wrapped at the newline (Qt Quick consists...)", + "many lines, with no broken words", + "many lines, words broken at the text boundary", + "many lines, with no broken words"], + Long: ["Long", + "one lone line", + "two lines, wrapped at the - (topboxesand...),", + "many lines, wrapped at the boundary", + "many lines, wrapped at the boundary, and specifically the - in set-top"], + Rich: ["Rich", + "two lines, wrapped at the break (Qt Quick consists...)", + "many lines, with no broken words", + "many lines, words broken at the text boundary", + "many lines, with no broken words"] + }, + + text_wrapping: function(texttype,noWrap,wordWrap,anywhereWrap,autoWrap) { + // Test Meta-data + testTitle = "Wrap Modes"; + testBinary = "qmlscene tests/testapplications/text/textedit.qml"; + testGoal = "Verify that text wraps correctly with different wrap methods and text formats"; + testPreconditions = "None"; + testGroups = "BAT"; + + // Test Steps + prompt(twiki('---+++ ' + testTitle + '<br><br> + *Goal:* ' + testGoal + '<br> + *Pre-Requisites:* ' + testPreconditions + '<br> + *Tested Binary:* ' + testBinary + '<br> + | *Step* | *Verification* | + | Run ' + testBinary + ' | Verify that the Text application is displayed | + | Select Text: '+texttype+', Format: AutoText controls | Verify '+noWrap+' is displayed | + | Select the Wrap: Word option | Verify '+wordWrap+' is displayed | + | Select the Wrap: Anywhere option | Verify '+anywhereWrap+' is displayed | + | Select the Wrap: Auto option | Verify '+autoWrap+' is displayed |')); + }, + + text_styling_data: { + // Text type + Basic: ["Basic"], + Long: ["Long"], + Rich: ["Rich"] + }, + + text_styling: function(texttype) { + // Test Meta-data + testTitle = "Style Effects"; + testBinary = "qmlscene tests/testapplications/text/textedit.qml"; + testGoal = "Verify that styling (underline, strikeout etc) works as intended"; + testPreconditions = "None"; + testGroups = "BAT"; + + // Test Steps + prompt(twiki('---+++ ' + testTitle + '<br><br> + *Goal:* ' + testGoal + '<br> + *Pre-Requisites:* ' + testPreconditions + '<br> + *Tested Binary:* ' + testBinary + '<br> + | *Step* | *Verification* | + | Run ' + testBinary + ' | Verify that the Text application is displayed | + | Select Text: '+texttype+', Wrap: WordWrap | Verify the text is displayed, wrapped if necessary | + | Select the U_Line: On option | Verify an underline is drawn under each character | + | Select the Strike: On option | Verify a strikethrough is drawn through each character |')); + }, + + select_text: function() + { + // Test meta data + testTitle = "Text Selection"; + testBinary = "qmlscene tests/testapplications/text/text.qml"; + testGoal = "Verify text can be selected via various methods"; + testPreconditions = "None"; + testGroups = "BAT"; + + // Test Steps + prompt(twiki('---+++ ' + testTitle + '<br><br> + *Goal:* ' + testGoal + '<br> + *Pre-Requisites:* ' + testPreconditions + '<br> + *Tested Binary:* ' + testBinary + '<br> + + | *Step* | *Verification* | + | Execute '+testBinary+' | "The TextInput item displays an editable line of text." is displayed | + | Select the Text: Short option | "Hello World" is shown | + | Press the Select Word button | World is selected | + | Press the Select All button | Hello World is selected | + | Press the Select None button | No text is selected | + | Select the Mouse: On option | | + | Drag over some text | Only that text is selected. On a touchscreen only device the virtual keyboard may show | + | Select the Mouse: Off option | | + | Press the Select None button | No text is selected | + | Drag over some text | No text is selected. On a touchscreen only device the virtual keyboard may show | ')); + }, + + cut_copy_and_paste: function() + { + // Test meta data + testTitle = "Cut, copy and paste"; + testBinary = "qmlscene tests/testapplications/text/textedit.qml"; + testGoal = "Verify selected text can be copied/cut to the clipboard, and returned"; + testPreconditions = "None"; + testGroups = "BAT"; + + // Test Steps + prompt(twiki('---+++ ' + testTitle + '<br><br> + *Goal:* ' + testGoal + '<br> + *Pre-Requisites:* ' + testPreconditions + '<br> + *Tested Binary:* ' + testBinary + '<br> + + | *Step* | *Verification* | + | Execute '+testBinary+' | "The TextInput item displays an editable line of text." is displayed | + | Select the Text: Short option | "Hello World" is shown | + | Press the Select All button | Hello World is selected | + | Press the Copy Button | | + | Tap at the end of the text | Text is no longer selected, cursor is at the text end | + | Press the Paste Button | "Hello WorldHello World" is shown | + | Press the Select Word button | World is highlighted | + | Press the Cut button | World is removed from the text | + | Press the Paste button | "Hello WorldHello World" is shown | ')); + }, + + activate_links: function() + { + // Test meta data + testTitle = "Link Activation"; + testBinary = "qmlscene tests/testapplications/text/textedit.qml"; + testGoal = "Verify http links in text can be activated"; + testPreconditions = "None"; + testGroups = "BAT"; + + // Test Steps + prompt(twiki('---+++ ' + testTitle + '<br><br> + *Goal:* ' + testGoal + '<br> + *Pre-Requisites:* ' + testPreconditions + '<br> + *Tested Binary:* ' + testBinary + '<br> + + | *Step* | *Verification* | + | Execute '+testBinary+' | "The TextInput item displays an editable line of text." is displayed | + | Select the Text: Links option | "This is a link..." is shown | + | Tap on the "Qt Docs" text | The border around the TextEdit will become red | ')); + } + +} diff --git a/tests/system/sys_textinput.qtt b/tests/system/sys_textinput.qtt new file mode 100644 index 0000000000..5533864c87 --- /dev/null +++ b/tests/system/sys_textinput.qtt @@ -0,0 +1,197 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//TESTED_COMPONENT=qtdeclarative + +testcase = { + + select_text: function() + { + // Test meta data + testTitle = "Text Selection"; + testBinary = "qmlscene tests/testapplications/text/text.qml"; + testGoal = "Verify text can be selected via various methods"; + testPreconditions = "None"; + testGroups = "BAT"; + + // Test Steps + prompt(twiki('---+++ ' + testTitle + '<br><br> + *Goal:* ' + testGoal + '<br> + *Pre-Requisites:* ' + testPreconditions + '<br> + *Tested Binary:* ' + testBinary + '<br> + + | *Step* | *Verification* | + | Execute '+testBinary+' | "The TextInput item displays an editable line of text." is displayed | + | Select the Text: Short option | "Hello World" is shown | + | Press the Select Word button | World is selected | + | Press the Select All button | Hello World is selected | + | Press the Select None button | No text is selected | + | Select the Mouse: On option | | + | Drag over some text | Only that text is selected. On a touchscreen only device the virtual keyboard may show | + | Select the Mouse: Off option | | + | Press the Select None button | No text is selected | + | Drag over some text | No text is selected. On a touchscreen only device the virtual keyboard may show |')); + }, + + cut_copy_and_paste: function() + { + // Test meta data + testTitle = "Cut, copy and paste"; + testBinary = "qmlscene tests/testapplications/text/text.qml"; + testGoal = "Verify selected text can be copied/cut to the clipboard, and returned"; + testPreconditions = "None"; + testGroups = "BAT"; + + // Test Steps + prompt(twiki('---+++ ' + testTitle + '<br><br> + *Goal:* ' + testGoal + '<br> + *Pre-Requisites:* ' + testPreconditions + '<br> + *Tested Binary:* ' + testBinary + '<br> + + | *Step* | *Verification* | + | Execute '+testBinary+' | "The TextInput item displays an editable line of text." is displayed | + | Select the Text: Short option | "Hello World" is shown | + | Press the Select All button | Hello World is selected | + | Press the Copy Button | | + | Press the Position End Button | Text is no longer selected, cursor is at the text end | + | Press the Paste Button | "Hello WorldHello World" is shown | + | Press the Select Word button | World is highlighted | + | Press the Cut button | World is removed from the text | + | Press the Paste button | "Hello WorldHello World" is shown |')); + }, + + password_echo_mode: function() + { + // Test meta data + testTitle = "Password Echo"; + testBinary = "qmlscene tests/testapplications/text/text.qml"; + testGoal = "Verify password echo modes display text correctly"; + testPreconditions = "None"; + testGroups = "BAT"; + + // Test Steps + prompt(twiki('---+++ ' + testTitle + '<br><br> + *Goal:* ' + testGoal + '<br> + *Pre-Requisites:* ' + testPreconditions + '<br> + *Tested Binary:* ' + testBinary + '<br> + + | *Step* | *Verification* | + | Execute '+testBinary+' | "The TextInput item displays an editable line of text." is displayed | + | Select the Text: Short option | "Hello World" is shown | + | Select the Echo: Password option | Hello World is now a string of asterisks | + | Enter an exclamation mark | An asterisk is added to the string | + | Select the Echo: None option | No text is visible | + | Enter an exclamation mark | No text is shown | + | Select the Echo: OnEdit option | A string of asterisks is shown | + | Enter an exclamation mark | An exclamation mark appears at the end of the asterisks, but shortly becomes an asterisk | + | Select the Echo: Normal option | Hello World!!! is now displayed |')); + }, + + styling: function() + { + // Test meta data + testTitle = "Text Styling"; + testBinary = "qmlscene tests/testapplications/text/text.qml"; + testGoal = "Verify text can be displayed using generic styling"; + testPreconditions = "None"; + testGroups = "BAT"; + + // Test Steps + prompt(twiki('---+++ ' + testTitle + '<br><br> + *Goal:* ' + testGoal + '<br> + *Pre-Requisites:* ' + testPreconditions + '<br> + *Tested Binary:* ' + testBinary + '<br> + + | *Step* | *Verification* | + | Execute '+testBinary+' | "The TextInput item displays an editable line of text." is displayed | + | Select the Text: Short option | "Hello World" is shown | + | Select the Bold: On option | Hello World is now in bold | + | Press the Italics: On option | Hello World is now in italics | + | Press the Strikeout: On option | Hello World now has a line passing through it | + | Press the Underline: On option | Hello World is now underlined | ')); + }, + + cursor_behavior: function() + { + // Test meta data + testTitle = "Cursor Behavior"; + testBinary = "qmlscene tests/testapplications/text/text.qml"; + testGoal = "Verify the text cursor displays correctly"; + testPreconditions = "None"; + testGroups = "BAT"; + + // Test Steps + prompt(twiki('---+++ ' + testTitle + '<br><br> + *Goal:* ' + testGoal + '<br> + *Pre-Requisites:* ' + testPreconditions + '<br> + *Tested Binary:* ' + testBinary + '<br> + + | *Step* | *Verification* | + | Execute '+testBinary+' | "The TextInput item displays an editable line of text." is displayed | + | Enter enough text into the field such that it passes beyond the far right | The text scrolls to the left when the edge is reached | + | Select the Autoscroll: Off button | The far left edge shows the first character of the text | + | Select the Cursor: Off option | The cursor disappears | + | Select the Cursor: On option | The cursor appears | ')); + }, + + capitalization: function() + { + // Test meta data + testTitle = "Capitalization"; + testBinary = "qmlscene tests/testapplications/text/text.qml"; + testGoal = "Verify character capitalization behaves correctly"; + testPreconditions = "None"; + testGroups = "BAT"; + + // Test Steps + prompt(twiki('---+++ ' + testTitle + '<br><br> + *Goal:* ' + testGoal + '<br> + *Pre-Requisites:* ' + testPreconditions + '<br> + *Tested Binary:* ' + testBinary + '<br> + + | *Step* | *Verification* | + | Execute '+testBinary+' | "The TextInput item displays an editable line of text." is displayed | + | Select the Cap10n: Upper option | The text is converted to all upper case | + | Select the Cap10n: Lower option | The text is converted to all lower case | + | Select the Cap10n: SmallCaps option | The text is converted to all small sized upper case characters | + | Select the Cap10n: Capitals option | The text is shown with each first character of every word capitalized | ')); + } +}
\ No newline at end of file diff --git a/tests/testapplications/elements/content/GridViewElement.qml b/tests/testapplications/elements/content/GridViewElement.qml index 2b9884d4a9..79b48d55c3 100644 --- a/tests/testapplications/elements/content/GridViewElement.qml +++ b/tests/testapplications/elements/content/GridViewElement.qml @@ -123,5 +123,6 @@ Rectangle { ListElement { label: "Shape"; help: "The Shape element allows you to specify an area for affectors and emitter." } ListElement { label: "TrailEmitter"; help: "The TrailEmitter element allows you to emit logical particles from other logical particles." } ListElement { label: "Direction"; help: "The Direction elements allow you to specify a vector space." } + ListElement { label: "SpriteImage"; help: "The SpriteImage element plays stochastic sprite animations." } } } diff --git a/tests/testapplications/elements/content/SpriteImageElement.qml b/tests/testapplications/elements/content/SpriteImageElement.qml new file mode 100644 index 0000000000..2015eabe8a --- /dev/null +++ b/tests/testapplications/elements/content/SpriteImageElement.qml @@ -0,0 +1,145 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Item { + id: spriteimageelementtest + anchors.fill: parent + property string testtext: "" + SpriteImage { + id: spriteimage + sprites: [Sprite { + name: "happy" + source: "pics/squarefacesprite2.png" + frames: 6 + duration: 120 + to: {"silly": 1, "sad":0} + }, Sprite { + name: "silly" + source: "pics/squarefacesprite.png" + frames: 6 + duration: 120 + to: {"happy": 1, "sad": 0} + }, Sprite { + name: "sad" + source: "pics/squarefacesprite3.png" + frames: 6 + duration: 120 + to: {"evil": 0.5, "sad": 1, "cyclops" : 0} + }, Sprite { + name: "cyclops" + source: "pics/squarefacesprite4.png" + frames: 6 + duration: 120 + to: {"love": 0.1, "boggled": 0.1, "cyclops" : 0.1} + }, Sprite { + name: "evil" + source: "pics/squarefacesprite5.png" + frames: 6 + duration: 120 + to: {"sad": 1.0, "cyclops" : 0} + }, Sprite { + name: "love" + source: "pics/squarefacesprite6.png" + frames: 6 + duration: 120 + to: {"love": 0.1, "boggled": 0.1, "cyclops" : 0.1} + }, Sprite { + name: "boggled" + source: "pics/squarefacesprite7.png" + frames: 6 + duration: 120 + to: {"love": 0.1, "boggled": 0.1, "cyclops" : 0.1, "dying":0} + }, Sprite { + name: "dying" + source: "pics/squarefacespriteX.png" + frames: 4 + duration: 120 + to: {"dead":1.0} + }, Sprite { + name: "dead" + source: "pics/squarefacespriteXX.png" + frames: 1 + duration: 10000 + }] + + width: 300 + height: 300 + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + } + + + SystemTestHelp { id: helpbubble; visible: statenum != 0 + anchors { top: parent.top; horizontalCenter: parent.horizontalCenter; topMargin: 50 } + } + BugPanel { id: bugpanel } + + states: [ + State { name: "start"; when: statenum == 1 + StateChangeScript { script: spriteimage.jumpTo("happy"); } + PropertyChanges { target: spriteimageelementtest + testtext: "This is a SpriteImage element. It should be animating currently."+ + "It should alternate between winking and sticking out its tongue." } + }, + State { name: "stochastic2"; when: statenum == 2 + StateChangeScript { script: spriteimage.jumpTo("sad"); } + PropertyChanges { target: spriteimageelementtest + testtext: "The sprite should now be animating between frowning and being evil."+ + "This should not be alternating, but mostly frowning with the occasional evil eyes."+ + "After an evil eyes animation, it should return to frowning at least once." } + }, + State { name: "stochastic3"; when: statenum == 3 + StateChangeScript { script: spriteimage.jumpTo("cyclops"); } + PropertyChanges { target: spriteimageelementtest + testtext: "The sprite should now be animating fairly randomly between three animations where it does silly things with its eyes.\n"+ + "Next the sprite will animate into a static 'dead' state."+ + "When it does, it should first animate to and play through the 'big eyes' animation (if it is not currently playing that animation) before it enters the dying animation."} + }, + State { name: "dead"; when: statenum == 4 + PropertyChanges { target: spriteimage; goalState: "dead" } + PropertyChanges { target: spriteimageelementtest + testtext: "After a brief dying animation, the image should now be static.\n"+ + "Advance to restart the test." } + } + ] +} diff --git a/tests/testapplications/elements/content/pics/squarefacesprite.png b/tests/testapplications/elements/content/pics/squarefacesprite.png Binary files differnew file mode 100644 index 0000000000..f9a5d5fcce --- /dev/null +++ b/tests/testapplications/elements/content/pics/squarefacesprite.png diff --git a/tests/testapplications/elements/content/pics/squarefacesprite2.png b/tests/testapplications/elements/content/pics/squarefacesprite2.png Binary files differnew file mode 100644 index 0000000000..7106a520a4 --- /dev/null +++ b/tests/testapplications/elements/content/pics/squarefacesprite2.png diff --git a/tests/testapplications/elements/content/pics/squarefacesprite3.png b/tests/testapplications/elements/content/pics/squarefacesprite3.png Binary files differnew file mode 100644 index 0000000000..f4e6f26856 --- /dev/null +++ b/tests/testapplications/elements/content/pics/squarefacesprite3.png diff --git a/tests/testapplications/elements/content/pics/squarefacesprite4.png b/tests/testapplications/elements/content/pics/squarefacesprite4.png Binary files differnew file mode 100644 index 0000000000..1e094eed4a --- /dev/null +++ b/tests/testapplications/elements/content/pics/squarefacesprite4.png diff --git a/tests/testapplications/elements/content/pics/squarefacesprite5.png b/tests/testapplications/elements/content/pics/squarefacesprite5.png Binary files differnew file mode 100644 index 0000000000..1cfc5c7f8c --- /dev/null +++ b/tests/testapplications/elements/content/pics/squarefacesprite5.png diff --git a/tests/testapplications/elements/content/pics/squarefacesprite6.png b/tests/testapplications/elements/content/pics/squarefacesprite6.png Binary files differnew file mode 100644 index 0000000000..b040139a9e --- /dev/null +++ b/tests/testapplications/elements/content/pics/squarefacesprite6.png diff --git a/tests/testapplications/elements/content/pics/squarefacesprite7.png b/tests/testapplications/elements/content/pics/squarefacesprite7.png Binary files differnew file mode 100644 index 0000000000..b1e5e4e339 --- /dev/null +++ b/tests/testapplications/elements/content/pics/squarefacesprite7.png diff --git a/tests/testapplications/elements/content/pics/squarefacespriteX.png b/tests/testapplications/elements/content/pics/squarefacespriteX.png Binary files differnew file mode 100644 index 0000000000..93a0181dd0 --- /dev/null +++ b/tests/testapplications/elements/content/pics/squarefacespriteX.png diff --git a/tests/testapplications/elements/content/pics/squarefacespriteXX.png b/tests/testapplications/elements/content/pics/squarefacespriteXX.png Binary files differnew file mode 100644 index 0000000000..3159efe246 --- /dev/null +++ b/tests/testapplications/elements/content/pics/squarefacespriteXX.png diff --git a/tests/testapplications/text/Button.qml b/tests/testapplications/text/Button.qml new file mode 100644 index 0000000000..95252bfab2 --- /dev/null +++ b/tests/testapplications/text/Button.qml @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +MouseArea { + property string buttontext: "" + width: parent.width / 4 + height: parent.height - 4 + Rectangle { + anchors.fill: parent + radius: 5 + color: "lightgray" + border.color: "black" + } + Text { + anchors.centerIn: parent + text: buttontext + color: "black" + } +}
\ No newline at end of file diff --git a/tests/testapplications/text/ControlView.qml b/tests/testapplications/text/ControlView.qml new file mode 100644 index 0000000000..a3a4a70507 --- /dev/null +++ b/tests/testapplications/text/ControlView.qml @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +ListView { + id: controlviewitem + property string controlname: "" + property variant controlvalue + signal reset + height: 40; width: 200; highlightRangeMode: ListView.StrictlyEnforceRange + orientation: ListView.Horizontal; snapMode: ListView.SnapOneItem + preferredHighlightBegin: 50; preferredHighlightEnd: 150; + delegate: Rectangle { height: 40; width: 100; border.color: "black" + Text { anchors.centerIn: parent; width: parent.width; text: model.name; elide: Text.ElideRight; horizontalAlignment: Text.AlignHCenter } } + header: headfoot + footer: headfoot + Component { + id: headfoot + Rectangle { + MouseArea { id: resetbutton; anchors.fill: parent; onClicked: { reset(); } } + color: "lightgray"; height: 40; width: 50; border.color: "gray" + Text { id: headertext; anchors.centerIn: parent; wrapMode: Text.WrapAnywhere + rotation: -40; text: controlviewitem.controlname; font.pixelSize: 12; horizontalAlignment: Text.AlignHCenter } + } + } +}
\ No newline at end of file diff --git a/tests/testapplications/text/text.qml b/tests/testapplications/text/text.qml new file mode 100644 index 0000000000..28166c962c --- /dev/null +++ b/tests/testapplications/text/text.qml @@ -0,0 +1,289 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Rectangle { + height: 360; width: 640 + + Connections { target: pointvalue; onReset: { textelement.font.pointSize = 12 } } + + Item { + id: textpanel + height: 360 + width: 440 + Text { + id: textelement + height: parent.height - 20; width: parent.width - 20 + anchors.centerIn: parent + + text: { textvalue.model.get(textvalue.currentIndex).value } + textFormat: { formatvalue.model.get(formatvalue.currentIndex).value } + color: { colorvalue.model.get(colorvalue.currentIndex).value } + elide: { elidevalue.model.get(elidevalue.currentIndex).value } + font.bold: { boldvalue.model.get(boldvalue.currentIndex).value } + font.italic: { italicsvalue.model.get(italicsvalue.currentIndex).value } + font.capitalization: { capsvalue.model.get(capsvalue.currentIndex).value } + font.family: { familyvalue.model.get(familyvalue.currentIndex).value } + font.strikeout: strikeoutvalue.currentIndex + font.underline: underlinevalue.currentIndex + font.letterSpacing: { lspacingvalue.model.get(lspacingvalue.currentIndex).value } + font.wordSpacing: { wspacingvalue.model.get(wspacingvalue.currentIndex).value } + font.weight: { weightvalue.model.get(weightvalue.currentIndex).value } + font.pointSize: { pointvalue.model.get(pointvalue.currentIndex).value } + font.pixelSize: { pixelvalue.model.get(pixelvalue.currentIndex).value } + horizontalAlignment: { halignvalue.model.get(halignvalue.currentIndex).value } + verticalAlignment: { valignvalue.model.get(valignvalue.currentIndex).value } + wrapMode: { wrapvalue.model.get(wrapvalue.currentIndex).value } + maximumLineCount: { maxlinevalue.model.get(maxlinevalue.currentIndex).value } + lineHeight: { lineheightvalue.model.get(lineheightvalue.currentIndex).value } + lineHeightMode: { lineheightmodevalue.model.get(lineheightmodevalue.currentIndex).value } + smooth: { smoothvalue.model.get(smoothvalue.currentIndex).value } + style: { stylevalue.model.get(stylevalue.currentIndex).value } + styleColor: { stylecolorvalue.model.get(stylecolorvalue.currentIndex).value } + + Rectangle{ color: "transparent"; border.color: "green"; anchors.fill: parent } + } + + Text { + id: infopanel + anchors { left: parent.left; leftMargin: 10; bottom: parent.bottom } + height: 150; color: "black"; width: 150 + function elidename() { + switch (textelement.elide) { + case Text.ElideNone: return "None"; + case Text.ElideLeft: return "Left"; + case Text.ElideMiddle: return "Middle"; + case Text.ElideRight: return "Right"; + } + } + text: + "LineCount: "+textelement.lineCount+" of "+textelement.maximumLineCount+ + "\nPaintedHeight/Width: "+textelement.paintedHeight+"/"+textelement.paintedWidth+ + "\nPointSize: "+textelement.font.pointSize+ + "\nPixelSize: "+textelement.font.pixelSize+ + "\nTruncated: "+textelement.truncated+ + "\nElide: "+ elidename() + + } + } + + Item { + id: controlpanel + width: 200; height: parent.height + anchors.right: parent.right + Rectangle { anchors.fill: parent; color: "transparent"; border.color: "black" } + ListView { id: controls; model: controlsmodel; anchors.fill: parent; clip: true; cacheBuffer: 500 } + VisualItemModel { + id: controlsmodel + ControlView { + id: textvalue + controlname: "Text" + model: textmodel + ListModel { id: textmodel } + Component.onCompleted: { + textmodel.append({ "name": "Basic", + "value": "Qt Quick is a collection of technologies that are designed to help developers create the kind of intuitive, "+ + "modern, fluid user interfaces that are increasingly used on mobile phones, media players, set-top boxes and other "+ + "portable devices.\n"+ + "Qt Quick consists of a rich set of user interface elements, a declarative language for describing user interfaces "+ + "and a language runtime. "+ + "A collection of C++ APIs is used to integrate these high level features with classic Qt applications."}); + textmodel.append({ "name": "Short", + "value": "Button Text."}); + textmodel.append({ "name": "Long", + "value": "QtQuickisacollectionoftechnologiesthataredesignedtohelpdeveloperscreatethekindofintuitive,"+ + "modern,fluiduserinterfacesthatareincreasinglyusedonmobilephones,mediaplayers,set-topboxesandother"+ + "portabledevices."}); + textmodel.append({ "name": "Rich", + "value": "<b>Qt Quick</b> is a collection of technologies that are designed to help developers create the kind of <i>intuitive, "+ + "modern, fluid</i> user interfaces that are increasingly used on mobile phones, media players, set-top boxes and other "+ + "portable devices.<br>"+ + "Qt Quick consists of a rich set of user interface elements, a declarative language for describing user interfaces "+ + "and a language runtime. "+ + "A collection of C++ APIs is used to integrate these high level features with classic Qt applications."}); + } + } + ControlView { + id: formatvalue + controlname: "Format" + model: ListModel { ListElement { name: "Auto"; value: Text.AutoText } ListElement { name: "Plain"; value: Text.PlainText } + ListElement { name: "Rich"; value: Text.RichText } ListElement { name: "Styled"; value: Text.StyledText } } } + ControlView { + id: colorvalue + controlname: "Color" + model: ListModel { ListElement { name: "Red"; value: "red" } + ListElement { name: "Green"; value: "green" } ListElement { name: "Blue"; value: "blue" } } + } + ControlView { + id: elidevalue + controlname: "Elide" + model: ListModel { ListElement { name: "None"; value: Text.ElideNone } ListElement { name: "Left"; value: Text.ElideLeft } + ListElement { name: "Middle"; value: Text.ElideMiddle } ListElement { name: "Right"; value: Text.ElideRight } } + } + ControlView { + id: boldvalue + controlname: "Bold" + model: ListModel { ListElement { name: "Off"; value: false } ListElement { name: "On"; value: true } } + } + ControlView { + id: italicsvalue + controlname: "Italic" + model: ListModel { ListElement { name: "Off"; value: false } ListElement { name: "On"; value: true } } + } + ControlView { + id: capsvalue + controlname: "Cap10n" + model: ListModel { + ListElement { name: "Mixed"; value: Font.MixedCase } ListElement { name: "Upper"; value: Font.AllUppercase } + ListElement { name: "Lower"; value: Font.AllLowercase } ListElement { name: "SmallCaps"; value: Font.SmallCaps } + ListElement { name: "Capitals"; value: Font.Capitalize } + } + } + ControlView { + id: familyvalue + controlname: "Font" + property variant fontfamilies + function setModel() { + familiesmodel.clear(); + for (var i = 0; i < fontfamilies.length; ++i) { + familiesmodel.append({ "name": fontfamilies[i], "value": fontfamilies[i] }); + } + familyvalue.currentIndex = 0; + } + model: familiesmodel + ListModel { id: familiesmodel } + Component.onCompleted: { fontfamilies = Qt.fontFamilies(); setModel(); } + } + ControlView { + id: lspacingvalue + controlname: "LSpacing" + model: ListModel { ListElement { name: "0"; value: 0 } ListElement { name: "1"; value: 1 } ListElement { name: "2.5"; value: 2.5 } } } + ControlView { + id: wspacingvalue + controlname: "WSpacing" + model: ListModel { ListElement { name: "-1"; value: -1 } ListElement { name: "8"; value: 8 } ListElement { name: "20"; value: 20 } } } + ControlView { + id: pixelvalue + controlname: "Pixel" + model: ListModel { ListElement { name: "-1"; value: -1 } ListElement { name: "8"; value: 8 } ListElement { name: "20"; value: 20 } } } + ControlView { + id: pointvalue + controlname: "Point" + model: ListModel { ListElement { name: "-1"; value: -1 } ListElement { name: "8"; value: 8 } ListElement { name: "20"; value: 20 } } } + ControlView { + id: strikeoutvalue + controlname: "Strike" + model: ListModel { ListElement { name: "Off"; value: false } ListElement { name: "On"; value: true } } } + ControlView { + id: underlinevalue + controlname: "U_line" + model: ListModel { ListElement { name: "Off"; value: false } ListElement { name: "On"; value: true } } } + ControlView { + id: weightvalue + controlname: "Weight" + model: ListModel { ListElement { name: "Light"; value: Font.Light } ListElement { name: "Normal"; value: Font.Normal } + ListElement { name: "DemiBold"; value: Font.DemiBold } ListElement { name: "Bold"; value: Font.Bold } + ListElement { name: "Black"; value: Font.Black } } + Component.onCompleted: { currentIndex = 1 } // set to default + } + ControlView { + id: halignvalue + controlname: "HAlign" + model: ListModel { ListElement { name: "Left"; value: Text.AlignLeft } ListElement { name: "Right"; value: Text.AlignRight } + ListElement { name: "Center"; value: Text.AlignHCenter } ListElement { name: "Justify"; value: Text.AlignJustify } } } + ControlView { + id: valignvalue + controlname: "VAlign" + model: ListModel { ListElement { name: "Top"; value: Text.AlignTop } ListElement { name: "Bottom"; value: Text.AlignBottom } + ListElement { name: "Center"; value: Text.AlignVCenter } } } + ControlView { + id: maxlinevalue + controlname: "Lines" + model: ListModel { ListElement { name: "Max"; value: 2147483647 } ListElement { name: "1"; value: 1 } + ListElement { name: "2"; value: 2 } ListElement { name: "10"; value: 10 }} } + ControlView { + id: lineheightvalue + controlname: "LHeight" + model: ListModel { ListElement { name: "1"; value: 1.0 } ListElement { name: "2"; value: 2.0 } ListElement { name: "30"; value: 30.0 }} } + ControlView { + id: lineheightmodevalue + controlname: "LHMode" + model: ListModel { + ListElement { name: "Multiply"; value: Text.ProportionalHeight } ListElement { name: "Fixed"; value: Text.FixedHeight } } } + ControlView { + id: smoothvalue + controlname: "Smooth" + model: ListModel { ListElement { name: "Off"; value: false } ListElement { name: "On"; value: true } } } + ControlView { + id: stylevalue + controlname: "Style" + model: ListModel { ListElement { name: "Normal"; value: Text.Normal } ListElement { name: "Outline"; value: Text.Outline } + ListElement { name: "Raised"; value: Text.Raised } ListElement { name: "Sunken"; value: Text.Sunken } } } + ControlView { + id: stylecolorvalue + controlname: "SColor" + model: ListModel { ListElement { name: "Green"; value: "green" } ListElement { name: "Blue"; value: "blue" } } } + ControlView { + id: wrapvalue + controlname: "Wrap" + model: ListModel { ListElement { name: "None"; value: Text.NoWrap } ListElement { name: "Word"; value: Text.WordWrap } + ListElement { name: "Anywhere"; value: Text.WrapAnywhere } ListElement { name: "Wrap"; value: Text.Wrap } } } + } + } +} + + + + + + + + + + + + + + + + + diff --git a/tests/testapplications/text/textedit.qml b/tests/testapplications/text/textedit.qml new file mode 100644 index 0000000000..a33859b0b8 --- /dev/null +++ b/tests/testapplications/text/textedit.qml @@ -0,0 +1,268 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Rectangle { + height: 360; width: 640 + property int intmax: 2147483647 + + Connections { target: pointvalue; onReset: { texteditelement.font.pointSize = 12 } } + + Item { + id: textpanel + height: 360 + width: 440 + TextEdit { + id: texteditelement + height: parent.height - 20; width: parent.width - 20 + anchors.centerIn: parent + + text: { textvalue.model.get(textvalue.currentIndex).value } + textFormat: { formatvalue.model.get(formatvalue.currentIndex).value } + color: { colorvalue.model.get(colorvalue.currentIndex).value } + font.bold: { boldvalue.model.get(boldvalue.currentIndex).value } + font.italic: { italicsvalue.model.get(italicsvalue.currentIndex).value } + font.capitalization: { capsvalue.model.get(capsvalue.currentIndex).value } + font.family: { familyvalue.model.get(familyvalue.currentIndex).value } + font.strikeout: strikeoutvalue.currentIndex + font.underline: underlinevalue.currentIndex + font.letterSpacing: { lspacingvalue.model.get(lspacingvalue.currentIndex).value } + font.wordSpacing: { wspacingvalue.model.get(wspacingvalue.currentIndex).value } + font.weight: { weightvalue.model.get(weightvalue.currentIndex).value } + font.pointSize: { pointvalue.model.get(pointvalue.currentIndex).value } + font.pixelSize: { pixelvalue.model.get(pixelvalue.currentIndex).value } + horizontalAlignment: { halignvalue.model.get(halignvalue.currentIndex).value } + verticalAlignment: { valignvalue.model.get(valignvalue.currentIndex).value } + wrapMode: { wrapvalue.model.get(wrapvalue.currentIndex).value } + smooth: { smoothvalue.model.get(smoothvalue.currentIndex).value } + selectByMouse: { mousevalue.model.get(mousevalue.currentIndex).value } + onLinkActivated: { bordercolor.border.color = "red" } + Rectangle { id: bordercolor; color: "transparent"; border.color: "green"; anchors.fill: parent } + } + + Text { + id: infopanel + anchors { left: parent.left; leftMargin: 10; bottom: parent.bottom } + height: 150; color: "black"; width: 150 + text: + "LineCount: "+texteditelement.lineCount+ + "\nPaintedHeight/Width: "+texteditelement.paintedHeight+"/"+texteditelement.paintedWidth+ + "\nPointSize: "+texteditelement.font.pointSize+"\nPixelSize: "+texteditelement.font.pixelSize+ + "\nCan Paste: "+texteditelement.canPaste + } + Row { + id: selectionbuttons + height:40 + width: 300 + anchors.right: texteditelement.right; anchors.bottom: texteditelement.bottom + Button { buttontext: "Select Word"; width: parent.width/3; onClicked: { texteditelement.selectWord() } } + Button { buttontext: "Select All"; width: parent.width/3; onClicked: { texteditelement.selectAll() } } + Button { buttontext: "Select None"; width: parent.width/3; onClicked: { texteditelement.deselect() } } + } + Row { + height:40 + width: 300 + anchors.right: texteditelement.right; anchors.bottom: selectionbuttons.top + Button { buttontext: "Cut"; width: parent.width/3; onClicked: { texteditelement.cut() } } + Button { buttontext: "Copy"; width: parent.width/3; onClicked: { texteditelement.copy() } } + Button { buttontext: "Paste"; width: parent.width/3; onClicked: { texteditelement.paste() } } + } + } + + Item { + id: controlpanel + width: 200; height: parent.height + anchors.right: parent.right + Rectangle { anchors.fill: parent; color: "transparent"; border.color: "black" } + ListView { id: controls; model: controlsmodel; anchors.fill: parent; clip: true; cacheBuffer: 500 } + VisualItemModel { + id: controlsmodel + ControlView { + id: textvalue + controlname: "Text" + model: textmodel + ListModel { id: textmodel } + Component.onCompleted: { + textmodel.append({ "name": "Basic", + "value": "Qt Quick is a collection of technologies that are designed to help developers create the kind of intuitive, "+ + "modern, fluid user interfaces that are increasingly used on mobile phones, media players, set-top boxes and other "+ + "portable devices."+texteditelement.newline+ + "Qt Quick consists of a rich set of user interface elements, a declarative language for describing user interfaces "+ + "and a language runtime.\n"+ + "A collection of C++ APIs is used to integrate these high level features with classic Qt applications."}); + textmodel.append({ "name": "Short", + "value": "Hello World"}); + textmodel.append({ "name": "Long", + "value": "QtQuickisacollectionoftechnologiesthataredesignedtohelpdeveloperscreatethekindofintuitive,"+ + "modern,fluiduserinterfacesthatareincreasinglyusedonmobilephones,mediaplayers,set-topboxesandother"+ + "portabledevices."}); + textmodel.append({ "name": "Rich", + "value": "<b>Qt Quick</b> is a collection of technologies that are designed to help developers create the kind of <i>intuitive, "+ + "modern, fluid</i> user interfaces that are increasingly used on mobile phones, media players, set-top boxes and other "+ + "portable devices.<br>"+ + "Qt Quick consists of a rich set of user interface elements, a declarative language for describing user interfaces "+ + "and a language runtime. "+ + "A collection of C++ APIs is used to integrate these high level features with classic Qt applications."}); + textmodel.append({ "name": "Links", + "value": "This is a link - <a href=\"http://doc.qt.nokia.com\">Qt Docs</a>"}); + } + } + ControlView { + id: formatvalue + controlname: "Format" + model: ListModel { ListElement { name: "Auto"; value: Text.AutoText } ListElement { name: "Plain"; value: Text.PlainText } + ListElement { name: "Rich"; value: Text.RichText } ListElement { name: "Styled"; value: Text.StyledText } } } + ControlView { + id: colorvalue + controlname: "Color" + model: ListModel { ListElement { name: "Red"; value: "red" } + ListElement { name: "Green"; value: "green" } ListElement { name: "Blue"; value: "blue" } } + } + ControlView { + id: boldvalue + controlname: "Bold" + model: ListModel { ListElement { name: "Off"; value: false } ListElement { name: "On"; value: true } } + } + ControlView { + id: italicsvalue + controlname: "Italic" + model: ListModel { ListElement { name: "Off"; value: false } ListElement { name: "On"; value: true } } + } + ControlView { + id: capsvalue + controlname: "Cap10n" + model: ListModel { + ListElement { name: "Mixed"; value: Font.MixedCase } ListElement { name: "Upper"; value: Font.AllUppercase } + ListElement { name: "Lower"; value: Font.AllLowercase } ListElement { name: "SmallCaps"; value: Font.SmallCaps } + ListElement { name: "Capitals"; value: Font.Capitalize } + } + } + ControlView { + id: familyvalue + controlname: "Font" + property variant fontfamilies + function setModel() { + familiesmodel.clear(); + for (var i = 0; i < fontfamilies.length; ++i) { + familiesmodel.append({ "name": fontfamilies[i], "value": fontfamilies[i] }); + } + familyvalue.currentIndex = 0; + } + model: familiesmodel + ListModel { id: familiesmodel } + Component.onCompleted: { fontfamilies = Qt.fontFamilies(); setModel(); } + } + ControlView { + id: lspacingvalue + controlname: "LSpacing" + model: ListModel { ListElement { name: "0"; value: 0 } ListElement { name: "1"; value: 1 } ListElement { name: "2.5"; value: 2.5 } } } + ControlView { + id: wspacingvalue + controlname: "WSpacing" + model: ListModel { ListElement { name: "-1"; value: -1 } ListElement { name: "8"; value: 8 } ListElement { name: "20"; value: 20 } } } + ControlView { + id: pixelvalue + controlname: "Pixel" + model: ListModel { ListElement { name: "-1"; value: -1 } ListElement { name: "8"; value: 8 } ListElement { name: "20"; value: 20 } } } + ControlView { + id: pointvalue + controlname: "Point" + model: ListModel { ListElement { name: "-1"; value: -1 } ListElement { name: "8"; value: 8 } ListElement { name: "20"; value: 20 } } } + ControlView { + id: strikeoutvalue + controlname: "Strike" + model: ListModel { ListElement { name: "Off"; value: false } ListElement { name: "On"; value: true } } } + ControlView { + id: underlinevalue + controlname: "U_line" + model: ListModel { ListElement { name: "Off"; value: false } ListElement { name: "On"; value: true } } } + ControlView { + id: weightvalue + controlname: "Weight" + model: ListModel { ListElement { name: "Light"; value: Font.Light } ListElement { name: "Normal"; value: Font.Normal } + ListElement { name: "DemiBold"; value: Font.DemiBold } ListElement { name: "Bold"; value: Font.Bold } + ListElement { name: "Black"; value: Font.Black } } + Component.onCompleted: { currentIndex = 1 } // set to default + } + ControlView { + id: mousevalue + controlname: "Mouse" + model: ListModel { ListElement { name: "Off"; value: false } ListElement { name: "On"; value: true } } } + ControlView { + id: halignvalue + controlname: "HAlign" + model: ListModel { ListElement { name: "Left"; value: Text.AlignLeft } ListElement { name: "Right"; value: Text.AlignRight } + ListElement { name: "Center"; value: Text.AlignHCenter } ListElement { name: "Justify"; value: Text.AlignJustify } } } + ControlView { + id: valignvalue + controlname: "VAlign" + model: ListModel { ListElement { name: "Top"; value: Text.AlignTop } ListElement { name: "Bottom"; value: Text.AlignBottom } + ListElement { name: "Center"; value: Text.AlignVCenter } } } + ControlView { + id: smoothvalue + controlname: "Smooth" + model: ListModel { ListElement { name: "Off"; value: false } ListElement { name: "On"; value: true } } } + ControlView { + id: wrapvalue + controlname: "Wrap" + model: ListModel { ListElement { name: "None"; value: Text.NoWrap } ListElement { name: "Word"; value: Text.WordWrap } + ListElement { name: "Anywhere"; value: Text.WrapAnywhere } ListElement { name: "Wrap"; value: Text.Wrap } } } + } + } +} + + + + + + + + + + + + + + + + + diff --git a/tests/testapplications/text/textinput.qml b/tests/testapplications/text/textinput.qml new file mode 100644 index 0000000000..98f2628372 --- /dev/null +++ b/tests/testapplications/text/textinput.qml @@ -0,0 +1,343 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Rectangle { + height: 360; width: 640 + + Connections { target: pointvalue; onReset: { textinputelement.font.pointSize = 12 } } + + Item { + id: textpanel + height: 360 + width: 440 + MouseArea { anchors.fill: parent; onClicked: textinputelement.focus = false } + TextInput { + id: textinputelement + height: 50; width: parent.width - 20 + anchors.centerIn: parent + focus: true + property int validatorval + validatorval: { validvalue.model.get(validvalue.currentIndex).value } + text: { textvalue.model.get(textvalue.currentIndex).value } + autoScroll: { autoscrollvalue.model.get(autoscrollvalue.currentIndex).value } + color: { colorvalue.model.get(colorvalue.currentIndex).value } + font.bold: { boldvalue.model.get(boldvalue.currentIndex).value } + font.italic: { italicsvalue.model.get(italicsvalue.currentIndex).value } + font.capitalization: { capsvalue.model.get(capsvalue.currentIndex).value } + font.family: { familyvalue.model.get(familyvalue.currentIndex).value } + font.strikeout: strikeoutvalue.currentIndex + font.underline: underlinevalue.currentIndex + font.letterSpacing: { lspacingvalue.model.get(lspacingvalue.currentIndex).value } + font.wordSpacing: { wspacingvalue.model.get(wspacingvalue.currentIndex).value } + font.weight: { weightvalue.model.get(weightvalue.currentIndex).value } + font.pointSize: { pointvalue.model.get(pointvalue.currentIndex).value } + font.pixelSize: { pixelvalue.model.get(pixelvalue.currentIndex).value } + horizontalAlignment: { halignvalue.model.get(halignvalue.currentIndex).value } + smooth: { smoothvalue.model.get(smoothvalue.currentIndex).value } + selectByMouse: { mousevalue.model.get(mousevalue.currentIndex).value } + echoMode: { echovalue.model.get(echovalue.currentIndex).value } + cursorVisible: { cursorvisiblevalue.model.get(cursorvisiblevalue.currentIndex).value } + cursorDelegate: cursordelegate + onValidatorvalChanged: { + //console.log(validatorval); + if (validatorval == 0) + validator = intval; + else if (validatorval == 1) + validator = dubval; + else if (validatorval == 2) + validator = regval; + else + validator = noval; + } + IntValidator { id: intval; top: 30; bottom: 12 } + DoubleValidator { id: dubval; top: 30; bottom: 12 } + RegExpValidator { id: regval; regExp: /Qt/ } + RegExpValidator { id: noval; regExp: /.*/ } + Rectangle{ color: "transparent"; border.color: "green"; anchors.fill: parent } + } + + Row { + id: buttonrow + height: 40 + width: parent.width - 20 + anchors.left: textinputelement.left + anchors.bottom: buttonrow2.top; anchors.bottomMargin: 2 + Button { buttontext: "Select Word"; onClicked: { textinputelement.selectWord() } } + Button { buttontext: "Select All"; onClicked: { textinputelement.selectAll() } } + Button { buttontext: "Select to 5"; onClicked: { textinputelement.moveCursorSelection(5) } } + Button { buttontext: "Select None"; onClicked: { textinputelement.deselect() } } + } + Row { + id: buttonrow2 + height: 40 + width: parent.width - 20 + anchors.left: textinputelement.left + anchors.bottom: buttonrow3.top; anchors.bottomMargin: 2 + Button { buttontext: "Cut"; onClicked: { textinputelement.cut() } } + Button { buttontext: "Copy"; onClicked: { textinputelement.copy() } } + Button { buttontext: "Paste"; onClicked: { textinputelement.paste() } } + } + Row { + id: buttonrow3 + height: 40 + width: parent.width - 20 + anchors.left: textinputelement.left + anchors.bottom: textinputelement.top; anchors.bottomMargin: 2 + Button { buttontext: "Position 12px"; onClicked: { textinputelement.cursorPosition = textinputelement.positionAt(12) } } + Button { buttontext: "Select 3-6"; onClicked: { textinputelement.select(3,6) } } + Button { buttontext: "Position End"; onClicked: { textinputelement.cursorPosition = textinputelement.text.length } } + } + Component { + id: cursordelegate + Rectangle { + id: cursordelegaterect + height: 48; width: 3; color: "red"; visible: parent.cursorVisible + SequentialAnimation on opacity { running: true; loops: Animation.Infinite + NumberAnimation { to: 0; duration: 1000 } + NumberAnimation { to: 1; duration: 1000 } + } + } + } + + Text { + id: infopanel + anchors { left: parent.left; leftMargin: 10; bottom: parent.bottom } + height: 150; color: "black"; width: 150 + text: + "\nPointSize: "+textinputelement.font.pointSize+ + "\nPixelSize: "+textinputelement.font.pixelSize+ + "\nAcceptable Input: "+textinputelement.acceptableInput+ + "\nCan Paste: "+textinputelement.canPaste+ + "\nCursor Position: "+textinputelement.cursorPosition+ + "\nRight to Left: "+textinputelement.isRightToLeft(0,textinputelement.text.length); + } + } + + Item { + id: controlpanel + width: 200; height: parent.height + anchors.right: parent.right + Rectangle { anchors.fill: parent; color: "transparent"; border.color: "black" } + ListView { id: controls; model: controlsmodel; anchors.fill: parent; clip: true; cacheBuffer: 500 } + VisualItemModel { + id: controlsmodel + ControlView { + id: textvalue + controlname: "Text" + model: textmodel + ListModel { id: textmodel } + Component.onCompleted: { + textmodel.append({ "name": "Basic", "value": "The TextInput item displays an editable line of text."}); + textmodel.append({ "name": "Short", "value": "Hello World"}); + textmodel.append({ "name": "Long", + "value": "Qt Quick is a collection of technologies that are designed to help developers create the kind of intuitive, "+ + "modern, fluid user interfaces that are increasingly used on mobile phones, media players, set-top boxes and other "+ + "portable devices. "+ + "Qt Quick consists of a rich set of user interface elements, a declarative language for describing user interfaces "+ + "and a language runtime. "+ + "A collection of C++ APIs is used to integrate these high level features with classic Qt applications."}); + } + } + ControlView { + id: autoscrollvalue + controlname: "AutoScroll" + model: ListModel { ListElement { name: "On"; value: true } ListElement { name: "Off"; value: false } } + } + ControlView { + id: colorvalue + controlname: "Color" + model: ListModel { ListElement { name: "Red"; value: "red" } + ListElement { name: "Green"; value: "green" } ListElement { name: "Blue"; value: "blue" } } + } + ControlView { + id: elidevalue + controlname: "Elide" + model: ListModel { ListElement { name: "None"; value: Text.ElideNone } ListElement { name: "Left"; value: Text.ElideLeft } + ListElement { name: "Middle"; value: Text.ElideMiddle } ListElement { name: "Right"; value: Text.ElideRight } } + } + ControlView { + id: boldvalue + controlname: "Bold" + model: ListModel { ListElement { name: "Off"; value: false } ListElement { name: "On"; value: true } } + } + ControlView { + id: italicsvalue + controlname: "Italic" + model: ListModel { ListElement { name: "Off"; value: false } ListElement { name: "On"; value: true } } + } + ControlView { + id: capsvalue + controlname: "Cap10n" + model: ListModel { + ListElement { name: "Mixed"; value: Font.MixedCase } ListElement { name: "Upper"; value: Font.AllUppercase } + ListElement { name: "Lower"; value: Font.AllLowercase } ListElement { name: "SmallCaps"; value: Font.SmallCaps } + ListElement { name: "Capitals"; value: Font.Capitalize } + } + } + ControlView { + id: cursorvisiblevalue + controlname: "Cursor" + model: ListModel { ListElement { name: "On"; value: true } ListElement { name: "Off"; value: false } } + } + ControlView { + id: echovalue + controlname: "Echo" + model: ListModel { ListElement { name: "Normal"; value: TextInput.Normal } ListElement { name: "Password"; value: TextInput.Password } + ListElement { name: "None"; value: TextInput.NoEcho } ListElement { name: "OnEdit"; value: TextInput.PasswordEchoOnEdit } } } + ControlView { + id: familyvalue + controlname: "Font" + property variant fontfamilies + function setModel() { + familiesmodel.clear(); + for (var i = 0; i < fontfamilies.length; ++i) { + familiesmodel.append({ "name": fontfamilies[i], "value": fontfamilies[i] }); + } + familyvalue.currentIndex = 0; + } + model: familiesmodel + ListModel { id: familiesmodel } + Component.onCompleted: { fontfamilies = Qt.fontFamilies(); setModel(); } + } + ControlView { + id: lspacingvalue + controlname: "LSpacing" + model: ListModel { ListElement { name: "0"; value: 0 } ListElement { name: "1"; value: 1 } ListElement { name: "2.5"; value: 2.5 } } } + ControlView { + id: wspacingvalue + controlname: "WSpacing" + model: ListModel { ListElement { name: "-1"; value: -1 } ListElement { name: "8"; value: 8 } ListElement { name: "20"; value: 20 } } } + ControlView { + id: pixelvalue + controlname: "Pixel" + model: ListModel { ListElement { name: "-1"; value: -1 } ListElement { name: "8"; value: 8 } ListElement { name: "20"; value: 20 } } } + ControlView { + id: pointvalue + controlname: "Point" + model: ListModel { ListElement { name: "-1"; value: -1 } ListElement { name: "8"; value: 8 } ListElement { name: "20"; value: 20 } } } + ControlView { + id: strikeoutvalue + controlname: "Strike" + model: ListModel { ListElement { name: "Off"; value: false } ListElement { name: "On"; value: true } } } + ControlView { + id: underlinevalue + controlname: "U_line" + model: ListModel { ListElement { name: "Off"; value: false } ListElement { name: "On"; value: true } } } + ControlView { + id: weightvalue + controlname: "Weight" + model: ListModel { ListElement { name: "Light"; value: Font.Light } ListElement { name: "Normal"; value: Font.Normal } + ListElement { name: "DemiBold"; value: Font.DemiBold } ListElement { name: "Bold"; value: Font.Bold } + ListElement { name: "Black"; value: Font.Black } } + Component.onCompleted: { currentIndex = 1 } // set to default + } + ControlView { + id: halignvalue + controlname: "HAlign" + model: ListModel { ListElement { name: "Left"; value: Text.AlignLeft } ListElement { name: "Right"; value: Text.AlignRight } + ListElement { name: "Center"; value: Text.AlignHCenter } ListElement { name: "Justify"; value: Text.AlignJustify } } } + ControlView { + id: valignvalue + controlname: "VAlign" + model: ListModel { ListElement { name: "Top"; value: Text.AlignTop } ListElement { name: "Bottom"; value: Text.AlignBottom } + ListElement { name: "Center"; value: Text.AlignVCenter } } } + ControlView { + id: maxlinevalue + controlname: "Lines" + model: ListModel { ListElement { name: "Unset"; value: 1 } ListElement { name: "2"; value: 2 } ListElement { name: "10"; value: 10 }} } + ControlView { + id: lineheightvalue + controlname: "LHeight" + model: ListModel { ListElement { name: "1"; value: 1.0 } ListElement { name: "2"; value: 2.0 } ListElement { name: "30"; value: 30.0 }} } + ControlView { + id: lineheightmodevalue + controlname: "LHMode" + model: ListModel { + ListElement { name: "Multiply"; value: Text.ProportionalHeight } ListElement { name: "Fixed"; value: Text.FixedHeight } } } + ControlView { + id: mousevalue + controlname: "Mouse" + model: ListModel { ListElement { name: "Off"; value: false } ListElement { name: "On"; value: true } } } + ControlView { + id: smoothvalue + controlname: "Smooth" + model: ListModel { ListElement { name: "Off"; value: false } ListElement { name: "On"; value: true } } } + ControlView { + id: stylevalue + controlname: "Style" + model: ListModel { ListElement { name: "Normal"; value: Text.Normal } ListElement { name: "Outline"; value: Text.Outline } + ListElement { name: "Raised"; value: Text.Raised } ListElement { name: "Sunken"; value: Text.Sunken } } } + ControlView { + id: stylecolorvalue + controlname: "SColor" + model: ListModel { ListElement { name: "Green"; value: "green" } ListElement { name: "Blue"; value: "blue" } } } + ControlView { + id: wrapvalue + controlname: "Wrap" + model: ListModel { ListElement { name: "None"; value: Text.NoWrap } ListElement { name: "Word"; value: Text.WordWrap } + ListElement { name: "Anywhere"; value: Text.WrapAnywhere } ListElement { name: "Wrap"; value: Text.Wrap } } } + ControlView { + id: validvalue + controlname: "Valid" + model: ListModel { ListElement { name: "None"; value: -1 } ListElement { name: "Int"; value: 0 } + ListElement { name: "Double"; value: 1 } ListElement { name: "RegExp"; value: 2 } } } + } + } +} + + + + + + + + + + + + + + + + + |