aboutsummaryrefslogtreecommitdiffstats
path: root/src/imports
diff options
context:
space:
mode:
authorShawn Rutledge <shawn.rutledge@qt.io>2016-12-20 09:37:14 +0100
committerShawn Rutledge <shawn.rutledge@qt.io>2016-12-20 09:37:14 +0100
commitc07610b208268e6b6b952d634a6540ff66a0a8a8 (patch)
treedf8f0a71db8e1d3a6144e35468125c2b263dc372 /src/imports
parent6f94828e8f1865259ff1b1cd7fda5064ffd9576c (diff)
parentc4eefa4a8d6d3e95062deb78229940460a7ef605 (diff)
Merge branch remote-tracking branch 'origin/dev' into wip/pointerhandler
Diffstat (limited to 'src/imports')
-rw-r--r--src/imports/folderlistmodel/fileinfothread.cpp16
-rw-r--r--src/imports/folderlistmodel/fileinfothread_p.h4
-rw-r--r--src/imports/folderlistmodel/plugin.cpp2
-rw-r--r--src/imports/folderlistmodel/qquickfolderlistmodel.cpp6
-rw-r--r--src/imports/layouts/qquicklayout.cpp32
-rw-r--r--src/imports/layouts/qquicklayout_p.h4
-rw-r--r--src/imports/layouts/qquicklinearlayout.cpp54
-rw-r--r--src/imports/layouts/qquicklinearlayout_p.h9
-rw-r--r--src/imports/localstorage/plugin.cpp6
-rw-r--r--src/imports/testlib/SignalSpy.qml10
-rw-r--r--src/imports/testlib/TestCase.qml269
-rw-r--r--src/imports/testlib/main.cpp1
-rw-r--r--src/imports/testlib/qmldir1
-rw-r--r--src/imports/testlib/toucheventsequence.qdoc110
-rw-r--r--src/imports/window/plugins.qmltypes8
15 files changed, 459 insertions, 73 deletions
diff --git a/src/imports/folderlistmodel/fileinfothread.cpp b/src/imports/folderlistmodel/fileinfothread.cpp
index 0b62935f87..d3e256bb7e 100644
--- a/src/imports/folderlistmodel/fileinfothread.cpp
+++ b/src/imports/folderlistmodel/fileinfothread.cpp
@@ -46,7 +46,7 @@
FileInfoThread::FileInfoThread(QObject *parent)
: QThread(parent),
abort(false),
-#ifndef QT_NO_FILESYSTEMWATCHER
+#if QT_CONFIG(filesystemwatcher)
watcher(0),
#endif
sortFlags(QDir::Name),
@@ -61,11 +61,11 @@ FileInfoThread::FileInfoThread(QObject *parent)
showOnlyReadable(false),
caseSensitive(true)
{
-#ifndef QT_NO_FILESYSTEMWATCHER
+#if QT_CONFIG(filesystemwatcher)
watcher = new QFileSystemWatcher(this);
connect(watcher, SIGNAL(directoryChanged(QString)), this, SLOT(dirChanged(QString)));
connect(watcher, SIGNAL(fileChanged(QString)), this, SLOT(updateFile(QString)));
-#endif // !QT_NO_FILESYSTEMWATCHER
+#endif // filesystemwatcher
}
FileInfoThread::~FileInfoThread()
@@ -80,7 +80,7 @@ FileInfoThread::~FileInfoThread()
void FileInfoThread::clear()
{
QMutexLocker locker(&mutex);
-#ifndef QT_NO_FILESYSTEMWATCHER
+#if QT_CONFIG(filesystemwatcher)
watcher->removePaths(watcher->files());
watcher->removePaths(watcher->directories());
#endif
@@ -89,7 +89,7 @@ void FileInfoThread::clear()
void FileInfoThread::removePath(const QString &path)
{
QMutexLocker locker(&mutex);
-#ifndef QT_NO_FILESYSTEMWATCHER
+#if QT_CONFIG(filesystemwatcher)
if (!path.startsWith(QLatin1Char(':')))
watcher->removePath(path);
#else
@@ -103,7 +103,7 @@ void FileInfoThread::setPath(const QString &path)
Q_ASSERT(!path.isEmpty());
QMutexLocker locker(&mutex);
-#ifndef QT_NO_FILESYSTEMWATCHER
+#if QT_CONFIG(filesystemwatcher)
if (!path.startsWith(QLatin1Char(':')))
watcher->addPath(path);
#endif
@@ -120,7 +120,7 @@ void FileInfoThread::setRootPath(const QString &path)
rootPath = path;
}
-#ifndef QT_NO_FILESYSTEMWATCHER
+#if QT_CONFIG(filesystemwatcher)
void FileInfoThread::dirChanged(const QString &directoryPath)
{
Q_UNUSED(directoryPath);
@@ -204,7 +204,7 @@ void FileInfoThread::setCaseSensitive(bool on)
condition.wakeAll();
}
-#ifndef QT_NO_FILESYSTEMWATCHER
+#if QT_CONFIG(filesystemwatcher)
void FileInfoThread::updateFile(const QString &path)
{
Q_UNUSED(path);
diff --git a/src/imports/folderlistmodel/fileinfothread_p.h b/src/imports/folderlistmodel/fileinfothread_p.h
index 56058fd6be..b505ece750 100644
--- a/src/imports/folderlistmodel/fileinfothread_p.h
+++ b/src/imports/folderlistmodel/fileinfothread_p.h
@@ -88,7 +88,7 @@ public:
void setCaseSensitive(bool on);
public Q_SLOTS:
-#ifndef QT_NO_FILESYSTEMWATCHER
+#if QT_CONFIG(filesystemwatcher)
void dirChanged(const QString &directoryPath);
void updateFile(const QString &path);
#endif
@@ -103,7 +103,7 @@ private:
QWaitCondition condition;
volatile bool abort;
-#ifndef QT_NO_FILESYSTEMWATCHER
+#if QT_CONFIG(filesystemwatcher)
QFileSystemWatcher *watcher;
#endif
QList<FileProperty> currentFileList;
diff --git a/src/imports/folderlistmodel/plugin.cpp b/src/imports/folderlistmodel/plugin.cpp
index affde1c3aa..ef719109bd 100644
--- a/src/imports/folderlistmodel/plugin.cpp
+++ b/src/imports/folderlistmodel/plugin.cpp
@@ -62,12 +62,10 @@ public:
void registerTypes(const char *uri) Q_DECL_OVERRIDE
{
Q_ASSERT(QLatin1String(uri) == QLatin1String("Qt.labs.folderlistmodel"));
-#ifndef QT_NO_DIRMODEL
qmlRegisterType<QQuickFolderListModel>(uri,1,0,"FolderListModel");
qmlRegisterType<QQuickFolderListModel>(uri,2,0,"FolderListModel");
qmlRegisterType<QQuickFolderListModel,1>(uri,2,1,"FolderListModel");
qmlRegisterType<QQuickFolderListModel,2>(uri,2,2,"FolderListModel");
-#endif
}
};
//![class decl]
diff --git a/src/imports/folderlistmodel/qquickfolderlistmodel.cpp b/src/imports/folderlistmodel/qquickfolderlistmodel.cpp
index 1c94fddecf..fdcce9c685 100644
--- a/src/imports/folderlistmodel/qquickfolderlistmodel.cpp
+++ b/src/imports/folderlistmodel/qquickfolderlistmodel.cpp
@@ -447,9 +447,9 @@ void QQuickFolderListModel::setFolder(const QUrl &folder)
/*!
\qmlproperty url FolderListModel::rootFolder
- When the rootFolder is set, then this folder will
- be threated as the root in the file system, so that
- you can only travers sub folders from this rootFolder.
+ When this property is set, the given folder will
+ be treated as the root in the file system, so that
+ you can only traverse subfolders within it.
*/
QUrl QQuickFolderListModel::rootFolder() const
{
diff --git a/src/imports/layouts/qquicklayout.cpp b/src/imports/layouts/qquicklayout.cpp
index 07ada75a5f..3786d21727 100644
--- a/src/imports/layouts/qquicklayout.cpp
+++ b/src/imports/layouts/qquicklayout.cpp
@@ -763,18 +763,14 @@ void QQuickLayout::itemChange(ItemChange change, const ItemChangeData &value)
{
if (change == ItemChildAddedChange) {
QQuickItem *item = value.item;
- qmlobject_connect(item, QQuickItem, SIGNAL(implicitWidthChanged()), this, QQuickLayout, SLOT(invalidateSenderItem()));
- qmlobject_connect(item, QQuickItem, SIGNAL(implicitHeightChanged()), this, QQuickLayout, SLOT(invalidateSenderItem()));
qmlobject_connect(item, QQuickItem, SIGNAL(baselineOffsetChanged(qreal)), this, QQuickLayout, SLOT(invalidateSenderItem()));
- QQuickItemPrivate::get(item)->addItemChangeListener(this, QQuickItemPrivate::SiblingOrder);
+ QQuickItemPrivate::get(item)->addItemChangeListener(this, QQuickItemPrivate::SiblingOrder | QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight | QQuickItemPrivate::Destroyed | QQuickItemPrivate::Visibility);
if (isReady())
updateLayoutItems();
} else if (change == ItemChildRemovedChange) {
QQuickItem *item = value.item;
- qmlobject_disconnect(item, QQuickItem, SIGNAL(implicitWidthChanged()), this, QQuickLayout, SLOT(invalidateSenderItem()));
- qmlobject_disconnect(item, QQuickItem, SIGNAL(implicitHeightChanged()), this, QQuickLayout, SLOT(invalidateSenderItem()));
qmlobject_disconnect(item, QQuickItem, SIGNAL(baselineOffsetChanged(qreal)), this, QQuickLayout, SLOT(invalidateSenderItem()));
- QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::SiblingOrder);
+ QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::SiblingOrder | QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight | QQuickItemPrivate::Destroyed | QQuickItemPrivate::Visibility);
if (isReady())
updateLayoutItems();
}
@@ -812,6 +808,30 @@ void QQuickLayout::itemSiblingOrderChanged(QQuickItem *item)
updateLayoutItems();
}
+void QQuickLayout::itemImplicitWidthChanged(QQuickItem *item)
+{
+ if (!isReady() || item->signalsBlocked())
+ return;
+ invalidate(item);
+}
+
+void QQuickLayout::itemImplicitHeightChanged(QQuickItem *item)
+{
+ if (!isReady() || item->signalsBlocked())
+ return;
+ invalidate(item);
+}
+
+void QQuickLayout::itemDestroyed(QQuickItem *item)
+{
+ Q_UNUSED(item);
+}
+
+void QQuickLayout::itemVisibilityChanged(QQuickItem *item)
+{
+ Q_UNUSED(item);
+}
+
void QQuickLayout::rearrange(const QSizeF &/*size*/)
{
m_dirty = false;
diff --git a/src/imports/layouts/qquicklayout_p.h b/src/imports/layouts/qquicklayout_p.h
index c7f04c1fed..eece6f8658 100644
--- a/src/imports/layouts/qquicklayout_p.h
+++ b/src/imports/layouts/qquicklayout_p.h
@@ -99,6 +99,10 @@ public:
/* QQuickItemChangeListener */
void itemSiblingOrderChanged(QQuickItem *item) Q_DECL_OVERRIDE;
+ void itemImplicitWidthChanged(QQuickItem *item) Q_DECL_OVERRIDE;
+ void itemImplicitHeightChanged(QQuickItem *item) Q_DECL_OVERRIDE;
+ void itemDestroyed(QQuickItem *item) Q_DECL_OVERRIDE;
+ void itemVisibilityChanged(QQuickItem *item) Q_DECL_OVERRIDE;
protected:
void updatePolish() Q_DECL_OVERRIDE;
diff --git a/src/imports/layouts/qquicklinearlayout.cpp b/src/imports/layouts/qquicklinearlayout.cpp
index 7fad395a29..13fdd496c2 100644
--- a/src/imports/layouts/qquicklinearlayout.cpp
+++ b/src/imports/layouts/qquicklinearlayout.cpp
@@ -303,17 +303,13 @@ QQuickGridLayoutBase::~QQuickGridLayoutBase()
{
Q_D(QQuickGridLayoutBase);
- /* Avoid messy deconstruction, should give:
- * Faster deconstruction
- * Less risk of signals reaching already deleted objects
- */
+ // Remove item listeners so we do not act on signalling unnecessarily
+ // (there is no point, as the layout will be torn down anyway).
for (int i = 0; i < itemCount(); ++i) {
QQuickItem *item = itemAt(i);
- qmlobject_disconnect(item, QQuickItem, SIGNAL(destroyed()), this, QQuickGridLayoutBase, SLOT(onItemDestroyed()));
- qmlobject_disconnect(item, QQuickItem, SIGNAL(visibleChanged()), this, QQuickGridLayoutBase, SLOT(onItemVisibleChanged()));
- qmlobject_disconnect(item, QQuickItem, SIGNAL(implicitWidthChanged()), this, QQuickGridLayoutBase, SLOT(invalidateSenderItem()));
- qmlobject_disconnect(item, QQuickItem, SIGNAL(implicitHeightChanged()), this, QQuickGridLayoutBase, SLOT(invalidateSenderItem()));
+ QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::SiblingOrder | QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight | QQuickItemPrivate::Destroyed | QQuickItemPrivate::Visibility);
}
+
delete d->styleInfo;
}
@@ -436,23 +432,6 @@ int QQuickGridLayoutBase::itemCount() const
return d->engine.itemCount();
}
-void QQuickGridLayoutBase::itemChange(ItemChange change, const ItemChangeData &value)
-{
- if (change == ItemChildAddedChange) {
- quickLayoutDebug() << "ItemChildAddedChange";
- QQuickItem *item = value.item;
- qmlobject_connect(item, QQuickItem, SIGNAL(destroyed()), this, QQuickGridLayoutBase, SLOT(onItemDestroyed()));
- qmlobject_connect(item, QQuickItem, SIGNAL(visibleChanged()), this, QQuickGridLayoutBase, SLOT(onItemVisibleChanged()));
- } else if (change == ItemChildRemovedChange) {
- quickLayoutDebug() << "ItemChildRemovedChange";
- QQuickItem *item = value.item;
- qmlobject_disconnect(item, QQuickItem, SIGNAL(destroyed()), this, QQuickGridLayoutBase, SLOT(onItemDestroyed()));
- qmlobject_disconnect(item, QQuickItem, SIGNAL(visibleChanged()), this, QQuickGridLayoutBase, SLOT(onItemVisibleChanged()));
- }
-
- QQuickLayout::itemChange(change, value);
-}
-
void QQuickGridLayoutBase::removeGridItem(QGridLayoutItem *gridItem)
{
Q_D(QQuickGridLayoutBase);
@@ -461,28 +440,29 @@ void QQuickGridLayoutBase::removeGridItem(QGridLayoutItem *gridItem)
d->engine.removeRows(index, 1, d->orientation);
}
-void QQuickGridLayoutBase::onItemVisibleChanged()
-{
- if (!isReady())
- return;
- quickLayoutDebug() << "QQuickGridLayoutBase::onItemVisibleChanged";
- updateLayoutItems();
-}
-
-void QQuickGridLayoutBase::onItemDestroyed()
+void QQuickGridLayoutBase::itemDestroyed(QQuickItem *item)
{
if (!isReady())
return;
Q_D(QQuickGridLayoutBase);
- quickLayoutDebug() << "QQuickGridLayoutBase::onItemDestroyed";
- QQuickItem *inDestruction = static_cast<QQuickItem *>(sender());
- if (QQuickGridLayoutItem *gridItem = d->engine.findLayoutItem(inDestruction)) {
+ quickLayoutDebug() << "QQuickGridLayoutBase::itemDestroyed";
+ if (QQuickGridLayoutItem *gridItem = d->engine.findLayoutItem(item)) {
removeGridItem(gridItem);
delete gridItem;
invalidate();
}
}
+void QQuickGridLayoutBase::itemVisibilityChanged(QQuickItem *item)
+{
+ Q_UNUSED(item);
+
+ if (!isReady())
+ return;
+ quickLayoutDebug() << "QQuickGridLayoutBase::itemVisibilityChanged";
+ updateLayoutItems();
+}
+
void QQuickGridLayoutBase::rearrange(const QSizeF &size)
{
Q_D(QQuickGridLayoutBase);
diff --git a/src/imports/layouts/qquicklinearlayout_p.h b/src/imports/layouts/qquicklinearlayout_p.h
index ca8b867824..b425df0fa4 100644
--- a/src/imports/layouts/qquicklinearlayout_p.h
+++ b/src/imports/layouts/qquicklinearlayout_p.h
@@ -77,6 +77,10 @@ public:
Qt::LayoutDirection effectiveLayoutDirection() const;
void setAlignment(QQuickItem *item, Qt::Alignment align) Q_DECL_OVERRIDE;
+ /* QQuickItemChangeListener */
+ void itemDestroyed(QQuickItem *item) Q_DECL_OVERRIDE;
+ void itemVisibilityChanged(QQuickItem *item) Q_DECL_OVERRIDE;
+
protected:
void updateLayoutItems() Q_DECL_OVERRIDE;
QQuickItem *itemAt(int index) const Q_DECL_OVERRIDE;
@@ -84,15 +88,10 @@ protected:
void rearrange(const QSizeF &size) Q_DECL_OVERRIDE;
virtual void insertLayoutItems() {}
- void itemChange(ItemChange change, const ItemChangeData &data) Q_DECL_OVERRIDE;
signals:
Q_REVISION(1) void layoutDirectionChanged();
-protected slots:
- void onItemVisibleChanged();
- void onItemDestroyed();
-
private:
void removeGridItem(QGridLayoutItem *gridItem);
Q_DECLARE_PRIVATE(QQuickGridLayoutBase)
diff --git a/src/imports/localstorage/plugin.cpp b/src/imports/localstorage/plugin.cpp
index b8fd307215..ebffb07346 100644
--- a/src/imports/localstorage/plugin.cpp
+++ b/src/imports/localstorage/plugin.cpp
@@ -449,7 +449,7 @@ static ReturnedValue qmlsqldatabase_changeVersion(CallContext *ctx)
if (ok) {
*w->d()->version = to_version;
-#ifndef QT_NO_SETTINGS
+#if QT_CONFIG(settings)
QSettings ini(qmlsqldatabase_databaseFile(db.connectionName(), scope.engine) + QLatin1String(".ini"), QSettings::IniFormat);
ini.setValue(QLatin1String("Version"), to_version);
#endif
@@ -700,7 +700,7 @@ public:
void QQuickLocalStorage::openDatabaseSync(QQmlV4Function *args)
{
-#ifndef QT_NO_SETTINGS
+#if QT_CONFIG(settings)
QV4::Scope scope(args->v4engine());
if (scope.engine->qmlEngine()->offlineStoragePath().isEmpty())
V4THROW_SQL2(SQLEXCEPTION_DATABASE_ERR, QQmlEngine::tr("SQL: can't create database, offline storage is disabled."));
@@ -770,7 +770,7 @@ void QQuickLocalStorage::openDatabaseSync(QQmlV4Function *args)
}
args->setReturnValue(db.asReturnedValue());
-#endif // QT_NO_SETTINGS
+#endif // settings
}
static QObject *module_api_factory(QQmlEngine *engine, QJSEngine *scriptEngine)
diff --git a/src/imports/testlib/SignalSpy.qml b/src/imports/testlib/SignalSpy.qml
index 200fc725f7..8a8e844a21 100644
--- a/src/imports/testlib/SignalSpy.qml
+++ b/src/imports/testlib/SignalSpy.qml
@@ -230,8 +230,14 @@ Item {
qtest_prevSignalName = ""
}
if (target != null && signalName != "") {
- var handlerName = qtest_signalHandlerName(signalName)
- var func = target[handlerName]
+ // Look for the signal name in the object
+ var func = target[signalName]
+ if (typeof func !== "function") {
+ // If it is not a function, try looking for signal handler
+ // i.e. (onSignal) this is needed for cases where there is a property
+ // and a signal with the same name, e.g. Mousearea.pressed
+ func = target[qtest_signalHandlerName(signalName)]
+ }
if (func === undefined) {
spy.qtest_valid = false
console.log("Signal '" + signalName + "' not found")
diff --git a/src/imports/testlib/TestCase.qml b/src/imports/testlib/TestCase.qml
index 683200a259..ad7533c550 100644
--- a/src/imports/testlib/TestCase.qml
+++ b/src/imports/testlib/TestCase.qml
@@ -206,6 +206,59 @@ import Qt.test.qtestroot 1.0
will fail. Use the \l when and windowShown properties to track
when the main window has been shown.
+ \section1 Managing Dynamically Created Test Objects
+
+ A typical pattern with QML tests is to
+ \l {Dynamic QML Object Creation from JavaScript}{dynamically create}
+ an item and then destroy it at the end of the test function:
+
+ \code
+ TestCase {
+ id: testCase
+ name: "MyTest"
+ when: windowShown
+
+ function test_click() {
+ var item = Qt.createQmlObject("import QtQuick 2.0; Item {}", testCase);
+ verify(item);
+
+ // Test item...
+
+ item.destroy();
+ }
+ }
+ \endcode
+
+ The problem with this pattern is that any failures in the test function
+ will cause the call to \c item.destroy() to be skipped, leaving the item
+ hanging around in the scene until the test case has finished. This can
+ result in interference with future tests; for example, by blocking input
+ events or producing unrelated debug output that makes it difficult to
+ follow the code's execution.
+
+ By calling \l createTemporaryQmlObject() instead, the object is guaranteed
+ to be destroyed at the end of the test function:
+
+ \code
+ TestCase {
+ id: testCase
+ name: "MyTest"
+ when: windowShown
+
+ function test_click() {
+ var item = createTemporaryQmlObject("import QtQuick 2.0; Item {}", testCase);
+ verify(item);
+
+ // Test item...
+
+ // Don't need to worry about destroying "item" here.
+ }
+ }
+ \endcode
+
+ For objects that are created via the \l {Component::}{createObject()} function
+ of \l Component, the \l createTemporaryObject() function can be used.
+
\sa {QtTest::SignalSpy}{SignalSpy}, {Qt Quick Test Reference Documentation}
*/
@@ -221,7 +274,7 @@ Item {
\qmlproperty string TestCase::name
This property defines the name of the test case for result reporting.
- The default is the empty string.
+ The default value is an empty string.
\code
TestCase {
@@ -358,6 +411,8 @@ Item {
/*! \internal */
property var qtest_events: qtest_events_normal
TestEvent { id: qtest_events_normal }
+ /*! \internal */
+ property var qtest_temporaryObjects: []
/*!
\qmlmethod TestCase::fail(message = "")
@@ -461,6 +516,110 @@ Item {
throw new Error("QtQuickTest::fail")
}
+ /*!
+ \since 5.9
+ \qmlmethod object TestCase::createTemporaryQmlObject(string qml, object parent, string filePath)
+
+ This function dynamically creates a QML object from the given \a qml
+ string with the specified \a parent. The returned object will be
+ destroyed (if it was not already) after \l cleanup() has finished
+ executing, meaning that objects created with this function are
+ guaranteed to be destroyed after each test, regardless of whether or
+ not the tests fail.
+
+ If there was an error while creating the object, \c null will be
+ returned.
+
+ If \a filePath is specified, it will be used for error reporting for
+ the created object.
+
+ This function calls
+ \l {QtQml::Qt::createQmlObject()}{Qt.createQmlObject()} internally.
+
+ \sa {Managing Dynamically Created Test Objects}
+ */
+ function createTemporaryQmlObject(qml, parent, filePath) {
+ if (typeof qml !== "string") {
+ qtest_results.fail("First argument must be a string of QML; actual type is " + typeof qml,
+ util.callerFile(), util.callerLine());
+ throw new Error("QtQuickTest::fail");
+ }
+
+ if (!parent || typeof parent !== "object") {
+ qtest_results.fail("Second argument must be a valid parent object; actual type is " + typeof parent,
+ util.callerFile(), util.callerLine());
+ throw new Error("QtQuickTest::fail");
+ }
+
+ if (filePath !== undefined && typeof filePath !== "string") {
+ qtest_results.fail("Third argument must be a file path string; actual type is " + typeof filePath,
+ util.callerFile(), util.callerLine());
+ throw new Error("QtQuickTest::fail");
+ }
+
+ var object = Qt.createQmlObject(qml, parent, filePath);
+ qtest_temporaryObjects.push(object);
+ return object;
+ }
+
+ /*!
+ \since 5.9
+ \qmlmethod object TestCase::createTemporaryObject(Component component, object parent, object properties)
+
+ This function dynamically creates a QML object from the given
+ \a component with the specified \a parent and \a properties.
+ The returned object will be destroyed (if it was not already) after
+ \l cleanup() has finished executing, meaning that objects created with
+ this function are guaranteed to be destroyed after each test,
+ regardless of whether or not the tests fail.
+
+ If there was an error while creating the object, \c null will be
+ returned.
+
+ This function calls
+ \l {QtQml::Component::createObject()}{component.createObject()}
+ internally.
+
+ \sa {Managing Dynamically Created Test Objects}
+ */
+ function createTemporaryObject(component, parent, properties) {
+ if (typeof component !== "object") {
+ qtest_results.fail("First argument must be a Component; actual type is " + typeof component,
+ util.callerFile(), util.callerLine());
+ throw new Error("QtQuickTest::fail");
+ }
+
+ if (!parent && parent !== null) {
+ qtest_results.fail("Second argument must be a parent object or null; actual type is " + typeof parent,
+ util.callerFile(), util.callerLine());
+ throw new Error("QtQuickTest::fail");
+ }
+
+ if (properties && typeof properties !== "object") {
+ qtest_results.fail("Third argument must be an object; actual type is " + typeof properties,
+ util.callerFile(), util.callerLine());
+ throw new Error("QtQuickTest::fail");
+ }
+
+ var object = component.createObject(parent, properties ? properties : ({}));
+ qtest_temporaryObjects.push(object);
+ return object;
+ }
+
+ /*!
+ \internal
+
+ Destroys all temporary objects that still exist.
+ */
+ function qtest_destroyTemporaryObjects() {
+ for (var i = 0; i < qtest_temporaryObjects.length; ++i) {
+ var temporaryObject = qtest_temporaryObjects[i];
+ if (temporaryObject)
+ temporaryObject.destroy();
+ }
+ qtest_temporaryObjects = [];
+ }
+
/*! \internal */
// Determine what is o.
// Discussions and reference: http://philrathe.com/articles/equiv
@@ -835,7 +994,7 @@ Item {
\c{QEXPECT_FAIL(tag, message, Abort)} in C++.
If the test is not data-driven, then \a tag must be set to
- the empty string.
+ an empty string.
\sa expectFailContinue()
*/
@@ -861,7 +1020,7 @@ Item {
\c{QEXPECT_FAIL(tag, message, Continue)} in C++.
If the test is not data-driven, then \a tag must be set to
- the empty string.
+ an empty string.
\sa expectFail()
*/
@@ -1317,6 +1476,109 @@ Item {
qtest_fail("window not shown", 2)
}
+ /*!
+ \qmlmethod TouchEventSequence TestCase::touchEvent(object item)
+
+ \since 5.9
+
+ Begins a sequence of touch events through a simulated QTouchDevice::TouchScreen.
+ Events are delivered to the window containing \a item.
+
+ The returned object is used to enumerate events to be delivered through a single
+ QTouchEvent. Touches are delivered to the window containing the TestCase unless
+ otherwise specified.
+
+ \code
+ Rectangle {
+ width: 640; height: 480
+
+ MultiPointTouchArea {
+ id: area
+ anchors.fill: parent
+
+ property bool touched: false
+
+ onPressed: touched = true
+ }
+
+ TestCase {
+ name: "ItemTests"
+ when: area.pressed
+ id: test1
+
+ function test_touch() {
+ var touch = touchEvent(area);
+ touch.press(0, area, 10, 10);
+ touch.commit();
+ verify(area.touched);
+ }
+ }
+ }
+ \endcode
+
+ \sa TouchEventSequence::press(), TouchEventSequence::move(), TouchEventSequence::release(), TouchEventSequence::stationary(), TouchEventSequence::commit(), QTouchDevice::TouchScreen
+ */
+
+ function touchEvent(item) {
+ if (!item)
+ qtest_fail("No item given to touchEvent", 1)
+
+ return {
+ _defaultItem: item,
+ _sequence: qtest_events.touchEvent(item),
+
+ press: function (id, target, x, y) {
+ if (!target)
+ target = this._defaultItem;
+ if (id === undefined)
+ qtest_fail("No id given to TouchEventSequence::press", 1);
+ if (x === undefined)
+ x = target.width / 2;
+ if (y === undefined)
+ y = target.height / 2;
+ this._sequence.press(id, target, x, y);
+ return this;
+ },
+
+ move: function (id, target, x, y) {
+ if (!target)
+ target = this._defaultItem;
+ if (id === undefined)
+ qtest_fail("No id given to TouchEventSequence::move", 1);
+ if (x === undefined)
+ x = target.width / 2;
+ if (y === undefined)
+ y = target.height / 2;
+ this._sequence.move(id, target, x, y);
+ return this;
+ },
+
+ stationary: function (id) {
+ if (id === undefined)
+ qtest_fail("No id given to TouchEventSequence::stationary", 1);
+ this._sequence.stationary(id);
+ return this;
+ },
+
+ release: function (id, target, x, y) {
+ if (!target)
+ target = this._defaultItem;
+ if (id === undefined)
+ qtest_fail("No id given to TouchEventSequence::release", 1);
+ if (x === undefined)
+ x = target.width / 2;
+ if (y === undefined)
+ y = target.height / 2;
+ this._sequence.release(id, target, x, y);
+ return this;
+ },
+
+ commit: function () {
+ this._sequence.commit();
+ return this;
+ }
+ };
+ }
// Functions that can be overridden in subclasses for init/cleanup duties.
/*!
@@ -1389,6 +1651,7 @@ Item {
qtest_runInternal(prop, arg)
qtest_results.finishTestData()
qtest_runInternal("cleanup")
+ qtest_destroyTemporaryObjects()
qtest_results.finishTestDataCleanup()
// wait(0) will call processEvents() so objects marked for deletion
// in the test function will be deleted.
diff --git a/src/imports/testlib/main.cpp b/src/imports/testlib/main.cpp
index 4e2bd919e9..3c28000e35 100644
--- a/src/imports/testlib/main.cpp
+++ b/src/imports/testlib/main.cpp
@@ -158,6 +158,7 @@ public:
qmlRegisterType<QuickTestResult, 1>(uri,1,1,"TestResult");
qmlRegisterType<QuickTestEvent>(uri,1,0,"TestEvent");
qmlRegisterType<QuickTestUtil>(uri,1,0,"TestUtil");
+ qmlRegisterType<QQuickTouchEventSequence>();
}
};
diff --git a/src/imports/testlib/qmldir b/src/imports/testlib/qmldir
index 9da8ebb4be..e5757f6a88 100644
--- a/src/imports/testlib/qmldir
+++ b/src/imports/testlib/qmldir
@@ -3,4 +3,5 @@ plugin qmltestplugin
classname QTestQmlModule
typeinfo plugins.qmltypes
TestCase 1.0 TestCase.qml
+TestCase 1.2 TestCase.qml
SignalSpy 1.0 SignalSpy.qml
diff --git a/src/imports/testlib/toucheventsequence.qdoc b/src/imports/testlib/toucheventsequence.qdoc
new file mode 100644
index 0000000000..f85a1cd4f9
--- /dev/null
+++ b/src/imports/testlib/toucheventsequence.qdoc
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Jeremy Katz
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: http://www.gnu.org/copyleft/fdl.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \qmltype TouchEventSequence
+ \inqmlmodule QtTest
+ \ingroup qtquicktest
+ \brief TouchEventSequence is used to build and dispatch touch events
+ for testing.
+
+ \since 5.9
+
+ A TouchEventSequence is created by calling \l [QML] {TestCase::touchEvent()}{TestCase.touchEvent()}.
+ The type can not be directly instantiated. Each method provided by the type returns
+ the same object, allowing chained calls.
+
+ For example:
+ \code
+ touchEvent(item).press(0).commit();
+ \endcode
+ is equivalent to:
+ \code
+ var sequence = touchEvent(item);
+ sequence.press(0);
+ sequence.commit();
+ \endcode
+
+ Events are delivered to the window which contains the item specified in touchEvent.
+
+ \sa TestCase::touchEvent(), QTest::QTouchEventSequence
+*/
+
+/*!
+ \qmlmethod TouchEventSequence TouchEventSequence::press(int touchId, object item, real x = item.width / 2, real y = item.height / 2)
+
+ Creates a new point identified as \a touchId, at the point indicated by \a x and \a y relative to \a item.
+ Further use of the same touch point should maintain the same touchId.
+
+ Item defaults to the value provided via touchEvent().
+ X and y default to the midpoint of the item.
+*/
+
+/*!
+ \qmlmethod TouchEventSequence TouchEventSequence::move(int touchId, object item, real x = item.width / 2, real y = item.height / 2)
+
+ Moves \a touchId to the point indicated by \a x and \a y relative to \a item.
+
+ Item defaults to the value provided via touchEvent().
+ X and y default to the midpoint of the item.
+*/
+
+/*!
+ \qmlmethod TouchEventSequence TouchEventSequence::release(int touchId, object item, real x = item.width / 2, real y = item.height / 2)
+
+ Removes \a touchId at the point indicated by \a x and \a y relative to \a item.
+
+ Item defaults to the value provided via touchEvent().
+ X and y default to the midpoint of the item.
+*/
+
+/*!
+ \qmlmethod TouchEventSequence TouchEventSequence::stationary(int touchId)
+
+ Indicates that \a touchId is present but otherwise unchanged from prior events.
+*/
+
+/*!
+ \qmlmethod TouchEventSequence TouchEventSequence::commit()
+
+ Sends the touch event composed by prior use of press(), move(), release(), and stationary().
+ Following commit's return, the TouchEventSequence can be used to compose a new event.
+
+ \code
+ var sequence = touchEvent(target);
+ // Touch the middle of target with 1 point
+ sequence.press(1);
+ sequence.commit();
+
+ // Begin a new event
+ // Move the point to target's upper left corner
+ sequence.move(1, target, 0, 0);
+ sequence.commit();
+ \endcode
+
+ Commit is automatically invoked when the TouchEventSequence object is destroyed.
+*/
diff --git a/src/imports/window/plugins.qmltypes b/src/imports/window/plugins.qmltypes
index 6a8dbfa024..a79bd8c332 100644
--- a/src/imports/window/plugins.qmltypes
+++ b/src/imports/window/plugins.qmltypes
@@ -55,8 +55,12 @@ Module {
name: "QQuickWindow"
defaultProperty: "data"
prototype: "QWindow"
- exports: ["QtQuick.Window/Window 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtQuick.Window/Window 2.0",
+ "QtQuick.Window/Window 2.1",
+ "QtQuick.Window/Window 2.2"
+ ]
+ exportMetaObjectRevisions: [0, 1, 2]
Enum {
name: "SceneGraphError"
values: {