aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMorten Johan Sørvig <morten.sorvig@qt.io>2018-05-11 10:24:18 +0200
committerMorten Johan Sørvig <morten.sorvig@qt.io>2018-05-11 11:13:04 +0200
commit809d305f938177cfb8488dc7fbfc28bc8eef9d20 (patch)
treed43688a9a3ef61af95c91bae3de8b00e6466c817
parentb742bf9415b42c6e34fab91d2f407eb23dc8e0da (diff)
parent1e82f11629e5572783e5bfc36f24ad10c235ca53 (diff)
Merge remote-tracking branch 'origin/5.11.0' into wip/webassembly
-rw-r--r--.gitmodules1
-rw-r--r--dist/changes-5.11.0167
-rw-r--r--examples/qml/referenceexamples/properties/birthdayparty.cpp2
-rw-r--r--src/3rdparty/masm/yarr/YarrInterpreter.cpp1
-rw-r--r--src/imports/builtins/builtins.qmltypes39
-rw-r--r--src/imports/layouts/layouts.pro2
-rw-r--r--src/imports/layouts/plugin.cpp3
-rw-r--r--src/imports/localstorage/localstorage.pro2
-rw-r--r--src/imports/localstorage/plugin.cpp5
-rw-r--r--src/imports/localstorage/plugins.qmltypes2
-rw-r--r--src/imports/models/models.pro2
-rw-r--r--src/imports/models/plugin.cpp8
-rw-r--r--src/imports/models/plugins.qmltypes11
-rw-r--r--src/imports/particles/particles.pro2
-rw-r--r--src/imports/particles/plugin.cpp4
-rw-r--r--src/imports/qtqml/qtqml.pro2
-rw-r--r--src/imports/qtquick2/plugins.qmltypes46
-rw-r--r--src/imports/qtquick2/qtquick2.pro2
-rw-r--r--src/imports/shapes/qquickshapegenericrenderer.cpp1
-rw-r--r--src/imports/statemachine/plugin.cpp3
-rw-r--r--src/imports/statemachine/plugins.qmltypes2
-rw-r--r--src/imports/statemachine/signaltransition.cpp7
-rw-r--r--src/imports/statemachine/statemachine.pro2
-rw-r--r--src/imports/testlib/main.cpp3
-rw-r--r--src/imports/testlib/testlib.pro2
-rw-r--r--src/imports/window/plugin.cpp7
-rw-r--r--src/imports/window/window.pro2
-rw-r--r--src/imports/xmllistmodel/plugin.cpp3
-rw-r--r--src/imports/xmllistmodel/qqmlxmllistmodel.cpp4
-rw-r--r--src/imports/xmllistmodel/xmllistmodel.pro2
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp3
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp10
-rw-r--r--src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp10
-rw-r--r--src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp15
-rw-r--r--src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.h3
-rw-r--r--src/qml/compiler/compiler.pri2
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp10
-rw-r--r--src/qml/compiler/qqmlpropertyvalidator.cpp2
-rw-r--r--src/qml/compiler/qv4bytecodegenerator_p.h19
-rw-r--r--src/qml/compiler/qv4codegen.cpp22
-rw-r--r--src/qml/compiler/qv4codegen_p.h2
-rw-r--r--src/qml/compiler/qv4compilationunitmapper.cpp32
-rw-r--r--src/qml/compiler/qv4compilationunitmapper_p.h2
-rw-r--r--src/qml/compiler/qv4compilationunitmapper_unix.cpp2
-rw-r--r--src/qml/compiler/qv4compilationunitmapper_win.cpp2
-rw-r--r--src/qml/compiler/qv4compileddata.cpp83
-rw-r--r--src/qml/compiler/qv4compileddata_p.h10
-rw-r--r--src/qml/compiler/qv4compiler.cpp8
-rw-r--r--src/qml/compiler/qv4compilercontext.cpp2
-rw-r--r--src/qml/compiler/qv4compilercontext_p.h44
-rw-r--r--src/qml/compiler/qv4compilerscanfunctions.cpp49
-rw-r--r--src/qml/compiler/qv4compilerscanfunctions_p.h7
-rw-r--r--src/qml/compiler/qv4instr_moth.cpp4
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h6
-rw-r--r--src/qml/configure.json9
-rw-r--r--src/qml/debugger/qqmlprofiler_p.h2
-rw-r--r--src/qml/doc/images/cpp-qml-integration-flowchart.odgbin0 -> 16080 bytes
-rw-r--r--src/qml/doc/images/cpp-qml-integration-flowchart.pngbin0 -> 113781 bytes
-rw-r--r--src/qml/doc/src/cppintegration/definetypes.qdoc2
-rw-r--r--src/qml/doc/src/cppintegration/interactqmlfromcpp.qdoc19
-rw-r--r--src/qml/doc/src/cppintegration/topic.qdoc6
-rw-r--r--src/qml/doc/src/external-resources.qdoc28
-rw-r--r--src/qml/doc/src/javascript/hostenvironment.qdoc18
-rw-r--r--src/qml/doc/src/qmlfunctions.qdoc85
-rw-r--r--src/qml/doc/src/qmltypereference.qdoc8
-rw-r--r--src/qml/doc/src/qtqml.qdoc2
-rw-r--r--src/qml/doc/src/statemachine.qdoc2
-rw-r--r--src/qml/jit/qv4assembler.cpp51
-rw-r--r--src/qml/jit/qv4jit.cpp11
-rw-r--r--src/qml/jit/qv4jit_p.h1
-rw-r--r--src/qml/jsruntime/qv4arraybuffer.cpp3
-rw-r--r--src/qml/jsruntime/qv4arraydata.cpp9
-rw-r--r--src/qml/jsruntime/qv4arraydata_p.h8
-rw-r--r--src/qml/jsruntime/qv4engine.cpp21
-rw-r--r--src/qml/jsruntime/qv4engine_p.h1
-rw-r--r--src/qml/jsruntime/qv4function_p.h7
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp49
-rw-r--r--src/qml/jsruntime/qv4functionobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4global_p.h5
-rw-r--r--src/qml/jsruntime/qv4include.cpp10
-rw-r--r--src/qml/jsruntime/qv4include_p.h3
-rw-r--r--src/qml/jsruntime/qv4jsonobject.cpp8
-rw-r--r--src/qml/jsruntime/qv4object.cpp4
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp5
-rw-r--r--src/qml/jsruntime/qv4regexp.cpp2
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp11
-rw-r--r--src/qml/jsruntime/qv4runtimeapi_p.h1
-rw-r--r--src/qml/jsruntime/qv4script.cpp30
-rw-r--r--src/qml/jsruntime/qv4script_p.h4
-rw-r--r--src/qml/jsruntime/qv4value_p.h2
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp4
-rw-r--r--src/qml/memory/qv4mmdefs_p.h28
-rw-r--r--src/qml/qml.pro3
-rw-r--r--src/qml/qml/ftw/qqmlthread.cpp6
-rw-r--r--src/qml/qml/ftw/qqmlthread_p.h2
-rw-r--r--src/qml/qml/qqmlbinding.cpp62
-rw-r--r--src/qml/qml/qqmlbinding_p.h15
-rw-r--r--src/qml/qml/qqmlboundsignal.cpp12
-rw-r--r--src/qml/qml/qqmlcomponent.cpp3
-rw-r--r--src/qml/qml/qqmlcontext.cpp8
-rw-r--r--src/qml/qml/qqmlcontext_p.h1
-rw-r--r--src/qml/qml/qqmldata_p.h57
-rw-r--r--src/qml/qml/qqmldirparser_p.h2
-rw-r--r--src/qml/qml/qqmlengine.cpp104
-rw-r--r--src/qml/qml/qqmlengine_p.h2
-rw-r--r--src/qml/qml/qqmlexpression.cpp5
-rw-r--r--src/qml/qml/qqmlimport.cpp62
-rw-r--r--src/qml/qml/qqmlimport_p.h2
-rw-r--r--src/qml/qml/qqmlincubator.cpp12
-rw-r--r--src/qml/qml/qqmljavascriptexpression.cpp28
-rw-r--r--src/qml/qml/qqmljavascriptexpression_p.h20
-rw-r--r--src/qml/qml/qqmlmetatype.cpp35
-rw-r--r--src/qml/qml/qqmlmetatype_p.h12
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp147
-rw-r--r--src/qml/qml/qqmlobjectcreator_p.h3
-rw-r--r--src/qml/qml/qqmlproperty.cpp1
-rw-r--r--src/qml/qml/qqmlpropertycache_p.h19
-rw-r--r--src/qml/qml/qqmltypeloader.cpp109
-rw-r--r--src/qml/qml/qqmltypeloader_p.h19
-rw-r--r--src/qml/qml/qqmltypewrapper.cpp1
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper.cpp8
-rw-r--r--src/qml/qml/qqmlxmlhttprequest.cpp62
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions.cpp9
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions_p.h8
-rw-r--r--src/qml/types/qqmlconnections.cpp7
-rw-r--r--src/qml/types/qqmldelegatemodel_p.h2
-rw-r--r--src/qml/types/qqmldelegatemodel_p_p.h2
-rw-r--r--src/qml/types/qqmlinstantiator.cpp27
-rw-r--r--src/qml/types/qqmlinstantiator_p_p.h4
-rw-r--r--src/qml/types/qqmllistmodel.cpp23
-rw-r--r--src/qml/types/qqmlmodelsmodule.cpp4
-rw-r--r--src/qml/types/qquickworkerscript.cpp6
-rw-r--r--src/qml/types/types.pri12
-rw-r--r--src/qml/util/qqmladaptormodel_p.h2
-rw-r--r--src/qml/util/util.pri10
-rw-r--r--src/qmltest/doc/src/qtquicktest-index.qdoc9
-rw-r--r--src/qmltest/qtestoptions_p.h2
-rw-r--r--src/quick/configure.json8
-rw-r--r--src/quick/designer/qquickdesignercustomobjectdata.cpp12
-rw-r--r--src/quick/designer/qquickdesignersupportitems.cpp13
-rw-r--r--src/quick/designer/qquickdesignersupportproperties.cpp11
-rw-r--r--src/quick/doc/QtQuickDoc2
-rw-r--r--src/quick/doc/images/qtquickcontrols2-gallery-welcome.pngbin0 -> 20138 bytes
-rw-r--r--src/quick/doc/qtquick.qdocconf4
-rw-r--r--src/quick/doc/snippets/qml/image-ext.qml68
-rw-r--r--src/quick/doc/src/concepts/effects/particles.qdoc6
-rw-r--r--src/quick/doc/src/concepts/effects/sprites.qdoc60
-rw-r--r--src/quick/doc/src/concepts/layouts/qtquicklayouts-index.qdoc9
-rw-r--r--src/quick/doc/src/concepts/layouts/qtquicklayouts-overview.qdoc2
-rw-r--r--src/quick/doc/src/concepts/layouts/qtquicklayouts.qdoc4
-rw-r--r--src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc428
-rw-r--r--src/quick/doc/src/guidelines/qtquick-toolsnutilities.qdoc113
-rw-r--r--src/quick/doc/src/qmltypereference.qdoc10
-rw-r--r--src/quick/doc/src/qtquick.qdoc1
-rw-r--r--src/quick/handlers/qquickpointerhandler.cpp10
-rw-r--r--src/quick/handlers/qquickpointerhandler_p.h8
-rw-r--r--src/quick/items/qquickanimatedsprite.cpp32
-rw-r--r--src/quick/items/qquickevents_p_p.h1
-rw-r--r--src/quick/items/qquickflickable.cpp10
-rw-r--r--src/quick/items/qquickimage.cpp46
-rw-r--r--src/quick/items/qquickitemgrabresult.cpp2
-rw-r--r--src/quick/items/qquickloader.cpp9
-rw-r--r--src/quick/items/qquicksprite.cpp4
-rw-r--r--src/quick/items/qquickspritesequence.cpp24
-rw-r--r--src/quick/items/qquicktext.cpp4
-rw-r--r--src/quick/items/qquickwindow.cpp12
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode.cpp14
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode_p.h1
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarelayer.cpp4
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer.cpp2
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp2
-rw-r--r--src/quick/scenegraph/qsgdefaultglyphnode_p.cpp4
-rw-r--r--src/quick/scenegraph/qsgrenderloop.cpp5
-rw-r--r--src/quick/util/qquickimageprovider.cpp9
-rw-r--r--src/quickwidgets/qquickwidget.cpp22
-rw-r--r--src/quickwidgets/qquickwidget.h1
-rw-r--r--tests/auto/cmake/CMakeLists.txt1
-rw-r--r--tests/auto/cmake/qtquickcompiler/CMakeLists.txt7
-rw-r--r--tests/auto/cmake/qtquickcompiler/main.cpp29
-rw-r--r--tests/auto/cmake/qtquickcompiler/resources with space/main.qml (renamed from tests/auto/cmake/qtquickcompiler/main.qml)2
-rw-r--r--tests/auto/cmake/qtquickcompiler/resources with space/qqc_test.qrc (renamed from tests/auto/cmake/qtquickcompiler/qqc_test.qrc)2
-rw-r--r--tests/auto/qml/debugger/qqmldebuggingenabler/qqmldebuggingenabler/tst_qqmldebuggingenabler.cpp12
-rw-r--r--tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp24
-rw-r--r--tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp52
-rw-r--r--tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp32
m---------tests/auto/qml/ecmascripttests/test2620
-rw-r--r--tests/auto/qml/qjsengine/tst_qjsengine.cpp31
-rw-r--r--tests/auto/qml/qml.pro1
-rw-r--r--tests/auto/qml/qmlcachegen/qmlcachegen.pro4
-rw-r--r--tests/auto/qml/qmlcachegen/trickypaths.qml4
-rw-r--r--tests/auto/qml/qmlcachegen/trickypaths.qrc5
-rw-r--r--tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp124
-rw-r--r--tests/auto/qml/qmlcachegen/versionchecks.qml4
-rw-r--r--tests/auto/qml/qqmlecmascript/data/bindingBoundFunctions.qml34
-rw-r--r--tests/auto/qml/qqmlecmascript/data/include_callback.js2
-rw-r--r--tests/auto/qml/qqmlecmascript/data/sequenceConversion.array.qml14
-rw-r--r--tests/auto/qml/qqmlecmascript/data/signalHandlers.qml13
-rw-r--r--tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp71
-rw-r--r--tests/auto/qml/qqmlexpression/tst_qqmlexpression.cpp6
-rw-r--r--tests/auto/qml/qqmllanguage/data/alias.16.qml15
-rw-r--r--tests/auto/qml/qqmllanguage/data/assignLiteralToJSValue.qml1
-rw-r--r--tests/auto/qml/qqmllanguage/data/empty.errors.txt3
-rw-r--r--tests/auto/qml/qqmllanguage/data/lib/org/qtproject/MixedModule/SingletonType.qml3
-rw-r--r--tests/auto/qml/qqmllanguage/data/noDoubleEvaluationForFlushedBindings.2.qml9
-rw-r--r--tests/auto/qml/qqmllanguage/data/noDoubleEvaluationForFlushedBindings.qml9
-rw-r--r--tests/auto/qml/qqmllanguage/data/usingTypeWithEnum.qml2
-rw-r--r--tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp524
-rw-r--r--tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp22
-rw-r--r--tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp29
-rw-r--r--tests/auto/qml/qqmlxmlhttprequest/data/noqmlcontext.js11
-rw-r--r--tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp26
-rw-r--r--tests/auto/qml/qv4assembler/qv4assembler.pro7
-rw-r--r--tests/auto/qml/qv4assembler/tst_qv4assembler.cpp91
-rw-r--r--tests/auto/qmltest/statemachine/tst_triggeredArguments2.qml1
-rw-r--r--tests/auto/quick/examples/tst_examples.cpp1
-rw-r--r--tests/auto/quick/qquickimage/tst_qquickimage.cpp6
-rw-r--r--tests/auto/quick/qquickitem/BLACKLIST2
-rw-r--r--tests/auto/quick/qquickloader/data/rootContext.qml55
-rw-r--r--tests/auto/quick/qquickloader/tst_qquickloader.cpp61
-rw-r--r--tests/auto/quick/qquicktext/data/elideParentChanged.qml13
-rw-r--r--tests/auto/quick/qquicktext/tst_qquicktext.cpp41
-rw-r--r--tests/auto/quickwidgets/qquickwidget/data/activeFocusOnTab.qml60
-rw-r--r--tests/auto/quickwidgets/qquickwidget/data/noActiveFocusOnTab.qml57
-rw-r--r--tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp40
-rw-r--r--tests/manual/imagehandler/embeddedimage.svg10
-rw-r--r--tests/manual/imagehandler/heart.pngbin0 -> 15194 bytes
-rw-r--r--tests/manual/imagehandler/main.qml6
-rw-r--r--tools/qmlcachegen/Qt5QuickCompilerConfig.cmake2
-rw-r--r--tools/qmlcachegen/generateloader.cpp15
-rw-r--r--tools/qmlcachegen/qtquickcompiler.prf14
230 files changed, 3580 insertions, 1105 deletions
diff --git a/.gitmodules b/.gitmodules
index c9561f396d..e6e5650150 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,4 @@
[submodule "tests/auto/qml/ecmascripttests/test262"]
path = tests/auto/qml/ecmascripttests/test262
url = ../qtdeclarative-testsuites.git
+ branch = snapshot-20150317-8f6a508-based
diff --git a/dist/changes-5.11.0 b/dist/changes-5.11.0
new file mode 100644
index 0000000000..f7afe87eb7
--- /dev/null
+++ b/dist/changes-5.11.0
@@ -0,0 +1,167 @@
+Qt 5.11 introduces many new features and improvements as well as bugfixes
+over the 5.10.x series. For more details, refer to the online documentation
+included in this distribution. The documentation is also available online:
+
+http://doc.qt.io/qt-5/index.html
+
+The Qt version 5.11 series is binary compatible with the 5.10.x series.
+Applications compiled for 5.10 will continue to run with 5.11.
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+****************************************************************************
+* Important Behavior Changes *
+****************************************************************************
+
+* QML module plugins used to be limited to type registrations in the
+ primary module namespace in the virtual registerTypes() function.
+ Module authors worked around this limitation by placing necessary
+ internal type registrations into initializeEngine() that may cause
+ memory leaks. Therefore this restriction has been moved and types in
+ any (non-protected) namespaces can be registered in the
+ registerTypes() function.
+
+* In Qt 5.11 and newer versions, QML plugin modules are available with
+ the same minor version as the Qt release minor version number. For
+ example it's possible to import QtQuick.Window 2.11 or import
+ QtQuick.Layouts 1.11 even though there haven't been any API changes in
+ these modules for Qt 5.11, and the maximum possible import version
+ will automatically increment in future Qt versions. This is intended
+ to reduce confusion.
+
+****************************************************************************
+* Library *
+****************************************************************************
+
+QtQml
+-----
+
+ - Qt Qml uses a completely new compiler pipeline to compile Javascript (and QML) first
+ into bytecode and then JIT heavily used functions into assembly.
+ * Lots of cleanups and performance improvement to the way function calls and Javascript
+ scopes are being handled.
+ * Improved performance of JS property lookups.
+ * A new bytecode format that is very compact, saving memory in many cases.
+ * significantly faster bytecode interpreter than in earlier versions of Qt, in many cases
+ reaching almost the performance of the old JIT.
+ * A new JIT that works on top of the bytecode interpreter and only compiles hot functions
+ into assembly.
+ * Overall test results show almost a doubling of the JS performance on platforms where we
+ can't use a JIT (iOS and WinRT) compared to 5.10.
+ * With the new JIT, JS performance is usually around 10-40% faster than in older Qt versions
+ (depending on the use case).
+
+ - The commercial only Qt Quick Compiler has been removed and replaced with a common solution
+ that works in both the open source and commercial version of Qt. No code changes are needed
+ for users of the old compiler.
+
+ - Fix qmlplugindump to work correctly with shadow builds.
+
+ - Fixed creation of QWidgets in QML.
+
+ - Various fixes to the debugging bridge.
+
+ - ListModel
+ * Support assignment of function declarations in ListElement, to allow for
+ models with actions.
+
+QtQuick
+-------
+
+ - QQuickWindow:
+ * [QTBUG-66329] We no longer synthesize redundant mouse events based on
+ touch events that come from a trackpad which can generate mouse events.
+
+ - Item:
+ * [QTBUG-20524] Added a containmentMask property. This allows any
+ QObject which defines Q_INVOKABLE bool contains(const QPointF &point)
+ (including a Shape) to mask the area of an Item that will be
+ sensitive to mouse and touch events.
+
+ - AnimatedSprite:
+ * [QTBUG-36341] AnimatedSprite's implicitWidth and implicitHeight are
+ now based on frameWidth and frameHeight, respectively. This means it
+ is no longer necessary to explicitly size AnimatedSprite.
+
+ - Image:
+ * [QTBUG-66127] Support detection of suitable file extension.
+ * Add support for ktx files containing compressed textures.
+ * Add experimental automatic atlasing of ETC-compressed
+ textures (can be enabled with QSG_ENABLE_COMPRESSED_ATLAS=1).
+ * [QTBUG-67019] SVG images are now scaled up if the source size is larger
+ than the original size.
+ * [QTBUG-65789] SVG images are rendered with the correct aspect ratio
+ when width or height is set to zero.
+
+ - AnimatedImage:
+ * Added a speed property. It's also OK to set it to 0 to pause
+ the animation.
+ * There is now an example to demonstrate usage of AnimatedImage.
+ * [QTBUG-62913] frameCount now has a NOTIFY signal to avoid binding warnings.
+
+ - Path:
+ * [QTBUG-62684] Add new PathAngleArc type.
+
+ - Shape:
+ * A containsMode property is added. If it is set to FillContains, then
+ Shape.contains() returns true only within the visible bounds, so its
+ Pointer Handlers also respond only within those bounds.
+
+ - ShapePath:
+ * Improved performance for complex paths.
+
+ - Text:
+ * [QTBUG-60328][QTBUG-67145] Fixed Text with ElideRight not being rendered
+ when reparented.
+ * [QTBUG-67007] Fixed non-integer scale factors with Text native rendering.
+
+ - Pointer Handlers:
+ * Added singleTapped and doubleTapped convenience signals to TapHandler.
+ * PointerHandlers implement QQmlParserStatus, so that subclasses can
+ have custom initialization in componentComplete() (just as Items can).
+ * [QTBUG-65651] Restore 5.9 behavior: if an Item has no PointerHandlers,
+ childMouseEventFilter() will not be called during post-delivery of
+ an unhandled event.
+ * TapHandler.gesturePolicy is now DragThreshold by default.
+ * DragHandler with target: null no longer crashes.
+ * [QTBUG-64852] DragHandler enforces its axis constraints even when
+ the parent coordinate system changes during the drag. For example
+ the knob of a DragHandler-based slider inside a Flickable doesn't
+ come out of its "groove" if you manage to drag the slider and the
+ Flickable at the same time.
+
+ - Loader:
+ * [QTBUG-63729] Avoid evaluating bindings during destruction, to
+ avoid some spurious errors.
+ * [QTBUG-66822] When deactivating a loader, do not immediately clear
+ its context.
+
+ - Software renderer
+ * [QTBUG-63185][QTBUG-65975] QSGLayer::grab now works correctly.
+ * [QTBUG-66381] Fixed a crash when a Window has a QObject parent
+ (such as Loader).
+ * [QTBUG-65934] Fixed renering of rounded rectangles with floating point
+ pixel device ratios.
+
+ - Platform Specific Changes:
+ * [QTBUG-67460] Fixed a problem with jumping back to the highlight
+ while slowly scrolling a ListView on macOS.
+
+QtQuickTest
+-----------
+
+ - [QTBUG-50064] Added QUICK_TEST_MAIN_WITH_SETUP macro to allow executing
+ C++ before a QML test (such as registering context properties).
+
+QQuickWidget
+------------
+
+ - [QTBUG-45641] Tab presses are now passed on to the root item to be
+ handled first. When not handled by the root item, it will be handled
+ like a standard QWidget.
diff --git a/examples/qml/referenceexamples/properties/birthdayparty.cpp b/examples/qml/referenceexamples/properties/birthdayparty.cpp
index 8a5e9e553e..717c3e0f71 100644
--- a/examples/qml/referenceexamples/properties/birthdayparty.cpp
+++ b/examples/qml/referenceexamples/properties/birthdayparty.cpp
@@ -90,7 +90,7 @@ Person *BirthdayParty::guest(int index) const
}
void BirthdayParty::clearGuests() {
- return m_guests.clear();
+ m_guests.clear();
}
// ![0]
diff --git a/src/3rdparty/masm/yarr/YarrInterpreter.cpp b/src/3rdparty/masm/yarr/YarrInterpreter.cpp
index 4a789f6f28..16fc183cad 100644
--- a/src/3rdparty/masm/yarr/YarrInterpreter.cpp
+++ b/src/3rdparty/masm/yarr/YarrInterpreter.cpp
@@ -731,6 +731,7 @@ public:
context->term -= term.atom.parenthesesWidth;
return false;
}
+ Q_FALLTHROUGH();
case QuantifierNonGreedy:
if (backTrack->begin == notFound) {
backTrack->begin = input.getPos();
diff --git a/src/imports/builtins/builtins.qmltypes b/src/imports/builtins/builtins.qmltypes
index 5fb68d15d9..53c5300685 100644
--- a/src/imports/builtins/builtins.qmltypes
+++ b/src/imports/builtins/builtins.qmltypes
@@ -4,7 +4,7 @@ import QtQuick.tooling 1.2
// It is used for QML tooling purposes only.
//
// This file was auto-generated by:
-// 'qmlplugindump -nonrelocatable -builtins'
+// 'qmlplugindump -builtins'
Module {
dependencies: []
@@ -427,7 +427,8 @@ Module {
"WA_MacNoShadow": 127,
"WA_AlwaysStackOnTop": 128,
"WA_TabletTracking": 129,
- "WA_AttributeCount": 130
+ "WA_ContentsMarginsRespectsSafeArea": 130,
+ "WA_AttributeCount": 131
}
}
Enum {
@@ -760,6 +761,36 @@ Module {
"Key_Dead_Belowdot": 16781920,
"Key_Dead_Hook": 16781921,
"Key_Dead_Horn": 16781922,
+ "Key_Dead_Stroke": 16781923,
+ "Key_Dead_Abovecomma": 16781924,
+ "Key_Dead_Abovereversedcomma": 16781925,
+ "Key_Dead_Doublegrave": 16781926,
+ "Key_Dead_Belowring": 16781927,
+ "Key_Dead_Belowmacron": 16781928,
+ "Key_Dead_Belowcircumflex": 16781929,
+ "Key_Dead_Belowtilde": 16781930,
+ "Key_Dead_Belowbreve": 16781931,
+ "Key_Dead_Belowdiaeresis": 16781932,
+ "Key_Dead_Invertedbreve": 16781933,
+ "Key_Dead_Belowcomma": 16781934,
+ "Key_Dead_Currency": 16781935,
+ "Key_Dead_a": 16781952,
+ "Key_Dead_A": 16781953,
+ "Key_Dead_e": 16781954,
+ "Key_Dead_E": 16781955,
+ "Key_Dead_i": 16781956,
+ "Key_Dead_I": 16781957,
+ "Key_Dead_o": 16781958,
+ "Key_Dead_O": 16781959,
+ "Key_Dead_u": 16781960,
+ "Key_Dead_U": 16781961,
+ "Key_Dead_Small_Schwa": 16781962,
+ "Key_Dead_Capital_Schwa": 16781963,
+ "Key_Dead_Greek": 16781964,
+ "Key_Dead_Lowline": 16781968,
+ "Key_Dead_Aboveverticalline": 16781969,
+ "Key_Dead_Belowverticalline": 16781970,
+ "Key_Dead_Longsolidusoverlay": 16781971,
"Key_Back": 16777313,
"Key_Forward": 16777314,
"Key_Stop": 16777315,
@@ -1348,6 +1379,8 @@ Module {
"ImhTime": 256,
"ImhPreferLatin": 512,
"ImhMultiLine": 1024,
+ "ImhNoEditMenu": 2048,
+ "ImhNoTextHandles": 4096,
"ImhDigitsOnly": 65536,
"ImhFormattedNumbersOnly": 131072,
"ImhUppercaseOnly": 262144,
@@ -1374,6 +1407,8 @@ Module {
"ImhTime": 256,
"ImhPreferLatin": 512,
"ImhMultiLine": 1024,
+ "ImhNoEditMenu": 2048,
+ "ImhNoTextHandles": 4096,
"ImhDigitsOnly": 65536,
"ImhFormattedNumbersOnly": 131072,
"ImhUppercaseOnly": 262144,
diff --git a/src/imports/layouts/layouts.pro b/src/imports/layouts/layouts.pro
index 26574150de..addf396746 100644
--- a/src/imports/layouts/layouts.pro
+++ b/src/imports/layouts/layouts.pro
@@ -1,7 +1,7 @@
CXX_MODULE = qml
TARGET = qquicklayoutsplugin
TARGETPATH = QtQuick/Layouts
-IMPORT_VERSION = 1.2
+IMPORT_VERSION = 1.$$QT_MINOR_VERSION
QT *= qml-private quick-private gui-private core-private
diff --git a/src/imports/layouts/plugin.cpp b/src/imports/layouts/plugin.cpp
index 25d5bacc90..c805c9fb43 100644
--- a/src/imports/layouts/plugin.cpp
+++ b/src/imports/layouts/plugin.cpp
@@ -75,6 +75,9 @@ public:
qmlRegisterUncreatableType<QQuickLayout>(uri, 1, 2, "Layout",
QStringLiteral("Do not create objects of type Layout"));
qmlRegisterRevision<QQuickGridLayoutBase, 1>(uri, 1, 1);
+
+ // Auto-increment the import to stay in sync with ALL future QtQuick minor versions from 5.11 onward
+ qmlRegisterModule(uri, 1, QT_VERSION_MINOR);
}
};
//![class decl]
diff --git a/src/imports/localstorage/localstorage.pro b/src/imports/localstorage/localstorage.pro
index 15753263b8..2fc976d37d 100644
--- a/src/imports/localstorage/localstorage.pro
+++ b/src/imports/localstorage/localstorage.pro
@@ -1,7 +1,7 @@
CXX_MODULE = qml
TARGET = qmllocalstorageplugin
TARGETPATH = QtQuick/LocalStorage
-IMPORT_VERSION = 2.0
+IMPORT_VERSION = 2.$${QT_MINOR_VERSION}
QT = sql qml-private core-private
diff --git a/src/imports/localstorage/plugin.cpp b/src/imports/localstorage/plugin.cpp
index 88121df66c..9cca11ac5d 100644
--- a/src/imports/localstorage/plugin.cpp
+++ b/src/imports/localstorage/plugin.cpp
@@ -523,7 +523,7 @@ through the data.
/*!
- \qmlmodule QtQuick.LocalStorage 2
+ \qmlmodule QtQuick.LocalStorage 2.11
\title Qt Quick Local Storage QML Types
\ingroup qmlmodules
\brief Provides a JavaScript object singleton type for accessing a local
@@ -820,6 +820,9 @@ public:
{
Q_ASSERT(QLatin1String(uri) == QLatin1String("QtQuick.LocalStorage"));
qmlRegisterSingletonType<QQuickLocalStorage>(uri, 2, 0, "LocalStorage", module_api_factory);
+
+ // Auto-increment the import to stay in sync with ALL future QtQuick minor versions from 5.11 onward
+ qmlRegisterModule(uri, 2, QT_VERSION_MINOR);
}
};
diff --git a/src/imports/localstorage/plugins.qmltypes b/src/imports/localstorage/plugins.qmltypes
index dee81a78d0..412989c001 100644
--- a/src/imports/localstorage/plugins.qmltypes
+++ b/src/imports/localstorage/plugins.qmltypes
@@ -4,7 +4,7 @@ import QtQuick.tooling 1.2
// It is used for QML tooling purposes only.
//
// This file was auto-generated by:
-// 'qmlplugindump -nonrelocatable -noforceqtquick QtQuick.LocalStorage 2.0'
+// 'qmlplugindump -nonrelocatable QtQuick.LocalStorage 2.11'
Module {
dependencies: []
diff --git a/src/imports/models/models.pro b/src/imports/models/models.pro
index c94ba833ad..fc87533cea 100644
--- a/src/imports/models/models.pro
+++ b/src/imports/models/models.pro
@@ -1,7 +1,7 @@
CXX_MODULE = qml
TARGET = modelsplugin
TARGETPATH = QtQml/Models.2
-IMPORT_VERSION = 2.3
+IMPORT_VERSION = 2.$$QT_MINOR_VERSION
SOURCES += \
plugin.cpp
diff --git a/src/imports/models/plugin.cpp b/src/imports/models/plugin.cpp
index 2f8a9713d2..83f8597408 100644
--- a/src/imports/models/plugin.cpp
+++ b/src/imports/models/plugin.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include <QtQml/qqmlextensionplugin.h>
+#include <QtQml/qqml.h>
#include <private/qqmlmodelsmodule_p.h>
@@ -51,7 +52,7 @@ static void initResources()
QT_BEGIN_NAMESPACE
/*!
- \qmlmodule QtQml.Models 2.2
+ \qmlmodule QtQml.Models 2.11
\title Qt QML Models QML Types
\ingroup qmlmodules
\brief Provides QML types for data models
@@ -62,7 +63,7 @@ QT_BEGIN_NAMESPACE
To use the types in this module, import the module with the following line:
\code
- import QtQml.Models 2.2
+ import QtQml.Models 2.11
\endcode
Note that QtQml.Models module started at version 2.1 to match the version
@@ -83,6 +84,9 @@ public:
Q_ASSERT(QLatin1String(uri) == QLatin1String("QtQml.Models"));
Q_UNUSED(uri);
QQmlModelsModule::defineModule();
+
+ // Auto-increment the import to stay in sync with ALL future QtQuick minor versions from 5.11 onward
+ qmlRegisterModule(uri, 2, QT_VERSION_MINOR);
}
};
//![class decl]
diff --git a/src/imports/models/plugins.qmltypes b/src/imports/models/plugins.qmltypes
index e6d09b76d6..60146f51ba 100644
--- a/src/imports/models/plugins.qmltypes
+++ b/src/imports/models/plugins.qmltypes
@@ -4,7 +4,7 @@ import QtQuick.tooling 1.2
// It is used for QML tooling purposes only.
//
// This file was auto-generated by:
-// 'qmlplugindump -nonrelocatable -noforceqtquick QtQml.Models 2.3'
+// 'qmlplugindump -nonrelocatable QtQml.Models 2.11'
Module {
dependencies: []
@@ -19,6 +19,15 @@ Module {
"HorizontalSortHint": 2
}
}
+ Enum {
+ name: "CheckIndexOption"
+ values: {
+ "NoOption": 0,
+ "IndexIsValid": 1,
+ "DoNotUseParent": 2,
+ "ParentIsInvalid": 4
+ }
+ }
Signal {
name: "dataChanged"
Parameter { name: "topLeft"; type: "QModelIndex" }
diff --git a/src/imports/particles/particles.pro b/src/imports/particles/particles.pro
index 4460d03a04..41146c75b0 100644
--- a/src/imports/particles/particles.pro
+++ b/src/imports/particles/particles.pro
@@ -1,7 +1,7 @@
CXX_MODULE = qml
TARGET = particlesplugin
TARGETPATH = QtQuick/Particles.2
-IMPORT_VERSION = 2.0
+IMPORT_VERSION = 2.$$QT_MINOR_VERSION
SOURCES += \
plugin.cpp
diff --git a/src/imports/particles/plugin.cpp b/src/imports/particles/plugin.cpp
index a04e115976..d548f26599 100644
--- a/src/imports/particles/plugin.cpp
+++ b/src/imports/particles/plugin.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include <QtQml/qqmlextensionplugin.h>
+#include <QtQml/qqml.h>
#include <private/qquickparticlesmodule_p.h>
@@ -62,6 +63,9 @@ public:
Q_ASSERT(QLatin1String(uri) == QLatin1String("QtQuick.Particles"));
Q_UNUSED(uri);
QQuickParticlesModule::defineModule();
+
+ // Auto-increment the import to stay in sync with ALL future QtQuick minor versions from 5.11 onward
+ qmlRegisterModule(uri, 2, QT_VERSION_MINOR);
}
};
//![class decl]
diff --git a/src/imports/qtqml/qtqml.pro b/src/imports/qtqml/qtqml.pro
index 05ef15a542..8804c944e7 100644
--- a/src/imports/qtqml/qtqml.pro
+++ b/src/imports/qtqml/qtqml.pro
@@ -1,5 +1,5 @@
TARGETPATH = QtQml
-QML_FILES += plugins.qmltypes
+AUX_QML_FILES += plugins.qmltypes
load(qml_module)
diff --git a/src/imports/qtquick2/plugins.qmltypes b/src/imports/qtquick2/plugins.qmltypes
index 0fce98a212..6f6f1de8c3 100644
--- a/src/imports/qtquick2/plugins.qmltypes
+++ b/src/imports/qtquick2/plugins.qmltypes
@@ -4,7 +4,7 @@ import QtQuick.tooling 1.2
// It is used for QML tooling purposes only.
//
// This file was auto-generated by:
-// 'qmlplugindump -nonrelocatable -noforceqtquick QtQuick 2.10'
+// 'qmlplugindump -nonrelocatable QtQuick 2.11'
Module {
dependencies: []
@@ -19,6 +19,15 @@ Module {
"HorizontalSortHint": 2
}
}
+ Enum {
+ name: "CheckIndexOption"
+ values: {
+ "NoOption": 0,
+ "IndexIsValid": 1,
+ "DoNotUseParent": 2,
+ "ParentIsInvalid": 4
+ }
+ }
Signal {
name: "dataChanged"
Parameter { name: "topLeft"; type: "QModelIndex" }
@@ -936,14 +945,16 @@ Module {
name: "QQuickAnimatedImage"
defaultProperty: "data"
prototype: "QQuickImage"
- exports: ["QtQuick/AnimatedImage 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: ["QtQuick/AnimatedImage 2.0", "QtQuick/AnimatedImage 2.11"]
+ exportMetaObjectRevisions: [0, 11]
Property { name: "playing"; type: "bool" }
Property { name: "paused"; type: "bool" }
Property { name: "currentFrame"; type: "int" }
Property { name: "frameCount"; type: "int"; isReadonly: true }
+ Property { name: "speed"; revision: 11; type: "double" }
Property { name: "sourceSize"; type: "QSize"; isReadonly: true }
Signal { name: "frameChanged" }
+ Signal { name: "speedChanged"; revision: 11 }
}
Component {
name: "QQuickAnimatedSprite"
@@ -1814,6 +1825,9 @@ Module {
Component {
name: "QQuickGrabGestureEvent"
prototype: "QObject"
+ exports: ["QtQuick/GestureEvent 2.0"]
+ isCreatable: false
+ exportMetaObjectRevisions: [0]
Property { name: "touchPoints"; type: "QObject"; isList: true; isReadonly: true }
Property { name: "dragThreshold"; type: "double"; isReadonly: true }
Method { name: "grab" }
@@ -2118,10 +2132,11 @@ Module {
exports: [
"QtQuick/Item 2.0",
"QtQuick/Item 2.1",
+ "QtQuick/Item 2.11",
"QtQuick/Item 2.4",
"QtQuick/Item 2.7"
]
- exportMetaObjectRevisions: [0, 1, 2, 7]
+ exportMetaObjectRevisions: [0, 1, 11, 2, 7]
Enum {
name: "TransformOrigin"
values: {
@@ -2175,6 +2190,7 @@ Module {
Property { name: "antialiasing"; type: "bool" }
Property { name: "implicitWidth"; type: "double" }
Property { name: "implicitHeight"; type: "double" }
+ Property { name: "containmentMask"; revision: 11; type: "QObject"; isPointer: true }
Property { name: "layer"; type: "QQuickItemLayer"; isReadonly: true; isPointer: true }
Signal {
name: "childrenRectChanged"
@@ -2226,6 +2242,7 @@ Module {
revision: 1
Parameter { name: "window"; type: "QQuickWindow"; isPointer: true }
}
+ Signal { name: "containmentMaskChanged"; revision: 11 }
Method { name: "update" }
Method {
name: "grabToImage"
@@ -3027,6 +3044,19 @@ Module {
Signal { name: "changed" }
}
Component {
+ name: "QQuickPathAngleArc"
+ prototype: "QQuickCurve"
+ exports: ["QtQuick/PathAngleArc 2.11"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "centerX"; type: "double" }
+ Property { name: "centerY"; type: "double" }
+ Property { name: "radiusX"; type: "double" }
+ Property { name: "radiusY"; type: "double" }
+ Property { name: "startAngle"; type: "double" }
+ Property { name: "sweepAngle"; type: "double" }
+ Property { name: "moveToStart"; type: "bool" }
+ }
+ Component {
name: "QQuickPathAnimation"
prototype: "QQuickAbstractAnimation"
exports: ["QtQuick/PathAnimation 2.0"]
@@ -3416,14 +3446,6 @@ Module {
Parameter { type: "int" }
}
Signal {
- name: "fromChanged"
- Parameter { type: "QVariant" }
- }
- Signal {
- name: "toChanged"
- Parameter { type: "QVariant" }
- }
- Signal {
name: "easingChanged"
Parameter { type: "QEasingCurve" }
}
diff --git a/src/imports/qtquick2/qtquick2.pro b/src/imports/qtquick2/qtquick2.pro
index 118343588a..01ac034104 100644
--- a/src/imports/qtquick2/qtquick2.pro
+++ b/src/imports/qtquick2/qtquick2.pro
@@ -1,7 +1,7 @@
CXX_MODULE = qml
TARGET = qtquick2plugin
TARGETPATH = QtQuick.2
-IMPORT_VERSION = 2.6
+IMPORT_VERSION = 2.11
SOURCES += \
plugin.cpp
diff --git a/src/imports/shapes/qquickshapegenericrenderer.cpp b/src/imports/shapes/qquickshapegenericrenderer.cpp
index 4933aab69e..e3d47430c7 100644
--- a/src/imports/shapes/qquickshapegenericrenderer.cpp
+++ b/src/imports/shapes/qquickshapegenericrenderer.cpp
@@ -607,6 +607,7 @@ void QQuickShapeGenericRenderer::updateFillNode(ShapePathData *d, QQuickShapeGen
break;
default:
Q_UNREACHABLE();
+ return;
}
n->activateMaterial(m_item->window(), gradMat);
if (d->effectiveDirty & DirtyFillGradient) {
diff --git a/src/imports/statemachine/plugin.cpp b/src/imports/statemachine/plugin.cpp
index 1357743126..93ced6e280 100644
--- a/src/imports/statemachine/plugin.cpp
+++ b/src/imports/statemachine/plugin.cpp
@@ -75,6 +75,9 @@ public:
qmlRegisterCustomType<SignalTransition>(uri, 1, 0, "SignalTransition", new SignalTransitionParser);
qmlRegisterType<TimeoutTransition>(uri, 1, 0, "TimeoutTransition");
qmlProtectModule(uri, 1);
+
+ // Auto-increment the import to stay in sync with ALL future QtQuick minor versions from 5.11 onward
+ qmlRegisterModule(uri, 1, QT_VERSION_MINOR);
}
};
diff --git a/src/imports/statemachine/plugins.qmltypes b/src/imports/statemachine/plugins.qmltypes
index 0fe9b63e03..e6ecaa75c8 100644
--- a/src/imports/statemachine/plugins.qmltypes
+++ b/src/imports/statemachine/plugins.qmltypes
@@ -4,7 +4,7 @@ import QtQuick.tooling 1.2
// It is used for QML tooling purposes only.
//
// This file was auto-generated by:
-// 'qmlplugindump -nonrelocatable -noforceqtquick QtQml.StateMachine 1.0'
+// 'qmlplugindump -nonrelocatable QtQml.StateMachine 1.11'
Module {
dependencies: []
diff --git a/src/imports/statemachine/signaltransition.cpp b/src/imports/statemachine/signaltransition.cpp
index 63a969c0e8..ab625788bb 100644
--- a/src/imports/statemachine/signaltransition.cpp
+++ b/src/imports/statemachine/signaltransition.cpp
@@ -176,9 +176,10 @@ void SignalTransition::connectTriggered()
QMetaMethod metaMethod = target->metaObject()->method(qobjectSignal->methodIndex());
int signalIndex = QMetaObjectPrivate::signalIndex(metaMethod);
- QQmlBoundSignalExpression *expression = ctxtdata ?
- new QQmlBoundSignalExpression(target, signalIndex,
- ctxtdata, this, m_compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex]) : nullptr;
+ auto f = m_compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex];
+ QQmlBoundSignalExpression *expression =
+ ctxtdata ? new QQmlBoundSignalExpression(target, signalIndex, ctxtdata, this, f)
+ : nullptr;
if (expression)
expression->setNotifyOnValueChanged(false);
m_signalExpression = expression;
diff --git a/src/imports/statemachine/statemachine.pro b/src/imports/statemachine/statemachine.pro
index 9bb88074e9..926a9d4a5e 100644
--- a/src/imports/statemachine/statemachine.pro
+++ b/src/imports/statemachine/statemachine.pro
@@ -1,7 +1,7 @@
CXX_MODULE = qml
TARGET = qtqmlstatemachine
TARGETPATH = QtQml/StateMachine
-IMPORT_VERSION = 1.0
+IMPORT_VERSION = 1.$$QT_MINOR_VERSION
QT = core-private qml-private
diff --git a/src/imports/testlib/main.cpp b/src/imports/testlib/main.cpp
index 45e9bd2cf6..443229bee9 100644
--- a/src/imports/testlib/main.cpp
+++ b/src/imports/testlib/main.cpp
@@ -160,6 +160,9 @@ public:
qmlRegisterType<QuickTestEvent>(uri,1,2,"TestEvent");
qmlRegisterType<QuickTestUtil>(uri,1,0,"TestUtil");
qmlRegisterType<QQuickTouchEventSequence>();
+
+ // Auto-increment the import to stay in sync with ALL future QtQuick minor versions from 5.11 onward
+ qmlRegisterModule(uri, 1, QT_VERSION_MINOR);
}
};
diff --git a/src/imports/testlib/testlib.pro b/src/imports/testlib/testlib.pro
index 6e8a6aee72..acbe82e5e6 100644
--- a/src/imports/testlib/testlib.pro
+++ b/src/imports/testlib/testlib.pro
@@ -1,7 +1,7 @@
CXX_MODULE = qml
TARGET = qmltestplugin
TARGETPATH = QtTest
-IMPORT_VERSION = 1.0
+IMPORT_VERSION = 1.$$QT_MINOR_VERSION
QT += qml quick qmltest qmltest-private qml-private core-private testlib
diff --git a/src/imports/window/plugin.cpp b/src/imports/window/plugin.cpp
index 4e6eedf326..907eecb060 100644
--- a/src/imports/window/plugin.cpp
+++ b/src/imports/window/plugin.cpp
@@ -51,7 +51,7 @@ static void initResources()
QT_BEGIN_NAMESPACE
/*!
- \qmlmodule QtQuick.Window 2.2
+ \qmlmodule QtQuick.Window 2.11
\title Qt Quick Window QML Types
\ingroup qmlmodules
\brief Provides QML types for window management
@@ -61,7 +61,7 @@ QT_BEGIN_NAMESPACE
To use the types in this module, import the module with the following line:
\code
- import QtQuick.Window 2.2
+ import QtQuick.Window 2.11
\endcode
*/
@@ -78,6 +78,9 @@ public:
Q_ASSERT(QLatin1String(uri) == QLatin1String("QtQuick.Window"));
Q_UNUSED(uri);
QQuickWindowModule::defineModule();
+
+ // Auto-increment the import to stay in sync with ALL future QtQuick minor versions from 5.11 onward
+ qmlRegisterModule(uri, 2, QT_VERSION_MINOR);
}
};
//![class decl]
diff --git a/src/imports/window/window.pro b/src/imports/window/window.pro
index a938e0eeef..77bd9518e9 100644
--- a/src/imports/window/window.pro
+++ b/src/imports/window/window.pro
@@ -1,7 +1,7 @@
CXX_MODULE = qml
TARGET = windowplugin
TARGETPATH = QtQuick/Window.2
-IMPORT_VERSION = 2.2
+IMPORT_VERSION = 2.$$QT_MINOR_VERSION
SOURCES += \
plugin.cpp
diff --git a/src/imports/xmllistmodel/plugin.cpp b/src/imports/xmllistmodel/plugin.cpp
index dc6a02918b..82e11eeeb3 100644
--- a/src/imports/xmllistmodel/plugin.cpp
+++ b/src/imports/xmllistmodel/plugin.cpp
@@ -63,6 +63,9 @@ public:
Q_ASSERT(QLatin1String(uri) == QLatin1String("QtQuick.XmlListModel"));
qmlRegisterType<QQuickXmlListModel>(uri,2,0,"XmlListModel");
qmlRegisterType<QQuickXmlListModelRole>(uri,2,0,"XmlRole");
+
+ // Auto-increment the import to stay in sync with ALL future QtQuick minor versions from 5.11 onward
+ qmlRegisterModule(uri, 2, QT_VERSION_MINOR);
}
};
diff --git a/src/imports/xmllistmodel/qqmlxmllistmodel.cpp b/src/imports/xmllistmodel/qqmlxmllistmodel.cpp
index d14810a01b..a08b59a598 100644
--- a/src/imports/xmllistmodel/qqmlxmllistmodel.cpp
+++ b/src/imports/xmllistmodel/qqmlxmllistmodel.cpp
@@ -72,7 +72,7 @@ typedef QPair<int, int> QQuickXmlListRange;
#define XMLLISTMODEL_CLEAR_ID 0
/*!
- \qmlmodule QtQuick.XmlListModel 2
+ \qmlmodule QtQuick.XmlListModel 2.11
\title Qt Quick XmlListModel QML Types
\ingroup qmlmodules
\brief Provides QML types for creating models from XML data
@@ -82,7 +82,7 @@ typedef QPair<int, int> QQuickXmlListRange;
To use the types in this module, import the module with the following line:
\code
- import QtQuick.XmlListModel 2.0
+ import QtQuick.XmlListModel 2.11
\endcode
*/
diff --git a/src/imports/xmllistmodel/xmllistmodel.pro b/src/imports/xmllistmodel/xmllistmodel.pro
index 2308f26d1b..b5f559fc93 100644
--- a/src/imports/xmllistmodel/xmllistmodel.pro
+++ b/src/imports/xmllistmodel/xmllistmodel.pro
@@ -1,7 +1,7 @@
CXX_MODULE = qml
TARGET = qmlxmllistmodelplugin
TARGETPATH = QtQuick/XmlListModel
-IMPORT_VERSION = 2.0
+IMPORT_VERSION = 2.$$QT_MINOR_VERSION
QT = network xmlpatterns qml-private core-private
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp
index 288ad243ce..236109d041 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp
@@ -812,7 +812,8 @@ void QQmlEngineDebugServiceImpl::engineAboutToBeRemoved(QJSEngine *engine)
void QQmlEngineDebugServiceImpl::objectCreated(QJSEngine *engine, QObject *object)
{
Q_ASSERT(engine);
- Q_ASSERT(m_engines.contains(engine));
+ if (!m_engines.contains(engine))
+ return;
int engineId = QQmlDebugService::idForObject(engine);
int objectId = QQmlDebugService::idForObject(object);
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp
index 5b049ab521..7950d21612 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp
@@ -112,8 +112,14 @@ void JavaScriptJob::run()
script.inheritContext = true;
script.parse();
QV4::ScopedValue result(scope);
- if (!scope.engine->hasException)
- result = script.run();
+ if (!scope.engine->hasException) {
+ if (frame) {
+ QV4::ScopedValue thisObject(scope, frame->thisObject());
+ result = script.run(thisObject);
+ } else {
+ result = script.run();
+ }
+ }
if (scope.engine->hasException) {
result = scope.engine->catchException();
resultIsException = true;
diff --git a/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp b/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp
index 718975275a..e17fe92983 100644
--- a/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp
+++ b/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp
@@ -260,8 +260,14 @@ QV4::ReturnedValue NativeDebugger::evaluateExpression(const QString &expression)
// That is a side-effect of inheritContext.
script.inheritContext = true;
script.parse();
- if (!m_engine->hasException)
- return script.run();
+ if (!m_engine->hasException) {
+ if (m_engine->currentStackFrame) {
+ QV4::ScopedValue thisObject(scope, m_engine->currentStackFrame->thisObject());
+ script.run(thisObject);
+ } else {
+ script.run();
+ }
+ }
m_runningJob = false;
return QV4::Encode::undefined();
diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp
index eb6fbce101..7014249c83 100644
--- a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp
+++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp
@@ -59,7 +59,7 @@ Q_QML_DEBUG_PLUGIN_LOADER(QQmlAbstractProfilerAdapter)
QQmlProfilerServiceImpl::QQmlProfilerServiceImpl(QObject *parent) :
QQmlConfigurableDebugService<QQmlProfilerService>(1, parent),
- m_waitingForStop(false), m_useMessageTypes(false)
+ m_waitingForStop(false), m_useMessageTypes(false), m_globalEnabled(false), m_globalFeatures(0)
{
m_timer.start();
QQmlAbstractProfilerAdapter *quickAdapter =
@@ -137,6 +137,10 @@ void QQmlProfilerServiceImpl::engineAdded(QJSEngine *engine)
"QML profilers have to be added from the engine thread");
QMutexLocker lock(&m_configMutex);
+
+ if (m_globalEnabled)
+ startProfiling(engine, m_globalFeatures);
+
const auto range = qAsConst(m_engineProfilers).equal_range(engine);
for (auto it = range.first; it != range.second; ++it)
(*it)->stopWaiting();
@@ -254,6 +258,9 @@ void QQmlProfilerServiceImpl::startProfiling(QJSEngine *engine, quint64 features
if (startedAny)
d << idForObject(engine);
} else {
+ m_globalEnabled = true;
+ m_globalFeatures = features;
+
QSet<QJSEngine *> engines;
for (QMultiHash<QJSEngine *, QQmlAbstractProfilerAdapter *>::iterator i(m_engineProfilers.begin());
i != m_engineProfilers.end(); ++i) {
@@ -274,9 +281,8 @@ void QQmlProfilerServiceImpl::startProfiling(QJSEngine *engine, quint64 features
}
emit startFlushTimer();
+ emit messageToClient(name(), d.data());
}
-
- emit messageToClient(name(), d.data());
}
/*!
@@ -292,6 +298,9 @@ void QQmlProfilerServiceImpl::stopProfiling(QJSEngine *engine)
QList<QQmlAbstractProfilerAdapter *> stopping;
QList<QQmlAbstractProfilerAdapter *> reporting;
+ if (engine == nullptr)
+ m_globalEnabled = false;
+
bool stillRunning = false;
for (QMultiHash<QJSEngine *, QQmlAbstractProfilerAdapter *>::iterator i(m_engineProfilers.begin());
i != m_engineProfilers.end(); ++i) {
diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.h b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.h
index a5e060a1ab..a8c3047421 100644
--- a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.h
+++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.h
@@ -116,6 +116,9 @@ private:
bool m_waitingForStop;
bool m_useMessageTypes;
+ bool m_globalEnabled;
+ quint64 m_globalFeatures;
+
QList<QQmlAbstractProfilerAdapter *> m_globalProfilers;
QMultiHash<QJSEngine *, QQmlAbstractProfilerAdapter *> m_engineProfilers;
QList<QJSEngine *> m_stoppingEngines;
diff --git a/src/qml/compiler/compiler.pri b/src/qml/compiler/compiler.pri
index 2ca0c39acc..95096db51d 100644
--- a/src/qml/compiler/compiler.pri
+++ b/src/qml/compiler/compiler.pri
@@ -40,8 +40,6 @@ SOURCES += \
unix: SOURCES += $$PWD/qv4compilationunitmapper_unix.cpp
else: SOURCES += $$PWD/qv4compilationunitmapper_win.cpp
-
-qtConfig(private_tests):qtConfig(dlopen): QMAKE_USE_PRIVATE += libdl
}
gcc {
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp
index 237cd9bf3b..4a1b27d7aa 100644
--- a/src/qml/compiler/qqmlirbuilder.cpp
+++ b/src/qml/compiler/qqmlirbuilder.cpp
@@ -1809,8 +1809,7 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil
QVector<int> runtimeFunctionIndices(functions.size());
QV4::Compiler::ScanFunctions scan(this, sourceCode, QV4::Compiler::GlobalCode);
- scan.enterEnvironment(nullptr, QV4::Compiler::QmlBinding);
- scan.enterQmlScope(qmlRoot, QStringLiteral("context scope"));
+ scan.enterGlobalEnvironment(QV4::Compiler::QmlBinding);
for (const CompiledFunctionOrExpression &f : functions) {
Q_ASSERT(f.node != qmlRoot);
QQmlJS::AST::FunctionDeclaration *function = QQmlJS::AST::cast<QQmlJS::AST::FunctionDeclaration*>(f.node);
@@ -1824,7 +1823,6 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil
scan.leaveEnvironment();
}
scan.leaveEnvironment();
- scan.leaveEnvironment();
_context = nullptr;
@@ -2213,12 +2211,6 @@ QV4::Compiler::Codegen::Reference JSCodeGen::fallbackNameLookup(const QString &n
Reference imports = Reference::fromStackSlot(this, _importedScriptsSlot);
return Reference::fromSubscript(imports, Reference::fromConst(this, QV4::Encode(r.scriptIndex)));
} else if (r.type.isValid()) {
- if (r.type.isCompositeSingleton()) {
- Instruction::LoadQmlSingleton load;
- load.name = registerString(name);
- bytecodeGenerator->addInstruction(load);
- return Reference::fromAccumulator(this);
- }
return Reference::fromName(this, name);
} else {
Q_ASSERT(r.importNamespace);
diff --git a/src/qml/compiler/qqmlpropertyvalidator.cpp b/src/qml/compiler/qqmlpropertyvalidator.cpp
index 00bb694ef4..ffd3b5975a 100644
--- a/src/qml/compiler/qqmlpropertyvalidator.cpp
+++ b/src/qml/compiler/qqmlpropertyvalidator.cpp
@@ -653,7 +653,7 @@ QQmlCompileError QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *
// Can only check at instantiation time if the created sub-object successfully casts to the
// target interface.
return noError;
- } else if (property->propType() == QMetaType::QVariant) {
+ } else if (property->propType() == QMetaType::QVariant || property->propType() == qMetaTypeId<QJSValue>()) {
// We can convert everything to QVariant :)
return noError;
} else if (property->isQList()) {
diff --git a/src/qml/compiler/qv4bytecodegenerator_p.h b/src/qml/compiler/qv4bytecodegenerator_p.h
index 3b3c766bfe..e69f2cd310 100644
--- a/src/qml/compiler/qv4bytecodegenerator_p.h
+++ b/src/qml/compiler/qv4bytecodegenerator_p.h
@@ -102,14 +102,19 @@ public:
Jump(BytecodeGenerator *generator, int instruction)
: generator(generator),
index(instruction)
- {}
+ { Q_ASSERT(generator && index != -1); }
+
~Jump() {
- Q_ASSERT(generator->instructions[index].linkedLabel != -1);
+ Q_ASSERT(index == -1 || generator->instructions[index].linkedLabel != -1); // make sure link() got called
}
+ Jump(Jump &&j) {
+ std::swap(generator, j.generator);
+ std::swap(index, j.index);
+ }
- BytecodeGenerator *generator;
- int index;
+ BytecodeGenerator *generator = nullptr;
+ int index = -1;
void link() {
link(generator->label());
@@ -119,6 +124,12 @@ public:
Q_ASSERT(generator->instructions[index].linkedLabel == -1);
generator->instructions[index].linkedLabel = l.index;
}
+
+ private:
+ // make this type move-only:
+ Q_DISABLE_COPY(Jump)
+ // we never move-assign this type anywhere, so disable it:
+ Jump &operator=(Jump &&) = delete;
};
struct ExceptionHandler : public Label {
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index bc4ca5d6f4..c281275da1 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -784,9 +784,10 @@ bool Codegen::visit(BinaryExpression *ast)
left = left.asLValue();
if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(left, ast->left->lastSourceLocation()))
return false;
- expression(ast->right).loadInAccumulator();
+ Reference r = expression(ast->right);
if (hasError)
return false;
+ r.loadInAccumulator();
if (_expr.accept(nx))
_expr.setResult(left.storeConsumeAccumulator());
else
@@ -2075,6 +2076,14 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
_context->hasDirectEval |= (_context->compilationMode == EvalCode || _context->compilationMode == GlobalCode || _module->debugMode); // Conditional breakpoints are like eval in the function
+ // When a user writes the following QML signal binding:
+ // onSignal: function() { doSomethingUsefull }
+ // we will generate a binding function that just returns the closure. However, that's not useful
+ // at all, because if the onSignal is a signal handler, the user is actually making it explicit
+ // that the binding is a function, so we should execute that. However, we don't know that during
+ // AOT compilation, so mark the surrounding function as only-returning-a-closure.
+ _context->returnsClosure = cast<ExpressionStatement *>(ast) && cast<FunctionExpression *>(cast<ExpressionStatement *>(ast)->expression);
+
BytecodeGenerator bytecode(_context->line, _module->debugMode);
BytecodeGenerator *savedBytecodeGenerator;
savedBytecodeGenerator = bytecodeGenerator;
@@ -2095,9 +2104,14 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
_context->addLocalVar(QStringLiteral("arguments"), Context::VariableDeclaration, AST::VariableDeclaration::FunctionScope);
bool allVarsEscape = _context->hasWith || _context->hasTry || _context->hasDirectEval;
- if (_context->compilationMode == QmlBinding // we don't really need this for bindings, but we do for signal handlers, and we don't know if the code is a signal handler or not.
- || (!_context->canUseSimpleCall() && _context->compilationMode != GlobalCode &&
- (_context->compilationMode != EvalCode || _context->isStrict))) {
+ bool needsCallContext = false;
+ const QLatin1String exprForOn("expression for on");
+ if (!_context->canUseSimpleCall() && _context->compilationMode != GlobalCode && (_context->compilationMode != EvalCode || _context->isStrict))
+ needsCallContext = true;
+ else if (_context->compilationMode == QmlBinding && name.length() > exprForOn.size() && name.startsWith(exprForOn) && name.at(exprForOn.size()).isUpper())
+ // we don't really need this for bindings, but we do for signal handlers, and we don't know if the code is a signal handler or not.
+ needsCallContext = true;
+ if (needsCallContext) {
Instruction::CreateCallContext createContext;
bytecodeGenerator->addInstruction(createContext);
}
diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h
index a46d47cb67..d51dc29517 100644
--- a/src/qml/compiler/qv4codegen_p.h
+++ b/src/qml/compiler/qv4codegen_p.h
@@ -188,7 +188,7 @@ public:
Const
} type = Invalid;
- bool isLValue() const { return !isReadonly; }
+ bool isLValue() const { return !isReadonly && type > Accumulator; }
Reference(Codegen *cg, Type type = Invalid) : type(type), codegen(cg) {}
Reference() {}
diff --git a/src/qml/compiler/qv4compilationunitmapper.cpp b/src/qml/compiler/qv4compilationunitmapper.cpp
index d94f7ac238..350f6f9485 100644
--- a/src/qml/compiler/qv4compilationunitmapper.cpp
+++ b/src/qml/compiler/qv4compilationunitmapper.cpp
@@ -59,36 +59,4 @@ CompilationUnitMapper::~CompilationUnitMapper()
close();
}
-bool CompilationUnitMapper::verifyHeader(const CompiledData::Unit *header, QDateTime sourceTimeStamp, QString *errorString)
-{
- if (strncmp(header->magic, CompiledData::magic_str, sizeof(header->magic))) {
- *errorString = QStringLiteral("Magic bytes in the header do not match");
- return false;
- }
-
- if (header->version != quint32(QV4_DATA_STRUCTURE_VERSION)) {
- *errorString = QString::fromUtf8("V4 data structure version mismatch. Found %1 expected %2").arg(header->version, 0, 16).arg(QV4_DATA_STRUCTURE_VERSION, 0, 16);
- return false;
- }
-
- if (header->qtVersion != quint32(QT_VERSION)) {
- *errorString = QString::fromUtf8("Qt version mismatch. Found %1 expected %2").arg(header->qtVersion, 0, 16).arg(QT_VERSION, 0, 16);
- return false;
- }
-
- if (header->sourceTimeStamp) {
- // Files from the resource system do not have any time stamps, so fall back to the application
- // executable.
- if (!sourceTimeStamp.isValid())
- sourceTimeStamp = QFileInfo(QCoreApplication::applicationFilePath()).lastModified();
-
- if (sourceTimeStamp.isValid() && sourceTimeStamp.toMSecsSinceEpoch() != header->sourceTimeStamp) {
- *errorString = QStringLiteral("QML source file has a different time stamp than cached file.");
- return false;
- }
- }
-
- return true;
-}
-
QT_END_NAMESPACE
diff --git a/src/qml/compiler/qv4compilationunitmapper_p.h b/src/qml/compiler/qv4compilationunitmapper_p.h
index b24f98df7c..80f914c141 100644
--- a/src/qml/compiler/qv4compilationunitmapper_p.h
+++ b/src/qml/compiler/qv4compilationunitmapper_p.h
@@ -72,8 +72,6 @@ public:
void close();
private:
- static bool verifyHeader(const QV4::CompiledData::Unit *header, QDateTime sourceTimeStamp, QString *errorString);
-
#if defined(Q_OS_UNIX)
size_t length;
#endif
diff --git a/src/qml/compiler/qv4compilationunitmapper_unix.cpp b/src/qml/compiler/qv4compilationunitmapper_unix.cpp
index 38dabc41cf..8348613888 100644
--- a/src/qml/compiler/qv4compilationunitmapper_unix.cpp
+++ b/src/qml/compiler/qv4compilationunitmapper_unix.cpp
@@ -73,7 +73,7 @@ CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, co
return nullptr;
}
- if (!verifyHeader(&header, sourceTimeStamp, errorString))
+ if (!header.verifyHeader(sourceTimeStamp, errorString))
return nullptr;
// Data structure and qt version matched, so now we can access the rest of the file safely.
diff --git a/src/qml/compiler/qv4compilationunitmapper_win.cpp b/src/qml/compiler/qv4compilationunitmapper_win.cpp
index d7a93ae233..8b000021f8 100644
--- a/src/qml/compiler/qv4compilationunitmapper_win.cpp
+++ b/src/qml/compiler/qv4compilationunitmapper_win.cpp
@@ -87,7 +87,7 @@ CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, co
return nullptr;
}
- if (!verifyHeader(&header, sourceTimeStamp, errorString))
+ if (!header.verifyHeader(sourceTimeStamp, errorString))
return nullptr;
const uint mappingFlags = header.flags & QV4::CompiledData::Unit::ContainsMachineCode
diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp
index cc11b250f3..8dcc068a06 100644
--- a/src/qml/compiler/qv4compileddata.cpp
+++ b/src/qml/compiler/qv4compileddata.cpp
@@ -70,18 +70,14 @@
#include <algorithm>
-#if defined(QT_BUILD_INTERNAL)
-#if defined(Q_OS_UNIX) && !defined(QT_NO_DYNAMIC_CAST)
-#include <dlfcn.h>
-#endif
-#endif
-
QT_BEGIN_NAMESPACE
namespace QV4 {
namespace CompiledData {
+static_assert(sizeof(Unit::libraryVersionHash) >= QML_COMPILE_HASH_LENGTH + 1, "Compile hash length exceeds reserved size in data structure. Please adjust and bump the format version");
+
#if !defined(V4_BOOTSTRAP)
static QString cacheFilePath(const QUrl &url)
{
@@ -686,32 +682,6 @@ void ResolvedTypeReference::doDynamicTypeCheck()
isFullyDynamicType = qtTypeInherits<QQmlPropertyMap>(mo);
}
-static QByteArray ownLibraryChecksum()
-{
- static QByteArray libraryChecksum;
- static bool checksumInitialized = false;
- if (checksumInitialized)
- return libraryChecksum;
- checksumInitialized = true;
-#if defined(QT_BUILD_INTERNAL) && !defined(QT_NO_DYNAMIC_CAST) && QT_CONFIG(dlopen)
- // This is a bit of a hack to make development easier. When hacking on the code generator
- // the cache files may end up being re-used. To avoid that we also add the checksum of
- // the QtQml library.
- Dl_info libInfo;
- if (dladdr(reinterpret_cast<void *>(&ownLibraryChecksum), &libInfo) != 0) {
- QFile library(QFile::decodeName(libInfo.dli_fname));
- if (library.open(QIODevice::ReadOnly)) {
- QCryptographicHash hash(QCryptographicHash::Md5);
- hash.addData(&library);
- libraryChecksum = hash.result();
- }
- }
-#else
- libraryChecksum = QByteArray(QML_COMPILE_HASH);
-#endif
- return libraryChecksum;
-}
-
bool ResolvedTypeReferenceMap::addToHash(QCryptographicHash *hash, QQmlEngine *engine) const
{
for (auto it = constBegin(), end = constEnd(); it != end; ++it) {
@@ -719,8 +689,6 @@ bool ResolvedTypeReferenceMap::addToHash(QCryptographicHash *hash, QQmlEngine *e
return false;
}
- hash->addData(ownLibraryChecksum());
-
return true;
}
@@ -755,6 +723,53 @@ void Unit::generateChecksum()
#endif
}
+bool Unit::verifyHeader(QDateTime expectedSourceTimeStamp, QString *errorString) const
+{
+#ifndef V4_BOOTSTRAP
+ if (strncmp(magic, CompiledData::magic_str, sizeof(magic))) {
+ *errorString = QStringLiteral("Magic bytes in the header do not match");
+ return false;
+ }
+
+ if (version != quint32(QV4_DATA_STRUCTURE_VERSION)) {
+ *errorString = QString::fromUtf8("V4 data structure version mismatch. Found %1 expected %2").arg(version, 0, 16).arg(QV4_DATA_STRUCTURE_VERSION, 0, 16);
+ return false;
+ }
+
+ if (qtVersion != quint32(QT_VERSION)) {
+ *errorString = QString::fromUtf8("Qt version mismatch. Found %1 expected %2").arg(qtVersion, 0, 16).arg(QT_VERSION, 0, 16);
+ return false;
+ }
+
+ if (sourceTimeStamp) {
+ // Files from the resource system do not have any time stamps, so fall back to the application
+ // executable.
+ if (!expectedSourceTimeStamp.isValid())
+ expectedSourceTimeStamp = QFileInfo(QCoreApplication::applicationFilePath()).lastModified();
+
+ if (expectedSourceTimeStamp.isValid() && expectedSourceTimeStamp.toMSecsSinceEpoch() != sourceTimeStamp) {
+ *errorString = QStringLiteral("QML source file has a different time stamp than cached file.");
+ return false;
+ }
+ }
+
+#if defined(QML_COMPILE_HASH)
+ if (qstrcmp(QML_COMPILE_HASH, libraryVersionHash) != 0) {
+ *errorString = QStringLiteral("QML library version mismatch. Expected compile hash does not match");
+ return false;
+ }
+#else
+#error "QML_COMPILE_HASH must be defined for the build of QtDeclarative to ensure version checking for cache files"
+#endif
+
+ return true;
+#else
+ Q_UNUSED(expectedSourceTimeStamp)
+ Q_UNUSED(errorString)
+ return false;
+#endif
+}
+
}
}
diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h
index 2c0320f7f1..1df9d6794f 100644
--- a/src/qml/compiler/qv4compileddata_p.h
+++ b/src/qml/compiler/qv4compileddata_p.h
@@ -72,7 +72,7 @@
QT_BEGIN_NAMESPACE
// Bump this whenever the compiler data structures change in an incompatible way.
-#define QV4_DATA_STRUCTURE_VERSION 0x17
+#define QV4_DATA_STRUCTURE_VERSION 0x19
class QIODevice;
class QQmlPropertyCache;
@@ -225,7 +225,7 @@ struct Function
quint32_le localsOffset;
quint32_le nLineNumbers;
quint32_le lineNumberOffset;
- quint32_le nInnerFunctions;
+ quint32_le nestedFunctionIndex; // for functions that only return a single closure, used in signal handlers
quint32_le nRegisters;
Location location;
@@ -688,6 +688,8 @@ struct Unit
quint32_le unitSize; // Size of the Unit and any depending data.
// END DO NOT CHANGE THESE FIELDS EVER
+ char libraryVersionHash[48];
+
char md5Checksum[16]; // checksum of all bytes following this field.
void generateChecksum();
@@ -727,6 +729,8 @@ struct Unit
quint32_le padding;
+ bool verifyHeader(QDateTime expectedSourceTimeStamp, QString *errorString) const;
+
const Import *importAt(int idx) const {
return reinterpret_cast<const Import*>((reinterpret_cast<const char *>(this)) + offsetToImports + idx * sizeof(Import));
}
@@ -791,7 +795,7 @@ struct Unit
}
};
-static_assert(sizeof(Unit) == 144, "Unit structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
+static_assert(sizeof(Unit) == 192, "Unit structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
struct TypeReference
{
diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp
index f2e1f4a0de..c9e535c93f 100644
--- a/src/qml/compiler/qv4compiler.cpp
+++ b/src/qml/compiler/qv4compiler.cpp
@@ -48,6 +48,9 @@
#include <wtf/MathExtras.h>
#include <QCryptographicHash>
+// generated by qmake:
+#include "qml_compile_hash_p.h"
+
QV4::Compiler::StringTableGenerator::StringTableGenerator()
{
clear();
@@ -305,6 +308,9 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::Compiler::Conte
function->flags |= CompiledData::Function::IsStrict;
if (irFunction->hasTry || irFunction->hasWith)
function->flags |= CompiledData::Function::HasCatchOrWith;
+ function->nestedFunctionIndex =
+ irFunction->returnsClosure ? quint32(module->functions.indexOf(irFunction->nestedContexts.first()))
+ : std::numeric_limits<uint32_t>::max();
function->nFormals = irFunction->arguments.size();
function->formalsOffset = currentOffset;
currentOffset += function->nFormals * sizeof(quint32);
@@ -317,7 +323,6 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::Compiler::Conte
function->lineNumberOffset = currentOffset;
currentOffset += function->nLineNumbers * sizeof(CompiledData::CodeOffsetToLine);
- function->nInnerFunctions = irFunction->nestedContexts.size();
function->nRegisters = irFunction->registerCount;
@@ -394,6 +399,7 @@ QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Comp
unit.flags |= module->unitFlags;
unit.version = QV4_DATA_STRUCTURE_VERSION;
unit.qtVersion = QT_VERSION;
+ qstrcpy(unit.libraryVersionHash, QML_COMPILE_HASH);
memset(unit.md5Checksum, 0, sizeof(unit.md5Checksum));
memset(unit.dependencyMD5Checksum, 0, sizeof(unit.dependencyMD5Checksum));
diff --git a/src/qml/compiler/qv4compilercontext.cpp b/src/qml/compiler/qv4compilercontext.cpp
index 3293dc53c8..0a9d3d8efe 100644
--- a/src/qml/compiler/qv4compilercontext.cpp
+++ b/src/qml/compiler/qv4compilercontext.cpp
@@ -49,6 +49,8 @@ QT_BEGIN_NAMESPACE
Context *Module::newContext(Node *node, Context *parent, CompilationMode compilationMode)
{
+ Q_ASSERT(!contextMap.contains(node));
+
Context *c = new Context(parent, compilationMode);
if (node) {
SourceLocation loc = node->firstSourceLocation();
diff --git a/src/qml/compiler/qv4compilercontext_p.h b/src/qml/compiler/qv4compilercontext_p.h
index a78a66db52..455a76c729 100644
--- a/src/qml/compiler/qv4compilercontext_p.h
+++ b/src/qml/compiler/qv4compilercontext_p.h
@@ -144,6 +144,7 @@ struct Context {
bool usesThis = false;
bool hasTry = false;
bool hasWith = false;
+ bool returnsClosure = false;
mutable bool argumentsCanEscape = false;
enum UsesArgumentsObject {
@@ -256,29 +257,32 @@ struct Context {
usedVariables.insert(name);
}
- void addLocalVar(const QString &name, MemberType type, QQmlJS::AST::VariableDeclaration::VariableScope scope, QQmlJS::AST::FunctionExpression *function = nullptr)
+ bool addLocalVar(const QString &name, MemberType type, QQmlJS::AST::VariableDeclaration::VariableScope scope, QQmlJS::AST::FunctionExpression *function = nullptr)
{
- if (! name.isEmpty()) {
- if (type != FunctionDefinition) {
- for (QQmlJS::AST::FormalParameterList *it = formals; it; it = it->next)
- if (it->name == name)
- return;
- }
- MemberMap::iterator it = members.find(name);
- if (it == members.end()) {
- Member m;
- m.type = type;
- m.function = function;
- m.scope = scope;
- members.insert(name, m);
- } else {
- Q_ASSERT(scope == (*it).scope);
- if ((*it).type <= type) {
- (*it).type = type;
- (*it).function = function;
- }
+ if (name.isEmpty())
+ return true;
+
+ if (type != FunctionDefinition) {
+ for (QQmlJS::AST::FormalParameterList *it = formals; it; it = it->next)
+ if (it->name == name)
+ return (scope == QQmlJS::AST::VariableDeclaration::FunctionScope);
+ }
+ MemberMap::iterator it = members.find(name);
+ if (it != members.end()) {
+ if (scope != QQmlJS::AST::VariableDeclaration::FunctionScope || (*it).scope != QQmlJS::AST::VariableDeclaration::FunctionScope)
+ return false;
+ if ((*it).type <= type) {
+ (*it).type = type;
+ (*it).function = function;
}
+ return true;
}
+ Member m;
+ m.type = type;
+ m.function = function;
+ m.scope = scope;
+ members.insert(name, m);
+ return true;
}
};
diff --git a/src/qml/compiler/qv4compilerscanfunctions.cpp b/src/qml/compiler/qv4compilerscanfunctions.cpp
index 89f602b409..84ee452332 100644
--- a/src/qml/compiler/qv4compilerscanfunctions.cpp
+++ b/src/qml/compiler/qv4compilerscanfunctions.cpp
@@ -73,13 +73,20 @@ void ScanFunctions::operator()(Node *node)
calcEscapingVariables();
}
+void ScanFunctions::enterGlobalEnvironment(CompilationMode compilationMode)
+{
+ enterEnvironment(astNodeForGlobalEnvironment, compilationMode);
+}
+
void ScanFunctions::enterEnvironment(Node *node, CompilationMode compilationMode)
{
- Context *e = _cg->_module->newContext(node, _context, compilationMode);
- if (!e->isStrict)
- e->isStrict = _cg->_strictMode;
- _contextStack.append(e);
- _context = e;
+ Context *c = _cg->_module->contextMap.value(node);
+ if (!c)
+ c = _cg->_module->newContext(node, _context, compilationMode);
+ if (!c->isStrict)
+ c->isStrict = _cg->_strictMode;
+ _contextStack.append(c);
+ _context = c;
}
void ScanFunctions::leaveEnvironment()
@@ -208,14 +215,10 @@ bool ScanFunctions::visit(VariableDeclaration *ast)
return false;
}
QString name = ast->name.toString();
- const Context::Member *m = nullptr;
- if (_context->memberInfo(name, &m)) {
- if (m->isLexicallyScoped() || ast->isLexicallyScoped()) {
- _cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Identifier %1 has already been declared").arg(name));
- return false;
- }
+ if (!_context->addLocalVar(ast->name.toString(), ast->expression ? Context::VariableDefinition : Context::VariableDeclaration, ast->scope)) {
+ _cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Identifier %1 has already been declared").arg(name));
+ return false;
}
- _context->addLocalVar(ast->name.toString(), ast->expression ? Context::VariableDefinition : Context::VariableDeclaration, ast->scope);
return true;
}
@@ -390,16 +393,22 @@ bool ScanFunctions::visit(Block *ast) {
void ScanFunctions::enterFunction(Node *ast, const QString &name, FormalParameterList *formals, FunctionBody *body, FunctionExpression *expr)
{
- if (_context) {
- _context->hasNestedFunctions = true;
+ Context *outerContext = _context;
+ enterEnvironment(ast, FunctionCode);
+
+ if (outerContext) {
+ outerContext->hasNestedFunctions = true;
// The identifier of a function expression cannot be referenced from the enclosing environment.
- if (expr)
- _context->addLocalVar(name, Context::FunctionDefinition, AST::VariableDeclaration::FunctionScope, expr);
+ if (expr) {
+ if (!outerContext->addLocalVar(name, Context::FunctionDefinition, AST::VariableDeclaration::FunctionScope, expr)) {
+ _cg->throwSyntaxError(ast->firstSourceLocation(), QStringLiteral("Identifier %1 has already been declared").arg(name));
+ return;
+ }
+ }
if (name == QLatin1String("arguments"))
- _context->usesArgumentsObject = Context::ArgumentsObjectNotUsed;
+ outerContext->usesArgumentsObject = Context::ArgumentsObjectNotUsed;
}
- enterEnvironment(ast, FunctionCode);
if (formalsContainName(formals, QStringLiteral("arguments")))
_context->usesArgumentsObject = Context::ArgumentsObjectNotUsed;
@@ -440,7 +449,7 @@ void ScanFunctions::calcEscapingVariables()
{
Module *m = _cg->_module;
- for (Context *inner : m->contextMap) {
+ for (Context *inner : qAsConst(m->contextMap)) {
for (const QString &var : qAsConst(inner->usedVariables)) {
Context *c = inner;
while (c) {
@@ -468,7 +477,7 @@ void ScanFunctions::calcEscapingVariables()
static const bool showEscapingVars = qEnvironmentVariableIsSet("QV4_SHOW_ESCAPING_VARS");
if (showEscapingVars) {
qDebug() << "==== escaping variables ====";
- for (Context *c : m->contextMap) {
+ for (Context *c : qAsConst(m->contextMap)) {
qDebug() << "Context" << c->name << ":";
qDebug() << " Arguments escape" << c->argumentsCanEscape;
for (auto it = c->members.constBegin(); it != c->members.constEnd(); ++it) {
diff --git a/src/qml/compiler/qv4compilerscanfunctions_p.h b/src/qml/compiler/qv4compilerscanfunctions_p.h
index 745e9f8a73..87b7210879 100644
--- a/src/qml/compiler/qv4compilerscanfunctions_p.h
+++ b/src/qml/compiler/qv4compilerscanfunctions_p.h
@@ -84,12 +84,10 @@ public:
ScanFunctions(Codegen *cg, const QString &sourceCode, CompilationMode defaultProgramMode);
void operator()(AST::Node *node);
+ void enterGlobalEnvironment(CompilationMode compilationMode);
void enterEnvironment(AST::Node *node, CompilationMode compilationMode);
void leaveEnvironment();
- void enterQmlScope(AST::Node *ast, const QString &name)
- { enterFunction(ast, name, /*formals*/nullptr, /*body*/nullptr, /*expr*/nullptr); }
-
void enterQmlFunction(AST::FunctionDeclaration *ast)
{ enterFunction(ast, false); }
@@ -149,6 +147,9 @@ protected:
bool _allowFuncDecls;
CompilationMode defaultProgramMode;
+
+private:
+ static constexpr AST::Node *astNodeForGlobalEnvironment = nullptr;
};
}
diff --git a/src/qml/compiler/qv4instr_moth.cpp b/src/qml/compiler/qv4instr_moth.cpp
index 34953d52ce..450fa50528 100644
--- a/src/qml/compiler/qv4instr_moth.cpp
+++ b/src/qml/compiler/qv4instr_moth.cpp
@@ -634,10 +634,6 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_BEGIN_INSTR(LoadQmlImportedScripts)
d << dumpRegister(result, nFormals);
MOTH_END_INSTR(LoadQmlImportedScripts)
-
- MOTH_BEGIN_INSTR(LoadQmlSingleton)
- d << name;
- MOTH_END_INSTR(LoadQmlSingleton)
}
}
diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h
index 2d1428bd19..7dd639c94c 100644
--- a/src/qml/compiler/qv4instr_moth_p.h
+++ b/src/qml/compiler/qv4instr_moth_p.h
@@ -174,7 +174,6 @@ QT_BEGIN_NAMESPACE
#define INSTR_Sub(op) INSTRUCTION(op, Sub, 1, lhs)
#define INSTR_LoadQmlContext(op) INSTRUCTION(op, LoadQmlContext, 1, result)
#define INSTR_LoadQmlImportedScripts(op) INSTRUCTION(op, LoadQmlImportedScripts, 1, result)
-#define INSTR_LoadQmlSingleton(op) INSTRUCTION(op, LoadQmlSingleton, 1, name)
#define FOR_EACH_MOTH_INSTR(F) \
@@ -290,9 +289,8 @@ QT_BEGIN_NAMESPACE
F(Mod) \
F(Sub) \
F(LoadQmlContext) \
- F(LoadQmlImportedScripts) \
- F(LoadQmlSingleton)
-#define MOTH_NUM_INSTRUCTIONS() (static_cast<int>(Moth::Instr::Type::LoadQmlSingleton) + 1)
+ F(LoadQmlImportedScripts)
+#define MOTH_NUM_INSTRUCTIONS() (static_cast<int>(Moth::Instr::Type::LoadQmlImportedScripts) + 1)
#if defined(Q_CC_GNU) && !defined(Q_CC_INTEL)
// icc before version 1200 doesn't support computed goto, and at least up to version 18.0.0 the
diff --git a/src/qml/configure.json b/src/qml/configure.json
index b744ea6948..681cecea99 100644
--- a/src/qml/configure.json
+++ b/src/qml/configure.json
@@ -39,6 +39,12 @@
"features.xmlstreamwriter"
],
"output": [ "privateFeature" ]
+ },
+ "qml-delegate-model": {
+ "label": "QML delegate model",
+ "purpose": "Provides the DelegateModel QML type.",
+ "section": "QML",
+ "output": [ "privateFeature" ]
}
},
@@ -47,7 +53,8 @@
"section": "Qt QML",
"entries": [
"qml-network",
- "qml-debug"
+ "qml-debug",
+ "qml-delegate-model"
]
}
]
diff --git a/src/qml/debugger/qqmlprofiler_p.h b/src/qml/debugger/qqmlprofiler_p.h
index deb4d107d6..287c53ea05 100644
--- a/src/qml/debugger/qqmlprofiler_p.h
+++ b/src/qml/debugger/qqmlprofiler_p.h
@@ -190,7 +190,7 @@ public:
}
RefLocation(QQmlDataBlob *ref)
- : Location(QQmlSourceLocation()), locationType(Compiling), sent(false)
+ : Location(QQmlSourceLocation(), ref->url()), locationType(Compiling), sent(false)
{
blob = ref;
blob->addref();
diff --git a/src/qml/doc/images/cpp-qml-integration-flowchart.odg b/src/qml/doc/images/cpp-qml-integration-flowchart.odg
new file mode 100644
index 0000000000..8482bd4bf4
--- /dev/null
+++ b/src/qml/doc/images/cpp-qml-integration-flowchart.odg
Binary files differ
diff --git a/src/qml/doc/images/cpp-qml-integration-flowchart.png b/src/qml/doc/images/cpp-qml-integration-flowchart.png
new file mode 100644
index 0000000000..56a33205fd
--- /dev/null
+++ b/src/qml/doc/images/cpp-qml-integration-flowchart.png
Binary files differ
diff --git a/src/qml/doc/src/cppintegration/definetypes.qdoc b/src/qml/doc/src/cppintegration/definetypes.qdoc
index 027e4b9923..7f3ff416a1 100644
--- a/src/qml/doc/src/cppintegration/definetypes.qdoc
+++ b/src/qml/doc/src/cppintegration/definetypes.qdoc
@@ -297,6 +297,8 @@ qmlRegisterRevision<BaseType,1>("MyTypes", 1, 1);
This is useful when deriving from base classes provided by other authors,
e.g. when extending classes from the Qt Quick module.
+\note The QML engine does not support revisions for properties or signals of
+grouped and attached property objects.
\section2 Registering Extension Objects
diff --git a/src/qml/doc/src/cppintegration/interactqmlfromcpp.qdoc b/src/qml/doc/src/cppintegration/interactqmlfromcpp.qdoc
index 7c2ff703c6..9c33979f40 100644
--- a/src/qml/doc/src/cppintegration/interactqmlfromcpp.qdoc
+++ b/src/qml/doc/src/cppintegration/interactqmlfromcpp.qdoc
@@ -75,11 +75,26 @@ component, which is accessible via QQuickView::rootObject():
\endtable
This \c object is the instance of the \c MyItem.qml component that has been
-created. You can now modify the item's properties using QObject::setProperty()
-or QQmlProperty:
+created. You can now modify the item's properties using
+\l QObject::setProperty() or \l QQmlProperty::write():
\snippet qml/qtbinding/loading/main.cpp properties
+The difference between \c QObject::setProperty() and \c QQmlProperty::write()
+is that the latter will also remove the binding in addition to setting the
+property value. For example, suppose the \c width assignment above had been a
+binding to \c height:
+
+\code
+ width: height
+\endcode
+
+If the \c height of the \c Item changed after the
+\c {object->setProperty("width", 500)} call, the \c width would be updated
+again, as the binding remains active. However, if the \c height changes after the
+\c {QQmlProperty(object, "width").write(500)} call, the \c width will not be
+changed, as the binding does not exist anymore.
+
Alternatively, you can cast the object to its actual type and call methods with
compile-time safety. In this case the base object of \c MyItem.qml is an
\l Item, which is defined by the QQuickItem class:
diff --git a/src/qml/doc/src/cppintegration/topic.qdoc b/src/qml/doc/src/cppintegration/topic.qdoc
index 6b6e308edf..fbb654378d 100644
--- a/src/qml/doc/src/cppintegration/topic.qdoc
+++ b/src/qml/doc/src/cppintegration/topic.qdoc
@@ -143,6 +143,12 @@ with a QML module that can then be imported and used by QML code in other applic
\l{qtqml-modules-cppplugins.html}{Providing Types and Functionality in a C++ Plugin} for more
information.
+\section1 Choosing the Correct Integration Method Between C++ and QML
+
+To quickly determine which integration method is appropriate for your situation, the following
+flowchart can be used:
+
+\image cpp-qml-integration-flowchart
\section1 Exposing Attributes of C++ Classes to QML
diff --git a/src/qml/doc/src/external-resources.qdoc b/src/qml/doc/src/external-resources.qdoc
index 717e983517..d26288ee6e 100644
--- a/src/qml/doc/src/external-resources.qdoc
+++ b/src/qml/doc/src/external-resources.qdoc
@@ -44,3 +44,31 @@
\externalpage https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date
\title Mozilla Developer Network Date Reference
*/
+/*!
+ \externalpage hhttps://www.froglogic.com/squish/gui-testing
+ \title Squish
+*/
+/*!
+ \externalpage http://doc.qt.io/GammaRay
+ \title GammaRay
+*/
+/*!
+ \externalpage http://doc.qt.io/QtQmlLive
+ \title QmlLive
+*/
+/*!
+ \externalpage http://doc.qt.io/qtcreator/creator-debugging-qml.html
+ \title QML Debugger
+*/
+/*!
+ \externalpage http://doc.qt.io/qtcreator/creator-qml-performance-monitor.html
+ \title QML Profiler
+*/
+/*!
+ \externalpage http://doc.qt.io/qtcreator/index.html
+ \title Qt Creator Manual
+*/
+/*!
+ \externalpage https://fontawesome.com/
+ \title Font Awesome
+*/
diff --git a/src/qml/doc/src/javascript/hostenvironment.qdoc b/src/qml/doc/src/javascript/hostenvironment.qdoc
index d11e96df2b..eb40f10065 100644
--- a/src/qml/doc/src/javascript/hostenvironment.qdoc
+++ b/src/qml/doc/src/javascript/hostenvironment.qdoc
@@ -154,10 +154,11 @@ This restriction exists as the QML environment is not yet fully established.
To run code after the environment setup has completed, see
\l {JavaScript in Application Startup Code}.
-\li The value of \c this is currently undefined in QML in the majority of contexts.
+\li The value of \c this is undefined in QML in the majority of contexts.
The \c this keyword is supported when binding properties from JavaScript.
-In all other situations, the value of
+In QML binding expressions, QML signal handlers, and QML declared functions,
+\c this refers to the scope object. In all other situations, the value of
\c this is undefined in QML.
To refer to a specific object, provide an \c id. For example:
@@ -168,20 +169,17 @@ Item {
function mouseAreaClicked(area) {
console.log("Clicked in area at: " + area.x + ", " + area.y);
}
- // This will not work because this is undefined
+ // This will pass area to the function
MouseArea {
- height: 50; width: 200
- onClicked: mouseAreaClicked(this)
- }
- // This will pass area2 to the function
- MouseArea {
- id: area2
+ id: area
y: 50; height: 50; width: 200
- onClicked: mouseAreaClicked(area2)
+ onClicked: mouseAreaClicked(area)
}
}
\endqml
+\sa {Scope and Naming Resolution}
+
\endlist
diff --git a/src/qml/doc/src/qmlfunctions.qdoc b/src/qml/doc/src/qmlfunctions.qdoc
index ede213b84a..55ca040af6 100644
--- a/src/qml/doc/src/qmlfunctions.qdoc
+++ b/src/qml/doc/src/qmlfunctions.qdoc
@@ -105,6 +105,8 @@
than the actual version of the library. Indeed, it is normal for the new library to allow
QML written to previous versions to continue to work, even if more advanced versions of
some of its types are available.
+
+ \sa {Choosing the Correct Integration Method Between C++ and QML}
*/
/*!
@@ -141,7 +143,8 @@
Returns the QML type id.
- \sa qmlRegisterTypeNotAvailable()
+ \sa qmlRegisterTypeNotAvailable(),
+ {Choosing the Correct Integration Method Between C++ and QML}
*/
/*!
@@ -266,7 +269,8 @@
Without this, a generic "Game is not a type" message would be given.
- \sa qmlRegisterUncreatableType()
+ \sa qmlRegisterUncreatableType(),
+ {Choosing the Correct Integration Method Between C++ and QML}
*/
/*!
@@ -278,7 +282,77 @@
system. Instances of this type cannot be created from the QML
system.
+ This function should be used when the type will not be referenced by name.
+ Specifically, it has to be used for C++ types that are used as the left-hand
+ side of a property binding.
+
+ For example, consider the following two classes:
+
+ \code
+ class Bar : public QObject
+ {
+ Q_OBJECT
+ Q_PROPERTY(QString baz READ baz WRITE setBaz NOTIFY bazChanged)
+
+ public:
+ Bar() {}
+
+ QString baz() const { return mBaz; }
+
+ void setBaz(const QString &baz)
+ {
+ if (baz == mBaz)
+ return;
+
+ mBaz = baz;
+ emit bazChanged();
+ }
+
+ signals:
+ void bazChanged();
+
+ private:
+ QString mBaz;
+ };
+
+ class Foo : public QObject
+ {
+ Q_OBJECT
+ Q_PROPERTY(Bar *bar READ bar CONSTANT FINAL)
+
+ public:
+ Foo() {}
+
+ Bar *bar() { return &mBar; }
+
+ private:
+ Bar mBar;
+ };
+ \endcode
+
+ In QML, we assign a string to the \c baz property of \c bar:
+
+ \code
+ Foo {
+ bar.baz: "abc"
+ Component.onCompleted: print(bar.baz)
+ }
+ \endcode
+
+ For the QML engine to know that the \c Bar type has a \c baz property,
+ we have to make \c Bar known:
+
+ \code
+ qmlRegisterType<Foo>("App", 1, 0, "Foo");
+ qmlRegisterType<Bar>();
+ \endcode
+
+ As the \c Foo type is instantiated in QML, it must be registered
+ with the version of \l qmlRegisterType() that takes an import URI.
+
Returns the QML type id.
+
+ \sa {Choosing the Correct Integration Method Between C++ and QML}
*/
/*!
@@ -346,7 +420,9 @@
property int someValue: ExampleApi.MyApi.someProperty
}
\endqml
- */
+
+ \sa {Choosing the Correct Integration Method Between C++ and QML}
+*/
/*!
\fn template<typename T> QObject *qmlAttachedPropertiesObject(const QObject *attachee, bool create = true)
@@ -486,7 +562,8 @@
}
\endcode
- */
+ \sa {Choosing the Correct Integration Method Between C++ and QML}
+*/
/*!
\fn int qmlRegisterSingletonType(const QUrl &url, const char *uri, int versionMajor, int versionMinor, const char *qmlName)
diff --git a/src/qml/doc/src/qmltypereference.qdoc b/src/qml/doc/src/qmltypereference.qdoc
index cfd4d55a24..960ea116c9 100644
--- a/src/qml/doc/src/qmltypereference.qdoc
+++ b/src/qml/doc/src/qmltypereference.qdoc
@@ -26,7 +26,7 @@
****************************************************************************/
/*!
-\qmlmodule QtQml 2.2
+\qmlmodule QtQml 2.11
\title Qt QML QML Types
\ingroup qmlmodules
\brief List of QML types provided by the Qt QML module
@@ -43,11 +43,11 @@ The types provided by the \c QtQml module are only available in a QML document
if that document imports the \c QtQml namespace (or if the document imports the
\c QtQuick namespace, as noted below).
-The current version of the \c QtQml module is version 2.2, and thus it may be
+The current version of the \c QtQml module is version 2.11, and thus it may be
imported via the following statement:
\qml
-import QtQml 2.2
+import QtQml 2.11
\endqml
Most clients will never need to use the \c QtQml import, as all of the types
@@ -55,7 +55,7 @@ are also provided by the \c QtQuick namespace which may be imported as
follows:
\qml
-import QtQuick 2.7
+import QtQuick 2.11
\endqml
See the \l{Qt Quick} module documentation for more information about the \c
diff --git a/src/qml/doc/src/qtqml.qdoc b/src/qml/doc/src/qtqml.qdoc
index a9f8e2a960..b4bc9a0774 100644
--- a/src/qml/doc/src/qtqml.qdoc
+++ b/src/qml/doc/src/qtqml.qdoc
@@ -58,7 +58,7 @@ following directive:
The QML types in Qt QML are available through the \c QtQML import. To use the
types, add the following import statement to your .qml file:
\code
-import QtQml 2.0
+import QtQml 2.11
\endcode
diff --git a/src/qml/doc/src/statemachine.qdoc b/src/qml/doc/src/statemachine.qdoc
index 0cd19d2a68..59170a223f 100644
--- a/src/qml/doc/src/statemachine.qdoc
+++ b/src/qml/doc/src/statemachine.qdoc
@@ -26,7 +26,7 @@
****************************************************************************/
/*!
- \qmlmodule QtQml.StateMachine 1.0
+ \qmlmodule QtQml.StateMachine 1.11
\title Declarative State Machine QML Types
\brief Provides QML types to create and execute state graphs.
diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp
index 186e5952da..c3e16c4093 100644
--- a/src/qml/jit/qv4assembler.cpp
+++ b/src/qml/jit/qv4assembler.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include <QBuffer>
+#include <QFile>
#include "qv4engine_p.h"
#include "qv4assembler_p.h"
@@ -275,12 +276,16 @@ struct PlatformAssembler_X86_All : JSC::MacroAssembler<JSC::MacroAssemblerX86>
push(JSStackFrameRegister);
push(CppStackFrameRegister);
push(EngineRegister);
+ // Ensure the stack is 16-byte aligned in order for compiler generated aligned SSE2
+ // instructions to be able to target the stack.
+ subPtr(TrustedImm32(8), StackPointerRegister);
loadPtr(Address(FramePointerRegister, 2 * PointerSize), CppStackFrameRegister);
loadPtr(Address(FramePointerRegister, 3 * PointerSize), EngineRegister);
}
void generatePlatformFunctionExit()
{
+ addPtr(TrustedImm32(8), StackPointerRegister);
pop(EngineRegister);
pop(CppStackFrameRegister);
pop(JSStackFrameRegister);
@@ -1367,6 +1372,17 @@ static void printDisassembledOutputWithCalls(QByteArray processedOutput,
qDebug("%s", processedOutput.constData());
}
+static QByteArray functionName(Function *function)
+{
+ QByteArray name = function->name()->toQString().toUtf8();
+ if (name.isEmpty()) {
+ name = QByteArray::number(reinterpret_cast<quintptr>(function), 16);
+ name.prepend("QV4::Function(0x");
+ name.append(')');
+ }
+ return name;
+}
+
void Assembler::link(Function *function)
{
for (const auto &jumpTarget : pasm()->patches)
@@ -1388,12 +1404,7 @@ void Assembler::link(Function *function)
buf.open(QIODevice::WriteOnly);
WTF::setDataFile(new QIODevicePrintStream(&buf));
- QByteArray name = function->name()->toQString().toUtf8();
- if (name.isEmpty()) {
- name = QByteArray::number(quintptr(function), 16);
- name.prepend("QV4::Function(0x");
- name.append(')');
- }
+ QByteArray name = functionName(function);
codeRef = linkBuffer.finalizeCodeWithDisassembly("%s", name.data());
WTF::setDataFile(stderr);
@@ -1404,6 +1415,34 @@ void Assembler::link(Function *function)
function->codeRef = new JSC::MacroAssemblerCodeRef(codeRef);
function->jittedCode = reinterpret_cast<Function::JittedCode>(function->codeRef->code().executableAddress());
+
+#if defined(Q_OS_LINUX)
+ // This implements writing of JIT'd addresses so that perf can find the
+ // symbol names.
+ //
+ // Perf expects the mapping to be in a certain place and have certain
+ // content, for more information, see:
+ // https://github.com/torvalds/linux/blob/master/tools/perf/Documentation/jit-interface.txt
+ static bool doProfile = !qEnvironmentVariableIsEmpty("QV4_PROFILE_WRITE_PERF_MAP");
+ if (doProfile) {
+ static QFile perfMapFile(QString::fromLatin1("/tmp/perf-%1.map")
+ .arg(QCoreApplication::applicationPid()));
+ static const bool isOpen = perfMapFile.open(QIODevice::WriteOnly);
+ if (!isOpen) {
+ qWarning("QV4::JIT::Assembler: Cannot write perf map file.");
+ doProfile = false;
+ } else {
+ perfMapFile.write(QByteArray::number(reinterpret_cast<quintptr>(
+ codeRef.code().executableAddress()), 16));
+ perfMapFile.putChar(' ');
+ perfMapFile.write(QByteArray::number(static_cast<qsizetype>(codeRef.size()), 16));
+ perfMapFile.putChar(' ');
+ perfMapFile.write(functionName(function));
+ perfMapFile.putChar('\n');
+ perfMapFile.flush();
+ }
+ }
+#endif
}
void Assembler::addLabel(int offset)
diff --git a/src/qml/jit/qv4jit.cpp b/src/qml/jit/qv4jit.cpp
index 5dc98a591a..bc46c0ca1d 100644
--- a/src/qml/jit/qv4jit.cpp
+++ b/src/qml/jit/qv4jit.cpp
@@ -917,14 +917,6 @@ void BaselineJIT::generate_LoadQmlImportedScripts(int result)
as->storeReg(result);
}
-void BaselineJIT::generate_LoadQmlSingleton(int name)
-{
- as->prepareCallWithArgCount(2);
- as->passInt32AsArg(name, 1);
- as->passEngineAsArg(0);
- JIT_GENERATE_RUNTIME_CALL(Runtime::method_loadQmlSingleton, Assembler::ResultInAccumulator);
-}
-
void BaselineJIT::startInstruction(Instr::Type /*instr*/)
{
if (hasLabel())
@@ -1328,9 +1320,6 @@ void BaselineJIT::collectLabelsInBytecode()
MOTH_BEGIN_INSTR(LoadQmlImportedScripts)
MOTH_END_INSTR(LoadQmlImportedScripts)
-
- MOTH_BEGIN_INSTR(LoadQmlSingleton)
- MOTH_END_INSTR(LoadQmlSingleton)
}
}
#undef MOTH_BEGIN_INSTR
diff --git a/src/qml/jit/qv4jit_p.h b/src/qml/jit/qv4jit_p.h
index c17ab4ff6e..5aebf78a8d 100644
--- a/src/qml/jit/qv4jit_p.h
+++ b/src/qml/jit/qv4jit_p.h
@@ -240,7 +240,6 @@ public:
void generate_Sub(int lhs) override;
void generate_LoadQmlContext(int result) override;
void generate_LoadQmlImportedScripts(int result) override;
- void generate_LoadQmlSingleton(int name) override;
void startInstruction(Moth::Instr::Type instr) override;
void endInstruction(Moth::Instr::Type instr) override;
diff --git a/src/qml/jsruntime/qv4arraybuffer.cpp b/src/qml/jsruntime/qv4arraybuffer.cpp
index c4eddb6b2a..59a2b9d913 100644
--- a/src/qml/jsruntime/qv4arraybuffer.cpp
+++ b/src/qml/jsruntime/qv4arraybuffer.cpp
@@ -96,7 +96,6 @@ void Heap::ArrayBuffer::init(size_t length)
Object::init();
data = QTypedArrayData<char>::allocate(length + 1);
if (!data) {
- data = nullptr;
internalClass->engine->throwRangeError(QStringLiteral("ArrayBuffer: out of memory"));
return;
}
@@ -113,7 +112,7 @@ void Heap::ArrayBuffer::init(const QByteArray& array)
void Heap::ArrayBuffer::destroy()
{
- if (!data->ref.deref())
+ if (data && !data->ref.deref())
QTypedArrayData<char>::deallocate(data);
Object::destroy();
}
diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp
index 30c8527f21..b33b34ee08 100644
--- a/src/qml/jsruntime/qv4arraydata.cpp
+++ b/src/qml/jsruntime/qv4arraydata.cpp
@@ -617,7 +617,7 @@ uint ArrayData::append(Object *obj, ArrayObject *otherObj, uint n)
uint toCopy = n;
uint chunk = toCopy;
if (chunk > os->values.alloc - os->offset)
- chunk -= os->values.alloc - os->offset;
+ chunk = os->values.alloc - os->offset;
obj->arrayPut(oldSize, os->values.data() + os->offset, chunk);
toCopy -= chunk;
if (toCopy)
@@ -662,14 +662,13 @@ void ArrayData::insert(Object *o, uint index, const Value *v, bool isAccessor)
class ArrayElementLessThan
{
public:
- inline ArrayElementLessThan(ExecutionEngine *engine, Object *thisObject, const Value &comparefn)
- : m_engine(engine), thisObject(thisObject), m_comparefn(comparefn) {}
+ inline ArrayElementLessThan(ExecutionEngine *engine, const Value &comparefn)
+ : m_engine(engine), m_comparefn(comparefn) {}
bool operator()(Value v1, Value v2) const;
private:
ExecutionEngine *m_engine;
- Object *thisObject;
const Value &m_comparefn;
};
@@ -842,7 +841,7 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c
}
- ArrayElementLessThan lessThan(engine, thisObject, static_cast<const FunctionObject &>(comparefn));
+ ArrayElementLessThan lessThan(engine, static_cast<const FunctionObject &>(comparefn));
Value *begin = thisObject->arrayData()->values.values;
sortHelper(begin, begin + len, *begin, lessThan);
diff --git a/src/qml/jsruntime/qv4arraydata_p.h b/src/qml/jsruntime/qv4arraydata_p.h
index 9356670b6d..b2573b4491 100644
--- a/src/qml/jsruntime/qv4arraydata_p.h
+++ b/src/qml/jsruntime/qv4arraydata_p.h
@@ -304,9 +304,11 @@ bool ArrayData::getProperty(uint index, Property *p, PropertyAttributes *attrs)
}
*attrs = attributes(index);
- p->value = *(Index{ this, mapped });
- if (attrs->isAccessor())
- p->set = *(Index{ this, mapped + 1 /*Object::SetterOffset*/ });
+ if (p) {
+ p->value = *(Index{ this, mapped });
+ if (attrs->isAccessor())
+ p->set = *(Index{ this, mapped + 1 /*Object::SetterOffset*/ });
+ }
return true;
}
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 5f59e1e809..5521633db7 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -758,27 +758,6 @@ QObject *ExecutionEngine::qmlScopeObject() const
return ctx->qml()->scopeObject;
}
-ReturnedValue ExecutionEngine::qmlSingletonWrapper(String *name)
-{
- QQmlContextData *ctx = callingQmlContext();
- if (!ctx->imports)
- return Encode::undefined();
- // Search for attached properties, enums and imported scripts
- QQmlTypeNameCache::Result r = ctx->imports->query(name);
-
- Q_ASSERT(r.isValid());
- Q_ASSERT(r.type.isValid());
- Q_ASSERT(r.type.isSingleton());
-
- QQmlType::SingletonInstanceInfo *siinfo = r.type.singletonInstanceInfo();
- QQmlEngine *e = qmlEngine();
- siinfo->init(e);
-
- if (QObject *qobjectSingleton = siinfo->qobjectApi(e))
- return QV4::QObjectWrapper::wrap(this, qobjectSingleton);
- return QJSValuePrivate::convertedToValue(this, siinfo->scriptApi(e));
-}
-
QQmlContextData *ExecutionEngine::callingQmlContext() const
{
Heap::QmlContext *ctx = qmlContext();
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index 5edf89f720..c7fb743088 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -441,7 +441,6 @@ public:
Heap::QmlContext *qmlContext() const;
QObject *qmlScopeObject() const;
- ReturnedValue qmlSingletonWrapper(String *name);
QQmlContextData *callingQmlContext() const;
diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h
index 4c8c790ca7..59a94e5dde 100644
--- a/src/qml/jsruntime/qv4function_p.h
+++ b/src/qml/jsruntime/qv4function_p.h
@@ -105,6 +105,13 @@ struct Q_QML_EXPORT Function {
{
return QQmlSourceLocation(sourceFile(), compiledFunction->location.line, compiledFunction->location.column);
}
+
+ Function *nestedFunction() const
+ {
+ if (compiledFunction->nestedFunctionIndex == std::numeric_limits<uint32_t>::max())
+ return nullptr;
+ return compilationUnit->runtimeFunctions[compiledFunction->nestedFunctionIndex];
+ }
};
}
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index a8c1640767..83608070ec 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -75,7 +75,6 @@ void Heap::FunctionObject::init(QV4::ExecutionContext *scope, QV4::String *name,
jsConstruct = QV4::FunctionObject::callAsConstructor;
Object::init();
- function = nullptr;
this->scope.set(scope->engine(), scope->d());
Scope s(scope->engine());
ScopedFunctionObject f(s, this);
@@ -88,7 +87,6 @@ void Heap::FunctionObject::init(QV4::ExecutionContext *scope, QV4::String *name,
jsConstruct = reinterpret_cast<const ObjectVTable *>(vtable())->callAsConstructor;
Object::init();
- function = nullptr;
this->scope.set(scope->engine(), scope->d());
Scope s(scope->engine());
ScopedFunctionObject f(s, this);
@@ -101,8 +99,7 @@ void Heap::FunctionObject::init(QV4::ExecutionContext *scope, Function *function
jsConstruct = reinterpret_cast<const ObjectVTable *>(vtable())->callAsConstructor;
Object::init();
- this->function = function;
- function->compilationUnit->addref();
+ setFunction(function);
this->scope.set(scope->engine(), scope->d());
Scope s(scope->engine());
ScopedString name(s, function->name());
@@ -123,13 +120,18 @@ void Heap::FunctionObject::init()
jsConstruct = reinterpret_cast<const ObjectVTable *>(vtable())->callAsConstructor;
Object::init();
- function = nullptr;
this->scope.set(internalClass->engine, internalClass->engine->rootContext()->d());
Q_ASSERT(internalClass && internalClass->find(internalClass->engine->id_prototype()) == Index_Prototype);
setProperty(internalClass->engine, Index_Prototype, Primitive::undefinedValue());
}
-
+void Heap::FunctionObject::setFunction(Function *f)
+{
+ if (f) {
+ function = f;
+ function->compilationUnit->addref();
+ }
+}
void Heap::FunctionObject::destroy()
{
if (function)
@@ -347,20 +349,38 @@ ReturnedValue FunctionPrototype::method_bind(const FunctionObject *b, const Valu
{
QV4::Scope scope(b);
ScopedFunctionObject target(scope, thisObject);
- if (!target)
+ if (!target || target->isBinding())
return scope.engine->throwTypeError();
ScopedValue boundThis(scope, argc ? argv[0] : Primitive::undefinedValue());
Scoped<MemberData> boundArgs(scope, (Heap::MemberData *)nullptr);
- if (argc > 1) {
- boundArgs = MemberData::allocate(scope.engine, argc - 1);
- boundArgs->d()->values.size = argc - 1;
- for (uint i = 0, ei = static_cast<uint>(argc - 1); i < ei; ++i)
+
+ int nArgs = (argc - 1 >= 0) ? argc - 1 : 0;
+ if (target->isBoundFunction()) {
+ BoundFunction *bound = static_cast<BoundFunction *>(target.getPointer());
+ Scoped<MemberData> oldArgs(scope, bound->boundArgs());
+ boundThis = bound->boundThis();
+ int oldSize = !oldArgs ? 0 : oldArgs->size();
+ if (oldSize + nArgs) {
+ boundArgs = MemberData::allocate(scope.engine, oldSize + nArgs);
+ boundArgs->d()->values.size = oldSize + nArgs;
+ for (uint i = 0; i < static_cast<uint>(oldSize); ++i)
+ boundArgs->set(scope.engine, i, oldArgs->data()[i]);
+ for (uint i = 0; i < static_cast<uint>(nArgs); ++i)
+ boundArgs->set(scope.engine, oldSize + i, argv[i + 1]);
+ }
+ target = bound->target();
+ } else if (nArgs) {
+ boundArgs = MemberData::allocate(scope.engine, nArgs);
+ boundArgs->d()->values.size = nArgs;
+ for (uint i = 0, ei = static_cast<uint>(nArgs); i < ei; ++i)
boundArgs->set(scope.engine, i, argv[i + 1]);
}
- ExecutionContext *global = scope.engine->rootContext();
- return BoundFunction::create(global, target, boundThis, boundArgs)->asReturnedValue();
+ ScopedContext ctx(scope, target->scope());
+ Heap::BoundFunction *bound = BoundFunction::create(ctx, target, boundThis, boundArgs);
+ bound->setFunction(target->function());
+ return bound->asReturnedValue();
}
DEFINE_OBJECT_VTABLE(ScriptFunction);
@@ -393,8 +413,7 @@ void Heap::ScriptFunction::init(QV4::ExecutionContext *scope, Function *function
FunctionObject::init();
this->scope.set(scope->engine(), scope->d());
- this->function = function;
- function->compilationUnit->addref();
+ setFunction(function);
Q_ASSERT(function);
Q_ASSERT(function->code);
diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h
index d6066ec648..32e71a175b 100644
--- a/src/qml/jsruntime/qv4functionobject_p.h
+++ b/src/qml/jsruntime/qv4functionobject_p.h
@@ -90,6 +90,8 @@ DECLARE_HEAP_OBJECT(FunctionObject, Object) {
void init();
void destroy();
+ void setFunction(Function *f);
+
unsigned int formalParameterCount() { return function ? function->nFormals : 0; }
unsigned int varCount() { return function ? function->compiledFunction->nLocals : 0; }
diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h
index 7f82a02ae0..9b13d4e341 100644
--- a/src/qml/jsruntime/qv4global_p.h
+++ b/src/qml/jsruntime/qv4global_p.h
@@ -108,6 +108,11 @@ inline double trunc(double d) { return d > 0 ? floor(d) : ceil(d); }
//# define V4_ENABLE_JIT
#endif
+// check FPU with double precision on ARM platform
+#if (defined(Q_PROCESSOR_ARM_64) || defined(Q_PROCESSOR_ARM_32)) && defined(V4_ENABLE_JIT) && defined(__ARM_FP) && (__ARM_FP <= 0x04)
+# undef V4_ENABLE_JIT
+#endif
+
// Black list some platforms
#if defined(V4_ENABLE_JIT)
#if defined(Q_OS_IOS) || defined(Q_OS_TVOS)
diff --git a/src/qml/jsruntime/qv4include.cpp b/src/qml/jsruntime/qv4include.cpp
index aaf5e3b857..d0d66c9b9a 100644
--- a/src/qml/jsruntime/qv4include.cpp
+++ b/src/qml/jsruntime/qv4include.cpp
@@ -92,7 +92,8 @@ QV4Include::~QV4Include()
#endif
}
-QV4::ReturnedValue QV4Include::resultValue(QV4::ExecutionEngine *v4, Status status)
+QV4::ReturnedValue QV4Include::resultValue(QV4::ExecutionEngine *v4, Status status,
+ const QString &statusText)
{
QV4::Scope scope(v4);
@@ -105,6 +106,8 @@ QV4::ReturnedValue QV4Include::resultValue(QV4::ExecutionEngine *v4, Status stat
o->put((s = v4->newString(QStringLiteral("NETWORK_ERROR"))), (v = QV4::Primitive::fromInt32(NetworkError)));
o->put((s = v4->newString(QStringLiteral("EXCEPTION"))), (v = QV4::Primitive::fromInt32(Exception)));
o->put((s = v4->newString(QStringLiteral("status"))), (v = QV4::Primitive::fromInt32(status)));
+ if (!statusText.isEmpty())
+ o->put((s = v4->newString(QStringLiteral("statusText"))), (v = v4->newString(statusText)));
return o.asReturnedValue();
}
@@ -227,7 +230,8 @@ QV4::ReturnedValue QV4Include::method_include(const QV4::FunctionObject *b, cons
} else {
QScopedPointer<QV4::Script> script;
- script.reset(QV4::Script::createFromFileOrCache(scope.engine, qmlcontext, localFile, url));
+ QString error;
+ script.reset(QV4::Script::createFromFileOrCache(scope.engine, qmlcontext, localFile, url, &error));
if (!script.isNull()) {
script->parse();
@@ -242,7 +246,7 @@ QV4::ReturnedValue QV4Include::method_include(const QV4::FunctionObject *b, cons
result = resultValue(scope.engine, Ok);
}
} else {
- result = resultValue(scope.engine, NetworkError);
+ result = resultValue(scope.engine, NetworkError, error);
}
callback(callbackFunction, result);
diff --git a/src/qml/jsruntime/qv4include_p.h b/src/qml/jsruntime/qv4include_p.h
index 8015722afc..70ccfbf223 100644
--- a/src/qml/jsruntime/qv4include_p.h
+++ b/src/qml/jsruntime/qv4include_p.h
@@ -88,7 +88,8 @@ private:
QV4::ReturnedValue result();
- static QV4::ReturnedValue resultValue(QV4::ExecutionEngine *v4, Status status = Loading);
+ static QV4::ReturnedValue resultValue(QV4::ExecutionEngine *v4, Status status = Loading,
+ const QString &statusText = QString());
static void callback(const QV4::Value &callback, const QV4::Value &status);
QV4::ExecutionEngine *v4;
diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp
index 99666806be..c3569c29d2 100644
--- a/src/qml/jsruntime/qv4jsonobject.cpp
+++ b/src/qml/jsruntime/qv4jsonobject.cpp
@@ -637,7 +637,7 @@ struct Stringify
Stringify(ExecutionEngine *e) : v4(e), replacerFunction(nullptr), propertyList(nullptr), propertyListSize(0) {}
QString Str(const QString &key, const Value &v);
- QString JA(ArrayObject *a);
+ QString JA(Object *a);
QString JO(Object *o);
QString makeMember(const QString &key, const Value &v);
@@ -743,8 +743,8 @@ QString Stringify::Str(const QString &key, const Value &v)
o = value->asReturnedValue();
if (o) {
if (!o->as<FunctionObject>()) {
- if (o->as<ArrayObject>()) {
- return JA(static_cast<ArrayObject *>(o.getPointer()));
+ if (o->as<ArrayObject>() || o->isListType()) {
+ return JA(o.getPointer());
} else {
return JO(o);
}
@@ -827,7 +827,7 @@ QString Stringify::JO(Object *o)
return result;
}
-QString Stringify::JA(ArrayObject *a)
+QString Stringify::JA(Object *a)
{
if (stackContains(a)) {
v4->throwTypeError();
diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp
index 8e9bf794a9..bcbe475c2c 100644
--- a/src/qml/jsruntime/qv4object.cpp
+++ b/src/qml/jsruntime/qv4object.cpp
@@ -1091,9 +1091,7 @@ bool Object::setArrayLength(uint newLen)
uint oldLen = getLength();
bool ok = true;
if (newLen < oldLen) {
- if (!arrayData()) {
- Q_ASSERT(!newLen);
- } else {
+ if (arrayData()) {
uint l = arrayData()->vtable()->truncate(this, newLen);
if (l != newLen)
ok = false;
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index c1bbe2a330..816c259b9b 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -460,9 +460,12 @@ void QObjectWrapper::setProperty(ExecutionEngine *engine, QObject *object, QQmlP
QV4::Scoped<QQmlBindingFunction> bindingFunction(scope, (const Value &)f);
+ QV4::ScopedFunctionObject f(scope, bindingFunction->bindingFunction());
QV4::ScopedContext ctx(scope, bindingFunction->scope());
- newBinding = QQmlBinding::create(property, bindingFunction->function(), object, callingQmlContext, ctx);
+ newBinding = QQmlBinding::create(property, f->function(), object, callingQmlContext, ctx);
newBinding->setSourceLocation(bindingFunction->currentLocation());
+ if (f->isBoundFunction())
+ newBinding->setBoundFunction(static_cast<QV4::BoundFunction *>(f.getPointer()));
newBinding->setTarget(object, *property, nullptr);
}
}
diff --git a/src/qml/jsruntime/qv4regexp.cpp b/src/qml/jsruntime/qv4regexp.cpp
index d99536829b..e10493b879 100644
--- a/src/qml/jsruntime/qv4regexp.cpp
+++ b/src/qml/jsruntime/qv4regexp.cpp
@@ -111,6 +111,8 @@ void Heap::RegExp::init(ExecutionEngine *engine, const QString &pattern, bool ig
JSC::JSGlobalData dummy(internalClass->engine->regExpAllocator);
JSC::Yarr::jitCompile(yarrPattern, JSC::Yarr::Char16, &dummy, *jitCode);
}
+#else
+ Q_UNUSED(engine)
#endif
if (hasValidJITCode()) {
valid = true;
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 04cad8ddb7..0211ad1011 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -1271,7 +1271,9 @@ QV4::ReturnedValue Runtime::method_createUnmappedArgumentsObject(ExecutionEngine
ReturnedValue Runtime::method_loadQmlContext(NoThrowEngine *engine)
{
- return engine->qmlContext()->asReturnedValue();
+ Heap::QmlContext *ctx = engine->qmlContext();
+ Q_ASSERT(ctx);
+ return ctx->asReturnedValue();
}
ReturnedValue Runtime::method_regexpLiteral(ExecutionEngine *engine, int id)
@@ -1326,13 +1328,6 @@ ReturnedValue Runtime::method_loadQmlImportedScripts(NoThrowEngine *engine)
return context->importedScripts.value();
}
-QV4::ReturnedValue Runtime::method_loadQmlSingleton(QV4::NoThrowEngine *engine, int nameIndex)
-{
- Scope scope(engine);
- ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
- return engine->qmlSingletonWrapper(name);
-}
-
ReturnedValue Runtime::method_uMinus(const Value &value)
{
TRACE1(value);
diff --git a/src/qml/jsruntime/qv4runtimeapi_p.h b/src/qml/jsruntime/qv4runtimeapi_p.h
index 2956a4a463..91232256a9 100644
--- a/src/qml/jsruntime/qv4runtimeapi_p.h
+++ b/src/qml/jsruntime/qv4runtimeapi_p.h
@@ -184,7 +184,6 @@ struct ExceptionCheck<void (*)(QV4::NoThrowEngine *, A, B, C)> {
/* qml */ \
F(ReturnedValue, loadQmlContext, (NoThrowEngine *engine)) \
F(ReturnedValue, loadQmlImportedScripts, (NoThrowEngine *engine)) \
- F(ReturnedValue, loadQmlSingleton, (NoThrowEngine *engine, int nameIndex)) \
F(ReturnedValue, loadQmlScopeObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, bool captureRequired)) \
F(ReturnedValue, loadQmlContextObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, bool captureRequired)) \
F(ReturnedValue, loadQmlIdObject, (ExecutionEngine *engine, const Value &context, uint index)) \
diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp
index bb6608bec0..afa7d2ed52 100644
--- a/src/qml/jsruntime/qv4script.cpp
+++ b/src/qml/jsruntime/qv4script.cpp
@@ -90,6 +90,12 @@ void Script::parse()
Module module(v4->debugger() != nullptr);
+ if (sourceCode.startsWith(QLatin1String("function("))) {
+ qWarning() << "Warning: Using function expressions as statements in scripts in not compliant with the ECMAScript specification at\n"
+ << (sourceCode.leftRef(70) + QLatin1String("..."))
+ << "\nThis will throw a syntax error in Qt 5.12. If you want a function expression, surround it by parentheses.";
+ }
+
Engine ee, *engine = &ee;
Lexer lexer(engine);
lexer.setCode(sourceCode, line, parseAsBinding);
@@ -136,7 +142,7 @@ void Script::parse()
}
}
-ReturnedValue Script::run()
+ReturnedValue Script::run(const QV4::Value *thisObject)
{
if (!parsed)
parse();
@@ -149,10 +155,11 @@ ReturnedValue Script::run()
if (qmlContext.isUndefined()) {
TemporaryAssignment<Function*> savedGlobalCode(engine->globalCode, vmFunction);
- return vmFunction->call(engine->globalObject, nullptr, 0, context);
+ return vmFunction->call(thisObject ? thisObject : engine->globalObject, nullptr, 0,
+ context);
} else {
Scoped<QmlContext> qml(valueScope, qmlContext.value());
- return vmFunction->call(nullptr, nullptr, 0, qml);
+ return vmFunction->call(thisObject, nullptr, 0, qml);
}
}
@@ -222,17 +229,28 @@ QQmlRefPointer<QV4::CompiledData::CompilationUnit> Script::precompile(QV4::Compi
return cg.generateCompilationUnit(/*generate unit data*/false);
}
-Script *Script::createFromFileOrCache(ExecutionEngine *engine, QmlContext *qmlContext, const QString &fileName, const QUrl &originalUrl)
+Script *Script::createFromFileOrCache(ExecutionEngine *engine, QmlContext *qmlContext, const QString &fileName, const QUrl &originalUrl, QString *error)
{
- if (const QV4::CompiledData::Unit *cachedUnit = QQmlMetaType::findCachedCompilationUnit(originalUrl)) {
+ if (error)
+ error->clear();
+
+ QQmlMetaType::CachedUnitLookupError cacheError = QQmlMetaType::CachedUnitLookupError::NoError;
+ if (const QV4::CompiledData::Unit *cachedUnit = QQmlMetaType::findCachedCompilationUnit(originalUrl, &cacheError)) {
QQmlRefPointer<QV4::CompiledData::CompilationUnit> jsUnit;
jsUnit.adopt(new QV4::CompiledData::CompilationUnit(cachedUnit));
return new QV4::Script(engine, qmlContext, jsUnit);
}
QFile f(fileName);
- if (!f.open(QIODevice::ReadOnly))
+ if (!f.open(QIODevice::ReadOnly)) {
+ if (error) {
+ if (cacheError == QQmlMetaType::CachedUnitLookupError::VersionMismatch)
+ *error = originalUrl.toString() + QString::fromUtf8(" was compiled ahead of time with an incompatible version of Qt and the original source code cannot be found. Please recompile");
+ else
+ *error = QString::fromUtf8("Error opening source file %1: %2").arg(originalUrl.toString()).arg(f.errorString());
+ }
return nullptr;
+ }
QByteArray data = f.readAll();
QString sourceCode = QString::fromUtf8(data);
diff --git a/src/qml/jsruntime/qv4script_p.h b/src/qml/jsruntime/qv4script_p.h
index 24291b9aa6..b4ac150044 100644
--- a/src/qml/jsruntime/qv4script_p.h
+++ b/src/qml/jsruntime/qv4script_p.h
@@ -93,7 +93,7 @@ struct Q_QML_EXPORT Script {
bool parseAsBinding;
void parse();
- ReturnedValue run();
+ ReturnedValue run(const QV4::Value *thisObject = nullptr);
Function *function();
@@ -101,7 +101,7 @@ struct Q_QML_EXPORT Script {
QV4::Compiler::Module *module, Compiler::JSUnitGenerator *unitGenerator,
const QString &fileName, const QString &finalUrl, const QString &source,
QList<QQmlError> *reportedErrors = nullptr, QQmlJS::Directives *directivesCollector = nullptr);
- static Script *createFromFileOrCache(ExecutionEngine *engine, QmlContext *qmlContext, const QString &fileName, const QUrl &originalUrl);
+ static Script *createFromFileOrCache(ExecutionEngine *engine, QmlContext *qmlContext, const QString &fileName, const QUrl &originalUrl, QString *error);
static ReturnedValue evaluate(ExecutionEngine *engine, const QString &script, QmlContext *qmlContext);
};
diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h
index 97ed13cd91..a5ee6b5373 100644
--- a/src/qml/jsruntime/qv4value_p.h
+++ b/src/qml/jsruntime/qv4value_p.h
@@ -339,7 +339,7 @@ public:
if (isDouble()) {
double d = doubleValue();
int i = (int)d;
- if (i == d) {
+ if (i == d && !(d == 0 && std::signbit(d))) {
setInt_32(i);
return true;
}
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index de86a3be5e..6adb25f964 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -1369,10 +1369,6 @@ QV4::ReturnedValue VME::exec(const FunctionObject *fo, const Value *thisObject,
STACK_VALUE(result) = Runtime::method_loadQmlImportedScripts(static_cast<QV4::NoThrowEngine*>(engine));
MOTH_END_INSTR(LoadQmlImportedScripts)
- MOTH_BEGIN_INSTR(LoadQmlSingleton)
- acc = Runtime::method_loadQmlSingleton(static_cast<QV4::NoThrowEngine*>(engine), name);
- MOTH_END_INSTR(LoadQmlSingleton)
-
catchException:
Q_ASSERT(engine->hasException);
if (!exceptionHandler) {
diff --git a/src/qml/memory/qv4mmdefs_p.h b/src/qml/memory/qv4mmdefs_p.h
index 3e2bae46c2..8a53492822 100644
--- a/src/qml/memory/qv4mmdefs_p.h
+++ b/src/qml/memory/qv4mmdefs_p.h
@@ -323,23 +323,23 @@ struct MarkStack {
#define DECLARE_HEAP_OBJECT_BASE(name, base) \
-struct name##OffsetStruct { \
- name##Members(name, HEAP_OBJECT_OFFSET_MEMBER_EXPANSION) \
-}; \
-struct name##SizeStruct : base, name##OffsetStruct {}; \
-struct name##Data { \
- typedef base SuperClass; \
- static Q_CONSTEXPR size_t baseOffset = sizeof(name##SizeStruct) - sizeof(name##OffsetStruct); \
- name##Members(name, HEAP_OBJECT_MEMBER_EXPANSION) \
-}; \
-Q_STATIC_ASSERT(sizeof(name##SizeStruct) == sizeof(name##Data) + name##Data::baseOffset); \
+ struct name##OffsetStruct { \
+ name##Members(name, HEAP_OBJECT_OFFSET_MEMBER_EXPANSION) \
+ }; \
+ struct name##SizeStruct : base, name##OffsetStruct {}; \
+ struct name##Data { \
+ typedef base SuperClass; \
+ static Q_CONSTEXPR size_t baseOffset = sizeof(name##SizeStruct) - sizeof(name##OffsetStruct); \
+ name##Members(name, HEAP_OBJECT_MEMBER_EXPANSION) \
+ }; \
+ Q_STATIC_ASSERT(sizeof(name##SizeStruct) == sizeof(name##Data) + name##Data::baseOffset); \
#define DECLARE_HEAP_OBJECT(name, base) \
-DECLARE_HEAP_OBJECT_BASE(name, base) \
-struct name : base, name##Data
+ DECLARE_HEAP_OBJECT_BASE(name, base) \
+ struct name : base, name##Data
#define DECLARE_EXPORTED_HEAP_OBJECT(name, base) \
-DECLARE_HEAP_OBJECT_BASE(name, base) \
-struct Q_QML_EXPORT name : base, name##Data
+ DECLARE_HEAP_OBJECT_BASE(name, base) \
+ struct Q_QML_EXPORT name : base, name##Data
#define DECLARE_MARKOBJECTS(class) \
static void markObjects(Heap::Base *b, MarkStack *stack) { \
diff --git a/src/qml/qml.pro b/src/qml/qml.pro
index f75bfa0313..2137877427 100644
--- a/src/qml/qml.pro
+++ b/src/qml/qml.pro
@@ -36,7 +36,8 @@ DEFINES += QT_NO_FOREACH
}
compile_hash_contents = \
"// Generated file, DO NOT EDIT" \
- "$${LITERAL_HASH}define QML_COMPILE_HASH \"$$QML_COMPILE_HASH\""
+ "$${LITERAL_HASH}define QML_COMPILE_HASH \"$$QML_COMPILE_HASH\"" \
+ "$${LITERAL_HASH}define QML_COMPILE_HASH_LENGTH $$str_size($$QML_COMPILE_HASH)"
write_file("$$OUT_PWD/qml_compile_hash_p.h", compile_hash_contents)|error()
}
diff --git a/src/qml/qml/ftw/qqmlthread.cpp b/src/qml/qml/ftw/qqmlthread.cpp
index a36a599f24..9c44e18b87 100644
--- a/src/qml/qml/ftw/qqmlthread.cpp
+++ b/src/qml/qml/ftw/qqmlthread.cpp
@@ -57,6 +57,7 @@ public:
void run() override;
+ inline QMutex &mutex() { return _mutex; }
inline void lock() { _mutex.lock(); }
inline void unlock() { _mutex.unlock(); }
inline void wait() { _wait.wait(&_mutex); }
@@ -269,6 +270,11 @@ bool QQmlThread::isShutdown() const
return d->m_shutdown;
}
+QMutex &QQmlThread::mutex()
+{
+ return d->mutex();
+}
+
void QQmlThread::lock()
{
d->lock();
diff --git a/src/qml/qml/ftw/qqmlthread_p.h b/src/qml/qml/ftw/qqmlthread_p.h
index 0ed12a2972..b5c580fe8b 100644
--- a/src/qml/qml/ftw/qqmlthread_p.h
+++ b/src/qml/qml/ftw/qqmlthread_p.h
@@ -59,6 +59,7 @@
QT_BEGIN_NAMESPACE
class QThread;
+class QMutex;
class QQmlThreadPrivate;
class QQmlThread
@@ -71,6 +72,7 @@ public:
void shutdown();
bool isShutdown() const;
+ QMutex &mutex();
void lock();
void unlock();
void wakeOne();
diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp
index ca3bff43a4..30a18440a8 100644
--- a/src/qml/qml/qqmlbinding.cpp
+++ b/src/qml/qml/qqmlbinding.cpp
@@ -51,6 +51,7 @@
#include <private/qqmlvaluetypewrapper_p.h>
#include <private/qv4qobjectwrapper_p.h>
#include <private/qv4variantobject_p.h>
+#include <private/qv4jscall_p.h>
#include <QVariant>
#include <QtCore/qdebug.h>
@@ -97,6 +98,21 @@ QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, const QQmlScr
return b;
}
+QQmlSourceLocation QQmlBinding::sourceLocation() const
+{
+ if (m_sourceLocation)
+ return *m_sourceLocation;
+ return QQmlJavaScriptExpression::sourceLocation();
+}
+
+void QQmlBinding::setSourceLocation(const QQmlSourceLocation &location)
+{
+ if (m_sourceLocation)
+ delete m_sourceLocation;
+ m_sourceLocation = new QQmlSourceLocation(location);
+}
+
+
QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, const QString &str, QObject *obj,
QQmlContextData *ctxt, const QString &url, quint16 lineNumber)
{
@@ -128,6 +144,7 @@ QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, QV4::Function
QQmlBinding::~QQmlBinding()
{
+ delete m_sourceLocation;
}
void QQmlBinding::setNotifyOnValueChanged(bool v)
@@ -171,6 +188,28 @@ void QQmlBinding::update(QQmlPropertyData::WriteFlags flags)
setUpdatingFlag(false);
}
+QV4::ReturnedValue QQmlBinding::evaluate(bool *isUndefined)
+{
+ QV4::ExecutionEngine *v4 = context()->engine->handle();
+ int argc = 0;
+ const QV4::Value *argv = nullptr;
+ const QV4::Value *thisObject = nullptr;
+ QV4::BoundFunction *b = nullptr;
+ if ((b = static_cast<QV4::BoundFunction *>(m_boundFunction.valueRef()))) {
+ QV4::Heap::MemberData *args = b->boundArgs();
+ if (args) {
+ argc = args->values.size;
+ argv = args->values.data();
+ }
+ thisObject = &b->d()->boundThis;
+ }
+ QV4::Scope scope(v4);
+ QV4::JSCallData jsCall(scope, argc, argv, thisObject);
+
+ return QQmlJavaScriptExpression::evaluate(jsCall.callData(), isUndefined);
+}
+
+
// QQmlBindingBinding is for target properties which are of type "binding" (instead of, say, int or
// double). The reason for being is that GenericBinding::fastWrite needs a compile-time constant
// expression for the switch for the compiler to generate the optimal code, but
@@ -203,7 +242,7 @@ protected:
bool isUndefined = false;
- QV4::ScopedValue result(scope, QQmlJavaScriptExpression::evaluate(&isUndefined));
+ QV4::ScopedValue result(scope, evaluate(&isUndefined));
bool error = false;
if (!watcher.wasDeleted() && isAddedToObject() && !hasError())
@@ -302,9 +341,14 @@ public:
{
setCompilationUnit(compilationUnit);
m_binding = binding;
- setSourceLocation(QQmlSourceLocation(compilationUnit->fileName(), binding->valueLocation.line, binding->valueLocation.column));
}
+ QQmlSourceLocation sourceLocation() const override final
+ {
+ return QQmlSourceLocation(m_compilationUnit->fileName(), m_binding->valueLocation.line, m_binding->valueLocation.column);
+ }
+
+
void doUpdate(const DeleteWatcher &watcher,
QQmlPropertyData::WriteFlags flags, QV4::Scope &scope) override final
{
@@ -490,6 +534,7 @@ void QQmlBinding::refresh()
void QQmlBinding::setEnabled(bool e, QQmlPropertyData::WriteFlags flags)
{
+ const bool wasEnabled = enabledFlag();
setEnabledFlag(e);
setNotifyOnValueChanged(e);
@@ -499,7 +544,7 @@ void QQmlBinding::setEnabled(bool e, QQmlPropertyData::WriteFlags flags)
m_nextBinding.clearFlag2();
}
- if (e)
+ if (e && !wasEnabled)
update(flags);
}
@@ -514,13 +559,13 @@ void QQmlBinding::setTarget(const QQmlProperty &prop)
setTarget(prop.object(), pd->core, &pd->valueTypeData);
}
-void QQmlBinding::setTarget(QObject *object, const QQmlPropertyData &core, const QQmlPropertyData *valueType)
+bool QQmlBinding::setTarget(QObject *object, const QQmlPropertyData &core, const QQmlPropertyData *valueType)
{
m_target = object;
if (!object) {
m_targetIndex = QQmlPropertyIndex();
- return;
+ return false;
}
int coreIndex = core.coreIndex();
@@ -530,9 +575,10 @@ void QQmlBinding::setTarget(QObject *object, const QQmlPropertyData &core, const
int aValueTypeIndex;
if (!vme->aliasTarget(coreIndex, &object, &coreIndex, &aValueTypeIndex)) {
+ // can't resolve id (yet)
m_target = nullptr;
m_targetIndex = QQmlPropertyIndex();
- return;
+ return false;
}
if (valueTypeIndex == -1)
valueTypeIndex = aValueTypeIndex;
@@ -541,7 +587,7 @@ void QQmlBinding::setTarget(QObject *object, const QQmlPropertyData &core, const
if (!data || !data->propertyCache) {
m_target = nullptr;
m_targetIndex = QQmlPropertyIndex();
- return;
+ return false;
}
QQmlPropertyData *propertyData = data->propertyCache->property(coreIndex);
Q_ASSERT(propertyData);
@@ -557,6 +603,8 @@ void QQmlBinding::setTarget(QObject *object, const QQmlPropertyData &core, const
data->propertyCache = QQmlEnginePrivate::get(context()->engine)->cache(m_target->metaObject());
data->propertyCache->addref();
}
+
+ return true;
}
void QQmlBinding::getPropertyData(QQmlPropertyData **propertyData, QQmlPropertyData *valueTypeData) const
diff --git a/src/qml/qml/qqmlbinding_p.h b/src/qml/qml/qqmlbinding_p.h
index 19ec3f5d4f..a1295bd0ac 100644
--- a/src/qml/qml/qqmlbinding_p.h
+++ b/src/qml/qml/qqmlbinding_p.h
@@ -72,6 +72,8 @@ class Q_QML_PRIVATE_EXPORT QQmlBinding : public QQmlJavaScriptExpression,
{
friend class QQmlAbstractBinding;
public:
+ typedef QExplicitlySharedDataPointer<QQmlBinding> Ptr;
+
static QQmlBinding *create(const QQmlPropertyData *, const QQmlScriptString &, QObject *, QQmlContext *);
static QQmlBinding *create(const QQmlPropertyData *, const QString &, QObject *, QQmlContextData *,
const QString &url = QString(), quint16 lineNumber = 0);
@@ -82,7 +84,7 @@ public:
~QQmlBinding() override;
void setTarget(const QQmlProperty &);
- void setTarget(QObject *, const QQmlPropertyData &, const QQmlPropertyData *valueType);
+ bool setTarget(QObject *, const QQmlPropertyData &, const QQmlPropertyData *valueType);
void setNotifyOnValueChanged(bool);
@@ -102,6 +104,12 @@ public:
QString expressionIdentifier() const override;
void expressionChanged() override;
+ QQmlSourceLocation sourceLocation() const override;
+ void setSourceLocation(const QQmlSourceLocation &location);
+ void setBoundFunction(QV4::BoundFunction *boundFunction) {
+ m_boundFunction.set(boundFunction->engine(), *boundFunction);
+ }
+
/**
* This method returns a snapshot of the currently tracked dependencies of
* this binding. The dependencies can change upon reevaluation. This method is
@@ -121,6 +129,8 @@ protected:
bool slowWrite(const QQmlPropertyData &core, const QQmlPropertyData &valueTypeData,
const QV4::Value &result, bool isUndefined, QQmlPropertyData::WriteFlags flags);
+ QV4::ReturnedValue evaluate(bool *isUndefined);
+
private:
inline bool updatingFlag() const;
inline void setUpdatingFlag(bool);
@@ -128,6 +138,9 @@ private:
inline void setEnabledFlag(bool);
static QQmlBinding *newBinding(QQmlEnginePrivate *engine, const QQmlPropertyData *property);
+
+ QQmlSourceLocation *m_sourceLocation = nullptr; // used for Qt.binding() created functions
+ QV4::PersistentValue m_boundFunction; // used for Qt.binding() that are created from a bound function object
};
bool QQmlBinding::updatingFlag() const
diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp
index 060706ac50..d5117c8cec 100644
--- a/src/qml/qml/qqmlboundsignal.cpp
+++ b/src/qml/qml/qqmlboundsignal.cpp
@@ -110,6 +110,12 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index,
m_index(index),
m_target(target)
{
+ // If the function is marked as having a nested function, then the user wrote:
+ // onSomeSignal: function() { /*....*/ }
+ // So take that nested function:
+ if (auto closure = function->nestedFunction())
+ function = closure;
+
setupFunction(scope, function);
init(ctxt, scopeObject);
}
@@ -122,6 +128,12 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index,
// It's important to call init first, because m_index gets remapped in case of cloned signals.
init(ctxt, scope);
+ // If the function is marked as having a nested function, then the user wrote:
+ // onSomeSignal: function() { /*....*/ }
+ // So take that nested function:
+ if (auto closure = runtimeFunction->nestedFunction())
+ runtimeFunction = closure;
+
QV4::ExecutionEngine *engine = ctxt->engine->handle();
QList<QByteArray> signalParameters = QMetaObjectPrivate::signal(m_target->metaObject(), m_index).parameterNames();
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index 3174bbecd3..fe4768db15 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -929,8 +929,7 @@ void QQmlComponentPrivate::complete(QQmlEnginePrivate *enginePriv, ConstructionS
if (0 == enginePriv->inProgressCreations) {
while (enginePriv->erroredBindings) {
- enginePriv->warning(enginePriv->erroredBindings);
- enginePriv->erroredBindings->removeError();
+ enginePriv->warning(enginePriv->erroredBindings->removeError());
}
}
}
diff --git a/src/qml/qml/qqmlcontext.cpp b/src/qml/qml/qqmlcontext.cpp
index 6e43bc735f..5dd3278b4c 100644
--- a/src/qml/qml/qqmlcontext.cpp
+++ b/src/qml/qml/qqmlcontext.cpp
@@ -593,6 +593,14 @@ void QQmlContextData::invalidate()
parent = nullptr;
}
+void QQmlContextData::clearContextRecursively()
+{
+ clearContext();
+
+ for (auto ctxIt = childContexts; ctxIt; ctxIt = ctxIt->nextChild)
+ ctxIt->clearContextRecursively();
+}
+
void QQmlContextData::clearContext()
{
emitDestruction();
diff --git a/src/qml/qml/qqmlcontext_p.h b/src/qml/qml/qqmlcontext_p.h
index ff36d6c9a8..5dfee48848 100644
--- a/src/qml/qml/qqmlcontext_p.h
+++ b/src/qml/qml/qqmlcontext_p.h
@@ -115,6 +115,7 @@ public:
QQmlContextData(QQmlContext *);
void emitDestruction();
void clearContext();
+ void clearContextRecursively();
void invalidate();
inline bool isValid() const {
diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h
index 20b96d2c4b..59fefde893 100644
--- a/src/qml/qml/qqmldata_p.h
+++ b/src/qml/qml/qqmldata_p.h
@@ -208,12 +208,12 @@ public:
QQmlData**prevContextObject;
inline bool hasBindingBit(int) const;
- void clearBindingBit(int);
- void setBindingBit(QObject *obj, int);
+ inline void setBindingBit(QObject *obj, int);
+ inline void clearBindingBit(int);
inline bool hasPendingBindingBit(int index) const;
- void setPendingBindingBit(QObject *obj, int);
- void clearPendingBindingBit(int);
+ inline void setPendingBindingBit(QObject *obj, int);
+ inline void clearPendingBindingBit(int);
quint16 lineNumber;
quint16 columnNumber;
@@ -304,6 +304,27 @@ private:
const BindingBitsType *bits = (bindingBitsArraySize == InlineBindingArraySize) ? bindingBitsValue : bindingBits;
return bits[offset] & bitFlagForBit(bit);
}
+
+ Q_ALWAYS_INLINE void clearBit(int bit)
+ {
+ uint offset = QQmlData::offsetForBit(bit);
+ if (bindingBitsArraySize > offset) {
+ BindingBitsType *bits = (bindingBitsArraySize == InlineBindingArraySize) ? bindingBitsValue : bindingBits;
+ bits[offset] &= ~QQmlData::bitFlagForBit(bit);
+ }
+ }
+
+ Q_ALWAYS_INLINE void setBit(QObject *obj, int bit)
+ {
+ uint offset = QQmlData::offsetForBit(bit);
+ BindingBitsType *bits = (bindingBitsArraySize == InlineBindingArraySize) ? bindingBitsValue : bindingBits;
+ if (Q_UNLIKELY(bindingBitsArraySize <= offset))
+ bits = growBits(obj, bit);
+ bits[offset] |= QQmlData::bitFlagForBit(bit);
+ }
+
+ Q_NEVER_INLINE BindingBitsType *growBits(QObject *obj, int bit);
+
Q_DISABLE_COPY(QQmlData);
};
@@ -356,6 +377,20 @@ bool QQmlData::hasBindingBit(int coreIndex) const
return hasBitSet(coreIndex * 2);
}
+void QQmlData::setBindingBit(QObject *obj, int coreIndex)
+{
+ Q_ASSERT(coreIndex >= 0);
+ Q_ASSERT(coreIndex <= 0xffff);
+ setBit(obj, coreIndex * 2);
+}
+
+void QQmlData::clearBindingBit(int coreIndex)
+{
+ Q_ASSERT(coreIndex >= 0);
+ Q_ASSERT(coreIndex <= 0xffff);
+ clearBit(coreIndex * 2);
+}
+
bool QQmlData::hasPendingBindingBit(int coreIndex) const
{
Q_ASSERT(coreIndex >= 0);
@@ -364,6 +399,20 @@ bool QQmlData::hasPendingBindingBit(int coreIndex) const
return hasBitSet(coreIndex * 2 + 1);
}
+void QQmlData::setPendingBindingBit(QObject *obj, int coreIndex)
+{
+ Q_ASSERT(coreIndex >= 0);
+ Q_ASSERT(coreIndex <= 0xffff);
+ setBit(obj, coreIndex * 2 + 1);
+}
+
+void QQmlData::clearPendingBindingBit(int coreIndex)
+{
+ Q_ASSERT(coreIndex >= 0);
+ Q_ASSERT(coreIndex <= 0xffff);
+ clearBit(coreIndex * 2 + 1);
+}
+
void QQmlData::flushPendingBinding(QObject *o, QQmlPropertyIndex propertyIndex)
{
QQmlData *data = QQmlData::get(o, false);
diff --git a/src/qml/qml/qqmldirparser_p.h b/src/qml/qml/qqmldirparser_p.h
index 95370398ad..820c40238d 100644
--- a/src/qml/qml/qqmldirparser_p.h
+++ b/src/qml/qml/qqmldirparser_p.h
@@ -63,8 +63,6 @@ class QQmlError;
class QQmlEngine;
class Q_QML_PRIVATE_EXPORT QQmlDirParser
{
- Q_DISABLE_COPY(QQmlDirParser)
-
public:
QQmlDirParser();
~QQmlDirParser();
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index 4054d2f0be..7e11177caa 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -88,7 +88,9 @@
#include <private/qqmllistmodel_p.h>
#include <private/qqmlplatform_p.h>
#include <private/qquickpackage_p.h>
+#if QT_CONFIG(qml_delegate_model)
#include <private/qqmldelegatemodel_p.h>
+#endif
#include <private/qqmlobjectmodel_p.h>
#include <private/qquickworkerscript_p.h>
#include <private/qqmlinstantiator_p.h>
@@ -109,12 +111,6 @@ Q_DECLARE_METATYPE(QQmlProperty)
QT_BEGIN_NAMESPACE
-typedef QQmlData::BindingBitsType BindingBitsType;
-enum {
- BitsPerType = QQmlData::BitsPerType,
- InlineBindingArraySize = QQmlData::InlineBindingArraySize
-};
-
void qmlRegisterBaseTypes(const char *uri, int versionMajor, int versionMinor)
{
QQmlEnginePrivate::registerBaseTypes(uri, versionMajor, versionMinor);
@@ -240,8 +236,10 @@ void QQmlEnginePrivate::registerQtQuick2Types(const char *uri, int versionMajor,
qmlRegisterCustomType<QQmlListModel>(uri, versionMajor, versionMinor, "ListModel", new QQmlListModelParser); // Now in QtQml.Models, here for compatibility
qmlRegisterType<QQuickWorkerScript>(uri, versionMajor, versionMinor, "WorkerScript");
qmlRegisterType<QQuickPackage>(uri, versionMajor, versionMinor, "Package");
+#if QT_CONFIG(qml_delegate_model)
qmlRegisterType<QQmlDelegateModel>(uri, versionMajor, versionMinor, "VisualDataModel");
qmlRegisterType<QQmlDelegateModelGroup>(uri, versionMajor, versionMinor, "VisualDataGroup");
+#endif
qmlRegisterType<QQmlObjectModel>(uri, versionMajor, versionMinor, "VisualItemModel");
}
@@ -253,6 +251,9 @@ void QQmlEnginePrivate::defineQtQuick2Module()
// register the QtQuick2 types which are implemented in the QtQml module.
registerQtQuick2Types("QtQuick",2,0);
qmlRegisterUncreatableType<QQmlLocale>("QtQuick", 2, 0, "Locale", QQmlEngine::tr("Locale cannot be instantiated. Use Qt.locale()"));
+
+ // Auto-increment the import to stay in sync with ALL future QtQuick minor versions from 5.11 onward
+ qmlRegisterModule("QtQuick", 2, QT_VERSION_MINOR);
}
bool QQmlEnginePrivate::designerMode()
@@ -952,6 +953,9 @@ void QQmlEnginePrivate::init()
registerBaseTypes("QtQml", 2, 0); // import which provides language building blocks.
qmlRegisterUncreatableType<QQmlLocale>("QtQml", 2, 2, "Locale", QQmlEngine::tr("Locale cannot be instantiated. Use Qt.locale()"));
+ // Auto-increment the import to stay in sync with ALL future QtQml minor versions from 5.11 onward
+ qmlRegisterModule("QtQml", 2, QT_VERSION_MINOR);
+
QQmlData::init();
baseModulesUninitialized = false;
}
@@ -1104,7 +1108,9 @@ QQmlEngine::~QQmlEngine()
void QQmlEngine::clearComponentCache()
{
Q_D(QQmlEngine);
+ d->typeLoader.lock();
d->typeLoader.clearCache();
+ d->typeLoader.unlock();
}
/*!
@@ -1884,66 +1890,27 @@ void QQmlData::parentChanged(QObject *object, QObject *parent)
}
}
-static void QQmlData_setBit(QQmlData *data, QObject *obj, int bit)
+QQmlData::BindingBitsType *QQmlData::growBits(QObject *obj, int bit)
{
- uint offset = QQmlData::offsetForBit(bit);
- BindingBitsType *bits = (data->bindingBitsArraySize == InlineBindingArraySize) ? data->bindingBitsValue : data->bindingBits;
- if (Q_UNLIKELY(data->bindingBitsArraySize <= offset)) {
- int props = QQmlMetaObject(obj).propertyCount();
- Q_ASSERT(bit < 2 * props);
-
- uint arraySize = (2 * static_cast<uint>(props) + BitsPerType - 1) / BitsPerType;
- Q_ASSERT(arraySize > InlineBindingArraySize && arraySize > data->bindingBitsArraySize);
+ BindingBitsType *bits = (bindingBitsArraySize == InlineBindingArraySize) ? bindingBitsValue : bindingBits;
+ int props = QQmlMetaObject(obj).propertyCount();
+ Q_ASSERT(bit < 2 * props);
+ Q_UNUSED(bit); // .. for Q_NO_DEBUG mode when the assert above expands to empty
- BindingBitsType *newBits = static_cast<BindingBitsType *>(malloc(arraySize*sizeof(BindingBitsType)));
- memcpy(newBits, bits, data->bindingBitsArraySize * sizeof(BindingBitsType));
- memset(newBits + data->bindingBitsArraySize, 0, sizeof(BindingBitsType) * (arraySize - data->bindingBitsArraySize));
+ uint arraySize = (2 * static_cast<uint>(props) + BitsPerType - 1) / BitsPerType;
+ Q_ASSERT(arraySize > 1);
+ Q_ASSERT(arraySize <= 0xffff); // max for bindingBitsArraySize
- if (data->bindingBitsArraySize > InlineBindingArraySize)
- free(bits);
- data->bindingBits = newBits;
- bits = newBits;
- data->bindingBitsArraySize = arraySize;
- }
- Q_ASSERT(offset < data->bindingBitsArraySize);
- bits[offset] |= QQmlData::bitFlagForBit(bit);
-}
+ BindingBitsType *newBits = static_cast<BindingBitsType *>(malloc(arraySize*sizeof(BindingBitsType)));
+ memcpy(newBits, bits, bindingBitsArraySize * sizeof(BindingBitsType));
+ memset(newBits + bindingBitsArraySize, 0, sizeof(BindingBitsType) * (arraySize - bindingBitsArraySize));
-static void QQmlData_clearBit(QQmlData *data, int bit)
-{
- uint offset = QQmlData::offsetForBit(bit);
- if (data->bindingBitsArraySize > offset) {
- BindingBitsType *bits = (data->bindingBitsArraySize == InlineBindingArraySize) ? data->bindingBitsValue : data->bindingBits;
- bits[offset] &= ~QQmlData::bitFlagForBit(bit);
- }
-}
-
-void QQmlData::clearBindingBit(int coreIndex)
-{
- Q_ASSERT(coreIndex >= 0);
- Q_ASSERT(coreIndex <= 0xffff);
- QQmlData_clearBit(this, coreIndex * 2);
-}
-
-void QQmlData::setBindingBit(QObject *obj, int coreIndex)
-{
- Q_ASSERT(coreIndex >= 0);
- Q_ASSERT(coreIndex <= 0xffff);
- QQmlData_setBit(this, obj, coreIndex * 2);
-}
-
-void QQmlData::clearPendingBindingBit(int coreIndex)
-{
- Q_ASSERT(coreIndex >= 0);
- Q_ASSERT(coreIndex <= 0xffff);
- QQmlData_clearBit(this, coreIndex * 2 + 1);
-}
-
-void QQmlData::setPendingBindingBit(QObject *obj, int coreIndex)
-{
- Q_ASSERT(coreIndex >= 0);
- Q_ASSERT(coreIndex <= 0xffff);
- QQmlData_setBit(this, obj, coreIndex * 2 + 1);
+ if (bindingBitsArraySize > InlineBindingArraySize)
+ free(bits);
+ bindingBits = newBits;
+ bits = newBits;
+ bindingBitsArraySize = arraySize;
+ return bits;
}
QQmlData *QQmlData::createQQmlData(QObjectPrivate *priv)
@@ -2029,11 +1996,6 @@ void QQmlEnginePrivate::warning(const QList<QQmlError> &errors)
dumpwarning(errors);
}
-void QQmlEnginePrivate::warning(QQmlDelayedError *error)
-{
- warning(error->error());
-}
-
void QQmlEnginePrivate::warning(QQmlEngine *engine, const QQmlError &error)
{
if (engine)
@@ -2050,14 +2012,6 @@ void QQmlEnginePrivate::warning(QQmlEngine *engine, const QList<QQmlError> &erro
dumpwarning(error);
}
-void QQmlEnginePrivate::warning(QQmlEngine *engine, QQmlDelayedError *error)
-{
- if (engine)
- QQmlEnginePrivate::get(engine)->warning(error);
- else
- dumpwarning(error->error());
-}
-
void QQmlEnginePrivate::warning(QQmlEnginePrivate *engine, const QQmlError &error)
{
if (engine)
diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h
index d6110c6699..da52e01793 100644
--- a/src/qml/qml/qqmlengine_p.h
+++ b/src/qml/qml/qqmlengine_p.h
@@ -231,10 +231,8 @@ public:
void sendExit(int retCode = 0);
void warning(const QQmlError &);
void warning(const QList<QQmlError> &);
- void warning(QQmlDelayedError *);
static void warning(QQmlEngine *, const QQmlError &);
static void warning(QQmlEngine *, const QList<QQmlError> &);
- static void warning(QQmlEngine *, QQmlDelayedError *);
static void warning(QQmlEnginePrivate *, const QQmlError &);
static void warning(QQmlEnginePrivate *, const QList<QQmlError> &);
diff --git a/src/qml/qml/qqmlexpression.cpp b/src/qml/qml/qqmlexpression.cpp
index 59cc9bb09f..27d3acb9b7 100644
--- a/src/qml/qml/qqmlexpression.cpp
+++ b/src/qml/qml/qqmlexpression.cpp
@@ -252,6 +252,11 @@ QV4::ReturnedValue QQmlExpressionPrivate::v4value(bool *isUndefined)
if (!expressionFunctionValid) {
createQmlBinding(context(), scopeObject(), expression, url, line);
expressionFunctionValid = true;
+ if (hasError()) {
+ if (isUndefined)
+ *isUndefined = true;
+ return QV4::Encode::undefined();
+ }
}
return evaluate(isUndefined);
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index 92cecf9f0d..fe7e5d5a33 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -318,17 +318,17 @@ public:
QQmlImportDatabase *database,
QString *outQmldirFilePath, QString *outUrl);
- static bool validateQmldirVersion(const QQmlTypeLoaderQmldirContent *qmldir, const QString &uri, int vmaj, int vmin,
+ static bool validateQmldirVersion(const QQmlTypeLoaderQmldirContent &qmldir, const QString &uri, int vmaj, int vmin,
QList<QQmlError> *errors);
bool importExtension(const QString &absoluteFilePath, const QString &uri,
int vmaj, int vmin,
QQmlImportDatabase *database,
- const QQmlTypeLoaderQmldirContent *qmldir,
+ const QQmlTypeLoaderQmldirContent &qmldir,
QList<QQmlError> *errors);
bool getQmldirContent(const QString &qmldirIdentifier, const QString &uri,
- const QQmlTypeLoaderQmldirContent **qmldir, QList<QQmlError> *errors);
+ QQmlTypeLoaderQmldirContent *qmldir, QList<QQmlError> *errors);
QString resolvedUri(const QString &dir_arg, QQmlImportDatabase *database);
@@ -668,14 +668,14 @@ bool QQmlImports::resolveType(const QHashedStringRef &type,
return false;
}
-bool QQmlImportInstance::setQmldirContent(const QString &resolvedUrl, const QQmlTypeLoaderQmldirContent *qmldir, QQmlImportNamespace *nameSpace, QList<QQmlError> *errors)
+bool QQmlImportInstance::setQmldirContent(const QString &resolvedUrl, const QQmlTypeLoaderQmldirContent &qmldir, QQmlImportNamespace *nameSpace, QList<QQmlError> *errors)
{
Q_ASSERT(resolvedUrl.endsWith(Slash));
url = resolvedUrl;
- qmlDirComponents = qmldir->components();
+ qmlDirComponents = qmldir.components();
- const QQmlDirScripts &scripts = qmldir->scripts();
+ const QQmlDirScripts &scripts = qmldir.scripts();
if (!scripts.isEmpty()) {
// Verify that we haven't imported these scripts already
for (QList<QQmlImportInstance *>::const_iterator it = nameSpace->imports.constBegin();
@@ -1068,26 +1068,26 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath,
const QString &uri,
int vmaj, int vmin,
QQmlImportDatabase *database,
- const QQmlTypeLoaderQmldirContent *qmldir,
+ const QQmlTypeLoaderQmldirContent &qmldir,
QList<QQmlError> *errors)
{
- Q_ASSERT(qmldir);
+ Q_ASSERT(qmldir.hasContent());
if (qmlImportTrace())
qDebug().nospace() << "QQmlImports(" << qPrintable(base) << ")::importExtension: "
<< "loaded " << qmldirFilePath;
- if (designerSupportRequired && !qmldir->designerSupported()) {
+ if (designerSupportRequired && !qmldir.designerSupported()) {
if (errors) {
QQmlError error;
- error.setDescription(QQmlImportDatabase::tr("module does not support the designer \"%1\"").arg(qmldir->typeNamespace()));
+ error.setDescription(QQmlImportDatabase::tr("module does not support the designer \"%1\"").arg(qmldir.typeNamespace()));
error.setUrl(QUrl::fromLocalFile(qmldirFilePath));
errors->prepend(error);
}
return false;
}
- int qmldirPluginCount = qmldir->plugins().count();
+ int qmldirPluginCount = qmldir.plugins().count();
if (qmldirPluginCount == 0)
return true;
@@ -1098,7 +1098,7 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath,
// listed plugin inside qmldir. And for this reason, mixing dynamic and static plugins inside a
// single module is not recommended.
- QString typeNamespace = qmldir->typeNamespace();
+ QString typeNamespace = qmldir.typeNamespace();
QString qmldirPath = qmldirFilePath;
int slash = qmldirPath.lastIndexOf(Slash);
if (slash > 0)
@@ -1108,7 +1108,7 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath,
int staticPluginsFound = 0;
#if defined(QT_SHARED)
- const auto qmldirPlugins = qmldir->plugins();
+ const auto qmldirPlugins = qmldir.plugins();
for (const QQmlDirParser::Plugin &plugin : qmldirPlugins) {
QString resolvedFilePath = database->resolvePlugin(typeLoader, qmldirPath, plugin.path, plugin.name);
if (!resolvedFilePath.isEmpty()) {
@@ -1174,7 +1174,7 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath,
if (qmldirPluginCount > 1 && staticPluginsFound > 0)
error.setDescription(QQmlImportDatabase::tr("could not resolve all plugins for module \"%1\"").arg(uri));
else
- error.setDescription(QQmlImportDatabase::tr("module \"%1\" plugin \"%2\" not found").arg(uri).arg(qmldir->plugins()[dynamicPluginsFound].name));
+ error.setDescription(QQmlImportDatabase::tr("module \"%1\" plugin \"%2\" not found").arg(uri).arg(qmldir.plugins()[dynamicPluginsFound].name));
error.setUrl(QUrl::fromLocalFile(qmldirFilePath));
errors->prepend(error);
}
@@ -1187,17 +1187,17 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath,
}
bool QQmlImportsPrivate::getQmldirContent(const QString &qmldirIdentifier, const QString &uri,
- const QQmlTypeLoaderQmldirContent **qmldir, QList<QQmlError> *errors)
+ QQmlTypeLoaderQmldirContent *qmldir, QList<QQmlError> *errors)
{
Q_ASSERT(errors);
Q_ASSERT(qmldir);
*qmldir = typeLoader->qmldirContent(qmldirIdentifier);
- if (*qmldir) {
+ if ((*qmldir).hasContent()) {
// Ensure that parsing was successful
- if ((*qmldir)->hasError()) {
+ if ((*qmldir).hasError()) {
QUrl url = QUrl::fromLocalFile(qmldirIdentifier);
- const QList<QQmlError> qmldirErrors = (*qmldir)->errors(uri);
+ const QList<QQmlError> qmldirErrors = (*qmldir).errors(uri);
for (int i = 0; i < qmldirErrors.size(); ++i) {
QQmlError error = qmldirErrors.at(i);
error.setUrl(url);
@@ -1322,14 +1322,14 @@ bool QQmlImportsPrivate::locateQmldir(const QString &uri, int vmaj, int vmin, QQ
return false;
}
-bool QQmlImportsPrivate::validateQmldirVersion(const QQmlTypeLoaderQmldirContent *qmldir, const QString &uri, int vmaj, int vmin,
+bool QQmlImportsPrivate::validateQmldirVersion(const QQmlTypeLoaderQmldirContent &qmldir, const QString &uri, int vmaj, int vmin,
QList<QQmlError> *errors)
{
int lowest_min = INT_MAX;
int highest_min = INT_MIN;
typedef QQmlDirComponents::const_iterator ConstIterator;
- const QQmlDirComponents &components = qmldir->components();
+ const QQmlDirComponents &components = qmldir.components();
ConstIterator cend = components.constEnd();
for (ConstIterator cit = components.constBegin(); cit != cend; ++cit) {
@@ -1353,7 +1353,7 @@ bool QQmlImportsPrivate::validateQmldirVersion(const QQmlTypeLoaderQmldirContent
}
typedef QList<QQmlDirParser::Script>::const_iterator SConstIterator;
- const QQmlDirScripts &scripts = qmldir->scripts();
+ const QQmlDirScripts &scripts = qmldir.scripts();
SConstIterator send = scripts.constEnd();
for (SConstIterator sit = scripts.constBegin(); sit != send; ++sit) {
@@ -1445,14 +1445,14 @@ bool QQmlImportsPrivate::addLibraryImport(const QString& uri, const QString &pre
Q_ASSERT(inserted);
if (!incomplete) {
- const QQmlTypeLoaderQmldirContent *qmldir = nullptr;
+ QQmlTypeLoaderQmldirContent qmldir;
if (!qmldirIdentifier.isEmpty()) {
if (!getQmldirContent(qmldirIdentifier, uri, &qmldir, errors))
return false;
- if (qmldir) {
- if (!importExtension(qmldir->pluginLocation(), uri, vmaj, vmin, database, qmldir, errors))
+ if (qmldir.hasContent()) {
+ if (!importExtension(qmldir.pluginLocation(), uri, vmaj, vmin, database, qmldir, errors))
return false;
if (!inserted->setQmldirContent(qmldirUrl, qmldir, nameSpace, errors))
@@ -1470,7 +1470,7 @@ bool QQmlImportsPrivate::addLibraryImport(const QString& uri, const QString &pre
error.setDescription(QQmlImportDatabase::tr("module \"%1\" is not installed").arg(uri));
errors->prepend(error);
return false;
- } else if ((vmaj >= 0) && (vmin >= 0) && qmldir) {
+ } else if ((vmaj >= 0) && (vmin >= 0) && qmldir.hasContent()) {
// Verify that the qmldir content is valid for this version
if (!validateQmldirVersion(qmldir, uri, vmaj, vmin, errors))
return false;
@@ -1564,12 +1564,12 @@ bool QQmlImportsPrivate::addFileImport(const QString& uri, const QString &prefix
Q_ASSERT(inserted);
if (!incomplete && !qmldirIdentifier.isEmpty()) {
- const QQmlTypeLoaderQmldirContent *qmldir = nullptr;
+ QQmlTypeLoaderQmldirContent qmldir;
if (!getQmldirContent(qmldirIdentifier, importUri, &qmldir, errors))
return false;
- if (qmldir) {
- if (!importExtension(qmldir->pluginLocation(), importUri, vmaj, vmin, database, qmldir, errors))
+ if (qmldir.hasContent()) {
+ if (!importExtension(qmldir.pluginLocation(), importUri, vmaj, vmin, database, qmldir, errors))
return false;
if (!inserted->setQmldirContent(url, qmldir, nameSpace, errors))
@@ -1588,14 +1588,14 @@ bool QQmlImportsPrivate::updateQmldirContent(const QString &uri, const QString &
Q_ASSERT(nameSpace);
if (QQmlImportInstance *import = nameSpace->findImport(uri)) {
- const QQmlTypeLoaderQmldirContent *qmldir = nullptr;
+ QQmlTypeLoaderQmldirContent qmldir;
if (!getQmldirContent(qmldirIdentifier, uri, &qmldir, errors))
return false;
- if (qmldir) {
+ if (qmldir.hasContent()) {
int vmaj = import->majversion;
int vmin = import->minversion;
- if (!importExtension(qmldir->pluginLocation(), uri, vmaj, vmin, database, qmldir, errors))
+ if (!importExtension(qmldir.pluginLocation(), uri, vmaj, vmin, database, qmldir, errors))
return false;
if (import->setQmldirContent(qmldirUrl, qmldir, nameSpace, errors)) {
diff --git a/src/qml/qml/qqmlimport_p.h b/src/qml/qml/qqmlimport_p.h
index b70bb5253c..2437979ef8 100644
--- a/src/qml/qml/qqmlimport_p.h
+++ b/src/qml/qml/qqmlimport_p.h
@@ -85,7 +85,7 @@ struct QQmlImportInstance
QQmlDirComponents qmlDirComponents; // a copy of the components listed in the qmldir
QQmlDirScripts qmlDirScripts; // a copy of the scripts in the qmldir
- bool setQmldirContent(const QString &resolvedUrl, const QQmlTypeLoaderQmldirContent *qmldir,
+ bool setQmldirContent(const QString &resolvedUrl, const QQmlTypeLoaderQmldirContent &qmldir,
QQmlImportNamespace *nameSpace, QList<QQmlError> *errors);
static QQmlDirScripts getVersionedScripts(const QQmlDirScripts &qmldirscripts, int vmaj, int vmin);
diff --git a/src/qml/qml/qqmlincubator.cpp b/src/qml/qml/qqmlincubator.cpp
index 4546a4423f..df168960c6 100644
--- a/src/qml/qml/qqmlincubator.cpp
+++ b/src/qml/qml/qqmlincubator.cpp
@@ -367,10 +367,8 @@ finishIncubate:
enginePriv->inProgressCreations--;
if (0 == enginePriv->inProgressCreations) {
- while (enginePriv->erroredBindings) {
- enginePriv->warning(enginePriv->erroredBindings);
- enginePriv->erroredBindings->removeError();
- }
+ while (enginePriv->erroredBindings)
+ enginePriv->warning(enginePriv->erroredBindings->removeError());
}
} else if (!creator.isNull()) {
vmeGuard.guard(creator.data());
@@ -575,10 +573,8 @@ void QQmlIncubator::clear()
enginePriv->inProgressCreations--;
if (0 == enginePriv->inProgressCreations) {
- while (enginePriv->erroredBindings) {
- enginePriv->warning(enginePriv->erroredBindings);
- enginePriv->erroredBindings->removeError();
- }
+ while (enginePriv->erroredBindings)
+ enginePriv->warning(enginePriv->erroredBindings->removeError());
}
}
diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp
index 74148e3ca4..93ec9421ed 100644
--- a/src/qml/qml/qqmljavascriptexpression.cpp
+++ b/src/qml/qml/qqmljavascriptexpression.cpp
@@ -97,8 +97,7 @@ QQmlJavaScriptExpression::QQmlJavaScriptExpression()
m_context(nullptr),
m_prevExpression(nullptr),
m_nextExpression(nullptr),
- m_v4Function(nullptr),
- m_sourceLocation(nullptr)
+ m_v4Function(nullptr)
{
}
@@ -115,8 +114,6 @@ QQmlJavaScriptExpression::~QQmlJavaScriptExpression()
clearError();
if (m_scopeObject.isT2()) // notify DeleteWatcher of our deletion.
m_scopeObject.asT2()->_s = nullptr;
-
- delete m_sourceLocation;
}
void QQmlJavaScriptExpression::setNotifyOnValueChanged(bool v)
@@ -137,20 +134,11 @@ void QQmlJavaScriptExpression::resetNotifyOnValueChanged()
QQmlSourceLocation QQmlJavaScriptExpression::sourceLocation() const
{
- if (m_sourceLocation)
- return *m_sourceLocation;
if (m_v4Function)
return m_v4Function->sourceLocation();
return QQmlSourceLocation();
}
-void QQmlJavaScriptExpression::setSourceLocation(const QQmlSourceLocation &location)
-{
- if (m_sourceLocation)
- delete m_sourceLocation;
- m_sourceLocation = new QQmlSourceLocation(location);
-}
-
void QQmlJavaScriptExpression::setContext(QQmlContextData *context)
{
if (m_prevExpression) {
@@ -451,15 +439,11 @@ void QQmlJavaScriptExpression::createQmlBinding(QQmlContextData *ctxt, QObject *
QV4::Script script(v4, qmlContext, code, filename, line);
script.parse();
if (v4->hasException) {
- QQmlError error = v4->catchExceptionAsQmlError();
- if (error.description().isEmpty())
- error.setDescription(QLatin1String("Exception occurred during function evaluation"));
- if (error.line() == -1)
- error.setLine(line);
- if (error.url().isEmpty())
- error.setUrl(QUrl::fromLocalFile(filename));
- error.setObject(qmlScope);
- ep->warning(error);
+ QQmlDelayedError *error = delayedError();
+ error->catchJavaScriptException(v4);
+ error->setErrorObject(qmlScope);
+ if (!error->addError(ep))
+ ep->warning(error->error());
return;
}
setupFunction(qmlContext, script.vmFunction);
diff --git a/src/qml/qml/qqmljavascriptexpression_p.h b/src/qml/qml/qqmljavascriptexpression_p.h
index a028850074..01af3b89ca 100644
--- a/src/qml/qml/qqmljavascriptexpression_p.h
+++ b/src/qml/qml/qqmljavascriptexpression_p.h
@@ -63,16 +63,18 @@ class QQmlDelayedError
{
public:
inline QQmlDelayedError() : nextError(nullptr), prevError(nullptr) {}
- inline ~QQmlDelayedError() { removeError(); }
+ inline ~QQmlDelayedError() { (void)removeError(); }
bool addError(QQmlEnginePrivate *);
- inline void removeError() {
- if (!prevError) return;
- if (nextError) nextError->prevError = prevError;
- *prevError = nextError;
- nextError = nullptr;
- prevError = nullptr;
+ Q_REQUIRED_RESULT inline QQmlError removeError() {
+ if (prevError) {
+ if (nextError) nextError->prevError = prevError;
+ *prevError = nextError;
+ nextError = nullptr;
+ prevError = nullptr;
+ }
+ return m_error;
}
inline bool isValid() const { return m_error.isValid(); }
@@ -114,8 +116,7 @@ public:
inline QObject *scopeObject() const;
inline void setScopeObject(QObject *v);
- QQmlSourceLocation sourceLocation() const;
- void setSourceLocation(const QQmlSourceLocation &location);
+ virtual QQmlSourceLocation sourceLocation() const;
bool isValid() const { return context() != nullptr; }
@@ -186,7 +187,6 @@ private:
QV4::PersistentValue m_qmlScope;
QQmlRefPointer<QV4::CompiledData::CompilationUnit> m_compilationUnit;
QV4::Function *m_v4Function;
- QQmlSourceLocation *m_sourceLocation; // used for Qt.binding() created functions
};
class QQmlPropertyCapture
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index 7754f0fddc..8fda7f6f77 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -51,6 +51,7 @@
#include <QtCore/qbitarray.h>
#include <QtCore/qreadwritelock.h>
#include <QtCore/private/qmetaobject_p.h>
+#include <QtCore/qloggingcategory.h>
#include <qmetatype.h>
#include <qobjectdefs.h>
@@ -63,6 +64,8 @@
#include <ctype.h>
#include "qqmlcomponent.h"
+Q_DECLARE_LOGGING_CATEGORY(DBG_DISK_CACHE)
+
QT_BEGIN_NAMESPACE
struct QQmlMetaTypeData
@@ -2539,18 +2542,46 @@ QList<QQmlType> QQmlMetaType::qmlSingletonTypes()
return retn;
}
-const QV4::CompiledData::Unit *QQmlMetaType::findCachedCompilationUnit(const QUrl &uri)
+const QV4::CompiledData::Unit *QQmlMetaType::findCachedCompilationUnit(const QUrl &uri, CachedUnitLookupError *status)
{
QMutexLocker lock(metaTypeDataLock());
QQmlMetaTypeData *data = metaTypeData();
for (const auto lookup : qAsConst(data->lookupCachedQmlUnit)) {
- if (const QQmlPrivate::CachedQmlUnit *unit = lookup(uri))
+ if (const QQmlPrivate::CachedQmlUnit *unit = lookup(uri)) {
+ QString error;
+ if (!unit->qmlData->verifyHeader(QDateTime(), &error)) {
+ qCDebug(DBG_DISK_CACHE) << "Error loading pre-compiled file " << uri << ":" << error;
+ if (status)
+ *status = CachedUnitLookupError::VersionMismatch;
+ return nullptr;
+ }
+ if (status)
+ *status = CachedUnitLookupError::NoError;
return unit->qmlData;
+ }
}
+
+ if (status)
+ *status = CachedUnitLookupError::NoUnitFound;
+
return nullptr;
}
+void QQmlMetaType::prependCachedUnitLookupFunction(QQmlPrivate::QmlUnitCacheLookupFunction handler)
+{
+ QMutexLocker lock(metaTypeDataLock());
+ QQmlMetaTypeData *data = metaTypeData();
+ data->lookupCachedQmlUnit.prepend(handler);
+}
+
+void QQmlMetaType::removeCachedUnitLookupFunction(QQmlPrivate::QmlUnitCacheLookupFunction handler)
+{
+ QMutexLocker lock(metaTypeDataLock());
+ QQmlMetaTypeData *data = metaTypeData();
+ data->lookupCachedQmlUnit.removeAll(handler);
+}
+
/*!
Returns the pretty QML type name (e.g. 'Item' instead of 'QtQuickItem') for the given object.
*/
diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h
index 07bef526ba..cd7afc8a01 100644
--- a/src/qml/qml/qqmlmetatype_p.h
+++ b/src/qml/qml/qqmlmetatype_p.h
@@ -133,7 +133,17 @@ public:
static QList<QQmlPrivate::AutoParentFunction> parentFunctions();
- static const QV4::CompiledData::Unit *findCachedCompilationUnit(const QUrl &uri);
+ enum class CachedUnitLookupError {
+ NoError,
+ NoUnitFound,
+ VersionMismatch
+ };
+
+ static const QV4::CompiledData::Unit *findCachedCompilationUnit(const QUrl &uri, CachedUnitLookupError *status);
+
+ // used by tst_qqmlcachegen.cpp
+ static void prependCachedUnitLookupFunction(QQmlPrivate::QmlUnitCacheLookupFunction handler);
+ static void removeCachedUnitLookupFunction(QQmlPrivate::QmlUnitCacheLookupFunction handler);
static bool namespaceContainsRegistrations(const QString &, int majorVersion);
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index 36e56a01f8..7051fb51da 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -55,6 +55,7 @@
#include <private/qqmlvaluetypeproxybinding_p.h>
#include <private/qqmldebugconnector_p.h>
#include <private/qqmldebugserviceinterfaces_p.h>
+#include <private/qjsvalue_p.h>
QT_USE_NAMESPACE
@@ -780,7 +781,7 @@ void QQmlObjectCreator::setupBindings(bool applyDeferredBindings)
qSwap(_currentList, savedList);
}
-bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding)
+bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProperty, const QV4::CompiledData::Binding *binding)
{
if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
Q_ASSERT(stringAt(qmlUnit->objectAt(binding->value.objectIndex)->inheritedTypeNameIndex).isEmpty());
@@ -802,7 +803,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
}
// ### resolve this at compile time
- if (property && property->propType() == qMetaTypeId<QQmlScriptString>()) {
+ if (bindingProperty && bindingProperty->propType() == qMetaTypeId<QQmlScriptString>()) {
QQmlScriptString ss(binding->valueAsScriptString(qmlUnit), context->asQQmlContext(), _scopeObject);
ss.d.data()->bindingId = binding->type == QV4::CompiledData::Binding::Type_Script ? binding->value.compiledScriptIndex : (quint32)QQmlBinding::Invalid;
ss.d.data()->lineNumber = binding->location.line;
@@ -815,7 +816,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
QQmlPropertyData::RemoveBindingOnAliasWrite;
int propertyWriteStatus = -1;
void *argv[] = { &ss, nullptr, &propertyWriteStatus, &propertyWriteFlags };
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex(), argv);
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, bindingProperty->coreIndex(), argv);
return true;
}
@@ -826,7 +827,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
return false;
}
- if (!property) // ### error
+ if (!bindingProperty) // ### error
return true;
if (binding->type == QV4::CompiledData::Binding::Type_GroupProperty) {
@@ -838,20 +839,20 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
const QQmlPropertyData *valueTypeProperty = nullptr;
QObject *bindingTarget = _bindingTarget;
- if (QQmlValueTypeFactory::isValueType(property->propType())) {
- valueType = QQmlValueTypeFactory::valueType(property->propType());
+ if (QQmlValueTypeFactory::isValueType(bindingProperty->propType())) {
+ valueType = QQmlValueTypeFactory::valueType(bindingProperty->propType());
if (!valueType) {
recordError(binding->location, tr("Cannot set properties on %1 as it is null").arg(stringAt(binding->propertyNameIndex)));
return false;
}
- valueType->read(_qobject, property->coreIndex());
+ valueType->read(_qobject, bindingProperty->coreIndex());
groupObject = valueType;
- valueTypeProperty = property;
+ valueTypeProperty = bindingProperty;
} else {
void *argv[1] = { &groupObject };
- QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, property->coreIndex(), argv);
+ QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, bindingProperty->coreIndex(), argv);
if (!groupObject) {
recordError(binding->location, tr("Cannot set properties on %1 as it is null").arg(stringAt(binding->propertyNameIndex)));
return false;
@@ -864,21 +865,21 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
return false;
if (valueType)
- valueType->write(_qobject, property->coreIndex(), QQmlPropertyData::BypassInterceptor);
+ valueType->write(_qobject, bindingProperty->coreIndex(), QQmlPropertyData::BypassInterceptor);
return true;
}
}
- if (_ddata->hasBindingBit(property->coreIndex()) && !(binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression)
+ if (_ddata->hasBindingBit(bindingProperty->coreIndex()) && !(binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression)
&& !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment)
&& !_valueTypeProperty)
- QQmlPropertyPrivate::removeBinding(_bindingTarget, QQmlPropertyIndex(property->coreIndex()));
+ QQmlPropertyPrivate::removeBinding(_bindingTarget, QQmlPropertyIndex(bindingProperty->coreIndex()));
if (binding->type == QV4::CompiledData::Binding::Type_Script || binding->containsTranslations()) {
if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression) {
QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex];
- int signalIndex = _propertyCache->methodIndexToSignalIndex(property->coreIndex());
+ int signalIndex = _propertyCache->methodIndexToSignalIndex(bindingProperty->coreIndex());
QQmlBoundSignal *bs = new QQmlBoundSignal(_bindingTarget, signalIndex, _scopeObject, engine);
QQmlBoundSignalExpression *expr = new QQmlBoundSignalExpression(_bindingTarget, signalIndex,
context, _scopeObject, runtimeFunction, currentQmlContext());
@@ -890,34 +891,44 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
// the point property (_qobjectForBindings) and after evaluating the expression,
// the result is written to a value type virtual property, that contains the sub-index
// of the "x" property.
- QQmlBinding *qmlBinding;
- const QQmlPropertyData *prop = property;
+ QQmlBinding::Ptr qmlBinding;
+ const QQmlPropertyData *targetProperty = bindingProperty;
const QQmlPropertyData *subprop = nullptr;
if (_valueTypeProperty) {
- prop = _valueTypeProperty;
- subprop = property;
+ targetProperty = _valueTypeProperty;
+ subprop = bindingProperty;
}
if (binding->containsTranslations()) {
qmlBinding = QQmlBinding::createTranslationBinding(compilationUnit, binding, _scopeObject, context);
} else {
QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex];
- qmlBinding = QQmlBinding::create(prop, runtimeFunction, _scopeObject, context, currentQmlContext());
+ qmlBinding = QQmlBinding::create(targetProperty, runtimeFunction, _scopeObject, context, currentQmlContext());
}
- qmlBinding->setTarget(_bindingTarget, *prop, subprop);
- sharedState->allCreatedBindings.push(QQmlAbstractBinding::Ptr(qmlBinding));
+ auto bindingTarget = _bindingTarget;
+ auto valueTypeProperty = _valueTypeProperty;
+ auto assignBinding = [qmlBinding, bindingTarget, targetProperty, subprop, bindingProperty, valueTypeProperty](QQmlObjectCreatorSharedState *sharedState) -> bool {
+ if (!qmlBinding->setTarget(bindingTarget, *targetProperty, subprop) && targetProperty->isAlias())
+ return false;
- if (property->isAlias()) {
- QQmlPropertyPrivate::setBinding(qmlBinding, QQmlPropertyPrivate::DontEnable);
- } else {
- qmlBinding->addToObject();
+ sharedState->allCreatedBindings.push(qmlBinding);
+
+ if (bindingProperty->isAlias()) {
+ QQmlPropertyPrivate::setBinding(qmlBinding.data(), QQmlPropertyPrivate::DontEnable);
+ } else {
+ qmlBinding->addToObject();
- if (!_valueTypeProperty) {
- QQmlData *targetDeclarativeData = QQmlData::get(_bindingTarget);
- Q_ASSERT(targetDeclarativeData);
- targetDeclarativeData->setPendingBindingBit(_bindingTarget, property->coreIndex());
+ if (!valueTypeProperty) {
+ QQmlData *targetDeclarativeData = QQmlData::get(bindingTarget);
+ Q_ASSERT(targetDeclarativeData);
+ targetDeclarativeData->setPendingBindingBit(bindingTarget, bindingProperty->coreIndex());
+ }
}
- }
+
+ return true;
+ };
+ if (!assignBinding(sharedState.data()))
+ pendingAliasBindings.push_back(assignBinding);
}
return true;
}
@@ -934,9 +945,9 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
QObject *target = createdSubObject->parent();
QQmlProperty prop;
if (_valueTypeProperty)
- prop = QQmlPropertyPrivate::restore(target, *_valueTypeProperty, property, context);
+ prop = QQmlPropertyPrivate::restore(target, *_valueTypeProperty, bindingProperty, context);
else
- prop = QQmlPropertyPrivate::restore(target, *property, nullptr, context);
+ prop = QQmlPropertyPrivate::restore(target, *bindingProperty, nullptr, context);
vs->setTarget(prop);
return true;
}
@@ -946,8 +957,8 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
QObject *target = createdSubObject->parent();
QQmlPropertyIndex propertyIndex;
- if (property->isAlias()) {
- QQmlPropertyIndex originalIndex(property->coreIndex(), _valueTypeProperty ? _valueTypeProperty->coreIndex() : -1);
+ if (bindingProperty->isAlias()) {
+ QQmlPropertyIndex originalIndex(bindingProperty->coreIndex(), _valueTypeProperty ? _valueTypeProperty->coreIndex() : -1);
QQmlPropertyIndex propIndex;
QQmlPropertyPrivate::findAliasTarget(target, originalIndex, &target, &propIndex);
QQmlData *data = QQmlData::get(target);
@@ -964,9 +975,9 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
} else {
QQmlProperty prop;
if (_valueTypeProperty)
- prop = QQmlPropertyPrivate::restore(target, *_valueTypeProperty, property, context);
+ prop = QQmlPropertyPrivate::restore(target, *_valueTypeProperty, bindingProperty, context);
else
- prop = QQmlPropertyPrivate::restore(target, *property, nullptr, context);
+ prop = QQmlPropertyPrivate::restore(target, *bindingProperty, nullptr, context);
vi->setTarget(prop);
propertyIndex = QQmlPropertyPrivate::propertyIndex(prop);
}
@@ -982,8 +993,8 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
// Assigning object to signal property?
if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject) {
- if (!property->isFunction()) {
- recordError(binding->valueLocation, tr("Cannot assign an object to signal property %1").arg(property->name(_qobject)));
+ if (!bindingProperty->isFunction()) {
+ recordError(binding->valueLocation, tr("Cannot assign an object to signal property %1").arg(bindingProperty->name(_qobject)));
return false;
}
QMetaMethod method = QQmlMetaType::defaultMethod(createdSubObject);
@@ -992,7 +1003,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
return false;
}
- QMetaMethod signalMethod = _qobject->metaObject()->method(property->coreIndex());
+ QMetaMethod signalMethod = _qobject->metaObject()->method(bindingProperty->coreIndex());
if (!QMetaObject::checkConnectArgs(signalMethod, method)) {
recordError(binding->valueLocation,
tr("Cannot connect mismatched signal/slot %1 %vs. %2")
@@ -1001,7 +1012,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
return false;
}
- QQmlPropertyPrivate::connect(_qobject, property->coreIndex(), createdSubObject, method.methodIndex());
+ QQmlPropertyPrivate::connect(_qobject, bindingProperty->coreIndex(), createdSubObject, method.methodIndex());
return true;
}
@@ -1010,32 +1021,43 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
int propertyWriteStatus = -1;
void *argv[] = { nullptr, nullptr, &propertyWriteStatus, &propertyWriteFlags };
- if (const char *iid = QQmlMetaType::interfaceIId(property->propType())) {
+ if (const char *iid = QQmlMetaType::interfaceIId(bindingProperty->propType())) {
void *ptr = createdSubObject->qt_metacast(iid);
if (ptr) {
argv[0] = &ptr;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex(), argv);
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, bindingProperty->coreIndex(), argv);
} else {
recordError(binding->location, tr("Cannot assign object to interface property"));
return false;
}
- } else if (property->propType() == QMetaType::QVariant) {
- if (property->isVarProperty()) {
+ } else if (bindingProperty->propType() == QMetaType::QVariant) {
+ if (bindingProperty->isVarProperty()) {
QV4::Scope scope(v4);
QV4::ScopedValue wrappedObject(scope, QV4::QObjectWrapper::wrap(engine->handle(), createdSubObject));
- _vmeMetaObject->setVMEProperty(property->coreIndex(), wrappedObject);
+ _vmeMetaObject->setVMEProperty(bindingProperty->coreIndex(), wrappedObject);
} else {
QVariant value = QVariant::fromValue(createdSubObject);
argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex(), argv);
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, bindingProperty->coreIndex(), argv);
}
- } else if (property->isQList()) {
+ } else if (bindingProperty->propType() == qMetaTypeId<QJSValue>()) {
+ QV4::Scope scope(v4);
+ QV4::ScopedValue wrappedObject(scope, QV4::QObjectWrapper::wrap(engine->handle(), createdSubObject));
+ if (bindingProperty->isVarProperty()) {
+ _vmeMetaObject->setVMEProperty(bindingProperty->coreIndex(), wrappedObject);
+ } else {
+ QJSValue value;
+ QJSValuePrivate::setValue(&value, v4, wrappedObject);
+ argv[0] = &value;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, bindingProperty->coreIndex(), argv);
+ }
+ } else if (bindingProperty->isQList()) {
Q_ASSERT(_currentList.object);
void *itemToAdd = createdSubObject;
const char *iid = nullptr;
- int listItemType = QQmlEnginePrivate::get(engine)->listType(property->propType());
+ int listItemType = QQmlEnginePrivate::get(engine)->listType(bindingProperty->propType());
if (listItemType != -1)
iid = QQmlMetaType::interfaceIId(listItemType);
if (iid)
@@ -1051,17 +1073,17 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
} else {
// pointer compatibility was tested in QQmlPropertyValidator at type compile time
argv[0] = &createdSubObject;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex(), argv);
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, bindingProperty->coreIndex(), argv);
}
return true;
}
- if (property->isQList()) {
+ if (bindingProperty->isQList()) {
recordError(binding->location, tr("Cannot assign primitives to lists"));
return false;
}
- setPropertyValue(property, binding);
+ setPropertyValue(bindingProperty, binding);
return true;
}
@@ -1274,12 +1296,33 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
qSwap(_qmlContext, qmlContext);
- bool result = populateInstance(index, instance, /*binding target*/instance, /*value type property*/nullptr);
+ bool ok = populateInstance(index, instance, /*binding target*/instance, /*value type property*/nullptr);
+ if (ok) {
+ if (isContextObject && !pendingAliasBindings.empty()) {
+ bool processedAtLeastOneBinding = false;
+ do {
+ processedAtLeastOneBinding = false;
+ for (std::vector<PendingAliasBinding>::iterator it = pendingAliasBindings.begin();
+ it != pendingAliasBindings.end(); ) {
+ if ((*it)(sharedState.data())) {
+ it = pendingAliasBindings.erase(it);
+ processedAtLeastOneBinding = true;
+ } else {
+ ++it;
+ }
+ }
+ } while (processedAtLeastOneBinding && pendingAliasBindings.empty());
+ Q_ASSERT(pendingAliasBindings.empty());
+ }
+ } else {
+ // an error occurred, so we can't setup the pending alias bindings
+ pendingAliasBindings.clear();
+ }
qSwap(_qmlContext, qmlContext);
qSwap(_scopeObject, scopeObject);
- return result ? instance : nullptr;
+ return ok ? instance : nullptr;
}
QQmlContextData *QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interrupt)
diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h
index 399a5f6d4a..67a5bdd827 100644
--- a/src/qml/qml/qqmlobjectcreator_p.h
+++ b/src/qml/qml/qqmlobjectcreator_p.h
@@ -161,6 +161,9 @@ private:
QV4::QmlContext *_qmlContext;
friend struct QQmlObjectCreatorRecursionWatcher;
+
+ typedef std::function<bool(QQmlObjectCreatorSharedState *sharedState)> PendingAliasBinding;
+ std::vector<PendingAliasBinding> pendingAliasBindings;
};
struct QQmlObjectCreatorRecursionWatcher
diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp
index ebf296b29d..c4487f91a3 100644
--- a/src/qml/qml/qqmlproperty.cpp
+++ b/src/qml/qml/qqmlproperty.cpp
@@ -877,6 +877,7 @@ void QQmlPropertyPrivate::findAliasTarget(QObject *object, QQmlPropertyIndex bin
void QQmlPropertyPrivate::setBinding(QQmlAbstractBinding *binding, BindingFlags flags, QQmlPropertyData::WriteFlags writeFlags)
{
Q_ASSERT(binding);
+ Q_ASSERT(binding->targetObject());
QObject *object = binding->targetObject();
const QQmlPropertyIndex index = binding->targetPropertyIndex();
diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h
index 51a191a41f..b78a2ddd20 100644
--- a/src/qml/qml/qqmlpropertycache_p.h
+++ b/src/qml/qml/qqmlpropertycache_p.h
@@ -81,6 +81,7 @@ template <typename T> class QQmlPropertyCacheAliasCreator;
// We have this somewhat awful split between RawData and Data so that RawData can be
// used in unions. In normal code, you should always use Data which initializes RawData
// to an invalid state on construction.
+// ### We should be able to remove this split nowadays
class QQmlPropertyRawData
{
public:
@@ -273,20 +274,20 @@ public:
private:
Flags _flags;
- qint16 _coreIndex;
- quint16 _propType;
+ qint16 _coreIndex = 0;
+ quint16 _propType = 0;
// The notify index is in the range returned by QObjectPrivate::signalIndex().
// This is different from QMetaMethod::methodIndex().
- qint16 _notifyIndex;
- qint16 _overrideIndex;
+ qint16 _notifyIndex = 0;
+ qint16 _overrideIndex = 0;
- quint8 _revision;
- quint8 _typeMinorVersion;
- qint16 _metaObjectOffset;
+ quint8 _revision = 0;
+ quint8 _typeMinorVersion = 0;
+ qint16 _metaObjectOffset = 0;
- QQmlPropertyCacheMethodArguments *_arguments;
- StaticMetaCallFunction _staticMetaCallFunction;
+ QQmlPropertyCacheMethodArguments *_arguments = nullptr;
+ StaticMetaCallFunction _staticMetaCallFunction = nullptr;
friend class QQmlPropertyData;
friend class QQmlPropertyCache;
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 81bda2c3bb..ed742c3681 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -984,16 +984,6 @@ void QQmlTypeLoader::setProfiler(QQmlProfiler *profiler)
}
#endif
-void QQmlTypeLoader::lock()
-{
- m_thread->lock();
-}
-
-void QQmlTypeLoader::unlock()
-{
- m_thread->unlock();
-}
-
struct PlainLoader {
void loadThread(QQmlTypeLoader *loader, QQmlDataBlob *blob) const
{
@@ -1276,6 +1266,7 @@ void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QByteArray &data)
QML_MEMORY_SCOPE_URL(blob->url());
QQmlDataBlob::SourceCodeData d;
d.inlineSourceCode = QString::fromUtf8(data);
+ d.hasInlineSourceCode = true;
setData(blob, d);
}
@@ -1387,8 +1378,8 @@ bool QQmlTypeLoader::Blob::updateQmldir(QQmlQmldirData *data, const QV4::Compile
if (!importQualifier.isEmpty()) {
// Does this library contain any qualified scripts?
QUrl libraryUrl(qmldirUrl);
- const QQmlTypeLoaderQmldirContent *qmldir = typeLoader()->qmldirContent(qmldirIdentifier);
- const auto qmldirScripts = qmldir->scripts();
+ const QQmlTypeLoaderQmldirContent qmldir = typeLoader()->qmldirContent(qmldirIdentifier);
+ const auto qmldirScripts = qmldir.scripts();
for (const QQmlDirParser::Script &script : qmldirScripts) {
QUrl scriptUrl = libraryUrl.resolved(QUrl(script.fileName));
QQmlScriptBlob *blob = typeLoader()->getScript(scriptUrl);
@@ -1435,8 +1426,8 @@ bool QQmlTypeLoader::Blob::addImport(const QV4::CompiledData::Import *import, QL
if (!importQualifier.isEmpty()) {
// Does this library contain any qualified scripts?
QUrl libraryUrl(qmldirUrl);
- const QQmlTypeLoaderQmldirContent *qmldir = typeLoader()->qmldirContent(qmldirFilePath);
- const auto qmldirScripts = qmldir->scripts();
+ const QQmlTypeLoaderQmldirContent qmldir = typeLoader()->qmldirContent(qmldirFilePath);
+ const auto qmldirScripts = qmldir.scripts();
for (const QQmlDirParser::Script &script : qmldirScripts) {
QUrl scriptUrl = libraryUrl.resolved(QUrl(script.fileName));
QQmlScriptBlob *blob = typeLoader()->getScript(scriptUrl);
@@ -1601,6 +1592,7 @@ QString QQmlTypeLoaderQmldirContent::typeNamespace() const
void QQmlTypeLoaderQmldirContent::setContent(const QString &location, const QString &content)
{
+ m_hasContent = true;
m_location = location;
m_parser.parse(content);
}
@@ -1639,8 +1631,10 @@ bool QQmlTypeLoaderQmldirContent::designerSupported() const
Constructs a new type loader that uses the given \a engine.
*/
QQmlTypeLoader::QQmlTypeLoader(QQmlEngine *engine)
- : m_engine(engine), m_thread(new QQmlTypeLoaderThread(this)),
- m_typeCacheTrimThreshold(TYPELOADER_MINIMUM_TRIM_THRESHOLD)
+ : m_engine(engine)
+ , m_thread(new QQmlTypeLoaderThread(this))
+ , m_mutex(m_thread->mutex())
+ , m_typeCacheTrimThreshold(TYPELOADER_MINIMUM_TRIM_THRESHOLD)
{
}
@@ -1684,9 +1678,11 @@ QQmlTypeData *QQmlTypeLoader::getType(const QUrl &url, Mode mode)
typeData = new QQmlTypeData(url, this);
// TODO: if (compiledData == 0), is it safe to omit this insertion?
m_typeCache.insert(url, typeData);
- if (const QV4::CompiledData::Unit *cachedUnit = QQmlMetaType::findCachedCompilationUnit(typeData->url())) {
+ QQmlMetaType::CachedUnitLookupError error = QQmlMetaType::CachedUnitLookupError::NoError;
+ if (const QV4::CompiledData::Unit *cachedUnit = QQmlMetaType::findCachedCompilationUnit(typeData->url(), &error)) {
QQmlTypeLoader::loadWithCachedUnit(typeData, cachedUnit, mode);
} else {
+ typeData->setCachedUnitStatus(error);
QQmlTypeLoader::load(typeData, mode);
}
} else if ((mode == PreferSynchronous || mode == Synchronous) && QQmlFile::isSynchronous(url)) {
@@ -1745,9 +1741,11 @@ QQmlScriptBlob *QQmlTypeLoader::getScript(const QUrl &url)
scriptBlob = new QQmlScriptBlob(url, this);
m_scriptCache.insert(url, scriptBlob);
- if (const QV4::CompiledData::Unit *cachedUnit = QQmlMetaType::findCachedCompilationUnit(scriptBlob->url())) {
+ QQmlMetaType::CachedUnitLookupError error;
+ if (const QV4::CompiledData::Unit *cachedUnit = QQmlMetaType::findCachedCompilationUnit(scriptBlob->url(), &error)) {
QQmlTypeLoader::loadWithCachedUnit(scriptBlob, cachedUnit);
} else {
+ scriptBlob->setCachedUnitStatus(error);
QQmlTypeLoader::load(scriptBlob);
}
}
@@ -1831,6 +1829,7 @@ QString QQmlTypeLoader::absoluteFilePath(const QString &path)
int lastSlash = path.lastIndexOf(QLatin1Char('/'));
QString dirPath(path.left(lastSlash));
+ LockHolder<QQmlTypeLoader> holder(this);
if (!m_importDirCache.contains(dirPath)) {
bool exists = QDir(dirPath).exists();
QCache<QString, bool> *entry = exists ? new QCache<QString, bool> : nullptr;
@@ -1894,6 +1893,7 @@ bool QQmlTypeLoader::directoryExists(const QString &path)
--length;
QString dirPath(path.left(length));
+ LockHolder<QQmlTypeLoader> holder(this);
if (!m_importDirCache.contains(dirPath)) {
bool exists = QDir(dirPath).exists();
QCache<QString, bool> *files = exists ? new QCache<QString, bool> : nullptr;
@@ -1912,8 +1912,10 @@ Return a QQmlTypeLoaderQmldirContent for absoluteFilePath. The QQmlTypeLoaderQm
It can also be a remote path for a remote directory import, but it will have been cached by now in this case.
*/
-const QQmlTypeLoaderQmldirContent *QQmlTypeLoader::qmldirContent(const QString &filePathIn)
+const QQmlTypeLoaderQmldirContent QQmlTypeLoader::qmldirContent(const QString &filePathIn)
{
+ LockHolder<QQmlTypeLoader> holder(this);
+
QString filePath;
// Try to guess if filePathIn is already a URL. This is necessarily fragile, because
@@ -1927,39 +1929,39 @@ const QQmlTypeLoaderQmldirContent *QQmlTypeLoader::qmldirContent(const QString &
filePath = filePathIn;
} else {
filePath = QQmlFile::urlToLocalFileOrQrc(url);
- if (filePath.isEmpty()) // Can't load the remote here, but should be cached
- return *(m_importQmlDirCache.value(filePathIn));
+ if (filePath.isEmpty()) { // Can't load the remote here, but should be cached
+ if (auto entry = m_importQmlDirCache.value(filePathIn))
+ return **entry;
+ else
+ return QQmlTypeLoaderQmldirContent();
+ }
}
- QQmlTypeLoaderQmldirContent *qmldir;
QQmlTypeLoaderQmldirContent **val = m_importQmlDirCache.value(filePath);
- if (!val) {
- qmldir = new QQmlTypeLoaderQmldirContent;
+ if (val)
+ return **val;
+ QQmlTypeLoaderQmldirContent *qmldir = new QQmlTypeLoaderQmldirContent;
#define ERROR(description) { QQmlError e; e.setDescription(description); qmldir->setError(e); }
#define NOT_READABLE_ERROR QString(QLatin1String("module \"$$URI$$\" definition \"%1\" not readable"))
#define CASE_MISMATCH_ERROR QString(QLatin1String("cannot load module \"$$URI$$\": File name case mismatch for \"%1\""))
- QFile file(filePath);
- if (!QQml_isFileCaseCorrect(filePath)) {
- ERROR(CASE_MISMATCH_ERROR.arg(filePath));
- } else if (file.open(QFile::ReadOnly)) {
- QByteArray data = file.readAll();
- qmldir->setContent(filePath, QString::fromUtf8(data));
- } else {
- ERROR(NOT_READABLE_ERROR.arg(filePath));
- }
+ QFile file(filePath);
+ if (!QQml_isFileCaseCorrect(filePath)) {
+ ERROR(CASE_MISMATCH_ERROR.arg(filePath));
+ } else if (file.open(QFile::ReadOnly)) {
+ QByteArray data = file.readAll();
+ qmldir->setContent(filePath, QString::fromUtf8(data));
+ } else {
+ ERROR(NOT_READABLE_ERROR.arg(filePath));
+ }
#undef ERROR
#undef NOT_READABLE_ERROR
#undef CASE_MISMATCH_ERROR
- m_importQmlDirCache.insert(filePath, qmldir);
- } else {
- qmldir = *val;
- }
-
- return qmldir;
+ m_importQmlDirCache.insert(filePath, qmldir);
+ return *qmldir;
}
void QQmlTypeLoader::setQmldirContent(const QString &url, const QString &content)
@@ -2446,8 +2448,13 @@ void QQmlTypeData::dataReceived(const SourceCodeData &data)
if (isError())
return;
- if (!m_backupSourceCode.exists()) {
- setError(QQmlTypeLoader::tr("No such file or directory"));
+ if (!m_backupSourceCode.exists() || m_backupSourceCode.isEmpty()) {
+ if (m_cachedUnitStatus == QQmlMetaType::CachedUnitLookupError::VersionMismatch)
+ setError(QQmlTypeLoader::tr("File was compiled ahead of time with an incompatible version of Qt and the original file cannot be found. Please recompile"));
+ else if (!m_backupSourceCode.exists())
+ setError(QQmlTypeLoader::tr("No such file or directory"));
+ else
+ setError(QQmlTypeLoader::tr("File is empty"));
return;
}
@@ -2999,6 +3006,13 @@ void QQmlScriptBlob::dataReceived(const SourceCodeData &data)
}
}
+ if (!data.exists()) {
+ if (m_cachedUnitStatus == QQmlMetaType::CachedUnitLookupError::VersionMismatch)
+ setError(QQmlTypeLoader::tr("File was compiled ahead of time with an incompatible version of Qt and the original file cannot be found. Please recompile"));
+ else
+ setError(QQmlTypeLoader::tr("No such file or directory"));
+ return;
+ }
QmlIR::Document irUnit(isDebugging());
@@ -3196,7 +3210,7 @@ void QQmlQmldirData::initializeFromCachedUnit(const QV4::CompiledData::Unit *)
QString QQmlDataBlob::SourceCodeData::readAll(QString *error) const
{
error->clear();
- if (!inlineSourceCode.isEmpty())
+ if (hasInlineSourceCode)
return inlineSourceCode;
QFile f(fileInfo.absoluteFilePath());
@@ -3223,7 +3237,7 @@ QString QQmlDataBlob::SourceCodeData::readAll(QString *error) const
QDateTime QQmlDataBlob::SourceCodeData::sourceTimeStamp() const
{
- if (!inlineSourceCode.isEmpty())
+ if (hasInlineSourceCode)
return QDateTime();
QDateTime timeStamp = fileInfo.lastModified();
@@ -3238,11 +3252,18 @@ QDateTime QQmlDataBlob::SourceCodeData::sourceTimeStamp() const
bool QQmlDataBlob::SourceCodeData::exists() const
{
- if (!inlineSourceCode.isEmpty())
+ if (hasInlineSourceCode)
return true;
return fileInfo.exists();
}
+bool QQmlDataBlob::SourceCodeData::isEmpty() const
+{
+ if (hasInlineSourceCode)
+ return inlineSourceCode.isEmpty();
+ return fileInfo.size() == 0;
+}
+
QT_END_NAMESPACE
#include "qqmltypeloader.moc"
diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h
index 713f707387..5988632547 100644
--- a/src/qml/qml/qqmltypeloader_p.h
+++ b/src/qml/qml/qqmltypeloader_p.h
@@ -140,11 +140,13 @@ public:
QString readAll(QString *error) const;
QDateTime sourceTimeStamp() const;
bool exists() const;
+ bool isEmpty() const;
private:
friend class QQmlDataBlob;
friend class QQmlTypeLoader;
QString inlineSourceCode;
QFileInfo fileInfo;
+ bool hasInlineSourceCode = false;
};
protected:
@@ -228,12 +230,16 @@ class QQmlTypeLoaderQmldirContent
{
private:
friend class QQmlTypeLoader;
- QQmlTypeLoaderQmldirContent();
void setContent(const QString &location, const QString &content);
void setError(const QQmlError &);
public:
+ QQmlTypeLoaderQmldirContent();
+ QQmlTypeLoaderQmldirContent(const QQmlTypeLoaderQmldirContent &) = default;
+ QQmlTypeLoaderQmldirContent &operator=(const QQmlTypeLoaderQmldirContent &) = default;
+
+ bool hasContent() const { return m_hasContent; }
bool hasError() const;
QList<QQmlError> errors(const QString &uri) const;
@@ -250,6 +256,7 @@ public:
private:
QQmlDirParser m_parser;
QString m_location;
+ bool m_hasContent = false;
};
class Q_QML_PRIVATE_EXPORT QQmlTypeLoader
@@ -266,6 +273,8 @@ public:
const QQmlImports &imports() const { return m_importCache; }
+ void setCachedUnitStatus(QQmlMetaType::CachedUnitLookupError status) { m_cachedUnitStatus = status; }
+
protected:
bool addImport(const QV4::CompiledData::Import *import, QList<QQmlError> *errors);
@@ -288,6 +297,7 @@ public:
QQmlImports m_importCache;
QHash<const QV4::CompiledData::Import*, int> m_unresolvedImports;
QList<QQmlQmldirData *> m_qmldirs;
+ QQmlMetaType::CachedUnitLookupError m_cachedUnitStatus = QQmlMetaType::CachedUnitLookupError::NoError;
};
QQmlTypeLoader(QQmlEngine *);
@@ -304,7 +314,7 @@ public:
QString absoluteFilePath(const QString &path);
bool directoryExists(const QString &path);
- const QQmlTypeLoaderQmldirContent *qmldirContent(const QString &filePath);
+ const QQmlTypeLoaderQmldirContent qmldirContent(const QString &filePath);
void setQmldirContent(const QString &filePath, const QString &content);
void clearCache();
@@ -313,8 +323,8 @@ public:
bool isTypeLoaded(const QUrl &url) const;
bool isScriptLoaded(const QUrl &url) const;
- void lock();
- void unlock();
+ void lock() { m_mutex.lock(); }
+ void unlock() { m_mutex.unlock(); }
void load(QQmlDataBlob *, Mode = PreferSynchronous);
void loadWithStaticData(QQmlDataBlob *, const QByteArray &, Mode = PreferSynchronous);
@@ -381,6 +391,7 @@ private:
QQmlEngine *m_engine;
QQmlTypeLoaderThread *m_thread;
+ QMutex &m_mutex;
#if QT_CONFIG(qml_debug)
QScopedPointer<QQmlProfiler> m_profiler;
diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp
index 6dbf6ad8c1..ce35e966aa 100644
--- a/src/qml/qml/qqmltypewrapper.cpp
+++ b/src/qml/qml/qqmltypewrapper.cpp
@@ -388,6 +388,7 @@ ReturnedValue QQmlTypeWrapper::instanceOf(const Object *typeObject, const Value
QQmlTypeData *td = qenginepriv->typeLoader.getType(typeWrapper->d()->type().sourceUrl());
CompiledData::CompilationUnit *cu = td->compilationUnit();
myQmlType = qenginepriv->metaObjectForType(cu->metaTypeId);
+ td->release();
} else {
myQmlType = qenginepriv->metaObjectForType(myTypeId);
}
diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp
index a28115d192..6196a09d94 100644
--- a/src/qml/qml/qqmlvaluetypewrapper.cpp
+++ b/src/qml/qml/qqmlvaluetypewrapper.cpp
@@ -463,8 +463,12 @@ bool QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value)
QV4::Scoped<QQmlBindingFunction> bindingFunction(scope, (const Value &)f);
- QV4::ScopedContext ctx(scope, bindingFunction->scope());
- QQmlBinding *newBinding = QQmlBinding::create(&cacheData, bindingFunction->function(), referenceObject, context, ctx);
+ QV4::ScopedFunctionObject f(scope, bindingFunction->bindingFunction());
+ QV4::ScopedContext ctx(scope, f->scope());
+ QQmlBinding *newBinding = QQmlBinding::create(&cacheData, f->function(), referenceObject, context, ctx);
+ newBinding->setSourceLocation(bindingFunction->currentLocation());
+ if (f->isBoundFunction())
+ newBinding->setBoundFunction(static_cast<QV4::BoundFunction *>(f.getPointer()));
newBinding->setSourceLocation(bindingFunction->currentLocation());
newBinding->setTarget(referenceObject, cacheData, pd);
QQmlPropertyPrivate::setBinding(newBinding);
diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp
index 5673acec89..567d83f3ee 100644
--- a/src/qml/qml/qqmlxmlhttprequest.cpp
+++ b/src/qml/qml/qqmlxmlhttprequest.cpp
@@ -1019,7 +1019,7 @@ public:
Opened = 1, HeadersReceived = 2,
Loading = 3, Done = 4 };
- QQmlXMLHttpRequest(QNetworkAccessManager *manager);
+ QQmlXMLHttpRequest(QNetworkAccessManager *manager, QV4::ExecutionEngine *v4);
virtual ~QQmlXMLHttpRequest();
bool sendFlag() const;
@@ -1028,9 +1028,9 @@ public:
int replyStatus() const;
QString replyStatusText() const;
- ReturnedValue open(Object *thisObject, QQmlContextData *context, const QString &, const QUrl &, LoadType);
+ ReturnedValue open(Object *thisObject, const QString &, const QUrl &, LoadType);
ReturnedValue send(Object *thisObject, QQmlContextData *context, const QByteArray &);
- ReturnedValue abort(Object *thisObject, QQmlContextData *context);
+ ReturnedValue abort(Object *thisObject);
void addHeader(const QString &, const QString &);
QString header(const QString &name) const;
@@ -1078,9 +1078,10 @@ private:
PersistentValue m_thisObject;
QQmlContextDataRef m_qmlContext;
+ bool m_wasConstructedWithQmlContext = true;
- static void dispatchCallback(Object *thisObj, QQmlContextData *context);
- void dispatchCallback();
+ static void dispatchCallbackNow(Object *thisObj);
+ void dispatchCallbackSafely();
int m_status;
QString m_statusText;
@@ -1096,12 +1097,13 @@ private:
QV4::PersistentValue m_parsedDocument;
};
-QQmlXMLHttpRequest::QQmlXMLHttpRequest(QNetworkAccessManager *manager)
+QQmlXMLHttpRequest::QQmlXMLHttpRequest(QNetworkAccessManager *manager, QV4::ExecutionEngine *v4)
: m_state(Unsent), m_errorFlag(false), m_sendFlag(false)
, m_redirectCount(0), m_gotXml(false), m_textCodec(nullptr), m_network(nullptr), m_nam(manager)
, m_responseType()
, m_parsedDocument()
{
+ m_wasConstructedWithQmlContext = v4->callingQmlContext() != nullptr;
}
QQmlXMLHttpRequest::~QQmlXMLHttpRequest()
@@ -1134,7 +1136,7 @@ QString QQmlXMLHttpRequest::replyStatusText() const
return m_statusText;
}
-ReturnedValue QQmlXMLHttpRequest::open(Object *thisObject, QQmlContextData *context, const QString &method, const QUrl &url, LoadType loadType)
+ReturnedValue QQmlXMLHttpRequest::open(Object *thisObject, const QString &method, const QUrl &url, LoadType loadType)
{
destroyNetwork();
m_sendFlag = false;
@@ -1145,7 +1147,7 @@ ReturnedValue QQmlXMLHttpRequest::open(Object *thisObject, QQmlContextData *cont
m_request.setAttribute(QNetworkRequest::SynchronousRequestAttribute, loadType == SynchronousLoad);
m_state = Opened;
m_addedHeaders.clear();
- dispatchCallback(thisObject, context);
+ dispatchCallbackNow(thisObject);
return Encode::undefined();
}
@@ -1297,7 +1299,7 @@ ReturnedValue QQmlXMLHttpRequest::send(Object *thisObject, QQmlContextData *cont
return Encode::undefined();
}
-ReturnedValue QQmlXMLHttpRequest::abort(Object *thisObject, QQmlContextData *context)
+ReturnedValue QQmlXMLHttpRequest::abort(Object *thisObject)
{
destroyNetwork();
m_responseEntityBody = QByteArray();
@@ -1310,7 +1312,7 @@ ReturnedValue QQmlXMLHttpRequest::abort(Object *thisObject, QQmlContextData *con
m_state = Done;
m_sendFlag = false;
- dispatchCallback(thisObject, context);
+ dispatchCallbackNow(thisObject);
}
m_state = Unsent;
@@ -1329,7 +1331,7 @@ void QQmlXMLHttpRequest::readyRead()
if (m_state < HeadersReceived) {
m_state = HeadersReceived;
fillHeadersList ();
- dispatchCallback();
+ dispatchCallbackSafely();
}
bool wasEmpty = m_responseEntityBody.isEmpty();
@@ -1337,7 +1339,7 @@ void QQmlXMLHttpRequest::readyRead()
if (wasEmpty && !m_responseEntityBody.isEmpty())
m_state = Loading;
- dispatchCallback();
+ dispatchCallbackSafely();
}
static const char *errorToString(QNetworkReply::NetworkError error)
@@ -1380,14 +1382,14 @@ void QQmlXMLHttpRequest::error(QNetworkReply::NetworkError error)
error == QNetworkReply::ServiceUnavailableError ||
error == QNetworkReply::UnknownServerError) {
m_state = Loading;
- dispatchCallback();
+ dispatchCallbackSafely();
} else {
m_errorFlag = true;
m_responseEntityBody = QByteArray();
}
m_state = Done;
- dispatchCallback();
+ dispatchCallbackSafely();
}
#define XMLHTTPREQUEST_MAXIMUM_REDIRECT_RECURSION 15
@@ -1419,7 +1421,7 @@ void QQmlXMLHttpRequest::finished()
if (m_state < HeadersReceived) {
m_state = HeadersReceived;
fillHeadersList ();
- dispatchCallback();
+ dispatchCallbackSafely();
}
m_responseEntityBody.append(m_network->readAll());
readEncoding();
@@ -1436,11 +1438,11 @@ void QQmlXMLHttpRequest::finished()
destroyNetwork();
if (m_state < Loading) {
m_state = Loading;
- dispatchCallback();
+ dispatchCallbackSafely();
}
m_state = Done;
- dispatchCallback();
+ dispatchCallbackSafely();
m_thisObject.clear();
m_qmlContext.setContextData(nullptr);
@@ -1557,17 +1559,10 @@ const QByteArray &QQmlXMLHttpRequest::rawResponseBody() const
return m_responseEntityBody;
}
-void QQmlXMLHttpRequest::dispatchCallback(Object *thisObj, QQmlContextData *context)
+void QQmlXMLHttpRequest::dispatchCallbackNow(Object *thisObj)
{
Q_ASSERT(thisObj);
- if (!context)
- // if the calling context object is no longer valid, then it has been
- // deleted explicitly (e.g., by a Loader deleting the itemContext when
- // the source is changed). We do nothing in this case, as the evaluation
- // cannot succeed.
- return;
-
QV4::Scope scope(thisObj->engine());
ScopedString s(scope, scope.engine->newString(QStringLiteral("onreadystatechange")));
ScopedFunctionObject callback(scope, thisObj->get(s));
@@ -1585,9 +1580,16 @@ void QQmlXMLHttpRequest::dispatchCallback(Object *thisObj, QQmlContextData *cont
}
}
-void QQmlXMLHttpRequest::dispatchCallback()
+void QQmlXMLHttpRequest::dispatchCallbackSafely()
{
- dispatchCallback(m_thisObject.as<Object>(), m_qmlContext.contextData());
+ if (m_wasConstructedWithQmlContext && !m_qmlContext.contextData())
+ // if the calling context object is no longer valid, then it has been
+ // deleted explicitly (e.g., by a Loader deleting the itemContext when
+ // the source is changed). We do nothing in this case, as the evaluation
+ // cannot succeed.
+ return;
+
+ dispatchCallbackNow(m_thisObject.as<Object>());
}
void QQmlXMLHttpRequest::destroyNetwork()
@@ -1640,7 +1642,7 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject
Scope scope(f->engine());
const QQmlXMLHttpRequestCtor *ctor = static_cast<const QQmlXMLHttpRequestCtor *>(f);
- QQmlXMLHttpRequest *r = new QQmlXMLHttpRequest(scope.engine->v8Engine->networkAccessManager());
+ QQmlXMLHttpRequest *r = new QQmlXMLHttpRequest(scope.engine->v8Engine->networkAccessManager(), scope.engine);
Scoped<QQmlXMLHttpRequestWrapper> w(scope, scope.engine->memoryManager->allocObject<QQmlXMLHttpRequestWrapper>(r));
ScopedObject proto(scope, ctor->d()->proto);
w->setPrototype(proto);
@@ -1778,7 +1780,7 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_open(const FunctionObject *b, const
if (!username.isNull()) url.setUserName(username);
if (!password.isNull()) url.setPassword(password);
- return r->open(w, scope.engine->callingQmlContext(), method, url, async ? QQmlXMLHttpRequest::AsynchronousLoad : QQmlXMLHttpRequest::SynchronousLoad);
+ return r->open(w, method, url, async ? QQmlXMLHttpRequest::AsynchronousLoad : QQmlXMLHttpRequest::SynchronousLoad);
}
ReturnedValue QQmlXMLHttpRequestCtor::method_setRequestHeader(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
@@ -1860,7 +1862,7 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_abort(const FunctionObject *b, cons
V4THROW_REFERENCE("Not an XMLHttpRequest object");
QQmlXMLHttpRequest *r = w->d()->request;
- return r->abort(w, scope.engine->callingQmlContext());
+ return r->abort(w);
}
ReturnedValue QQmlXMLHttpRequestCtor::method_getResponseHeader(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
index 1371f1f041..9e7c84011b 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
@@ -1344,11 +1344,12 @@ ReturnedValue QtObject::method_locale(const FunctionObject *b, const Value *, co
return QQmlLocale::locale(scope.engine, code);
}
-void Heap::QQmlBindingFunction::init(const QV4::FunctionObject *originalFunction)
+void Heap::QQmlBindingFunction::init(const QV4::FunctionObject *bindingFunction)
{
- Scope scope(originalFunction->engine());
- ScopedContext context(scope, originalFunction->scope());
- FunctionObject::init(context, originalFunction->function());
+ Scope scope(bindingFunction->engine());
+ ScopedContext context(scope, bindingFunction->scope());
+ FunctionObject::init(context, bindingFunction->function());
+ this->bindingFunction.set(internalClass->engine, bindingFunction->d());
}
QQmlSourceLocation QQmlBindingFunction::currentLocation() const
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
index 104dae5d79..ee3b5f7d6e 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
@@ -80,8 +80,11 @@ struct ConsoleObject : Object {
void init();
};
-struct QQmlBindingFunction : FunctionObject {
- void init(const QV4::FunctionObject *originalFunction);
+#define QQmlBindingFunctionMembers(class, Member) \
+ Member(class, Pointer, FunctionObject *, bindingFunction)
+DECLARE_HEAP_OBJECT(QQmlBindingFunction, FunctionObject) {
+ DECLARE_MARKOBJECTS(QQmlBindingFunction)
+ void init(const QV4::FunctionObject *bindingFunction);
};
}
@@ -179,6 +182,7 @@ struct QQmlBindingFunction : public QV4::FunctionObject
{
V4_OBJECT2(QQmlBindingFunction, FunctionObject)
+ Heap::FunctionObject *bindingFunction() const { return d()->bindingFunction; }
QQmlSourceLocation currentLocation() const; // from caller stack trace
};
diff --git a/src/qml/types/qqmlconnections.cpp b/src/qml/types/qqmlconnections.cpp
index a43562a7b8..2ae3df6ebb 100644
--- a/src/qml/types/qqmlconnections.cpp
+++ b/src/qml/types/qqmlconnections.cpp
@@ -288,9 +288,10 @@ void QQmlConnections::connectSignals()
new QQmlBoundSignal(target, signalIndex, this, qmlEngine(this));
signal->setEnabled(d->enabled);
- QQmlBoundSignalExpression *expression = ctxtdata ?
- new QQmlBoundSignalExpression(target, signalIndex,
- ctxtdata, this, d->compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex]) : nullptr;
+ auto f = d->compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex];
+ QQmlBoundSignalExpression *expression =
+ ctxtdata ? new QQmlBoundSignalExpression(target, signalIndex, ctxtdata, this, f)
+ : nullptr;
signal->takeExpression(expression);
d->boundsignals += signal;
} else {
diff --git a/src/qml/types/qqmldelegatemodel_p.h b/src/qml/types/qqmldelegatemodel_p.h
index b894df8f82..b0786cd088 100644
--- a/src/qml/types/qqmldelegatemodel_p.h
+++ b/src/qml/types/qqmldelegatemodel_p.h
@@ -62,6 +62,8 @@
#include <private/qv8engine_p.h>
#include <private/qqmlglobal_p.h>
+QT_REQUIRE_CONFIG(qml_delegate_model);
+
QT_BEGIN_NAMESPACE
class QQmlChangeSet;
diff --git a/src/qml/types/qqmldelegatemodel_p_p.h b/src/qml/types/qqmldelegatemodel_p_p.h
index 68b987a5fa..18980cfd7c 100644
--- a/src/qml/types/qqmldelegatemodel_p_p.h
+++ b/src/qml/types/qqmldelegatemodel_p_p.h
@@ -60,6 +60,8 @@
// We mean it.
//
+QT_REQUIRE_CONFIG(qml_delegate_model);
+
QT_BEGIN_NAMESPACE
typedef QQmlListCompositor Compositor;
diff --git a/src/qml/types/qqmlinstantiator.cpp b/src/qml/types/qqmlinstantiator.cpp
index 213bef7879..030758fa3b 100644
--- a/src/qml/types/qqmlinstantiator.cpp
+++ b/src/qml/types/qqmlinstantiator.cpp
@@ -44,7 +44,9 @@
#include <QtQml/QQmlInfo>
#include <QtQml/QQmlError>
#include <QtQml/private/qqmlobjectmodel_p.h>
+#if QT_CONFIG(qml_delegate_model)
#include <QtQml/private/qqmldelegatemodel_p.h>
+#endif
QT_BEGIN_NAMESPACE
@@ -53,7 +55,9 @@ QQmlInstantiatorPrivate::QQmlInstantiatorPrivate()
, effectiveReset(false)
, active(true)
, async(false)
+#if QT_CONFIG(qml_delegate_model)
, ownModel(false)
+#endif
, requestedIndex(-1)
, model(QVariant(1))
, instanceModel(nullptr)
@@ -198,6 +202,7 @@ void QQmlInstantiatorPrivate::_q_modelUpdated(const QQmlChangeSet &changeSet, bo
q->countChanged();
}
+#if QT_CONFIG(qml_delegate_model)
void QQmlInstantiatorPrivate::makeModel()
{
Q_Q(QQmlInstantiator);
@@ -209,6 +214,7 @@ void QQmlInstantiatorPrivate::makeModel()
if (componentComplete)
delegateModel->componentComplete();
}
+#endif
/*!
@@ -349,6 +355,7 @@ void QQmlInstantiator::setDelegate(QQmlComponent* c)
d->delegate = c;
emit delegateChanged();
+#if QT_CONFIG(qml_delegate_model)
if (!d->ownModel)
return;
@@ -356,6 +363,7 @@ void QQmlInstantiator::setDelegate(QQmlComponent* c)
dModel->setDelegate(c);
if (d->componentComplete)
d->regenerate();
+#endif
}
/*!
@@ -398,12 +406,15 @@ void QQmlInstantiator::setModel(const QVariant &v)
QObject *object = qvariant_cast<QObject*>(v);
QQmlInstanceModel *vim = nullptr;
if (object && (vim = qobject_cast<QQmlInstanceModel *>(object))) {
+#if QT_CONFIG(qml_delegate_model)
if (d->ownModel) {
delete d->instanceModel;
prevModel = nullptr;
d->ownModel = false;
}
+#endif
d->instanceModel = vim;
+#if QT_CONFIG(qml_delegate_model)
} else if (v != QVariant(0)){
if (!d->ownModel)
d->makeModel();
@@ -413,6 +424,7 @@ void QQmlInstantiator::setModel(const QVariant &v)
dataModel->setModel(v);
d->effectiveReset = false;
}
+#endif
}
if (d->instanceModel != prevModel) {
@@ -423,10 +435,12 @@ void QQmlInstantiator::setModel(const QVariant &v)
//disconnect(prevModel, SIGNAL(initItem(int,QObject*)), this, SLOT(initItem(int,QObject*)));
}
- connect(d->instanceModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)),
- this, SLOT(_q_modelUpdated(QQmlChangeSet,bool)));
- connect(d->instanceModel, SIGNAL(createdItem(int,QObject*)), this, SLOT(_q_createdItem(int,QObject*)));
- //connect(d->instanceModel, SIGNAL(initItem(int,QObject*)), this, SLOT(initItem(int,QObject*)));
+ if (d->instanceModel) {
+ connect(d->instanceModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)),
+ this, SLOT(_q_modelUpdated(QQmlChangeSet,bool)));
+ connect(d->instanceModel, SIGNAL(createdItem(int,QObject*)), this, SLOT(_q_createdItem(int,QObject*)));
+ //connect(d->instanceModel, SIGNAL(initItem(int,QObject*)), this, SLOT(initItem(int,QObject*)));
+ }
}
d->regenerate();
@@ -476,10 +490,13 @@ void QQmlInstantiator::componentComplete()
{
Q_D(QQmlInstantiator);
d->componentComplete = true;
+#if QT_CONFIG(qml_delegate_model)
if (d->ownModel) {
static_cast<QQmlDelegateModel*>(d->instanceModel)->componentComplete();
d->regenerate();
- } else {
+ } else
+#endif
+ {
QVariant realModel = d->model;
d->model = QVariant(0);
setModel(realModel); //If realModel == d->model this won't do anything, but that's fine since the model's 0
diff --git a/src/qml/types/qqmlinstantiator_p_p.h b/src/qml/types/qqmlinstantiator_p_p.h
index 9edaecf7a8..a5a4d1a32d 100644
--- a/src/qml/types/qqmlinstantiator_p_p.h
+++ b/src/qml/types/qqmlinstantiator_p_p.h
@@ -69,7 +69,9 @@ public:
void clear();
void regenerate();
+#if QT_CONFIG(qml_delegate_model)
void makeModel();
+#endif
void _q_createdItem(int, QObject *);
void _q_modelUpdated(const QQmlChangeSet &, bool);
QObject *modelObject(int index, bool async);
@@ -78,7 +80,9 @@ public:
bool effectiveReset:1;
bool active:1;
bool async:1;
+#if QT_CONFIG(qml_delegate_model)
bool ownModel:1;
+#endif
int requestedIndex;
QVariant model;
QQmlInstanceModel *instanceModel;
diff --git a/src/qml/types/qqmllistmodel.cpp b/src/qml/types/qqmllistmodel.cpp
index d4fc02cd3e..c4e33d572d 100644
--- a/src/qml/types/qqmllistmodel.cpp
+++ b/src/qml/types/qqmllistmodel.cpp
@@ -2351,21 +2351,22 @@ void QQmlListModel::append(QQmlV4Function *args)
QV4::ScopedObject argObject(scope);
int objectArrayLength = objectArray->getLength();
+ if (objectArrayLength > 0) {
+ int index = count();
+ emitItemsAboutToBeInserted(index, objectArrayLength);
- int index = count();
- emitItemsAboutToBeInserted(index, objectArrayLength);
+ for (int i=0 ; i < objectArrayLength ; ++i) {
+ argObject = objectArray->getIndexed(i);
- for (int i=0 ; i < objectArrayLength ; ++i) {
- argObject = objectArray->getIndexed(i);
-
- if (m_dynamicRoles) {
- m_modelObjects.append(DynamicRoleModelNode::create(scope.engine->variantMapFromJS(argObject), this));
- } else {
- m_listModel->append(argObject);
+ if (m_dynamicRoles) {
+ m_modelObjects.append(DynamicRoleModelNode::create(scope.engine->variantMapFromJS(argObject), this));
+ } else {
+ m_listModel->append(argObject);
+ }
}
- }
- emitItemsInserted();
+ emitItemsInserted();
+ }
} else if (argObject) {
int index;
diff --git a/src/qml/types/qqmlmodelsmodule.cpp b/src/qml/types/qqmlmodelsmodule.cpp
index c36e26a525..e217b63c6f 100644
--- a/src/qml/types/qqmlmodelsmodule.cpp
+++ b/src/qml/types/qqmlmodelsmodule.cpp
@@ -40,7 +40,9 @@
#include "qqmlmodelsmodule_p.h"
#include <QtCore/qitemselectionmodel.h>
#include <private/qqmllistmodel_p.h>
+#if QT_CONFIG(qml_delegate_model)
#include <private/qqmldelegatemodel_p.h>
+#endif
#include <private/qqmlobjectmodel_p.h>
QT_BEGIN_NAMESPACE
@@ -51,8 +53,10 @@ void QQmlModelsModule::defineModule()
qmlRegisterType<QQmlListElement>(uri, 2, 1, "ListElement");
qmlRegisterCustomType<QQmlListModel>(uri, 2, 1, "ListModel", new QQmlListModelParser);
+#if QT_CONFIG(qml_delegate_model)
qmlRegisterType<QQmlDelegateModel>(uri, 2, 1, "DelegateModel");
qmlRegisterType<QQmlDelegateModelGroup>(uri, 2, 1, "DelegateModelGroup");
+#endif
qmlRegisterType<QQmlObjectModel>(uri, 2, 1, "ObjectModel");
qmlRegisterType<QQmlObjectModel,3>(uri, 2, 3, "ObjectModel");
diff --git a/src/qml/types/qquickworkerscript.cpp b/src/qml/types/qquickworkerscript.cpp
index 80c2d3a4bc..ef92e4108d 100644
--- a/src/qml/types/qquickworkerscript.cpp
+++ b/src/qml/types/qquickworkerscript.cpp
@@ -397,9 +397,11 @@ void QQuickWorkerScriptEnginePrivate::processLoad(int id, const QUrl &url)
QV4::Scoped<QV4::QmlContext> qmlContext(scope, getWorker(script));
Q_ASSERT(!!qmlContext);
- program.reset(QV4::Script::createFromFileOrCache(v4, qmlContext, fileName, url));
+ QString error;
+ program.reset(QV4::Script::createFromFileOrCache(v4, qmlContext, fileName, url, &error));
if (program.isNull()) {
- qWarning().nospace() << "WorkerScript: Cannot find source file " << url.toString();
+ if (!error.isEmpty())
+ qWarning().nospace() << error;
return;
}
diff --git a/src/qml/types/types.pri b/src/qml/types/types.pri
index e85ab5982b..8bcbd6e544 100644
--- a/src/qml/types/types.pri
+++ b/src/qml/types/types.pri
@@ -1,7 +1,6 @@
SOURCES += \
$$PWD/qqmlbind.cpp \
$$PWD/qqmlconnections.cpp \
- $$PWD/qqmldelegatemodel.cpp \
$$PWD/qqmllistmodel.cpp \
$$PWD/qqmllistmodelworkeragent.cpp \
$$PWD/qqmlmodelsmodule.cpp \
@@ -14,8 +13,6 @@ SOURCES += \
HEADERS += \
$$PWD/qqmlbind_p.h \
$$PWD/qqmlconnections_p.h \
- $$PWD/qqmldelegatemodel_p.h \
- $$PWD/qqmldelegatemodel_p_p.h \
$$PWD/qqmllistmodel_p.h \
$$PWD/qqmllistmodel_p_p.h \
$$PWD/qqmllistmodelworkeragent_p.h \
@@ -27,6 +24,15 @@ HEADERS += \
$$PWD/qqmlinstantiator_p.h \
$$PWD/qqmlinstantiator_p_p.h
+qtConfig(qml-delegate-model) {
+ SOURCES += \
+ $$PWD/qqmldelegatemodel.cpp
+
+ HEADERS += \
+ $$PWD/qqmldelegatemodel_p.h \
+ $$PWD/qqmldelegatemodel_p_p.h
+}
+
qtConfig(animation) {
SOURCES += \
$$PWD/qqmltimer.cpp
diff --git a/src/qml/util/qqmladaptormodel_p.h b/src/qml/util/qqmladaptormodel_p.h
index 8f773efa20..b152a886a5 100644
--- a/src/qml/util/qqmladaptormodel_p.h
+++ b/src/qml/util/qqmladaptormodel_p.h
@@ -57,6 +57,8 @@
#include <private/qqmlguard_p.h>
+QT_REQUIRE_CONFIG(qml_delegate_model);
+
QT_BEGIN_NAMESPACE
class QQmlEngine;
diff --git a/src/qml/util/util.pri b/src/qml/util/util.pri
index a9c5ffe9b7..bebb271f1b 100644
--- a/src/qml/util/util.pri
+++ b/src/qml/util/util.pri
@@ -2,12 +2,18 @@ SOURCES += \
$$PWD/qqmlchangeset.cpp \
$$PWD/qqmllistaccessor.cpp \
$$PWD/qqmllistcompositor.cpp \
- $$PWD/qqmladaptormodel.cpp \
$$PWD/qqmlpropertymap.cpp
HEADERS += \
$$PWD/qqmlchangeset_p.h \
$$PWD/qqmllistaccessor_p.h \
$$PWD/qqmllistcompositor_p.h \
- $$PWD/qqmladaptormodel_p.h \
$$PWD/qqmlpropertymap.h
+
+qtConfig(qml-delegate-model) {
+ SOURCES += \
+ $$PWD/qqmladaptormodel.cpp
+
+ HEADERS += \
+ $$PWD/qqmladaptormodel_p.h
+}
diff --git a/src/qmltest/doc/src/qtquicktest-index.qdoc b/src/qmltest/doc/src/qtquicktest-index.qdoc
index 6b5f8fdf4c..1f84db405c 100644
--- a/src/qmltest/doc/src/qtquicktest-index.qdoc
+++ b/src/qmltest/doc/src/qtquicktest-index.qdoc
@@ -182,4 +182,13 @@
#include "tst_mytest.moc"
\endcode
+
+ \section1 Licenses
+
+ Qt Quick Tests is available under commercial licenses from \l{The Qt Company}.
+ In addition, it is available under free software licenses. Since Qt 5.4,
+ these free software licenses are
+ \l{GNU Lesser General Public License, version 3}, or
+ the \l{GNU General Public License, version 2}.
+ See \l{Qt Licensing} for further details.
*/
diff --git a/src/qmltest/qtestoptions_p.h b/src/qmltest/qtestoptions_p.h
index 02609a6189..68fe09f793 100644
--- a/src/qmltest/qtestoptions_p.h
+++ b/src/qmltest/qtestoptions_p.h
@@ -51,7 +51,7 @@
// We mean it.
//
-#include <QtTest/qtest_global.h>
+#include <QtTest/qttestglobal.h>
#include <QtCore/qstring.h>
#include <QtCore/qstringlist.h>
diff --git a/src/quick/configure.json b/src/quick/configure.json
index 7004ea7f7b..b77ea863b3 100644
--- a/src/quick/configure.json
+++ b/src/quick/configure.json
@@ -79,6 +79,7 @@
"label": "GridView item",
"purpose": "Provides the GridView item.",
"section": "Qt Quick",
+ "condition": "features.qml-delegate-model",
"output": [
"privateFeature"
]
@@ -101,6 +102,7 @@
"label": "ListView item",
"purpose": "Provides the ListView item.",
"section": "Qt Quick",
+ "condition": "features.qml-delegate-model",
"output": [
"privateFeature"
]
@@ -126,7 +128,10 @@
"label": "PathView item",
"purpose": "Provides the PathView item.",
"section": "Qt Quick",
- "condition": "features.quick-path",
+ "condition": [
+ "features.qml-delegate-model",
+ "features.quick-path"
+ ],
"output": [
"privateFeature"
]
@@ -143,6 +148,7 @@
"label": "Repeater item",
"purpose": "Provides the Repeater item.",
"section": "Qt Quick",
+ "condition": "features.qml-delegate-model",
"output": [
"privateFeature"
]
diff --git a/src/quick/designer/qquickdesignercustomobjectdata.cpp b/src/quick/designer/qquickdesignercustomobjectdata.cpp
index 59e086b5a3..8989de711e 100644
--- a/src/quick/designer/qquickdesignercustomobjectdata.cpp
+++ b/src/quick/designer/qquickdesignercustomobjectdata.cpp
@@ -148,7 +148,19 @@ void QQuickDesignerCustomObjectData::populateResetHashes()
const QQuickDesignerSupport::PropertyNameList propertyNameList =
QQuickDesignerSupportProperties::propertyNameListForWritableProperties(object());
+ const QMetaObject *mo = object()->metaObject();
+ QByteArrayList deferredPropertyNames;
+ const int namesIndex = mo->indexOfClassInfo("DeferredPropertyNames");
+ if (namesIndex != -1) {
+ QMetaClassInfo classInfo = mo->classInfo(namesIndex);
+ deferredPropertyNames = QByteArray(classInfo.value()).split(',');
+ }
+
for (const QQuickDesignerSupport::PropertyName &propertyName : propertyNameList) {
+
+ if (deferredPropertyNames.contains(propertyName))
+ continue;
+
QQmlProperty property(object(), QString::fromUtf8(propertyName), QQmlEngine::contextForObject(object()));
QQmlAbstractBinding::Ptr binding = QQmlAbstractBinding::Ptr(QQmlPropertyPrivate::binding(property));
diff --git a/src/quick/designer/qquickdesignersupportitems.cpp b/src/quick/designer/qquickdesignersupportitems.cpp
index 9fadbb2122..1c338fa79d 100644
--- a/src/quick/designer/qquickdesignersupportitems.cpp
+++ b/src/quick/designer/qquickdesignersupportitems.cpp
@@ -94,11 +94,24 @@ static void allSubObjects(QObject *object, QObjectList &objectList)
objectList.append(object);
+ const QMetaObject *mo = object->metaObject();
+
+ QByteArrayList deferredPropertyNames;
+ const int namesIndex = mo->indexOfClassInfo("DeferredPropertyNames");
+ if (namesIndex != -1) {
+ QMetaClassInfo classInfo = mo->classInfo(namesIndex);
+ deferredPropertyNames = QByteArray(classInfo.value()).split(',');
+ }
+
for (int index = QObject::staticMetaObject.propertyOffset();
index < object->metaObject()->propertyCount();
index++) {
+
QMetaProperty metaProperty = object->metaObject()->property(index);
+ if (deferredPropertyNames.contains(metaProperty.name()))
+ continue;
+
// search recursive in property objects
if (metaProperty.isReadable()
&& metaProperty.isWritable()
diff --git a/src/quick/designer/qquickdesignersupportproperties.cpp b/src/quick/designer/qquickdesignersupportproperties.cpp
index 674f811f8f..c746f55daa 100644
--- a/src/quick/designer/qquickdesignersupportproperties.cpp
+++ b/src/quick/designer/qquickdesignersupportproperties.cpp
@@ -202,11 +202,20 @@ QQuickDesignerSupport::PropertyNameList QQuickDesignerSupportProperties::allProp
const QMetaObject *metaObject = object->metaObject();
+
+ QStringList deferredPropertyNames;
+ const int namesIndex = metaObject->indexOfClassInfo("DeferredPropertyNames");
+ if (namesIndex != -1) {
+ QMetaClassInfo classInfo = metaObject->classInfo(namesIndex);
+ deferredPropertyNames = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
+ }
+
for (int index = 0; index < metaObject->propertyCount(); ++index) {
QMetaProperty metaProperty = metaObject->property(index);
QQmlProperty declarativeProperty(object, QString::fromUtf8(metaProperty.name()));
if (declarativeProperty.isValid() && declarativeProperty.propertyTypeCategory() == QQmlProperty::Object) {
- if (declarativeProperty.name() != QLatin1String("parent")) {
+ if (declarativeProperty.name() != QLatin1String("parent")
+ && !deferredPropertyNames.contains(declarativeProperty.name())) {
QObject *childObject = QQmlMetaType::toQObject(declarativeProperty.read());
if (childObject)
propertyNameList.append(allPropertyNames(childObject,
diff --git a/src/quick/doc/QtQuickDoc b/src/quick/doc/QtQuickDoc
new file mode 100644
index 0000000000..6c151f2ebd
--- /dev/null
+++ b/src/quick/doc/QtQuickDoc
@@ -0,0 +1,2 @@
+#include <QtQuick/QtQuick>
+#include <QtQuickWidgets/QtQuickWidgets>
diff --git a/src/quick/doc/images/qtquickcontrols2-gallery-welcome.png b/src/quick/doc/images/qtquickcontrols2-gallery-welcome.png
new file mode 100644
index 0000000000..e69e7e46a7
--- /dev/null
+++ b/src/quick/doc/images/qtquickcontrols2-gallery-welcome.png
Binary files differ
diff --git a/src/quick/doc/qtquick.qdocconf b/src/quick/doc/qtquick.qdocconf
index 7ce0dfcf09..c137d1d2c8 100644
--- a/src/quick/doc/qtquick.qdocconf
+++ b/src/quick/doc/qtquick.qdocconf
@@ -6,6 +6,10 @@ version = $QT_VERSION
examplesinstallpath = quick
+# Custom module header that pulls in also QtQuickWidgets
+moduleheader = QtQuickDoc
+includepaths = -I .
+
qhp.projects = QtQuick
qhp.QtQuick.file = qtquick.qhp
diff --git a/src/quick/doc/snippets/qml/image-ext.qml b/src/quick/doc/snippets/qml/image-ext.qml
new file mode 100644
index 0000000000..5e95f2b4cf
--- /dev/null
+++ b/src/quick/doc/snippets/qml/image-ext.qml
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [ext]
+// Assuming the "pics" directory contains the following files:
+// dog.jpg
+// cat.png
+// cat.pkm
+
+Image {
+ source: "pics/cat.png" // loads cat.png
+}
+
+Image {
+ source: "pics/dog" // loads dog.jpg
+}
+
+Image {
+ source: "pics/cat" // normally loads cat.pkm, but if no OpenGL, loads cat.png instead.
+}
+//! [ext]
diff --git a/src/quick/doc/src/concepts/effects/particles.qdoc b/src/quick/doc/src/concepts/effects/particles.qdoc
index 0de0aa93ad..59f9c0db83 100644
--- a/src/quick/doc/src/concepts/effects/particles.qdoc
+++ b/src/quick/doc/src/concepts/effects/particles.qdoc
@@ -26,14 +26,14 @@
****************************************************************************/
/*!
- \qmlmodule QtQuick.Particles 2
+ \qmlmodule QtQuick.Particles 2.11
\title Qt Quick Particles QML Types
\ingroup qmlmodules
\brief Provides QML types for particle effects
This QML module contains a particle system for Qt Quick. To use these types, import the module with the following line:
\code
- import QtQuick.Particles 2.0
+ import QtQuick.Particles 2.11
\endcode
For a simple overview of how the system can be used, see \l{Using the Qt Quick Particle System}.
@@ -50,7 +50,7 @@
Note that to use types from the particles module, you will need to import the types with the following line:
\code
- import QtQuick.Particles 2.0
+ import QtQuick.Particles 2.11
\endcode
\section1 The ParticleSystem
diff --git a/src/quick/doc/src/concepts/effects/sprites.qdoc b/src/quick/doc/src/concepts/effects/sprites.qdoc
index cb4d7e2ac6..004db90eb3 100644
--- a/src/quick/doc/src/concepts/effects/sprites.qdoc
+++ b/src/quick/doc/src/concepts/effects/sprites.qdoc
@@ -52,38 +52,38 @@ This allows you to easily insert a transitional animation between two different
\image spriteenginegraph.png
As an example, consider the above diagram which illustrates the sprites for a hypothetical 2D
-platform game character. The character starts by displaying the standing state. From this state,
-barring external input, he will transition to either the waiting animation, the walking animation,
-or play the standing animation again. Because the weights for those transitions are one, zero and three
-respectively, he has a one in four chance of playing the waiting animation when the standing animation
-finishes, and a three in four chance of playing the standing animation again. This allows for a character
+platform game character. The character starts by displaying the \e standing state. From this state,
+barring external input, he will transition to either the \e waiting animation, the \e walking animation,
+or play the \e standing animation again. Because the weights for those transitions are one, zero and three
+respectively, he has a one in four chance of playing the \e waiting animation when the \e standing animation
+finishes, and a three in four chance of playing the \e standing animation again. This allows for a character
who has a slightly animated and variable behavior while waiting.
-Because there is a zero weight transition to the walking animation, the standing animation will not normally
-transition there. But if you set the goal animation to be the walking animation, it would play the walking
-animation when it finished the standing animation. If it was previously in the waiting animation, it would
-finish playing that, then play the standing animation, then play the walking animation. It would then continue to
-play the walking animation until the goal animation is unset, at which point it would switch to the standing
-animation after finishing the walking animation.
-
-If you set the goal state then to the jumping animation, it would finish the walking animation before
-playing the jumping animation. Because the jumping animation does not transition to other states, it will still
-keep playing the jumping animation until the state is forced to change. In this example, you could set it back to
-walking and change to goal animation to walking or to nothing (which would lead it to play the standing animation
-after the walking animation). Note that by forcibly setting the animation, you can start playing the animation
+Because there is a zero weight transition to the \e walking animation, the \e standing animation will not normally
+transition there. But if you set the goal animation to be the \e walking animation, it would play the \e walking
+animation when it finished the \e standing animation. If it was previously in the \e waiting animation, it would
+finish playing that, then play the \e standing animation, then play the \e walking animation. It would then continue to
+play the \e walking animation until the goal animation is unset, at which point it would switch to the \e standing
+animation after finishing the \e walking animation.
+
+If you then set the goal state to the \e jumping animation, it would finish the \e walking animation before
+playing the \e jumping animation. Because the \e jumping animation does not transition to other states, it will still
+keep playing the \e jumping animation until the state is forced to change. In this example, you could set it back to
+\e walking and change the goal animation to \e walking or to nothing (which would lead it to play the \e standing animation
+after the \e walking animation). Note that by forcibly setting the animation, you can start playing the animation
immediately.
\section2 Input Format
-The file formats accepted by the sprite engine is the same as the file formats accepted by other QML types,
-such as \l Image. In order to animate the image however, the sprite engine requires the image file to contain
+The file formats accepted by the sprite engine are the same as the file formats accepted by other QML types,
+such as \l Image. In order to animate the image, however, the sprite engine requires the image file to contain
all of the frames of the animation. They should be arranged in a contiguous line, which may wrap from the right
edge of the file to a lower row starting from the left edge of the file (and which is placed directly below the
previous row).
\image spritecutting.png
-As an example, take the above image. For now just consider the black numbers, and assume the squares are 40x40 pixels.
+As an example, take the above image. For now, just consider the black numbers, and assume the squares are 40x40 pixels.
Normally, the image is read from the top-left corner. If you specified the frame size as 40x40 pixels, and a frame count
of 8, then it would read in the frames as they are numbered. The frame in the top left would be the first frame, the frame
in the top right would be the fifth frame, and then it would wrap to the next row (at pixel location 0,40 in the file) to read
@@ -97,9 +97,9 @@ The first 120x40 of the image will not be used, as it starts reading 40x40 block
When it reaches the end of the file at 160,0, it then starts to read the next row from 0,40.
The blue numbers show the frame numbers if you tried to load two frames of that size, starting from 40,40. Note
-that it is possible to load multiple sprites out of the one image file. The red, blue and black numbers can all
+that it is possible to load multiple sprites from one image file. The red, blue and black numbers can all
be loaded as separate animations to the same sprite engine. The following code loads the animations as per the image.
-It also specifies that animations are to played at 20 frames per second.
+It also specifies that animations are to be played at 20 frames per second.
\code
Sprite {
@@ -131,17 +131,17 @@ Sprite {
}
\endcode
-Frames within one animation must be the same size, however multiple animations within the same file
-do not. Sprites without a frameCount specified assume that they take the entire file, and you must specify
+Frames within one animation must be the same size. However, multiple animations within the same file
+do not. Sprites without a \l {Sprite::}{frameCount} specified assume that they take the entire file, and you must specify
the frame size. Sprites without a frame size assume that they are square and take the entire file without wrapping,
and you must specify a frame count.
-The sprite engine internally copies and cuts up images to fit in an easier to read internal format, which leads
+The sprite engine internally copies and cuts up images to fit in an easier-to-read internal format, which leads
to some graphics memory limitations. Because it requires all the sprites for a single engine to be in the same
texture, attempting to load many different animations can run into texture memory limits on embedded devices. In
these situations, a warning will be output to the console containing the maximum texture size.
-There are several tools to help turn a set of images into sprite sheets, here are some examples:
+There are several tools to help turn a set of images into sprite sheets. Here are some examples:
\list
\li Photoshop plugin: \l http://www.johnwordsworth.com/projects/photoshop-sprite-sheet-generator-script
\li Gimp plugin: \l http://registry.gimp.org/node/20943
@@ -150,23 +150,23 @@ There are several tools to help turn a set of images into sprite sheets, here ar
\section2 QML Types Using the Sprite Engine
-Sprites for the sprite engine can be defined using the \l Sprite type. This type includes the input parameters
+Sprites for the sprite engine can be defined using the \l Sprite type. This type includes the input parameters,
as well as the length of the animation and weighted transitions to other animations. It is purely a data class, and
does not render anything.
\l SpriteSequence is a type which uses a sprite engine to draw the sprites defined in it. It is a single and
self-contained sprite engine, and does not interact with other sprite engines. \l Sprite types can be shared between
-sprite engine using types, but this is not done automatically. So if you have defined a sprite in one \l SpriteSequence
+sprite engine-using types, but this is not done automatically. So, if you have defined a sprite in one \l SpriteSequence
you will need to redefine it (or reference the same \l Sprite type) in the sprites property of another \l SpriteSequence
in order to transition to that animation.
Additionally, \l ImageParticle can use \l Sprite types to define sprites for each particle. This is again a single
-sprite engine per type. This works similarly to SpriteSequence, but it also has the parametrized variability provided
+sprite engine per type. This works similarly to \c SpriteSequence, but it also has the parameterized variability provided
by the \l ImageParticle type.
\section1 AnimatedSprite Type
-For use-cases which do not need to transition between animations, consider the AnimatedSprite type.
+For use-cases which do not need to transition between animations, consider the \l AnimatedSprite type.
This type displays sprite animations with the same input format, but only one at a time. It also provides more fine-grained
manual control, as there is no sprite engine managing the timing and transitions behind the scenes.
diff --git a/src/quick/doc/src/concepts/layouts/qtquicklayouts-index.qdoc b/src/quick/doc/src/concepts/layouts/qtquicklayouts-index.qdoc
index f65b1152e9..a45ed4b45c 100644
--- a/src/quick/doc/src/concepts/layouts/qtquicklayouts-index.qdoc
+++ b/src/quick/doc/src/concepts/layouts/qtquicklayouts-index.qdoc
@@ -39,6 +39,15 @@
Visit the \l{Qt Quick Layouts Overview} page to get started.
+ \section1 Licenses
+
+ Qt Quick Layouts is available under commercial licenses from \l{The Qt Company}.
+ In addition, it is available under free software licenses. Since Qt 5.4,
+ these free software licenses are
+ \l{GNU Lesser General Public License, version 3}, or
+ the \l{GNU General Public License, version 2}.
+ See \l{Qt Licensing} for further details.
+
\section1 Layouts
\annotatedlist layouts
diff --git a/src/quick/doc/src/concepts/layouts/qtquicklayouts-overview.qdoc b/src/quick/doc/src/concepts/layouts/qtquicklayouts-overview.qdoc
index 06ebe2d3d1..a5f93b972a 100644
--- a/src/quick/doc/src/concepts/layouts/qtquicklayouts-overview.qdoc
+++ b/src/quick/doc/src/concepts/layouts/qtquicklayouts-overview.qdoc
@@ -38,7 +38,7 @@
The QML types can be imported into your application using the following import statement in your \c {.qml} file.
\code
- import QtQuick.Layouts 1.2
+ import QtQuick.Layouts 1.11
\endcode
\section1 Key Features
diff --git a/src/quick/doc/src/concepts/layouts/qtquicklayouts.qdoc b/src/quick/doc/src/concepts/layouts/qtquicklayouts.qdoc
index 8f390c83db..d82e35fb93 100644
--- a/src/quick/doc/src/concepts/layouts/qtquicklayouts.qdoc
+++ b/src/quick/doc/src/concepts/layouts/qtquicklayouts.qdoc
@@ -26,7 +26,7 @@
****************************************************************************/
/*!
- \qmlmodule QtQuick.Layouts 1.3
+ \qmlmodule QtQuick.Layouts 1.11
\title Qt Quick Layouts QML Types
\ingroup qmlmodules
\brief Provides QML types for arranging QML items in a user interface.
@@ -40,7 +40,7 @@
following import statement in your .qml file.
\code
- import QtQuick.Layouts 1.3
+ import QtQuick.Layouts 1.11
\endcode
*/
diff --git a/src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc b/src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc
new file mode 100644
index 0000000000..e70791d1c9
--- /dev/null
+++ b/src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc
@@ -0,0 +1,428 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://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 https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://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: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+\page qtquick-bestpractices.html
+\title Best Practices for QML and Qt Quick
+\brief Lists best practices for working with QML and Qt Quick
+
+Despite all of the benefits that QML and Qt Quick offer, they can be
+challenging in certain situations. The following sections elaborate on some of
+the best practices that will help you get better results when developing
+applications.
+
+\section1 Custom UI Controls
+
+A fluid and modern UI is key for any application's success in today's world, and
+that's where QML makes so much sense for a designer or developer. Qt offers the
+most basic UI controls that are necessary to create a fluid and modern-looking
+UI. It is recommended to browse this list of UI controls before creating your
+own custom UI control.
+
+Besides these basic UI controls offered by Qt Quick itself, a rich set of UI
+controls are also available with Qt Quick Controls 2. They cater to the most
+common use cases without any change, and offer a lot more possibilities with their
+customization options. In particular, Qt Quick Controls 2 provides styling
+options that align with the latest UI design trends. If these UI controls do not
+satisfy your application's needs, only then it is recommended to create a
+custom control.
+
+
+\section2 Related Information
+\list
+\li \l{Qt Quick Controls 2}
+\li \l{Qt Quick}
+\endlist
+
+\section1 Keep it Short and Simple or "KiSS"
+
+QML being a declarative language, a lot of the details are worked out by the underlying
+engine. So it is important for any QML application, especially one with a
+larger codebase, to have its code organized in smaller and simpler \c .qml files.
+
+\omit
+need a few snippet or example applications that showcase this.
+\endomit
+
+\section2 Related Information
+\list
+ \li \l{QML Coding Conventions}
+\endlist
+
+\section1 Bundle Application Resources
+
+Most applications depend on resources such as images and icons to provide a
+rich user experience. It can often be a challenge to make these resources
+available to the application regardless of the target OS. Most popular OS-es
+employ stricter security policies that restrict access to the file system,
+making it harder to load these resources. As an alternative, Qt offers its own
+\l {The Qt Resource System}{resource system} that is built into the
+application binary, enabling access to the application's resources regardless
+of the target OS.
+
+For example, consider the following project directory structure:
+
+\badcode
+project
+├── images
+│ ├── image1.png
+│ └── image2.png
+├── project.pro
+└── qml
+ └── main.qml
+\endcode
+
+The following entry in \c project.pro ensures that the resources are built into
+the application binary, making them available when needed:
+
+\badcode
+ RESOURCES += \
+ qml/main.qml \
+ images/image1.png \
+ images/image2.png
+\endcode
+
+A more convenient approach is to use the
+\l {files(pattern[, recursive=false])}{wildcard syntax} to select several files
+at once:
+
+\badcode
+ RESOURCES += \
+ $$files(qml/*.qml) \
+ $$files(images/*.png)
+\endcode
+
+This approach is convenient for applications that depend on a limited number
+of resources. However, whenever a new file is added to \c RESOURCES using this
+approach, it causes \e all of the other files in \c RESOURCES to be recompiled
+as well. This can be inefficient, especially for large sets of files.
+In this case, a better approach is to separate each type of resource into its
+own \l {Resource Collection Files (.qrc)}{.qrc} file. For example, the snippet
+above could be changed to the following:
+
+\badcode
+ qml.files = $$files(*.qml)
+ qml.prefix = /qml
+ RESOURCES += qml
+
+ images.files = $$files(*.png)
+ images.prefix = /images
+ RESOURCES += images
+\endcode
+
+Now, whenever a QML file is changed, only the QML files have to be recompiled.
+
+Sometimes it can be necessary to have more control over the path for a
+specific file managed by the resource system. For example, if we wanted to give
+\c image2.png an alias, we would need to switch to an explicit \c .qrc file.
+\l {Creating Resource Files} explains how to do this in detail.
+
+\section2 Related Information
+\list
+ \li \l{The Qt Resource System}
+\endlist
+
+\section1 Separate UI from Logic
+
+One of the key goals that most application developers want to achieve is to
+create a maintainable application. One of the ways to achieve this goal is
+to separate the user interface from the business logic. The following are a few
+reasons why an application's UI should be written in QML:
+
+\list
+ \li Declarative languages are strongly suited for defining UIs.
+ \li QML code is simpler to write, as it is less verbose than C++, and is not
+ strongly typed. This also results in it being an excellent language to
+ prototype in, a quality that is vital when collaborating with designers,
+ for example.
+ \li JavaScript can easily be used in QML to respond to events.
+\endlist
+
+Being a strongly typed language, C++ is best suited for an application's logic.
+Typically, such code performs tasks such as complex calculations
+or data processing, which are faster in C++ than QML.
+
+Qt offers various approaches to integrate QML and C++ code in an application.
+A typical use case is displaying a list of data in a user interface.
+If the data set is static, simple, and/or small, a model written in QML can be
+sufficient.
+
+The following snippet demonstrates examples of models written in QML:
+
+\qml
+ model: ListModel {
+ ListElement { name: "Item 1" }
+ ListElement { name: "Item 2" }
+ ListElement { name: "Item 3" }
+ }
+
+ model: [ "Item 1", "Item 2", "Item 3" ]
+
+ model: 10
+\endqml
+
+Use \l {QAbstractItemModel Subclass}{C++} for dynamic data sets that are large
+or frequently modified.
+
+\section2 Interacting with QML from C++
+
+Although Qt enables you to manipulate QML from C++, it is not recommended to do
+so. To explain why, let's take a look at a simplified example.
+
+\section3 Pulling References from QML
+
+Suppose we were writing the UI for a settings page:
+
+\qml
+ import QtQuick 2.11
+ import QtQuick.Controls 2.4
+
+ Page {
+ Button {
+ text: qsTr("Restore default settings")
+ }
+ }
+\endqml
+
+We want the button to do something in C++ when it is clicked. We know objects
+in QML can emit change signals just like they can in C++, so we give the button
+an \l [QML]{QtObject::}{objectName} so that we can find it from C++:
+
+\qml
+ Button {
+ objectName: "restoreDefaultsButton"
+ text: qsTr("Restore default settings")
+ }
+\endqml
+
+Then, in C++, we find that object and connect to its change signal:
+
+\code
+ #include <QGuiApplication>
+ #include <QQmlApplicationEngine>
+ #include <QSettings>
+
+ class Backend : public QObject
+ {
+ Q_OBJECT
+
+ public:
+ Backend() {}
+
+ public slots:
+ void restoreDefaults() {
+ settings.setValue("loadLastProject", QVariant(false));
+ }
+
+ private:
+ QSettings settings;
+ };
+
+ int main(int argc, char *argv[])
+ {
+ QGuiApplication app(argc, argv);
+
+ QQmlApplicationEngine engine;
+ engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
+ if (engine.rootObjects().isEmpty())
+ return -1;
+
+ Backend backend;
+
+ QObject *rootObject = engine.rootObjects().first();
+ QObject *restoreDefaultsButton = rootObject->findChild<QObject*>("restoreDefaultsButton");
+ QObject::connect(restoreDefaultsButton, SIGNAL(clicked()),
+ &backend, SLOT(restoreDefaults()));
+
+ return app.exec();
+ }
+
+ #include "main.moc"
+\endcode
+
+With this approach, references to objects are "pulled" from QML.
+The problem with this is that the C++ logic layer depends on the QML
+presentation layer. If we were to refactor the QML in such a way that the
+\c objectName changes, or some other change breaks the ability for the C++
+to find the QML object, our workflow becomes much more complicated and tedious.
+
+\section3 Pushing References to QML
+
+Refactoring QML is a lot easier than refactoring C++, so in order to make
+maintenance pain-free, we should strive to keep C++ types unaware of QML as
+much as possible. This can be achieved by "pushing" references to C++ types
+into QML:
+
+\code
+ int main(int argc, char *argv[])
+ {
+ QGuiApplication app(argc, argv);
+
+ Backend backend;
+
+ QQmlApplicationEngine engine;
+ engine.rootContext()->setContextProperty("backend", &backend);
+ engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
+ if (engine.rootObjects().isEmpty())
+ return -1;
+
+ return app.exec();
+ }
+\endcode
+
+The QML then calls the C++ slot directly:
+
+\qml
+ import QtQuick 2.11
+ import QtQuick.Controls 2.4
+
+ Page {
+ Button {
+ text: qsTr("Restore default settings")
+ onClicked: backend.restoreDefaults()
+ }
+ }
+\endqml
+
+With this approach, the C++ remains unchanged in the event that the QML needs
+to be refactored in the future.
+
+In the example above, we set a context property on the root context to expose
+the C++ object to QML. This means that the property is available to every
+component loaded by the engine. Context properties are useful for objects that
+must be available as soon as the QML is loaded and cannot be instantiated in
+QML.
+
+\l {Integrating QML and C++} demonstrates an alternative approach where QML is
+made aware of a C++ type so that it can instantiate it itself.
+
+\section2 Related Information
+\list
+\li \l{Integrating QML and C++}
+\li \l{Qt Quick Controls 2 - Chat Tutorial}{Chat application tutorial}
+\endlist
+
+\section1 Using Qt Quick Layouts
+
+Qt offers Qt Quick Layouts to arrange Qt Quick items visually in a layout.
+Unlike its alternative, the item positioners, the Qt Quick Layouts can also
+resize its children on window resize. Although Qt Quick Layouts are often
+the desired choice for most use cases, the following \e dos and \e{don'ts}
+must be considered while using them:
+
+\section2 Dos
+
+\list
+ \li Use anchors or the item's width and height properties to specify the size
+ of the layout against its parent.
+ \li Use the \l Layout attached property to set the size and alignment
+ attributes of the layout's immediate children.
+\endlist
+
+\section2 Don'ts
+
+\list
+ \li Do not rely on anchors to specify the preferred size of an item in a layout.
+ Instead, use \c Layout.preferredWidth and \c Layout.preferredHeight.
+ \li Do not define preferred sizes for items that provide implicitWidth and
+ implicitHeight, unless their implicit sizes are not satisfactory.
+ \li Do not mix anchors and layouts in ways that cause conflicts. For example,
+ do not apply anchor constraints to a layout's immediate children.
+
+ \snippet qml/windowconstraints.qml rowlayout
+\endlist
+
+\note Layouts and anchors are both types of objects that take more memory and
+instantiation time. Avoid using them (especially in list and table delegates,
+and styles for controls) when simple bindings to x, y, width, and height
+properties are enough.
+
+\section2 Related Information
+
+\list
+ \li \l{Item Positioners}
+ \li \l{Qt Quick Layouts Overview}
+\endlist
+
+\section1 Performance
+
+For information on performance in QML and Qt Quick,
+see \l {Performance Considerations And Suggestions}.
+
+\section1 Tools and Utilities
+
+For information on useful tools and utilies that make working with QML and
+Qt Quick easier, see \l {Qt Quick Tools and Utilities}.
+
+\section1 Scene Graph
+
+For information on Qt Quick's scene graph, see \l {Qt Quick Scene Graph}.
+
+\section1 Scalable User Interfaces
+
+As display resolutions improve, a scalable application UI becomes more and
+more important. One of the approaches to achieve this is to maintain several
+copies of the UI for different screen resolutions, and load the appropriate one
+depending on the available resolution. Although this works pretty
+well, it adds to the maintenance overhead.
+
+Qt offers a better solution to this problem and recommends the application
+developers to follow these tips:
+
+\list
+ \li Use anchors or the Qt Quick Layouts module to lay out the visual items.
+ \li Do not specify explicit width and height for a visual item.
+ \li Provide UI resources such as images and icons for each display resolution
+ that your application supports. The Qt Quick Controls 2 gallery example
+ demonstrates this well by providing the \c qt-logo.png for \c @2x, \c @3x,
+ and \c @4x resolutions, enabling the application to cater to high
+ resolution displays. Qt automatically chooses the appropriate
+ image that is suitable for the given display, provided the high DPI scaling
+ feature is explicitly enabled.
+ \li Use SVG images for small icons. While larger SVGs can be slow to render,
+ small ones work well. Vector images avoid the need to provide several
+ versions of an image, as is necessary with bitmap images.
+ \li Use font-based icons, such as Font Awesome. These scale to any display
+ resolution, and also allow colorization. The
+ Qt Quick Controls 2 Text Editor example demonstrates this well.
+\endlist
+
+With this in place, your application's UI should scale depending
+on the display resolution on offer.
+
+\image qtquickcontrols2-gallery-welcome.png
+
+\section2 Related Information
+
+\list
+ \li \l{Qt Quick Controls2 - Gallery Example}{Gallery example}
+ \li \l{Qt Quick Controls 2 - Text Editor}{Text Editor example}
+ \li \l{Font Awesome}
+ \li \l{Scalability}
+ \li \l{High DPI Displays}
+\endlist
+*/
diff --git a/src/quick/doc/src/guidelines/qtquick-toolsnutilities.qdoc b/src/quick/doc/src/guidelines/qtquick-toolsnutilities.qdoc
new file mode 100644
index 0000000000..5f00abc193
--- /dev/null
+++ b/src/quick/doc/src/guidelines/qtquick-toolsnutilities.qdoc
@@ -0,0 +1,113 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://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 https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://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: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+\page qtquick-tools-and-utilities.html
+\title Qt Quick Tools and Utilities
+\brief Lists the tools and utilities that enhance developer experience
+
+Qt offers several tools and utilities to enable a rich developer experience,
+especially for Qt Quick developers. The following sections provide a brief
+introduction to those tools and utilities, and provide links to further
+information about them.
+
+\section1 Qt Quick Designer
+
+The Qt Quick Designer enables designing Qt Quick-based UIs using simple
+drag-n-drop gestures that most designers are familiar with. It offers UI
+elements from the Qt Quick and Qt Quick Controls 2 modules, as well as
+integration for custom UI elements.
+
+The following is a list of example applications that use UIs created by
+the Qt Quick Designer:
+
+\list
+ \li \l{Qt Quick Controls 2 - Contact List}
+ \li \l{Qt Quick Controls 2 - Flat Style}
+\endlist
+
+\section2 QML Debugger and Profiler
+
+Being a declarative language, a piece of QML code provides minimal details
+about the entities defined. In such a scenario, the QML debugger is a very
+useful utility that enables:
+\list
+ \li debugging JavaScript functions,
+ \li executing JavaScript expressions,
+ \li and inspecting QML properties.
+\endlist
+
+Besides this, a QML profiler enables you to get necessary diagnostic information,
+allowing you to analyze the application code for performance issues. For
+example, too much JavaScript in each frame, long-running C++ functions, and
+so on.
+
+\section2 Related Information
+\list
+ \li \l{QML Debugger}
+ \li \l{QML Profiler}
+\endlist
+
+\section2 QmlLive, GammaRay, and Squish
+
+QmlLive is a 3rd party tool that offers a QML runtime capable of rendering
+changes to the code in realtime. It avoids the need to rebuild the
+application after every code change and install it on the target device.
+You can also extend it to build a custom runtime that suits your needs.
+
+GammaRay is a useful utility that provides diagnostic information
+about your application. It is similar to the QML Profiler described in the
+earlier section, but offers a lot more. For example, the number of items or
+QObjects created, function calls made, time taken by each function call,
+property value introspection at runtime, and so on. Such information is very
+handy, especially while debugging QML applications.
+
+Squish is a well-known testing tool that automates UI testing by recording
+your actions or running scripts. Once the tests are setup, UI tests are a lot
+easier to run.
+
+\section2 Related Information
+\list
+ \li \l{QmlLive}
+ \li \l{GammaRay}
+ \li \l{Squish}
+\endlist
+
+\section1 Qt Creator
+
+The Qt Creator IDE is the key tool that enhances the overall developer experience of
+working with Qt Quick. Its auto-completion and debugging features make working
+with Qt Quick easier. Besides this, most of the tools and utilities
+mentioned in the earlier sections are integrated into it, with the possibility of
+integrating 3rd party tools such as QmlLive and GammaRay.
+
+\section2 Related Information
+\list
+\li \l{Qt Creator Manual}
+\li \l{Qt Creator: Integrating 3rd Party Tools}
+\endlist
+*/
diff --git a/src/quick/doc/src/qmltypereference.qdoc b/src/quick/doc/src/qmltypereference.qdoc
index f5b189c580..80b9241f36 100644
--- a/src/quick/doc/src/qmltypereference.qdoc
+++ b/src/quick/doc/src/qmltypereference.qdoc
@@ -26,7 +26,7 @@
****************************************************************************/
/*!
-\qmlmodule QtQuick 2.7
+\qmlmodule QtQuick 2.11
\title Qt Quick QML Types
\ingroup qmlmodules
\brief Provides graphical QML types.
@@ -34,11 +34,11 @@
The \l{Qt Quick} module provides graphical primitive types. These types are only
available in a QML document if that document imports the \c QtQuick namespace.
-The current version of the \c QtQuick module is version 2.7, and thus it may be
+The current version of the \c QtQuick module is version 2.11, and thus it may be
imported via the following statement:
\qml
-import QtQuick 2.7
+import QtQuick 2.11
\endqml
Visit the \l {Qt Quick} module documentation for more
@@ -883,14 +883,14 @@ console.log(c + " " + d); // false true
*/
/*!
-\qmlmodule QtTest 1.1
+\qmlmodule QtTest 1.11
\title Qt Quick Test QML Types
\brief This module provides QML types to unit test your QML application
\ingroup qmlmodules
You can import this module using the following statement:
\code
-import QtTest 1.1
+import QtTest 1.11
\endcode
For more information about how to use these types, see
diff --git a/src/quick/doc/src/qtquick.qdoc b/src/quick/doc/src/qtquick.qdoc
index ece66cb589..4d8da5ed5a 100644
--- a/src/quick/doc/src/qtquick.qdoc
+++ b/src/quick/doc/src/qtquick.qdoc
@@ -118,6 +118,7 @@ Additional Qt Quick information:
\li \l{Qt Quick Test QML Types}{Tests} - contains types for writing unit test for a QML application
\endlist
\li \l{Qt Quick Examples and Tutorials}
+\li \l{Qt Quick Guidelines}
\endlist
Further information for writing QML applications:
diff --git a/src/quick/handlers/qquickpointerhandler.cpp b/src/quick/handlers/qquickpointerhandler.cpp
index 959030b8fe..e5b1dc8985 100644
--- a/src/quick/handlers/qquickpointerhandler.cpp
+++ b/src/quick/handlers/qquickpointerhandler.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
@@ -245,6 +245,14 @@ void QQuickPointerHandler::setGrabPermissions(GrabPermissions grabPermission)
emit grabPermissionChanged();
}
+void QQuickPointerHandler::classBegin()
+{
+}
+
+void QQuickPointerHandler::componentComplete()
+{
+}
+
/*!
\internal
Acquire or give up the exclusive grab of the given \a point, according to
diff --git a/src/quick/handlers/qquickpointerhandler_p.h b/src/quick/handlers/qquickpointerhandler_p.h
index 9ea6a8b5e2..e2bcce8fc9 100644
--- a/src/quick/handlers/qquickpointerhandler_p.h
+++ b/src/quick/handlers/qquickpointerhandler_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
@@ -106,9 +106,6 @@ public:
GrabPermissions grabPermissions() const { return static_cast<GrabPermissions>(m_grabPermissions); }
void setGrabPermissions(GrabPermissions grabPermissions);
- void classBegin() override { }
- void componentComplete() override { }
-
Q_SIGNALS:
void enabledChanged();
void activeChanged();
@@ -118,6 +115,9 @@ Q_SIGNALS:
void canceled(QQuickEventPoint *point);
protected:
+ void classBegin() override;
+ void componentComplete() override;
+
QQuickPointerEvent *currentEvent() { return m_currentEvent; }
virtual bool wantsPointerEvent(QQuickPointerEvent *event);
virtual void handlePointerEventImpl(QQuickPointerEvent *event);
diff --git a/src/quick/items/qquickanimatedsprite.cpp b/src/quick/items/qquickanimatedsprite.cpp
index 741e4607e5..190c48ac88 100644
--- a/src/quick/items/qquickanimatedsprite.cpp
+++ b/src/quick/items/qquickanimatedsprite.cpp
@@ -152,10 +152,10 @@ QT_BEGIN_NAMESPACE
/*!
\qmlproperty qreal QtQuick::AnimatedSprite::frameRate
- Frames per second to show in the animation. Values equal to or below 0 are invalid.
+ Frames per second to show in the animation. Values less than or equal to \c 0 are invalid.
- If frameRate is valid then it will be used to calculate the duration of the frames.
- If not, and frameDuration is valid , then frameDuration will be used.
+ If \c frameRate is valid, it will be used to calculate the duration of the frames.
+ If not, and \l frameDuration is valid, \c frameDuration will be used.
Changing this parameter will restart the animation.
*/
@@ -163,10 +163,10 @@ QT_BEGIN_NAMESPACE
/*!
\qmlproperty int QtQuick::AnimatedSprite::frameDuration
- Duration of each frame of the animation in milliseconds. Values equal to or below 0 are invalid.
+ Duration of each frame of the animation in milliseconds. Values less than or equal to \c 0 are invalid.
- If frameRate is valid then it will be used to calculate the duration of the frames.
- If not, and frameDuration is valid, then frameDuration will be used.
+ If frameRate is valid, it will be used to calculate the duration of the frames.
+ If not, and \l frameDuration is valid, \c frameDuration will be used.
Changing this parameter will restart the animation.
*/
@@ -218,21 +218,21 @@ QT_BEGIN_NAMESPACE
/*!
\qmlproperty bool QtQuick::AnimatedSprite::reverse
- If true, then the animation will be played in reverse.
+ If \c true, the animation will be played in reverse.
- Default is false.
+ Default is \c false.
*/
/*!
\qmlproperty bool QtQuick::AnimatedSprite::frameSync
- If true, then the animation will have no duration. Instead, the animation will advance
+ If \c true, the animation will have no duration. Instead, the animation will advance
one frame each time a frame is rendered to the screen. This synchronizes it with the painting
rate as opposed to elapsed time.
If frameSync is set to true, it overrides both frameRate and frameDuration.
- Default is false.
+ Default is \c false.
Changing this parameter will restart the animation.
*/
@@ -242,9 +242,9 @@ QT_BEGIN_NAMESPACE
After playing the animation this many times, the animation will automatically stop. Negative values are invalid.
- If this is set to AnimatedSprite.Infinite the animation will not stop playing on its own.
+ If this is set to \c AnimatedSprite.Infinite the animation will not stop playing on its own.
- Default is AnimatedSprite.Infinite
+ Default is \c AnimatedSprite.Infinite
*/
/*!
@@ -252,13 +252,13 @@ QT_BEGIN_NAMESPACE
When paused, the current frame can be advanced manually.
- Default is false.
+ Default is \c false.
*/
/*!
\qmlproperty int QtQuick::AnimatedSprite::currentFrame
- When paused, the current frame can be advanced manually by setting this property or calling advance().
+ When paused, the current frame can be advanced manually by setting this property or calling \l advance().
*/
@@ -452,7 +452,7 @@ void QQuickAnimatedSprite::maybeUpdate()
\qmlmethod int QtQuick::AnimatedSprite::pause()
Pauses the sprite animation. This does nothing if
- \l paused is true.
+ \l paused is \c true.
\sa resume()
*/
@@ -471,7 +471,7 @@ void QQuickAnimatedSprite::pause()
/*!
\qmlmethod int QtQuick::AnimatedSprite::resume()
- Resumes the sprite animation if \l paused is true;
+ Resumes the sprite animation if \l paused is \c true;
otherwise, this does nothing.
\sa pause()
diff --git a/src/quick/items/qquickevents_p_p.h b/src/quick/items/qquickevents_p_p.h
index c4f0b60d92..2a1e9dc184 100644
--- a/src/quick/items/qquickevents_p_p.h
+++ b/src/quick/items/qquickevents_p_p.h
@@ -597,6 +597,7 @@ public:
Area = QTouchDevice::Area,
Pressure = QTouchDevice::Pressure,
Velocity = QTouchDevice::Velocity,
+ MouseEmulation = QTouchDevice::MouseEmulation,
// some bits reserved in case we need more of QTouchDevice::Capabilities
Scroll = 0x0100, // mouse has a wheel, or there is OS-level scroll gesture recognition (dubious?)
Hover = 0x0200,
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp
index d4f10a9fd9..cefe2de883 100644
--- a/src/quick/items/qquickflickable.cpp
+++ b/src/quick/items/qquickflickable.cpp
@@ -1652,10 +1652,12 @@ void QQuickFlickable::timerEvent(QTimerEvent *event)
}
} else if (event->timerId() == d->movementEndingTimer.timerId()) {
d->movementEndingTimer.stop();
- d->pressed = false;
- d->stealMouse = false;
- if (!d->velocityTimeline.isActive() && !d->timeline.isActive())
- movementEnding(true, true);
+ if (!d->scrollingPhase) {
+ d->pressed = false;
+ d->stealMouse = false;
+ if (!d->velocityTimeline.isActive() && !d->timeline.isActive())
+ movementEnding(true, true);
+ }
}
}
diff --git a/src/quick/items/qquickimage.cpp b/src/quick/items/qquickimage.cpp
index dc2cd17b4e..db5cfd2526 100644
--- a/src/quick/items/qquickimage.cpp
+++ b/src/quick/items/qquickimage.cpp
@@ -135,6 +135,48 @@ QQuickImagePrivate::QQuickImagePrivate()
\clearfloat
+ \section1 OpenGL Texture Files
+
+ When the default OpenGL \l{Qt Quick Scene Graph}{scene graph} backend is in
+ use, images can also be supplied in compressed texture files. The content
+ must be a simple RGB(A) format 2D texture. Supported compression schemes
+ are only limited by the underlying OpenGL driver and GPU. The following
+ container file formats are supported:
+
+ \list
+ \li \c PKM (since Qt 5.10)
+ \li \c KTX (since Qt 5.11)
+ \endlist
+
+ \note Semi-transparent original images require alpha pre-multiplication
+ prior to texture compression in order to be correctly displayed in Qt
+ Quick. This can be done with the following ImageMagick command
+ line:
+ \badcode
+ convert MYORIGIMAGE \( +clone -alpha Extract \) -channel RGB -compose Multiply -composite MYPMIMAGE
+ \endcode
+
+ \section1 Automatic Detection of File Extension
+
+ If the \l source URL indicates a non-existing local file or resource, the
+ Image element attempts to auto-detect the file extension. If an existing
+ file can be found by appending any of the supported image file extensions
+ to the \l source URL, then that file will be loaded.
+
+ If the OpenGL \l{Qt Quick Scene Graph}{scene graph} backend is in use, the
+ file search the attempts the OpenGL texture file extensions first. If the
+ search is unsuccessful, it attempts to search with the file extensions for
+ the \l{QImageReader::supportedImageFormats()}{conventional image file
+ types}. For example:
+
+ \snippet qml/image-ext.qml ext
+
+ This functionality facilitates deploying different image asset file types
+ on different target platforms. This can be useful in order to tune
+ application performance and adapt to different graphics hardware.
+
+ This functionality was introduced in Qt 5.11.
+
\section1 Performance
By default, locally available images are loaded immediately, and the user interface
@@ -154,7 +196,7 @@ QQuickImagePrivate::QQuickImagePrivate()
size bounded via the \l sourceSize property. This is especially important for content
that is loaded from external sources or provided by the user.
- \sa {Qt Quick Examples - Image Elements}, QQuickImageProvider
+ \sa {Qt Quick Examples - Image Elements}, QQuickImageProvider, QImageReader::setAutoDetectImageFormat()
*/
QQuickImage::QQuickImage(QQuickItem *parent)
@@ -461,7 +503,7 @@ qreal QQuickImage::paintedHeight() const
The URL may be absolute, or relative to the URL of the component.
- \sa QQuickImageProvider
+ \sa QQuickImageProvider {OpenGL Texture Files} {Automatic Detection of File Extension}
*/
/*!
diff --git a/src/quick/items/qquickitemgrabresult.cpp b/src/quick/items/qquickitemgrabresult.cpp
index 003fde8c9e..b45cb09c4b 100644
--- a/src/quick/items/qquickitemgrabresult.cpp
+++ b/src/quick/items/qquickitemgrabresult.cpp
@@ -139,7 +139,7 @@ public:
* This property holds the pixel results from a grab.
*
* If the grab is not yet complete or if it failed,
- * an empty image is returned.
+ * a null image is returned (\c {image.isNull()} will return \c true).
*/
/*!
diff --git a/src/quick/items/qquickloader.cpp b/src/quick/items/qquickloader.cpp
index 34f30e81a3..cd48896e58 100644
--- a/src/quick/items/qquickloader.cpp
+++ b/src/quick/items/qquickloader.cpp
@@ -102,7 +102,7 @@ void QQuickLoaderPrivate::clear()
// this we may get transient errors from use of 'parent', for example.
QQmlContext *context = qmlContext(object);
if (context)
- QQmlContextData::get(context)->invalidate();
+ QQmlContextData::get(context)->clearContextRecursively();
if (loadingFromSource && component) {
// disconnect since we deleteLater
@@ -311,10 +311,7 @@ QQuickLoader::QQuickLoader(QQuickItem *parent)
QQuickLoader::~QQuickLoader()
{
Q_D(QQuickLoader);
- if (d->item) {
- QQuickItemPrivate *p = QQuickItemPrivate::get(d->item);
- p->removeItemChangeListener(d, watchedChanges);
- }
+ d->clear();
}
/*!
@@ -363,7 +360,7 @@ void QQuickLoader::setActive(bool newVal)
// this we may get transient errors from use of 'parent', for example.
QQmlContext *context = qmlContext(d->object);
if (context)
- QQmlContextData::get(context)->invalidate();
+ QQmlContextData::get(context)->clearContextRecursively();
if (d->item) {
QQuickItemPrivate *p = QQuickItemPrivate::get(d->item);
diff --git a/src/quick/items/qquicksprite.cpp b/src/quick/items/qquicksprite.cpp
index 99b1b1f430..6b8567439b 100644
--- a/src/quick/items/qquicksprite.cpp
+++ b/src/quick/items/qquicksprite.cpp
@@ -51,8 +51,8 @@ QT_BEGIN_NAMESPACE
\ingroup qtquick-visual-utility
\brief Specifies sprite animations
- QQuickSprite renders sprites of one or more frames and animates them. The sprites
- can be in the middle of an image file, or split along multiple rows, as long as they form
+ Sprite defines a series of one or more frames to be animated and rendered by SpriteSequence.
+ The sprites can be in the middle of an image file, or split along multiple rows, as long as they form
a contiguous line wrapping to the next row of the file from the left edge of the file.
For full details, see the \l{Sprite Animations} overview.
diff --git a/src/quick/items/qquickspritesequence.cpp b/src/quick/items/qquickspritesequence.cpp
index 0a39c09ebc..72761ab82b 100644
--- a/src/quick/items/qquickspritesequence.cpp
+++ b/src/quick/items/qquickspritesequence.cpp
@@ -73,38 +73,38 @@ QT_BEGIN_NAMESPACE
Whether the sprite is animating or not.
- Default is true
+ Default is \c true.
*/
/*!
\qmlproperty bool QtQuick::SpriteSequence::interpolate
- If true, interpolation will occur between sprite frames to make the
+ If \c true, interpolation will occur between sprite frames to make the
animation appear smoother.
- Default is true.
+ Default is \c true.
*/
/*!
\qmlproperty string QtQuick::SpriteSequence::currentSprite
- The name of the Sprite which is currently animating.
+ The name of the \l Sprite that is currently animating.
*/
/*!
\qmlproperty string QtQuick::SpriteSequence::goalSprite
- The name of the Sprite which the animation should move to.
+ The name of the \l Sprite that the animation should move to.
- Sprite states have defined durations and transitions between them, setting goalState
- will cause it to disregard any path weightings (including 0) and head down the path
- which will reach the goalState quickest (fewest animations). It will pass through
+ Sprite states have defined durations and transitions between them; setting \c goalSprite
+ will cause it to disregard any path weightings (including \c 0) and head down the path
+ that will reach the \c goalSprite quickest (fewest animations). It will pass through
intermediate states on that path, and animate them for their duration.
- If it is possible to return to the goalState from the starting point of the goalState
- it will continue to do so until goalState is set to "" or an unreachable state.
+ If it is possible to return to the \c goalSprite from the starting point of the \c goalSprite,
+ it will continue to do so until \c goalSprite is set to \c "" or an unreachable state.
*/
/*! \qmlmethod QtQuick::SpriteSequence::jumpTo(string sprite)
- This function causes the SpriteSequence to jump to the specified sprite immediately, intermediate
- sprites are not played. The \a sprite argument is the name of the sprite you wish to jump to.
+ This function causes the SpriteSequence to jump to the specified \a sprite immediately;
+ intermediate sprites are not played.
*/
/*!
\qmlproperty list<Sprite> QtQuick::SpriteSequence::sprites
diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp
index 383aa2b821..9eaf9f8d6d 100644
--- a/src/quick/items/qquicktext.cpp
+++ b/src/quick/items/qquicktext.cpp
@@ -2318,8 +2318,10 @@ void QQuickText::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeo
if (!(widthChanged || widthMaximum) && !d->isLineLaidOutConnected()) { // only height has changed
if (newGeometry.height() > oldGeometry.height()) {
- if (!d->heightExceeded) // Height is adequate and growing.
+ if (!d->heightExceeded && !qFuzzyIsNull(oldGeometry.height())) {
+ // Height is adequate and growing, and it wasn't 0 previously.
goto geomChangeDone;
+ }
if (d->lineCount == d->maximumLineCount()) // Reached maximum line and height is growing.
goto geomChangeDone;
} else if (newGeometry.height() < oldGeometry.height()) {
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 26b97d452a..02fe4809ab 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -656,6 +656,12 @@ bool QQuickWindowPrivate::deliverTouchAsMouse(QQuickItem *item, QQuickPointerEve
Q_Q(QQuickWindow);
auto device = pointerEvent->device();
+ // A touch event from a trackpad is likely to be followed by a mouse or gesture event, so mouse event synth is redundant
+ if (device->type() == QQuickPointerDevice::TouchPad && device->capabilities().testFlag(QQuickPointerDevice::MouseEmulation)) {
+ qCDebug(DBG_TOUCH_TARGET) << "skipping delivery of synth-mouse event from" << device;
+ return false;
+ }
+
// FIXME: make this work for mouse events too and get rid of the asTouchEvent in here.
Q_ASSERT(pointerEvent->asPointerTouchEvent());
QScopedPointer<QTouchEvent> event(pointerEvent->asPointerTouchEvent()->touchEventForItem(item));
@@ -2833,7 +2839,11 @@ bool QQuickWindowPrivate::sendFilteredPointerEventImpl(QQuickPointerEvent *event
// In versions prior to Qt 6, we can't trust item->acceptTouchEvents() here, because it defaults to true.
bool acceptsTouchEvents = false;
#endif
- if (acceptsTouchEvents || receiver->acceptedMouseButtons()) {
+ auto device = pte->device();
+ if (device->type() == QQuickPointerDevice::TouchPad &&
+ device->capabilities().testFlag(QQuickPointerDevice::MouseEmulation)) {
+ qCDebug(DBG_TOUCH_TARGET) << "skipping filtering of synth-mouse event from" << device;
+ } else if (acceptsTouchEvents || receiver->acceptedMouseButtons()) {
// get a touch event customized for delivery to filteringParent
QScopedPointer<QTouchEvent> filteringParentTouchEvent(pte->touchEventForItem(receiver, true));
if (filteringParentTouchEvent) {
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode.cpp
index 3b0f3c48ff..aa83709b72 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode.cpp
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode.cpp
@@ -320,6 +320,7 @@ QSGSoftwareInternalImageNode::QSGSoftwareInternalImageNode()
, m_subSourceRect(0, 0, 1, 1)
, m_texture(nullptr)
, m_mirror(false)
+ , m_textureIsLayer(false)
, m_smooth(true)
, m_tileHorizontal(false)
, m_tileVertical(false)
@@ -366,6 +367,7 @@ void QSGSoftwareInternalImageNode::setTexture(QSGTexture *texture)
{
m_texture = texture;
m_cachedMirroredPixmapIsDirty = true;
+ m_textureIsLayer = static_cast<bool>(qobject_cast<QSGSoftwareLayer*>(texture));
markDirty(DirtyMaterial);
}
@@ -415,8 +417,13 @@ void QSGSoftwareInternalImageNode::setVerticalWrapMode(QSGTexture::WrapMode wrap
void QSGSoftwareInternalImageNode::update()
{
if (m_cachedMirroredPixmapIsDirty) {
- if (m_mirror) {
- m_cachedMirroredPixmap = pixmap().transformed(QTransform(-1, 0, 0, 1, 0, 0));
+ if (m_mirror || m_textureIsLayer) {
+ QTransform transform(
+ (m_mirror ? -1 : 1), 0,
+ 0 , (m_textureIsLayer ? -1 :1),
+ 0 , 0
+ );
+ m_cachedMirroredPixmap = pixmap().transformed(transform);
} else {
//Cleanup cached pixmap if necessary
if (!m_cachedMirroredPixmap.isNull())
@@ -436,6 +443,7 @@ void QSGSoftwareInternalImageNode::preprocess()
}
if (doDirty)
markDirty(DirtyMaterial);
+ m_cachedMirroredPixmapIsDirty = doDirty;
}
static Qt::TileRule getTileRule(qreal factor)
@@ -454,7 +462,7 @@ void QSGSoftwareInternalImageNode::paint(QPainter *painter)
{
painter->setRenderHint(QPainter::SmoothPixmapTransform, m_smooth);
- const QPixmap &pm = m_mirror ? m_cachedMirroredPixmap : pixmap();
+ const QPixmap &pm = m_mirror || m_textureIsLayer ? m_cachedMirroredPixmap : pixmap();
if (m_innerTargetRect != m_targetRect) {
// border image
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode_p.h
index 5c95eb064a..b80bacbaa0 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode_p.h
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode_p.h
@@ -136,6 +136,7 @@ private:
QPixmap m_cachedMirroredPixmap;
bool m_mirror;
+ bool m_textureIsLayer;
bool m_smooth;
bool m_tileHorizontal;
bool m_tileVertical;
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarelayer.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarelayer.cpp
index b4301451d8..70378d2950 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwarelayer.cpp
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarelayer.cpp
@@ -240,9 +240,9 @@ void QSGSoftwareLayer::grab()
m_renderer->setDeviceRect(m_size);
m_renderer->setViewportRect(m_size);
QRect mirrored(m_mirrorHorizontal ? m_rect.right() * m_device_pixel_ratio : m_rect.left() * m_device_pixel_ratio,
- m_mirrorVertical ? m_rect.top() * m_device_pixel_ratio : m_rect.bottom() * m_device_pixel_ratio,
+ m_mirrorVertical ? m_rect.bottom() * m_device_pixel_ratio : m_rect.top() * m_device_pixel_ratio,
m_mirrorHorizontal ? -m_rect.width() * m_device_pixel_ratio : m_rect.width() * m_device_pixel_ratio,
- m_mirrorVertical ? m_rect.height() * m_device_pixel_ratio : -m_rect.height() * m_device_pixel_ratio);
+ m_mirrorVertical ? -m_rect.height() * m_device_pixel_ratio : m_rect.height() * m_device_pixel_ratio);
m_renderer->setProjectionRect(mirrored);
m_renderer->setClearColor(Qt::transparent);
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer.cpp
index 303f98c801..bb4afc8301 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer.cpp
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer.cpp
@@ -79,7 +79,7 @@ void QSGSoftwarePixmapRenderer::render(QPaintDevice *target)
QElapsedTimer renderTimer;
// Setup background item
- setBackgroundRect(m_projectionRect);
+ setBackgroundRect(m_projectionRect.normalized());
setBackgroundColor(clearColor());
renderTimer.start();
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp
index 423f5f7321..b400473128 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp
@@ -195,7 +195,7 @@ void QSGSoftwareRenderLoop::renderWindow(QQuickWindow *window, bool isNewExpose)
int(polishTime / 1000000),
int((syncTime - polishTime) / 1000000),
int((renderTime - syncTime) / 1000000),
- int((swapTime - renderTime) / 10000000),
+ int((swapTime - renderTime) / 1000000),
int(lastFrameTime.msecsTo(QTime::currentTime())));
lastFrameTime = QTime::currentTime();
}
diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
index dc473a6640..ce706d76f7 100644
--- a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
+++ b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
@@ -71,9 +71,9 @@ static inline QVector4D qsg_premultiply(const QVector4D &c, float globalOpacity)
return QVector4D(c.x() * o, c.y() * o, c.z() * o, o);
}
-static inline int qsg_device_pixel_ratio(QOpenGLContext *ctx)
+static inline qreal qsg_device_pixel_ratio(QOpenGLContext *ctx)
{
- int devicePixelRatio = 1;
+ qreal devicePixelRatio = 1;
if (ctx->surface()->surfaceClass() == QSurface::Window) {
QWindow *w = static_cast<QWindow *>(ctx->surface());
if (QQuickWindow *qw = qobject_cast<QQuickWindow *>(w))
diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp
index 88b9c93448..3cdf851a8f 100644
--- a/src/quick/scenegraph/qsgrenderloop.cpp
+++ b/src/quick/scenegraph/qsgrenderloop.cpp
@@ -310,6 +310,8 @@ void QSGGuiThreadRenderLoop::hide(QQuickWindow *window)
{
QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
cd->fireAboutToStop();
+ if (m_windows.contains(window))
+ m_windows[window].updatePending = false;
}
void QSGGuiThreadRenderLoop::windowDestroyed(QQuickWindow *window)
@@ -501,7 +503,8 @@ QImage QSGGuiThreadRenderLoop::grab(QQuickWindow *window)
void QSGGuiThreadRenderLoop::maybeUpdate(QQuickWindow *window)
{
- if (!m_windows.contains(window))
+ QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
+ if (!cd->isRenderable() || !m_windows.contains(window))
return;
m_windows[window].updatePending = true;
diff --git a/src/quick/util/qquickimageprovider.cpp b/src/quick/util/qquickimageprovider.cpp
index 1a13f6395a..2bb2af4fc0 100644
--- a/src/quick/util/qquickimageprovider.cpp
+++ b/src/quick/util/qquickimageprovider.cpp
@@ -680,15 +680,18 @@ QSize QQuickImageProviderWithOptions::loadSize(const QSize &originalSize, const
return res;
const bool preserveAspectCropOrFit = options.preserveAspectRatioCrop() || options.preserveAspectRatioFit();
+ const bool formatIsSvg = (format == "svg" || format == "svgz");
- if (!preserveAspectCropOrFit && (format == "svg" || format == "svgz") && !requestedSize.isEmpty())
+ if (!preserveAspectCropOrFit && formatIsSvg && !requestedSize.isEmpty())
return requestedSize;
qreal ratio = 0.0;
- if (requestedSize.width() && (preserveAspectCropOrFit || requestedSize.width() < originalSize.width())) {
+ if (requestedSize.width() && (preserveAspectCropOrFit || formatIsSvg ||
+ requestedSize.width() < originalSize.width())) {
ratio = qreal(requestedSize.width()) / originalSize.width();
}
- if (requestedSize.height() && (preserveAspectCropOrFit || requestedSize.height() < originalSize.height())) {
+ if (requestedSize.height() && (preserveAspectCropOrFit || formatIsSvg ||
+ requestedSize.height() < originalSize.height())) {
qreal hr = qreal(requestedSize.height()) / originalSize.height();
if (ratio == 0.0)
ratio = hr;
diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp
index 6f3b685974..920b400eac 100644
--- a/src/quickwidgets/qquickwidget.cpp
+++ b/src/quickwidgets/qquickwidget.cpp
@@ -485,6 +485,12 @@ QImage QQuickWidgetPrivate::grabFramebuffer()
compatible however and attempting to construct a QQuickWidget will lead to
problems.
+ \section1 Tab Key Handling
+
+ On press of the \c[TAB] key, the item inside the QQuickWidget gets focus. If
+ this item can handle \c[TAB] key press, focus will change accordingly within
+ the item, otherwise the next widget in the focus chain gets focus.
+
\sa {Exposing Attributes of C++ Types to QML}, {Qt Quick Widgets Example}, QQuickView
*/
@@ -1222,6 +1228,22 @@ void QQuickWidget::resizeEvent(QResizeEvent *e)
}
/*! \reimp */
+bool QQuickWidget::focusNextPrevChild(bool next)
+{
+ Q_D(QQuickWidget);
+ QKeyEvent event(QEvent::KeyPress, next ? Qt::Key_Tab : Qt::Key_Backtab, Qt::NoModifier);
+ Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyPress, event.key(),
+ Qt::NoModifier);
+ QCoreApplication::sendEvent(d->offscreenWindow, &event);
+
+ QKeyEvent releaseEvent(QEvent::KeyRelease, next ? Qt::Key_Tab : Qt::Key_Backtab, Qt::NoModifier);
+ Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyRelease, releaseEvent.key(),
+ Qt::NoModifier);
+ QCoreApplication::sendEvent(d->offscreenWindow, &releaseEvent);
+ return event.isAccepted();
+}
+
+/*! \reimp */
void QQuickWidget::keyPressEvent(QKeyEvent *e)
{
Q_D(QQuickWidget);
diff --git a/src/quickwidgets/qquickwidget.h b/src/quickwidgets/qquickwidget.h
index 3ddb0613ad..5543705f13 100644
--- a/src/quickwidgets/qquickwidget.h
+++ b/src/quickwidgets/qquickwidget.h
@@ -143,6 +143,7 @@ protected:
bool event(QEvent *) override;
void paintEvent(QPaintEvent *event) override;
+ bool focusNextPrevChild(bool next) override;
private:
Q_DISABLE_COPY(QQuickWidget)
diff --git a/tests/auto/cmake/CMakeLists.txt b/tests/auto/cmake/CMakeLists.txt
index 4d4d8e3db7..f304a99705 100644
--- a/tests/auto/cmake/CMakeLists.txt
+++ b/tests/auto/cmake/CMakeLists.txt
@@ -25,4 +25,5 @@ add_test(qtquickcompiler ${CMAKE_CTEST_COMMAND}
--build-makeprogram ${CMAKE_MAKE_PROGRAM}
--build-project qqc_test
--build-options "-DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}" ${BUILD_OPTIONS_LIST}
+ --test-command qqc_test
)
diff --git a/tests/auto/cmake/qtquickcompiler/CMakeLists.txt b/tests/auto/cmake/qtquickcompiler/CMakeLists.txt
index 6dee1e25dc..4e46544767 100644
--- a/tests/auto/cmake/qtquickcompiler/CMakeLists.txt
+++ b/tests/auto/cmake/qtquickcompiler/CMakeLists.txt
@@ -4,11 +4,14 @@ project(qqc_test)
find_package(Qt5Qml 5.0.0 REQUIRED)
find_package(Qt5Gui 5.0.0 REQUIRED)
+find_package(Qt5Test 5.0.0 REQUIRED)
find_package(Qt5QuickCompiler)
set(CMAKE_CXXFLAGS "${CMAKE_CXXFLAGS} ${Qt5Core_EXECUTABLE_COMPILE_FLAGS}")
-qtquick_compiler_add_resources(RESOURCES qqc_test.qrc)
+qtquick_compiler_add_resources(RESOURCES "resources with space/qqc_test.qrc")
+
+set(CMAKE_AUTOMOC ON)
add_executable(qqc_test "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp" ${RESOURCES})
-target_link_libraries(qqc_test Qt5::Gui Qt5::Qml)
+target_link_libraries(qqc_test Qt5::Gui Qt5::Qml Qt5::Test)
diff --git a/tests/auto/cmake/qtquickcompiler/main.cpp b/tests/auto/cmake/qtquickcompiler/main.cpp
index 47fc709c0a..c357ef60e6 100644
--- a/tests/auto/cmake/qtquickcompiler/main.cpp
+++ b/tests/auto/cmake/qtquickcompiler/main.cpp
@@ -1,9 +1,30 @@
-#include <QtGui>
+#include <QtCore>
#include <QtQml>
+#include <QtTest>
-int main(int argc, char **argv)
+class tst_QQC : public QObject
{
- QGuiApplication app(argc, argv);
- return app.exec();
+ Q_OBJECT
+private slots:
+ void packaging();
+};
+
+void tst_QQC::packaging()
+{
+ QVERIFY(QFile::exists(":/main.qml"));
+ QCOMPARE(QFileInfo(":/main.qml").size(), 0);
+ QVERIFY(QFile::exists(":/main.cpp"));
+ QVERIFY(QFileInfo(":/main.cpp").size() > 0);
+
+
+ QQmlEngine engine;
+ QQmlComponent component(&engine, QUrl("qrc:/main.qml"));
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+ QCOMPARE(obj->property("success").toInt(), 42);
}
+
+QTEST_MAIN(tst_QQC)
+
+#include "main.moc"
diff --git a/tests/auto/cmake/qtquickcompiler/main.qml b/tests/auto/cmake/qtquickcompiler/resources with space/main.qml
index 1f146d89c3..0836808dc2 100644
--- a/tests/auto/cmake/qtquickcompiler/main.qml
+++ b/tests/auto/cmake/qtquickcompiler/resources with space/main.qml
@@ -1,4 +1,4 @@
import QtQml 2.0
QtObject {
- property bool success: 42
+ property int success: 42
}
diff --git a/tests/auto/cmake/qtquickcompiler/qqc_test.qrc b/tests/auto/cmake/qtquickcompiler/resources with space/qqc_test.qrc
index f128b7004b..63d8d1f37e 100644
--- a/tests/auto/cmake/qtquickcompiler/qqc_test.qrc
+++ b/tests/auto/cmake/qtquickcompiler/resources with space/qqc_test.qrc
@@ -1,6 +1,6 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file>./main.qml</file>
-<file>./main.cpp</file>
+<file alias="main.cpp">../main.cpp</file>
</qresource>
</RCC>
diff --git a/tests/auto/qml/debugger/qqmldebuggingenabler/qqmldebuggingenabler/tst_qqmldebuggingenabler.cpp b/tests/auto/qml/debugger/qqmldebuggingenabler/qqmldebuggingenabler/tst_qqmldebuggingenabler.cpp
index a76740a3f9..52e7f85e52 100644
--- a/tests/auto/qml/debugger/qqmldebuggingenabler/qqmldebuggingenabler/tst_qqmldebuggingenabler.cpp
+++ b/tests/auto/qml/debugger/qqmldebuggingenabler/qqmldebuggingenabler/tst_qqmldebuggingenabler.cpp
@@ -126,8 +126,10 @@ void tst_QQmlDebuggingEnabler::qmlscene()
}
QCOMPARE(m_process->state(), QLatin1String("running"));
- if (!blockMode)
- QTRY_VERIFY(m_process->output().contains(QLatin1String("qml: Component.onCompleted")));
+ if (!blockMode) {
+ QTRY_VERIFY_WITH_TIMEOUT(m_process->output().contains(
+ QLatin1String("Component.onCompleted")), 15000);
+ }
}
void tst_QQmlDebuggingEnabler::custom_data()
@@ -171,8 +173,10 @@ void tst_QQmlDebuggingEnabler::custom()
}
QCOMPARE(m_process->state(), QLatin1String("running"));
- if (!blockMode)
- QTRY_VERIFY(m_process->output().contains(QLatin1String("QQmlEngine created")));
+ if (!blockMode) {
+ QTRY_VERIFY_WITH_TIMEOUT(m_process->output().contains(QLatin1String("QQmlEngine created")),
+ 15000);
+ }
}
QTEST_MAIN(tst_QQmlDebuggingEnabler)
diff --git a/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp b/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp
index d01d9a6791..89217e7556 100644
--- a/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp
+++ b/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp
@@ -141,6 +141,7 @@ private slots:
void queryObjectWithNonStreamableTypes();
void asynchronousCreate();
void invalidContexts();
+ void createObjectOnDestruction();
};
QmlDebugObjectReference tst_QQmlEngineDebugService::findRootObject(
@@ -1345,6 +1346,29 @@ void tst_QQmlEngineDebugService::invalidContexts()
QCOMPARE(m_dbg->rootContext().contexts.count(), 0);
}
+void tst_QQmlEngineDebugService::createObjectOnDestruction()
+{
+ QSignalSpy spy(m_dbg, SIGNAL(newObject(int)));
+ {
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.setData(
+ "import QtQml 2.0;"
+ "QtObject {"
+ "property Component x:"
+ "Qt.createQmlObject('import QtQml 2.0; Component { QtObject { } }',"
+ "this, 'x.qml');"
+ "Component.onDestruction: x.createObject(this, {});"
+ "}", QUrl::fromLocalFile("x.qml"));
+ QVERIFY(component.isReady());
+ QVERIFY(component.create());
+ QTRY_COMPARE(spy.count(), 2);
+ }
+ // Doesn't crash and doesn't give us another signal for the object created on destruction.
+ QTest::qWait(500);
+ QCOMPARE(spy.count(), 2);
+}
+
int main(int argc, char *argv[])
{
int _argc = argc + 1;
diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp
index cd8e4216f3..562804bc45 100644
--- a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp
+++ b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp
@@ -221,6 +221,7 @@ private slots:
void flushInterval();
void translationBinding();
void memory();
+ void compile();
private:
bool m_recordFromStart = true;
@@ -525,6 +526,8 @@ void tst_QQmlProfilerService::connect()
if (!traceEnabled)
m_client->client->setRecording(true);
+
+ QTRY_VERIFY(m_client->numLoadedEventTypes() > 0);
m_client->client->setRecording(false);
checkTraceReceived();
checkJsHeap();
@@ -643,6 +646,7 @@ void tst_QQmlProfilerService::controlFromJS()
{
QCOMPARE(connect(true, "controlFromJS.qml", false), ConnectSuccess);
+ QTRY_VERIFY(m_client->numLoadedEventTypes() > 0);
m_client->client->setRecording(false);
checkTraceReceived();
checkJsHeap();
@@ -749,6 +753,54 @@ void tst_QQmlProfilerService::memory()
QVERIFY(smallItems > 5);
}
+static bool hasCompileEvents(const QVector<QQmlProfilerEventType> &types)
+{
+ for (const QQmlProfilerEventType &type : types) {
+ if (type.message() == QQmlProfilerDefinitions::MaximumMessage
+ && type.rangeType() == QQmlProfilerDefinitions::Compiling)
+ return true;
+ }
+ return false;
+}
+
+void tst_QQmlProfilerService::compile()
+{
+ // Flush interval so that we actually get the events before we stop recording.
+ connect(true, "test.qml", true, 100);
+
+ // We need to check specifically for compile events as we can otherwise stop recording after the
+ // StartTrace has arrived, but before it compiles anything.
+ QTRY_VERIFY(hasCompileEvents(m_client->types));
+ m_client->client->setRecording(false);
+
+ checkTraceReceived();
+ checkJsHeap();
+
+ QQmlProfilerDefinitions::Message rangeStage = QQmlProfilerDefinitions::MaximumMessage;
+ for (auto message : m_client->qmlMessages) {
+ const QQmlProfilerEventType &type = m_client->types[message.typeIndex()];
+ if (type.rangeType() == QQmlProfilerDefinitions::Compiling) {
+ switch (rangeStage) {
+ case QQmlProfilerDefinitions::MaximumMessage:
+ QCOMPARE(message.rangeStage(), QQmlProfilerDefinitions::RangeStart);
+ break;
+ case QQmlProfilerDefinitions::RangeStart:
+ QCOMPARE(message.rangeStage(), QQmlProfilerDefinitions::RangeEnd);
+ break;
+ default:
+ QFAIL("Wrong range stage");
+ }
+ rangeStage = message.rangeStage();
+ QCOMPARE(type.message(), QQmlProfilerDefinitions::MaximumMessage);
+ QCOMPARE(type.location().filename(), testFileUrl("test.qml").toString());
+ QCOMPARE(type.location().line(), 0);
+ QCOMPARE(type.location().column(), 0);
+ }
+ }
+
+ QCOMPARE(rangeStage, QQmlProfilerDefinitions::RangeEnd);
+}
+
QTEST_MAIN(tst_QQmlProfilerService)
#include "tst_qqmlprofilerservice.moc"
diff --git a/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp b/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp
index 5dd62da15a..4ce0f9fd89 100644
--- a/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp
+++ b/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp
@@ -316,6 +316,8 @@ private slots:
void lastLineOfConditional_data();
void lastLineOfConditional();
+
+ void readThis();
private:
QV4Debugger *debugger() const
{
@@ -865,6 +867,36 @@ void tst_qv4debugger::lastLineOfConditional()
QCOMPARE(secondState.lineNumber, lastLine);
}
+void tst_qv4debugger::readThis()
+{
+ m_debuggerAgent->m_captureContextInfo = true;
+ QString script =
+ "var x = function() {\n"
+ " return this.a;\n"
+ "}.apply({a : 5}, []);\n";
+
+ TestAgent::ExpressionRequest request;
+ request.expression = "this";
+ request.frameNr = 0;
+ request.context = -1; // no extra context
+ m_debuggerAgent->m_expressionRequests << request;
+
+ debugger()->addBreakPoint("applyThis", 2);
+ evaluateJavaScript(script, "applyThis");
+ QVERIFY(m_debuggerAgent->m_wasPaused);
+
+ QCOMPARE(m_debuggerAgent->m_expressionResults.count(), 1);
+ QJsonObject result0 = m_debuggerAgent->m_expressionResults[0];
+ QCOMPARE(result0.value("type").toString(), QStringLiteral("object"));
+ QCOMPARE(result0.value("value").toInt(), 1);
+ QJsonArray properties = result0.value("properties").toArray();
+ QCOMPARE(properties.size(), 1);
+ QJsonObject a = properties.first().toObject();
+ QCOMPARE(a.value("name").toString(), QStringLiteral("a"));
+ QCOMPARE(a.value("type").toString(), QStringLiteral("number"));
+ QCOMPARE(a.value("value").toInt(), 5);
+}
+
void tst_qv4debugger::redundancy_data()
{
QTest::addColumn<bool>("redundantRefs");
diff --git a/tests/auto/qml/ecmascripttests/test262 b/tests/auto/qml/ecmascripttests/test262
-Subproject d60c4ed97e69639bc5bc1db43a98828debf80c8
+Subproject 40b4f28e98c416a092e26aa17489bf94ccb8bf4
diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
index 8f3011001b..f862cdb048 100644
--- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp
+++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
@@ -128,6 +128,8 @@ private slots:
void JSONparse();
void arraySort();
void lookupOnDisappearingProperty();
+ void arrayConcat();
+ void recursiveBoundFunctions();
void qRegExpInport_data();
void qRegExpInport();
@@ -2995,7 +2997,7 @@ void tst_QJSEngine::arraySort()
void tst_QJSEngine::lookupOnDisappearingProperty()
{
QJSEngine eng;
- QJSValue func = eng.evaluate("(function(){\"use strict\"; return eval(\"function(obj) { return obj.someProperty; }\")})()");
+ QJSValue func = eng.evaluate("(function(){\"use strict\"; return eval(\"(function(obj) { return obj.someProperty; })\")})()");
QVERIFY(func.isCallable());
QJSValue o = eng.newObject();
@@ -3008,6 +3010,31 @@ void tst_QJSEngine::lookupOnDisappearingProperty()
QVERIFY(func.call(QJSValueList()<< o).isUndefined());
}
+void tst_QJSEngine::arrayConcat()
+{
+ QJSEngine eng;
+ QJSValue v = eng.evaluate("var x = [1, 2, 3, 4, 5, 6];"
+ "var y = [];"
+ "for (var i = 0; i < 5; ++i)"
+ " x.shift();"
+ "for (var i = 10; i < 13; ++i)"
+ " x.push(i);"
+ "x.toString();");
+ QCOMPARE(v.toString(), QString::fromLatin1("6,10,11,12"));
+}
+
+void tst_QJSEngine::recursiveBoundFunctions()
+{
+
+ QJSEngine eng;
+ QJSValue v = eng.evaluate("function foo(x, y, z)"
+ "{ return this + x + y + z; }"
+ "var bar = foo.bind(-1, 10);"
+ "var baz = bar.bind(-2, 20);"
+ "baz(30)");
+ QCOMPARE(v.toInt(), 59);
+}
+
static QRegExp minimal(QRegExp r) { r.setMinimal(true); return r; }
void tst_QJSEngine::qRegExpInport_data()
@@ -3327,7 +3354,7 @@ void tst_QJSEngine::prototypeChainGc()
QJSValue getProto = engine.evaluate("Object.getPrototypeOf");
- QJSValue factory = engine.evaluate("function() { return Object.create(Object.create({})); }");
+ QJSValue factory = engine.evaluate("(function() { return Object.create(Object.create({})); })");
QVERIFY(factory.isCallable());
QJSValue obj = factory.call();
engine.collectGarbage();
diff --git a/tests/auto/qml/qml.pro b/tests/auto/qml/qml.pro
index 9557393a2e..3433b56864 100644
--- a/tests/auto/qml/qml.pro
+++ b/tests/auto/qml/qml.pro
@@ -69,6 +69,7 @@ PRIVATETESTS += \
qqmltranslation \
qqmlimport \
qqmlobjectmodel \
+ qv4assembler \
qv4mm \
ecmascripttests \
bindingdependencyapi
diff --git a/tests/auto/qml/qmlcachegen/qmlcachegen.pro b/tests/auto/qml/qmlcachegen/qmlcachegen.pro
index a8b72224ba..a2f963e8c3 100644
--- a/tests/auto/qml/qmlcachegen/qmlcachegen.pro
+++ b/tests/auto/qml/qmlcachegen/qmlcachegen.pro
@@ -8,4 +8,8 @@ workerscripts_test.files = worker.js worker.qml
workerscripts_test.prefix = /workerscripts
RESOURCES += workerscripts_test
+RESOURCES += versionchecks.qml
+
+RESOURCES += trickypaths.qrc
+
QT += core-private qml-private testlib
diff --git a/tests/auto/qml/qmlcachegen/trickypaths.qml b/tests/auto/qml/qmlcachegen/trickypaths.qml
new file mode 100644
index 0000000000..0836808dc2
--- /dev/null
+++ b/tests/auto/qml/qmlcachegen/trickypaths.qml
@@ -0,0 +1,4 @@
+import QtQml 2.0
+QtObject {
+ property int success: 42
+}
diff --git a/tests/auto/qml/qmlcachegen/trickypaths.qrc b/tests/auto/qml/qmlcachegen/trickypaths.qrc
new file mode 100644
index 0000000000..271cf6571e
--- /dev/null
+++ b/tests/auto/qml/qmlcachegen/trickypaths.qrc
@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="/directory with spaces">
+<file alias="file name with spaces.qml">trickypaths.qml</file>
+</qresource>
+</RCC>
diff --git a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp
index 2f5ff0022e..5c1692f086 100644
--- a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp
+++ b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp
@@ -33,6 +33,7 @@
#include <QProcess>
#include <QLibraryInfo>
#include <QSysInfo>
+#include <QLoggingCategory>
#include <private/qqmlcomponent_p.h>
class tst_qmlcachegen: public QObject
@@ -47,8 +48,12 @@ private slots:
void signalHandlerParameters();
void errorOnArgumentsInSignalHandler();
void aheadOfTimeCompilation();
+ void functionExpressions();
+ void versionChecksForAheadOfTimeUnits();
void workerScripts();
+
+ void trickyPaths();
};
// A wrapper around QQmlComponent to ensure the temporary reference counts
@@ -279,6 +284,50 @@ void tst_qmlcachegen::aheadOfTimeCompilation()
QCOMPARE(result.toInt(), 42);
}
+static QQmlPrivate::CachedQmlUnit *temporaryModifiedCachedUnit = nullptr;
+
+void tst_qmlcachegen::versionChecksForAheadOfTimeUnits()
+{
+ QVERIFY(QFile::exists(":/versionchecks.qml"));
+ QCOMPARE(QFileInfo(":/versionchecks.qml").size(), 0);
+
+ Q_ASSERT(!temporaryModifiedCachedUnit);
+ QQmlMetaType::CachedUnitLookupError error = QQmlMetaType::CachedUnitLookupError::NoError;
+ const QV4::CompiledData::Unit *originalUnit = QQmlMetaType::findCachedCompilationUnit(QUrl("qrc:/versionchecks.qml"), &error);
+ QVERIFY(originalUnit);
+ QV4::CompiledData::Unit *tweakedUnit = (QV4::CompiledData::Unit *)malloc(originalUnit->unitSize);
+ memcpy(reinterpret_cast<void *>(tweakedUnit), reinterpret_cast<const void *>(originalUnit), originalUnit->unitSize);
+ tweakedUnit->version = QV4_DATA_STRUCTURE_VERSION - 1;
+ temporaryModifiedCachedUnit = new QQmlPrivate::CachedQmlUnit{tweakedUnit, nullptr, nullptr};
+
+ auto testHandler = [](const QUrl &url) -> const QQmlPrivate::CachedQmlUnit * {
+ if (url == QUrl("qrc:/versionchecks.qml"))
+ return temporaryModifiedCachedUnit;
+ return nullptr;
+ };
+ QQmlMetaType::prependCachedUnitLookupFunction(testHandler);
+
+ {
+ QQmlMetaType::CachedUnitLookupError error = QQmlMetaType::CachedUnitLookupError::NoError;
+ QVERIFY(!QQmlMetaType::findCachedCompilationUnit(QUrl("qrc:/versionchecks.qml"), &error));
+ QCOMPARE(error, QQmlMetaType::CachedUnitLookupError::VersionMismatch);
+ }
+
+ {
+ QQmlEngine engine;
+ QQmlComponent component(&engine, QUrl("qrc:/versionchecks.qml"));
+ QCOMPARE(component.status(), QQmlComponent::Error);
+ QCOMPARE(component.errorString(), QString("qrc:/versionchecks.qml:-1 File was compiled ahead of time with an incompatible version of Qt and the original file cannot be found. Please recompile\n"));
+ }
+
+ Q_ASSERT(temporaryModifiedCachedUnit);
+ free(const_cast<QV4::CompiledData::Unit *>(temporaryModifiedCachedUnit->qmlData));
+ delete temporaryModifiedCachedUnit;
+ temporaryModifiedCachedUnit = nullptr;
+
+ QQmlMetaType::removeCachedUnitLookupFunction(testHandler);
+}
+
void tst_qmlcachegen::workerScripts()
{
QVERIFY(QFile::exists(":/workerscripts/worker.js"));
@@ -292,6 +341,81 @@ void tst_qmlcachegen::workerScripts()
QTRY_VERIFY(obj->property("success").toBool());
}
+void tst_qmlcachegen::functionExpressions()
+{
+ QTemporaryDir tempDir;
+ QVERIFY(tempDir.isValid());
+
+ const auto writeTempFile = [&tempDir](const QString &fileName, const char *contents) {
+ QFile f(tempDir.path() + '/' + fileName);
+ const bool ok = f.open(QIODevice::WriteOnly | QIODevice::Truncate);
+ Q_ASSERT(ok);
+ f.write(contents);
+ return f.fileName();
+ };
+
+ const QString testFilePath = writeTempFile(
+ "test.qml",
+ "import QtQuick 2.0\n"
+ "Item {\n"
+ " id: di\n"
+ " \n"
+ " property var f\n"
+ " property bool f_called: false\n"
+ " f : function() { f_called = true }\n"
+ " \n"
+ " signal g\n"
+ " property bool g_handler_called: false\n"
+ " onG: function() { g_handler_called = true }\n"
+ " \n"
+ " signal h(int i)\n"
+ " property bool h_connections_handler_called: false\n"
+ " Connections {\n"
+ " target: di\n"
+ " onH: function(magic) { h_connections_handler_called = (magic == 42)\n }\n"
+ " }\n"
+ " \n"
+ " function runTest() { \n"
+ " f()\n"
+ " g()\n"
+ " h(42)\n"
+ " }\n"
+ "}");
+
+ QVERIFY(generateCache(testFilePath));
+
+ const QString cacheFilePath = testFilePath + QLatin1Char('c');
+ QVERIFY(QFile::exists(cacheFilePath));
+ QVERIFY(QFile::remove(testFilePath));
+
+ QQmlEngine engine;
+ CleanlyLoadingComponent component(&engine, QUrl::fromLocalFile(testFilePath));
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+
+ QCOMPARE(obj->property("f_called").toBool(), false);
+ QCOMPARE(obj->property("g_handler_called").toBool(), false);
+ QCOMPARE(obj->property("h_connections_handler_called").toBool(), false);
+
+ QMetaObject::invokeMethod(obj.data(), "runTest");
+
+ QCOMPARE(obj->property("f_called").toBool(), true);
+ QCOMPARE(obj->property("g_handler_called").toBool(), true);
+ QCOMPARE(obj->property("h_connections_handler_called").toBool(), true);
+}
+
+void tst_qmlcachegen::trickyPaths()
+{
+ QString pathWithSpaces(QStringLiteral(":/directory with spaces/file name with spaces.qml"));
+ QVERIFY2(QFile::exists(pathWithSpaces), qPrintable(pathWithSpaces));
+ QCOMPARE(QFileInfo(pathWithSpaces).size(), 0);
+ QQmlEngine engine;
+ QQmlComponent component(&engine, QUrl("qrc" + pathWithSpaces));
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+ QCOMPARE(obj->property("success").toInt(), 42);
+}
+
QTEST_GUILESS_MAIN(tst_qmlcachegen)
#include "tst_qmlcachegen.moc"
diff --git a/tests/auto/qml/qmlcachegen/versionchecks.qml b/tests/auto/qml/qmlcachegen/versionchecks.qml
new file mode 100644
index 0000000000..77d67e7da4
--- /dev/null
+++ b/tests/auto/qml/qmlcachegen/versionchecks.qml
@@ -0,0 +1,4 @@
+import QtQml 2.0
+QtObject {
+ property bool ok: true
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/bindingBoundFunctions.qml b/tests/auto/qml/qqmlecmascript/data/bindingBoundFunctions.qml
new file mode 100644
index 0000000000..8dbd2fd3d9
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/bindingBoundFunctions.qml
@@ -0,0 +1,34 @@
+import QtQuick 2.6
+
+QtObject {
+ property bool success: false
+ property var num: 100
+ property var simple: 0
+ property var complex: 0
+
+
+ Component.onCompleted: {
+ function s(x) {
+ return x
+ }
+ function c(x) {
+ return x + num
+ }
+
+ var bound = s.bind(undefined, 100)
+ simple = Qt.binding(bound)
+ if (simple != 100)
+ return;
+ var bound = c.bind(undefined, 100)
+ complex = Qt.binding(bound);
+
+ if (complex != 200)
+ return;
+ num = 0;
+ if (complex != 100)
+ return;
+
+ print("success!!!");
+ success = true;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/include_callback.js b/tests/auto/qml/qqmlecmascript/data/include_callback.js
index ea19eba300..7f3195bb1f 100644
--- a/tests/auto/qml/qqmlecmascript/data/include_callback.js
+++ b/tests/auto/qml/qqmlecmascript/data/include_callback.js
@@ -1,6 +1,6 @@
function go() {
var a = Qt.include("missing.js", function(o) { test2 = o.status == o.NETWORK_ERROR });
- test1 = a.status == a.NETWORK_ERROR
+ test1 = (a.status == a.NETWORK_ERROR) && (a.statusText.indexOf("Error opening source file") != -1);
var b = Qt.include("blank.js", function(o) { test4 = o.status == o.OK });
test3 = b.status == b.OK
diff --git a/tests/auto/qml/qqmlecmascript/data/sequenceConversion.array.qml b/tests/auto/qml/qqmlecmascript/data/sequenceConversion.array.qml
index 5103168fd3..99c49ebf62 100644
--- a/tests/auto/qml/qqmlecmascript/data/sequenceConversion.array.qml
+++ b/tests/auto/qml/qqmlecmascript/data/sequenceConversion.array.qml
@@ -10,6 +10,11 @@ Item {
objectName: "msco"
}
+ Component {
+ id: mscoComponent
+ MySequenceConversionObject { }
+ }
+
property bool success: false
property variant intList
@@ -252,4 +257,13 @@ Item {
if (testSequence.valueOf() == prevValueOf) referenceDeletion = false;
if (testSequence.length == prevLength) referenceDeletion = false;
}
+
+ function jsonConversion() {
+ success = true
+ var msco = mscoComponent.createObject()
+ if (JSON.stringify(msco.intListProperty) != "[1,2,3,4]") success = false;
+ if (JSON.stringify(msco.qrealListProperty) != "[1.1,2.2,3.3,4.4]") success = false;
+ if (JSON.stringify(msco.boolListProperty) != "[true,false,true,false]") success = false;
+ if (JSON.stringify(msco.stringListProperty) != "[\"first\",\"second\",\"third\",\"fourth\"]") success = false;
+ }
}
diff --git a/tests/auto/qml/qqmlecmascript/data/signalHandlers.qml b/tests/auto/qml/qqmlecmascript/data/signalHandlers.qml
index cd68fb9b82..14326bb9e6 100644
--- a/tests/auto/qml/qqmlecmascript/data/signalHandlers.qml
+++ b/tests/auto/qml/qqmlecmascript/data/signalHandlers.qml
@@ -102,4 +102,17 @@ QtObject {
})
return testSuccess
}
+
+ property QtObject subObject: QtObject {
+ id: subObject
+ property int value
+ property bool ok: false
+ onValueChanged: this.ok = true
+ }
+
+ function testThisInSignalHandler() {
+ subObject.ok = false
+ subObject.value = subObject.value + 1
+ return subObject.ok
+ }
}
diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
index 5ff959515e..f40a9758f7 100644
--- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
+++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
@@ -289,6 +289,7 @@ private slots:
void withStatement();
void tryStatement();
void replaceBinding();
+ void bindingBoundFunctions();
void deleteRootObjectInCreation();
void onDestruction();
void onDestructionViaGC();
@@ -351,6 +352,7 @@ private slots:
void shadowedFunctionName();
void anotherNaN();
void callPropertyOnUndefined();
+ void jumpStrictNotEqualUndefined();
private:
// static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
@@ -5561,17 +5563,18 @@ void tst_qqmlecmascript::sequenceConversionArray()
// ensure that in JS the returned sequences act just like normal JS Arrays.
QUrl qmlFile = testFileUrl("sequenceConversion.array.qml");
QQmlComponent component(&engine, qmlFile);
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
- QMetaObject::invokeMethod(object, "indexedAccess");
+ QMetaObject::invokeMethod(object.data(), "indexedAccess");
QVERIFY(object->property("success").toBool());
- QMetaObject::invokeMethod(object, "arrayOperations");
+ QMetaObject::invokeMethod(object.data(), "arrayOperations");
QVERIFY(object->property("success").toBool());
- QMetaObject::invokeMethod(object, "testEqualitySemantics");
+ QMetaObject::invokeMethod(object.data(), "testEqualitySemantics");
QVERIFY(object->property("success").toBool());
- QMetaObject::invokeMethod(object, "testReferenceDeletion");
+ QMetaObject::invokeMethod(object.data(), "testReferenceDeletion");
QCOMPARE(object->property("referenceDeletion").toBool(), true);
- delete object;
+ QMetaObject::invokeMethod(object.data(), "jsonConversion");
+ QVERIFY(object->property("success").toBool());
}
@@ -6278,41 +6281,40 @@ void tst_qqmlecmascript::includeRemoteSuccess()
void tst_qqmlecmascript::signalHandlers()
{
QQmlComponent component(&engine, testFileUrl("signalHandlers.qml"));
- QObject *o = component.create();
+ QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
-
QCOMPARE(o->property("count").toInt(), 0);
- QMetaObject::invokeMethod(o, "testSignalCall");
+ QMetaObject::invokeMethod(o.data(), "testSignalCall");
QCOMPARE(o->property("count").toInt(), 1);
- QMetaObject::invokeMethod(o, "testSignalHandlerCall");
+ QMetaObject::invokeMethod(o.data(), "testSignalHandlerCall");
QCOMPARE(o->property("count").toInt(), 1);
QCOMPARE(o->property("errorString").toString(), QLatin1String("TypeError: Property 'onTestSignal' of object [object Object] is not a function"));
QCOMPARE(o->property("funcCount").toInt(), 0);
- QMetaObject::invokeMethod(o, "testSignalConnection");
+ QMetaObject::invokeMethod(o.data(), "testSignalConnection");
QCOMPARE(o->property("funcCount").toInt(), 1);
- QMetaObject::invokeMethod(o, "testSignalHandlerConnection");
+ QMetaObject::invokeMethod(o.data(), "testSignalHandlerConnection");
QCOMPARE(o->property("funcCount").toInt(), 2);
- QMetaObject::invokeMethod(o, "testSignalDefined");
+ QMetaObject::invokeMethod(o.data(), "testSignalDefined");
QCOMPARE(o->property("definedResult").toBool(), true);
- QMetaObject::invokeMethod(o, "testSignalHandlerDefined");
+ QMetaObject::invokeMethod(o.data(), "testSignalHandlerDefined");
QCOMPARE(o->property("definedHandlerResult").toBool(), true);
QVariant result;
- QMetaObject::invokeMethod(o, "testConnectionOnAlias", Q_RETURN_ARG(QVariant, result));
+ QMetaObject::invokeMethod(o.data(), "testConnectionOnAlias", Q_RETURN_ARG(QVariant, result));
QCOMPARE(result.toBool(), true);
- QMetaObject::invokeMethod(o, "testAliasSignalHandler", Q_RETURN_ARG(QVariant, result));
+ QMetaObject::invokeMethod(o.data(), "testAliasSignalHandler", Q_RETURN_ARG(QVariant, result));
QCOMPARE(result.toBool(), true);
- QMetaObject::invokeMethod(o, "testSignalWithClosureArgument", Q_RETURN_ARG(QVariant, result));
+ QMetaObject::invokeMethod(o.data(), "testSignalWithClosureArgument", Q_RETURN_ARG(QVariant, result));
+ QCOMPARE(result.toBool(), true);
+ QMetaObject::invokeMethod(o.data(), "testThisInSignalHandler", Q_RETURN_ARG(QVariant, result));
QCOMPARE(result.toBool(), true);
-
- delete o;
}
void tst_qqmlecmascript::qtbug_37351()
@@ -7246,6 +7248,17 @@ void tst_qqmlecmascript::replaceBinding()
delete obj;
}
+void tst_qqmlecmascript::bindingBoundFunctions()
+{
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("bindingBoundFunctions.qml"));
+ QObject *obj = c.create();
+ QVERIFY(obj != nullptr);
+
+ QVERIFY(obj->property("success").toBool());
+ delete obj;
+}
+
void tst_qqmlecmascript::deleteRootObjectInCreation()
{
{
@@ -8480,6 +8493,26 @@ void tst_qqmlecmascript::callPropertyOnUndefined()
QVERIFY(!v.isError()); // well, more importantly: this shouldn't fail on an assert.
}
+void tst_qqmlecmascript::jumpStrictNotEqualUndefined()
+{
+ QJSEngine engine;
+ QJSValue v = engine.evaluate(QString::fromLatin1(
+ "var ok = 0\n"
+ "var foo = 0\n"
+ "if (foo !== void 1)\n"
+ " ++ok;\n"
+ "else\n"
+ " --ok;\n"
+ "if (foo === void 1)\n"
+ " --ok;\n"
+ "else\n"
+ " ++ok;\n"
+ "ok\n"
+ ));
+ QVERIFY(!v.isError());
+ QCOMPARE(v.toInt(), 2);
+}
+
QTEST_MAIN(tst_qqmlecmascript)
#include "tst_qqmlecmascript.moc"
diff --git a/tests/auto/qml/qqmlexpression/tst_qqmlexpression.cpp b/tests/auto/qml/qqmlexpression/tst_qqmlexpression.cpp
index e1ad1e8c5f..1decc04ad2 100644
--- a/tests/auto/qml/qqmlexpression/tst_qqmlexpression.cpp
+++ b/tests/auto/qml/qqmlexpression/tst_qqmlexpression.cpp
@@ -101,8 +101,12 @@ void tst_qqmlexpression::syntaxError()
{
QQmlEngine engine;
QQmlExpression expression(engine.rootContext(), nullptr, "asd asd");
- QVariant v = expression.evaluate();
+ bool isUndefined = false;
+ QVariant v = expression.evaluate(&isUndefined);
QCOMPARE(v, QVariant());
+ QVERIFY(expression.hasError());
+ QCOMPARE(expression.error().description(), "SyntaxError: Expected token `;'");
+ QVERIFY(isUndefined);
}
void tst_qqmlexpression::exception()
diff --git a/tests/auto/qml/qqmllanguage/data/alias.16.qml b/tests/auto/qml/qqmllanguage/data/alias.16.qml
new file mode 100644
index 0000000000..4637aec58f
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/alias.16.qml
@@ -0,0 +1,15 @@
+import QtQuick 2.0
+import QtQuick.Window 2.0
+
+Window {
+ visible: true
+
+ property alias list: repeater.model
+
+ list: ["A", "B", "C"]
+
+ Repeater {
+ id: repeater
+ }
+}
+
diff --git a/tests/auto/qml/qqmllanguage/data/assignLiteralToJSValue.qml b/tests/auto/qml/qqmllanguage/data/assignLiteralToJSValue.qml
index fce248a381..69b0096a5e 100644
--- a/tests/auto/qml/qqmllanguage/data/assignLiteralToJSValue.qml
+++ b/tests/auto/qml/qqmllanguage/data/assignLiteralToJSValue.qml
@@ -30,6 +30,7 @@ QtObject {
MyQmlObject { id: testObj22; objectName: "test22"; qjsvalue: null },
MyQmlObject { id: testObj1Bound; objectName: "test1Bound"; qjsvalue: testObj1.qjsvalue + 4 }, // 1 + 4 + 4 = 9
MyQmlObject { id: testObj20Bound; objectName: "test20Bound"; qjsvalue: testObj20.qjsvalue(testObj1Bound.qjsvalue) }, // 9 * 3 = 27
+ MyQmlObject { id: testObj23; objectName: "test23"; qjsvalue: QtObject { objectName: "blah" } },
QtObject {
id: varProperties
objectName: "varProperties"
diff --git a/tests/auto/qml/qqmllanguage/data/empty.errors.txt b/tests/auto/qml/qqmllanguage/data/empty.errors.txt
index 620db2bbba..ba685d78ae 100644
--- a/tests/auto/qml/qqmllanguage/data/empty.errors.txt
+++ b/tests/auto/qml/qqmllanguage/data/empty.errors.txt
@@ -1,2 +1 @@
-1:1:Expected token `numeric literal'
-1:1:Expected a qualified name id
+-1:-1:File is empty
diff --git a/tests/auto/qml/qqmllanguage/data/lib/org/qtproject/MixedModule/SingletonType.qml b/tests/auto/qml/qqmllanguage/data/lib/org/qtproject/MixedModule/SingletonType.qml
index 7763c783f1..2913ceca08 100644
--- a/tests/auto/qml/qqmllanguage/data/lib/org/qtproject/MixedModule/SingletonType.qml
+++ b/tests/auto/qml/qqmllanguage/data/lib/org/qtproject/MixedModule/SingletonType.qml
@@ -2,4 +2,7 @@ import QtQuick 2.0
pragma Singleton
Item {
+ enum EnumInSingleton {
+ EnumValue = 42
+ }
}
diff --git a/tests/auto/qml/qqmllanguage/data/noDoubleEvaluationForFlushedBindings.2.qml b/tests/auto/qml/qqmllanguage/data/noDoubleEvaluationForFlushedBindings.2.qml
new file mode 100644
index 0000000000..ff2f0f5a2c
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/noDoubleEvaluationForFlushedBindings.2.qml
@@ -0,0 +1,9 @@
+import QtQml 2.0
+
+QtObject {
+ property int secondVar: {
+ stats.increaseEvaluationCounter()
+ return 1
+ }
+ property int firstVar: secondVar + 1
+}
diff --git a/tests/auto/qml/qqmllanguage/data/noDoubleEvaluationForFlushedBindings.qml b/tests/auto/qml/qqmllanguage/data/noDoubleEvaluationForFlushedBindings.qml
new file mode 100644
index 0000000000..0eb5e03642
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/noDoubleEvaluationForFlushedBindings.qml
@@ -0,0 +1,9 @@
+import QtQml 2.0
+
+QtObject {
+ property int firstVar: secondVar + 1
+ property int secondVar: {
+ stats.increaseEvaluationCounter()
+ return 1
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/usingTypeWithEnum.qml b/tests/auto/qml/qqmllanguage/data/usingTypeWithEnum.qml
index 2509fc0df1..43e54bbf1d 100644
--- a/tests/auto/qml/qqmllanguage/data/usingTypeWithEnum.qml
+++ b/tests/auto/qml/qqmllanguage/data/usingTypeWithEnum.qml
@@ -1,8 +1,10 @@
import QtQuick 2.0
+import org.qtproject.MixedModule 1.0
QtObject {
property int enumValue: TypeWithEnum.EnumValue2
property int enumValue2: -1
property int scopedEnumValue: TypeWithEnum.MyEnum.EnumValue3
+ property int enumValueFromSingleton: { var x = SingletonType.EnumValue; return x; }
Component.onCompleted: enumValue2 = TypeWithEnum.EnumValue1
}
diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
index 5bb2b69565..8913528d79 100644
--- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
+++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
@@ -125,6 +125,8 @@ private slots:
void dynamicObjectProperties();
void dynamicSignalsAndSlots();
void simpleBindings();
+ void noDoubleEvaluationForFlushedBindings_data();
+ void noDoubleEvaluationForFlushedBindings();
void autoComponentCreation();
void autoComponentCreationInGroupProperty();
void propertyValueSource();
@@ -372,9 +374,11 @@ void tst_qqmllanguage::insertedSemicolon()
QQmlComponent component(&engine, testFileUrl(file));
+ QScopedPointer<QObject> object;
+
if(create) {
- QObject *object = component.create();
- QVERIFY(!object);
+ object.reset(component.create());
+ QVERIFY(object.isNull());
}
VERIFY_ERRORS(errorFile.toLatin1().constData());
@@ -606,9 +610,11 @@ void tst_qqmllanguage::errors()
QQmlComponent component(&engine, testFileUrl(file));
+ QScopedPointer<QObject> object;
+
if (create) {
- QObject *object = component.create();
- QVERIFY(!object);
+ object.reset(component.create());
+ QVERIFY(object.isNull());
}
VERIFY_ERRORS(errorFile.toLatin1().constData());
@@ -618,7 +624,7 @@ void tst_qqmllanguage::simpleObject()
{
QQmlComponent component(&engine, testFileUrl("simpleObject.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
}
@@ -626,7 +632,7 @@ void tst_qqmllanguage::simpleContainer()
{
QQmlComponent component(&engine, testFileUrl("simpleContainer.qml"));
VERIFY_ERRORS(0);
- MyContainer *container= qobject_cast<MyContainer*>(component.create());
+ QScopedPointer<MyContainer> container(qobject_cast<MyContainer*>(component.create()));
QVERIFY(container != nullptr);
QCOMPARE(container->getChildren()->count(),2);
}
@@ -635,7 +641,7 @@ void tst_qqmllanguage::interfaceProperty()
{
QQmlComponent component(&engine, testFileUrl("interfaceProperty.qml"));
VERIFY_ERRORS(0);
- MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
+ QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject*>(component.create()));
QVERIFY(object != nullptr);
QVERIFY(object->interface());
QCOMPARE(object->interface()->id, 913);
@@ -645,7 +651,7 @@ void tst_qqmllanguage::interfaceQList()
{
QQmlComponent component(&engine, testFileUrl("interfaceQList.qml"));
VERIFY_ERRORS(0);
- MyContainer *container= qobject_cast<MyContainer*>(component.create());
+ QScopedPointer<MyContainer> container(qobject_cast<MyContainer*>(component.create()));
QVERIFY(container != nullptr);
QCOMPARE(container->getQListInterfaces()->count(), 2);
for(int ii = 0; ii < 2; ++ii)
@@ -656,7 +662,7 @@ void tst_qqmllanguage::assignObjectToSignal()
{
QQmlComponent component(&engine, testFileUrl("assignObjectToSignal.qml"));
VERIFY_ERRORS(0);
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
QVERIFY(object != nullptr);
QTest::ignoreMessage(QtWarningMsg, "MyQmlObject::basicSlot");
emit object->basicSignal();
@@ -666,7 +672,7 @@ void tst_qqmllanguage::assignObjectToVariant()
{
QQmlComponent component(&engine, testFileUrl("assignObjectToVariant.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
QVariant v = object->property("a");
QVERIFY(v.userType() == qMetaTypeId<QObject *>());
@@ -676,7 +682,7 @@ void tst_qqmllanguage::assignLiteralSignalProperty()
{
QQmlComponent component(&engine, testFileUrl("assignLiteralSignalProperty.qml"));
VERIFY_ERRORS(0);
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
QVERIFY(object != nullptr);
QCOMPARE(object->onLiteralSignal(), 10);
}
@@ -686,7 +692,7 @@ void tst_qqmllanguage::assignQmlComponent()
{
QQmlComponent component(&engine, testFileUrl("assignQmlComponent.qml"));
VERIFY_ERRORS(0);
- MyContainer *object = qobject_cast<MyContainer *>(component.create());
+ QScopedPointer<MyContainer> object(qobject_cast<MyContainer *>(component.create()));
QVERIFY(object != nullptr);
QCOMPARE(object->getChildren()->count(), 1);
QObject *child = object->getChildren()->at(0);
@@ -699,7 +705,7 @@ void tst_qqmllanguage::assignBasicTypes()
{
QQmlComponent component(&engine, testFileUrl("assignBasicTypes.qml"));
VERIFY_ERRORS(0);
- MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
+ QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject *>(component.create()));
QVERIFY(object != nullptr);
QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
@@ -744,7 +750,7 @@ void tst_qqmllanguage::assignTypeExtremes()
{
QQmlComponent component(&engine, testFileUrl("assignTypeExtremes.qml"));
VERIFY_ERRORS(0);
- MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
+ QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject *>(component.create()));
QVERIFY(object != nullptr);
QCOMPARE(object->uintProperty(), 0xEE6B2800);
QCOMPARE(object->intProperty(), -0x77359400);
@@ -755,7 +761,7 @@ void tst_qqmllanguage::assignCompositeToType()
{
QQmlComponent component(&engine, testFileUrl("assignCompositeToType.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
}
@@ -764,7 +770,7 @@ void tst_qqmllanguage::assignLiteralToVariant()
{
QQmlComponent component(&engine, testFileUrl("assignLiteralToVariant.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
QVERIFY(isJSNumberType(object->property("test1").userType()));
@@ -792,8 +798,6 @@ void tst_qqmllanguage::assignLiteralToVariant()
QCOMPARE(object->property("test10"), QVariant(bool(true)));
QCOMPARE(object->property("test11"), QVariant(bool(false)));
QVERIFY(object->property("test12") == QVariant(QVector4D(100, 100, 100, 100)));
-
- delete object;
}
// Test that literals are stored correctly in "var" properties
@@ -803,7 +807,7 @@ void tst_qqmllanguage::assignLiteralToVar()
{
QQmlComponent component(&engine, testFileUrl("assignLiteralToVar.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
QVERIFY(isJSNumberType(object->property("test1").userType()));
@@ -843,15 +847,13 @@ void tst_qqmllanguage::assignLiteralToVar()
QCOMPARE(object->property("test16"), QVariant(QVector3D(100, 100, 100)));
QCOMPARE(object->property("variantTest1Bound"), QVariant(9));
QCOMPARE(object->property("test1Bound"), QVariant(11));
-
- delete object;
}
void tst_qqmllanguage::assignLiteralToJSValue()
{
QQmlComponent component(&engine, testFileUrl("assignLiteralToJSValue.qml"));
VERIFY_ERRORS(0);
- QObject *root = component.create();
+ QScopedPointer<QObject> root(component.create());
QVERIFY(root != nullptr);
{
@@ -932,6 +934,11 @@ void tst_qqmllanguage::assignLiteralToJSValue()
QJSValue value = object->qjsvalue();
QVERIFY(value.isNumber());
QCOMPARE(value.toNumber(), qreal(27));
+ } {
+ MyQmlObject *object = root->findChild<MyQmlObject *>("test23");
+ QJSValue value = object->qjsvalue();
+ QVERIFY(value.isQObject());
+ QCOMPARE(value.toQObject()->objectName(), "blah");
}
}
@@ -939,11 +946,11 @@ void tst_qqmllanguage::assignNullStrings()
{
QQmlComponent component(&engine, testFileUrl("assignNullStrings.qml"));
VERIFY_ERRORS(0);
- MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
+ QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject *>(component.create()));
QVERIFY(object != nullptr);
QVERIFY(object->stringProperty().isNull());
QVERIFY(object->byteArrayProperty().isNull());
- QMetaObject::invokeMethod(object, "assignNullStringsFromJs", Qt::DirectConnection);
+ QMetaObject::invokeMethod(object.data(), "assignNullStringsFromJs", Qt::DirectConnection);
QVERIFY(object->stringProperty().isNull());
QVERIFY(object->byteArrayProperty().isNull());
}
@@ -953,7 +960,7 @@ void tst_qqmllanguage::bindJSValueToVar()
QQmlComponent component(&engine, testFileUrl("assignLiteralToJSValue.qml"));
VERIFY_ERRORS(0);
- QObject *root = component.create();
+ QScopedPointer<QObject> root(component.create());
QVERIFY(root != nullptr);
QObject *object = root->findChild<QObject *>("varProperties");
@@ -1002,7 +1009,7 @@ void tst_qqmllanguage::bindJSValueToVariant()
QQmlComponent component(&engine, testFileUrl("assignLiteralToJSValue.qml"));
VERIFY_ERRORS(0);
- QObject *root = component.create();
+ QScopedPointer<QObject> root(component.create());
QVERIFY(root != nullptr);
QObject *object = root->findChild<QObject *>("variantProperties");
@@ -1051,7 +1058,7 @@ void tst_qqmllanguage::bindJSValueToType()
QQmlComponent component(&engine, testFileUrl("assignLiteralToJSValue.qml"));
VERIFY_ERRORS(0);
- QObject *root = component.create();
+ QScopedPointer<QObject> root(component.create());
QVERIFY(root != nullptr);
{
@@ -1086,7 +1093,7 @@ void tst_qqmllanguage::bindTypeToJSValue()
QQmlComponent component(&engine, testFileUrl("bindTypeToJSValue.qml"));
VERIFY_ERRORS(0);
- QObject *root = component.create();
+ QScopedPointer<QObject> root(component.create());
QVERIFY(root != nullptr);
{
@@ -1225,7 +1232,7 @@ void tst_qqmllanguage::customParserTypes()
{
QQmlComponent component(&engine, testFileUrl("customParserTypes.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
QCOMPARE(object->property("count"), QVariant(2));
}
@@ -1235,7 +1242,7 @@ void tst_qqmllanguage::rootAsQmlComponent()
{
QQmlComponent component(&engine, testFileUrl("rootAsQmlComponent.qml"));
VERIFY_ERRORS(0);
- MyContainer *object = qobject_cast<MyContainer *>(component.create());
+ QScopedPointer<MyContainer> object(qobject_cast<MyContainer *>(component.create()));
QVERIFY(object != nullptr);
QCOMPARE(object->property("x"), QVariant(11));
QCOMPARE(object->getChildren()->count(), 2);
@@ -1259,12 +1266,12 @@ void tst_qqmllanguage::inlineQmlComponents()
{
QQmlComponent component(&engine, testFileUrl("inlineQmlComponents.qml"));
VERIFY_ERRORS(0);
- MyContainer *object = qobject_cast<MyContainer *>(component.create());
+ QScopedPointer<MyContainer> object(qobject_cast<MyContainer *>(component.create()));
QVERIFY(object != nullptr);
QCOMPARE(object->getChildren()->count(), 1);
QQmlComponent *comp = qobject_cast<QQmlComponent *>(object->getChildren()->at(0));
QVERIFY(comp != nullptr);
- MyQmlObject *compObject = qobject_cast<MyQmlObject *>(comp->create());
+ QScopedPointer<MyQmlObject> compObject(qobject_cast<MyQmlObject *>(comp->create()));
QVERIFY(compObject != nullptr);
QCOMPARE(compObject->value(), 11);
}
@@ -1275,7 +1282,7 @@ void tst_qqmllanguage::idProperty()
{
QQmlComponent component(&engine, testFileUrl("idProperty.qml"));
VERIFY_ERRORS(0);
- MyContainer *object = qobject_cast<MyContainer *>(component.create());
+ QScopedPointer<MyContainer> object(qobject_cast<MyContainer *>(component.create()));
QVERIFY(object != nullptr);
QCOMPARE(object->getChildren()->count(), 2);
MyTypeObject *child =
@@ -1306,14 +1313,14 @@ void tst_qqmllanguage::autoNotifyConnection()
{
QQmlComponent component(&engine, testFileUrl("autoNotifyConnection.qml"));
VERIFY_ERRORS(0);
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
QVERIFY(object != nullptr);
QMetaProperty prop = object->metaObject()->property(object->metaObject()->indexOfProperty("receivedNotify"));
QVERIFY(prop.isValid());
- QCOMPARE(prop.read(object), QVariant::fromValue(false));
+ QCOMPARE(prop.read(object.data()), QVariant::fromValue(false));
object->setPropertyWithNotify(1);
- QCOMPARE(prop.read(object), QVariant::fromValue(true));
+ QCOMPARE(prop.read(object.data()), QVariant::fromValue(true));
}
// Tests that signals can be assigned to
@@ -1321,7 +1328,7 @@ void tst_qqmllanguage::assignSignal()
{
QQmlComponent component(&engine, testFileUrl("assignSignal.qml"));
VERIFY_ERRORS(0);
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
QVERIFY(object != nullptr);
QTest::ignoreMessage(QtWarningMsg, "MyQmlObject::basicSlot");
emit object->basicSignal();
@@ -1333,7 +1340,7 @@ void tst_qqmllanguage::assignSignalFunctionExpression()
{
QQmlComponent component(&engine, testFileUrl("assignSignalFunctionExpression.qml"));
VERIFY_ERRORS(0);
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
QVERIFY(object != nullptr);
QTest::ignoreMessage(QtWarningMsg, "MyQmlObject::basicSlot");
emit object->basicSignal();
@@ -1362,10 +1369,9 @@ void tst_qqmllanguage::overrideSignal()
QQmlComponent component(&engine, testFileUrl(file));
if (errorFile.isEmpty()) {
VERIFY_ERRORS(0);
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
QVERIFY(object->property("success").toBool());
- delete object;
} else {
VERIFY_ERRORS(errorFile.toLatin1().constData());
}
@@ -1376,8 +1382,7 @@ void tst_qqmllanguage::dynamicProperties()
{
QQmlComponent component(&engine, testFileUrl("dynamicProperties.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
- QVERIFY(object != nullptr);
+ QScopedPointer<QObject> object(component.create());
QCOMPARE(object->property("intProperty"), QVariant(10));
QCOMPARE(object->property("boolProperty"), QVariant(false));
QCOMPARE(object->property("doubleProperty"), QVariant(-10.1));
@@ -1394,15 +1399,13 @@ void tst_qqmllanguage::dynamicPropertiesNested()
{
QQmlComponent component(&engine, testFileUrl("dynamicPropertiesNested.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
QCOMPARE(object->property("super_a").toInt(), 11); // Overridden
QCOMPARE(object->property("super_c").toInt(), 14); // Inherited
QCOMPARE(object->property("a").toInt(), 13); // New
QCOMPARE(object->property("b").toInt(), 12); // New
-
- delete object;
}
// Tests the creation and assignment to dynamic list properties
@@ -1410,7 +1413,7 @@ void tst_qqmllanguage::listProperties()
{
QQmlComponent component(&engine, testFileUrl("listProperties.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
QCOMPARE(object->property("test").toInt(), 2);
@@ -1430,7 +1433,7 @@ void tst_qqmllanguage::dynamicObjectProperties()
{
QQmlComponent component(&engine, testFileUrl("dynamicObjectProperties.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
QCOMPARE(object->property("objectProperty"), qVariantFromValue((QObject*)nullptr));
@@ -1439,7 +1442,7 @@ void tst_qqmllanguage::dynamicObjectProperties()
{
QQmlComponent component(&engine, testFileUrl("dynamicObjectProperties.2.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
QVERIFY(object->property("objectProperty") != qVariantFromValue((QObject*)nullptr));
@@ -1453,7 +1456,7 @@ void tst_qqmllanguage::dynamicSignalsAndSlots()
QQmlComponent component(&engine, testFileUrl("dynamicSignalsAndSlots.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
QVERIFY(object->metaObject()->indexOfMethod("signal1()") != -1);
QVERIFY(object->metaObject()->indexOfMethod("signal2()") != -1);
@@ -1461,7 +1464,7 @@ void tst_qqmllanguage::dynamicSignalsAndSlots()
QVERIFY(object->metaObject()->indexOfMethod("slot2()") != -1);
QCOMPARE(object->property("test").toInt(), 0);
- QMetaObject::invokeMethod(object, "slot3", Qt::DirectConnection, Q_ARG(QVariant, QVariant(10)));
+ QMetaObject::invokeMethod(object.data(), "slot3", Qt::DirectConnection, Q_ARG(QVariant, QVariant(10)));
QCOMPARE(object->property("test").toInt(), 10);
}
@@ -1469,13 +1472,44 @@ void tst_qqmllanguage::simpleBindings()
{
QQmlComponent component(&engine, testFileUrl("simpleBindings.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
QCOMPARE(object->property("value1"), QVariant(10));
QCOMPARE(object->property("value2"), QVariant(10));
QCOMPARE(object->property("value3"), QVariant(21));
QCOMPARE(object->property("value4"), QVariant(10));
- QCOMPARE(object->property("objectProperty"), QVariant::fromValue(object));
+ QCOMPARE(object->property("objectProperty"), QVariant::fromValue(object.data()));
+}
+
+class EvaluationCounter : public QObject
+{
+ Q_OBJECT
+public:
+ int counter = 0;
+ Q_INVOKABLE void increaseEvaluationCounter() { ++counter; }
+};
+
+void tst_qqmllanguage::noDoubleEvaluationForFlushedBindings_data()
+{
+ QTest::addColumn<QString>("fileName");
+ QTest::newRow("order1") << QString("noDoubleEvaluationForFlushedBindings.qml");
+ QTest::newRow("order2") << QString("noDoubleEvaluationForFlushedBindings.2.qml");
+}
+
+void tst_qqmllanguage::noDoubleEvaluationForFlushedBindings()
+{
+ QFETCH(QString, fileName);
+ QQmlEngine engine;
+
+ EvaluationCounter stats;
+ engine.rootContext()->setContextProperty("stats", &stats);
+
+ QQmlComponent component(&engine, testFileUrl(fileName));
+ VERIFY_ERRORS(0);
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+
+ QCOMPARE(stats.counter, 1);
}
void tst_qqmllanguage::autoComponentCreation()
@@ -1483,20 +1517,20 @@ void tst_qqmllanguage::autoComponentCreation()
{
QQmlComponent component(&engine, testFileUrl("autoComponentCreation.qml"));
VERIFY_ERRORS(0);
- MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
+ QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject *>(component.create()));
QVERIFY(object != nullptr);
QVERIFY(object->componentProperty() != nullptr);
- MyTypeObject *child = qobject_cast<MyTypeObject *>(object->componentProperty()->create());
+ QScopedPointer<MyTypeObject> child(qobject_cast<MyTypeObject *>(object->componentProperty()->create()));
QVERIFY(child != nullptr);
QCOMPARE(child->realProperty(), qreal(9));
}
{
QQmlComponent component(&engine, testFileUrl("autoComponentCreation.2.qml"));
VERIFY_ERRORS(0);
- MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
+ QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject *>(component.create()));
QVERIFY(object != nullptr);
QVERIFY(object->componentProperty() != nullptr);
- MyTypeObject *child = qobject_cast<MyTypeObject *>(object->componentProperty()->create());
+ QScopedPointer<MyTypeObject> child(qobject_cast<MyTypeObject *>(object->componentProperty()->create()));
QVERIFY(child != nullptr);
QCOMPARE(child->realProperty(), qreal(9));
}
@@ -1506,10 +1540,10 @@ void tst_qqmllanguage::autoComponentCreationInGroupProperty()
{
QQmlComponent component(&engine, testFileUrl("autoComponentCreationInGroupProperties.qml"));
VERIFY_ERRORS(0);
- MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
+ QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject *>(component.create()));
QVERIFY(object != nullptr);
QVERIFY(object->componentProperty() != nullptr);
- MyTypeObject *child = qobject_cast<MyTypeObject *>(object->componentProperty()->create());
+ QScopedPointer<MyTypeObject> child(qobject_cast<MyTypeObject *>(object->componentProperty()->create()));
QVERIFY(child != nullptr);
QCOMPARE(child->realProperty(), qreal(9));
}
@@ -1519,7 +1553,7 @@ void tst_qqmllanguage::propertyValueSource()
{
QQmlComponent component(&engine, testFileUrl("propertyValueSource.qml"));
VERIFY_ERRORS(0);
- MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
+ QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject *>(component.create()));
QVERIFY(object != nullptr);
QList<QObject *> valueSources;
@@ -1533,14 +1567,14 @@ void tst_qqmllanguage::propertyValueSource()
MyPropertyValueSource *valueSource =
qobject_cast<MyPropertyValueSource *>(valueSources.at(0));
QVERIFY(valueSource != nullptr);
- QCOMPARE(valueSource->prop.object(), qobject_cast<QObject*>(object));
+ QCOMPARE(valueSource->prop.object(), qobject_cast<QObject*>(object.data()));
QCOMPARE(valueSource->prop.name(), QString(QLatin1String("intProperty")));
}
{
QQmlComponent component(&engine, testFileUrl("propertyValueSource.2.qml"));
VERIFY_ERRORS(0);
- MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
+ QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject *>(component.create()));
QVERIFY(object != nullptr);
QList<QObject *> valueSources;
@@ -1554,7 +1588,7 @@ void tst_qqmllanguage::propertyValueSource()
MyPropertyValueSource *valueSource =
qobject_cast<MyPropertyValueSource *>(valueSources.at(0));
QVERIFY(valueSource != nullptr);
- QCOMPARE(valueSource->prop.object(), qobject_cast<QObject*>(object));
+ QCOMPARE(valueSource->prop.object(), qobject_cast<QObject*>(object.data()));
QCOMPARE(valueSource->prop.name(), QString(QLatin1String("intProperty")));
}
}
@@ -1563,9 +1597,9 @@ void tst_qqmllanguage::attachedProperties()
{
QQmlComponent component(&engine, testFileUrl("attachedProperties.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
- QObject *attached = qmlAttachedPropertiesObject<MyQmlObject>(object);
+ QObject *attached = qmlAttachedPropertiesObject<MyQmlObject>(object.data());
QVERIFY(attached != nullptr);
QCOMPARE(attached->property("value"), QVariant(10));
QCOMPARE(attached->property("value2"), QVariant(13));
@@ -1576,7 +1610,7 @@ void tst_qqmllanguage::dynamicObjects()
{
QQmlComponent component(&engine, testFileUrl("dynamicObject.1.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
}
@@ -1585,7 +1619,7 @@ void tst_qqmllanguage::customVariantTypes()
{
QQmlComponent component(&engine, testFileUrl("customVariantTypes.qml"));
VERIFY_ERRORS(0);
- MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
+ QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject*>(component.create()));
QVERIFY(object != nullptr);
QCOMPARE(object->customType().a, 10);
}
@@ -1599,7 +1633,7 @@ void tst_qqmllanguage::valueTypes()
QTest::ignoreMessage(QtWarningMsg, qPrintable(message));
QTest::ignoreMessage(QtWarningMsg, qPrintable(message));
- MyTypeObject *object = qobject_cast<MyTypeObject*>(component.create());
+ QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject*>(component.create()));
QVERIFY(object != nullptr);
@@ -1630,20 +1664,17 @@ void tst_qqmllanguage::cppnamespace()
{
QQmlComponent component(&engine, testFileUrl("cppnamespace.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
QCOMPARE(object->property("intProperty").toInt(), (int)MyNamespace::MyOtherNSEnum::OtherKey2);
-
- delete object;
}
{
QQmlComponent component(&engine, testFileUrl("cppnamespace.2.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
- delete object;
}
}
@@ -1653,7 +1684,7 @@ void tst_qqmllanguage::aliasProperties()
{
QQmlComponent component(&engine, testFileUrl("alias.1.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
// Read through alias
@@ -1665,15 +1696,13 @@ void tst_qqmllanguage::aliasProperties()
object->setProperty("valueAlias", QVariant(19));
QCOMPARE(object->property("valueAlias").toInt(), 19);
QCOMPARE(object->property("value").toInt(), 19);
-
- delete object;
}
// Complex object alias
{
QQmlComponent component(&engine, testFileUrl("alias.2.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
// Read through alias
@@ -1684,21 +1713,19 @@ void tst_qqmllanguage::aliasProperties()
// Write through alias
MyQmlObject *v2 = new MyQmlObject();
- v2->setParent(object);
+ v2->setParent(object.data());
object->setProperty("aliasObject", qVariantFromValue(v2));
MyQmlObject *v3 =
qvariant_cast<MyQmlObject *>(object->property("aliasObject"));
QVERIFY(v3 != nullptr);
QCOMPARE(v3, v2);
-
- delete object;
}
// Nested aliases
{
QQmlComponent component(&engine, testFileUrl("alias.3.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
QCOMPARE(object->property("value").toInt(), 1892);
@@ -1711,27 +1738,23 @@ void tst_qqmllanguage::aliasProperties()
object->setProperty("value2", QVariant(8080));
QCOMPARE(object->property("value").toInt(), 8080);
QCOMPARE(object->property("value2").toInt(), 8080);
-
- delete object;
}
// Enum aliases
{
QQmlComponent component(&engine, testFileUrl("alias.4.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
QCOMPARE(object->property("enumAlias").toInt(), 1);
-
- delete object;
}
// Id aliases
{
QQmlComponent component(&engine, testFileUrl("alias.5.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
QVariant v = object->property("otherAlias");
@@ -1745,15 +1768,13 @@ void tst_qqmllanguage::aliasProperties()
QCOMPARE(v.userType(), qMetaTypeId<MyQmlObject*>());
o = qvariant_cast<MyQmlObject*>(v);
QVERIFY(!o);
-
- delete object;
}
// Nested aliases - this used to cause a crash
{
QQmlComponent component(&engine, testFileUrl("alias.6.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
QCOMPARE(object->property("a").toInt(), 1923);
@@ -1765,7 +1786,7 @@ void tst_qqmllanguage::aliasProperties()
QQmlComponent component(&engine, testFileUrl("alias.7.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
QObject *object1 = qvariant_cast<QObject *>(object->property("object"));
@@ -1778,10 +1799,10 @@ void tst_qqmllanguage::aliasProperties()
delete object1;
- QObject *alias2 = object; // "Random" start value
+ QObject *alias2 = object.data(); // "Random" start value
int status = -1;
void *a[] = { &alias2, nullptr, &status };
- QMetaObject::metacall(object, QMetaObject::ReadProperty,
+ QMetaObject::metacall(object.data(), QMetaObject::ReadProperty,
object->metaObject()->indexOfProperty("aliasedObject"), a);
QVERIFY(!alias2);
}
@@ -1790,24 +1811,20 @@ void tst_qqmllanguage::aliasProperties()
{
QQmlComponent component(&engine, testFileUrl("alias.8.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
QCOMPARE(object->property("value").toInt(), 10);
-
- delete object;
}
// Complex composite type
{
QQmlComponent component(&engine, testFileUrl("alias.9.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
QCOMPARE(object->property("value").toInt(), 10);
-
- delete object;
}
// Valuetype alias
@@ -1815,7 +1832,7 @@ void tst_qqmllanguage::aliasProperties()
{
QQmlComponent component(&engine, testFileUrl("alias.10.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
// Read through alias
@@ -1827,15 +1844,13 @@ void tst_qqmllanguage::aliasProperties()
object->setProperty("valueAlias", QVariant(QRect(3, 3, 4, 9)));
QCOMPARE(object->property("valueAlias").toRect(), QRect(3, 3, 4, 9));
QCOMPARE(object->property("rectProperty").toRect(), QRect(3, 3, 4, 9));
-
- delete object;
}
// Valuetype sub-alias
{
QQmlComponent component(&engine, testFileUrl("alias.11.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
// Read through alias
@@ -1847,8 +1862,6 @@ void tst_qqmllanguage::aliasProperties()
object->setProperty("aliasProperty", QVariant(4));
QCOMPARE(object->property("aliasProperty").toInt(), 4);
QCOMPARE(object->property("rectProperty").toRect(), QRect(4, 8, 102, 111));
-
- delete object;
}
// Nested aliases with a qml file
@@ -1906,6 +1919,16 @@ void tst_qqmllanguage::aliasProperties()
QCOMPARE(subItem->property("y").toInt(), 1);
}
+
+ // Alias to sub-object with binding (QTBUG-57041)
+ {
+ // This is shold *not* crash.
+ QQmlComponent component(&engine, testFileUrl("alias.16.qml"));
+ VERIFY_ERRORS(0);
+
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
+ }
}
// QTBUG-13374 Test that alias properties and signals can coexist
@@ -1913,10 +1936,9 @@ void tst_qqmllanguage::aliasPropertiesAndSignals()
{
QQmlComponent component(&engine, testFileUrl("aliasPropertiesAndSignals.qml"));
VERIFY_ERRORS(0);
- QObject *o = component.create();
+ QScopedPointer<QObject> o(component.create());
QVERIFY(o);
QCOMPARE(o->property("test").toBool(), true);
- delete o;
}
// Test that the root element in a composite type can be a Component
@@ -1924,7 +1946,7 @@ void tst_qqmllanguage::componentCompositeType()
{
QQmlComponent component(&engine, testFileUrl("componentCompositeType.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
}
@@ -1958,11 +1980,9 @@ void tst_qqmllanguage::i18n()
QFETCH(QString, stringProperty);
QQmlComponent component(&engine, testFileUrl(file));
VERIFY_ERRORS(0);
- MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
+ QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject *>(component.create()));
QVERIFY(object != nullptr);
QCOMPARE(object->stringProperty(), stringProperty);
-
- delete object;
}
// Check that the Component::onCompleted attached property works
@@ -1973,7 +1993,7 @@ void tst_qqmllanguage::onCompleted()
QTest::ignoreMessage(QtDebugMsg, "Completed 6 10");
QTest::ignoreMessage(QtDebugMsg, "Completed 6 10");
QTest::ignoreMessage(QtDebugMsg, "Completed 10 11");
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
}
@@ -1982,12 +2002,11 @@ void tst_qqmllanguage::onDestruction()
{
QQmlComponent component(&engine, testFileUrl("onDestruction.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
QTest::ignoreMessage(QtDebugMsg, "Destruction 6 10");
QTest::ignoreMessage(QtDebugMsg, "Destruction 6 10");
QTest::ignoreMessage(QtDebugMsg, "Destruction 10 11");
- delete object;
}
// Check that assignments to QQmlScriptString properties work
@@ -1997,7 +2016,7 @@ void tst_qqmllanguage::scriptString()
QQmlComponent component(&engine, testFileUrl("scriptString.qml"));
VERIFY_ERRORS(0);
- MyTypeObject *object = qobject_cast<MyTypeObject*>(component.create());
+ QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject*>(component.create()));
QVERIFY(object != nullptr);
QVERIFY(!object->scriptProperty().isEmpty());
QCOMPARE(object->scriptProperty().stringLiteral(), QString());
@@ -2008,21 +2027,21 @@ void tst_qqmllanguage::scriptString()
const QQmlScriptStringPrivate *scriptPrivate = QQmlScriptStringPrivate::get(object->scriptProperty());
QVERIFY(scriptPrivate != nullptr);
QCOMPARE(scriptPrivate->script, QString("foo + bar"));
- QCOMPARE(scriptPrivate->scope, qobject_cast<QObject*>(object));
- QCOMPARE(scriptPrivate->context, qmlContext(object));
+ QCOMPARE(scriptPrivate->scope, qobject_cast<QObject*>(object.data()));
+ QCOMPARE(scriptPrivate->context, qmlContext(object.data()));
QVERIFY(object->grouped() != nullptr);
const QQmlScriptStringPrivate *groupedPrivate = QQmlScriptStringPrivate::get(object->grouped()->script());
QCOMPARE(groupedPrivate->script, QString("console.log(1921)"));
- QCOMPARE(groupedPrivate->scope, qobject_cast<QObject*>(object));
- QCOMPARE(groupedPrivate->context, qmlContext(object));
+ QCOMPARE(groupedPrivate->scope, qobject_cast<QObject*>(object.data()));
+ QCOMPARE(groupedPrivate->context, qmlContext(object.data()));
}
{
QQmlComponent component(&engine, testFileUrl("scriptString2.qml"));
VERIFY_ERRORS(0);
- MyTypeObject *object = qobject_cast<MyTypeObject*>(component.create());
+ QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject*>(component.create()));
QVERIFY(object != nullptr);
QCOMPARE(object->scriptProperty().stringLiteral(), QString("hello\\n\\\"world\\\""));
}
@@ -2031,7 +2050,7 @@ void tst_qqmllanguage::scriptString()
QQmlComponent component(&engine, testFileUrl("scriptString3.qml"));
VERIFY_ERRORS(0);
- MyTypeObject *object = qobject_cast<MyTypeObject*>(component.create());
+ QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject*>(component.create()));
QVERIFY(object != nullptr);
bool ok;
QCOMPARE(object->scriptProperty().numberLiteral(&ok), qreal(12.345));
@@ -2043,7 +2062,7 @@ void tst_qqmllanguage::scriptString()
QQmlComponent component(&engine, testFileUrl("scriptString4.qml"));
VERIFY_ERRORS(0);
- MyTypeObject *object = qobject_cast<MyTypeObject*>(component.create());
+ QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject*>(component.create()));
QVERIFY(object != nullptr);
bool ok;
QCOMPARE(object->scriptProperty().booleanLiteral(&ok), true);
@@ -2054,7 +2073,7 @@ void tst_qqmllanguage::scriptString()
QQmlComponent component(&engine, testFileUrl("scriptString5.qml"));
VERIFY_ERRORS(0);
- MyTypeObject *object = qobject_cast<MyTypeObject*>(component.create());
+ QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject*>(component.create()));
QVERIFY(object != nullptr);
QCOMPARE(object->scriptProperty().isNullLiteral(), true);
}
@@ -2063,7 +2082,7 @@ void tst_qqmllanguage::scriptString()
QQmlComponent component(&engine, testFileUrl("scriptString6.qml"));
VERIFY_ERRORS(0);
- MyTypeObject *object = qobject_cast<MyTypeObject*>(component.create());
+ QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject*>(component.create()));
QVERIFY(object != nullptr);
QCOMPARE(object->scriptProperty().isUndefinedLiteral(), true);
}
@@ -2071,12 +2090,12 @@ void tst_qqmllanguage::scriptString()
QQmlComponent component(&engine, testFileUrl("scriptString7.qml"));
VERIFY_ERRORS(0);
- MyTypeObject *object = qobject_cast<MyTypeObject*>(component.create());
+ QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject*>(component.create()));
QVERIFY(object != nullptr);
QQmlScriptString ss = object->scriptProperty();
{
- QQmlExpression expr(ss, /*context*/nullptr, object);
+ QQmlExpression expr(ss, /*context*/nullptr, object.data());
QCOMPARE(expr.evaluate().toInt(), int(100));
}
@@ -2097,9 +2116,9 @@ void tst_qqmllanguage::scriptStringJs()
QQmlComponent component(&engine, testFileUrl("scriptStringJs.qml"));
VERIFY_ERRORS(0);
- MyTypeObject *object = qobject_cast<MyTypeObject*>(component.create());
+ QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject*>(component.create()));
QVERIFY(object != nullptr);
- QQmlContext *context = QQmlEngine::contextForObject(object);
+ QQmlContext *context = QQmlEngine::contextForObject(object.data());
QVERIFY(context != nullptr);
bool ok;
@@ -2111,8 +2130,8 @@ void tst_qqmllanguage::scriptStringJs()
QVERIFY(object->scriptProperty().numberLiteral(&ok) == 0.0 && !ok);
QVERIFY(!object->scriptProperty().booleanLiteral(&ok) && !ok);
- QJSValue inst = engine.newQObject(object);
- QJSValue func = engine.evaluate("function(value) { this.scriptProperty = value }");
+ QJSValue inst = engine.newQObject(object.data());
+ QJSValue func = engine.evaluate("(function(value) { this.scriptProperty = value })");
func.callWithInstance(inst, QJSValueList() << "test a \"string ");
QCOMPARE(QQmlScriptStringPrivate::get(object->scriptProperty())->script, QString("\"test a \\\"string \""));
@@ -2201,7 +2220,7 @@ void tst_qqmllanguage::scriptStringWithoutSourceCode()
QQmlComponent component(&engine, url);
VERIFY_ERRORS(0);
- MyTypeObject *object = qobject_cast<MyTypeObject*>(component.create());
+ QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject*>(component.create()));
QVERIFY(object != nullptr);
QQmlScriptString ss = object->scriptProperty();
QVERIFY(!ss.isEmpty());
@@ -2213,11 +2232,11 @@ void tst_qqmllanguage::scriptStringWithoutSourceCode()
const QQmlScriptStringPrivate *scriptPrivate = QQmlScriptStringPrivate::get(ss);
QVERIFY(scriptPrivate != nullptr);
QVERIFY(scriptPrivate->script.isEmpty());
- QCOMPARE(scriptPrivate->scope, qobject_cast<QObject*>(object));
- QCOMPARE(scriptPrivate->context, qmlContext(object));
+ QCOMPARE(scriptPrivate->scope, qobject_cast<QObject*>(object.data()));
+ QCOMPARE(scriptPrivate->context, qmlContext(object.data()));
{
- QQmlExpression expr(ss, /*context*/nullptr, object);
+ QQmlExpression expr(ss, /*context*/nullptr, object.data());
QCOMPARE(expr.evaluate().toInt(), int(100));
}
}
@@ -2228,23 +2247,23 @@ void tst_qqmllanguage::scriptStringComparison()
{
QQmlComponent component1(&engine, testFileUrl("scriptString.qml"));
QVERIFY(!component1.isError() && component1.errors().isEmpty());
- MyTypeObject *object1 = qobject_cast<MyTypeObject*>(component1.create());
+ QScopedPointer<MyTypeObject> object1(qobject_cast<MyTypeObject*>(component1.create()));
QVERIFY(object1 != nullptr);
QQmlComponent component2(&engine, testFileUrl("scriptString2.qml"));
QVERIFY(!component2.isError() && component2.errors().isEmpty());
- MyTypeObject *object2 = qobject_cast<MyTypeObject*>(component2.create());
+ QScopedPointer<MyTypeObject> object2(qobject_cast<MyTypeObject*>(component2.create()));
QVERIFY(object2 != nullptr);
QQmlComponent component3(&engine, testFileUrl("scriptString3.qml"));
QVERIFY(!component3.isError() && component3.errors().isEmpty());
- MyTypeObject *object3 = qobject_cast<MyTypeObject*>(component3.create());
+ QScopedPointer<MyTypeObject> object3(qobject_cast<MyTypeObject*>(component3.create()));
QVERIFY(object3 != nullptr);
//QJSValue inst1 = engine.newQObject(object1);
- QJSValue inst2 = engine.newQObject(object2);
- QJSValue inst3 = engine.newQObject(object3);
- QJSValue func = engine.evaluate("function(value) { this.scriptProperty = value }");
+ QJSValue inst2 = engine.newQObject(object2.data());
+ QJSValue inst3 = engine.newQObject(object3.data());
+ QJSValue func = engine.evaluate("(function(value) { this.scriptProperty = value })");
const QString s = "hello\\n\\\"world\\\"";
const qreal n = 12.345;
@@ -2298,7 +2317,7 @@ void tst_qqmllanguage::scriptStringComparison()
// While this are two instances of the same object they are still considered different
// because the (none literal) script string may access variables which have different
// values in both instances and hence evaluated to different results.
- MyTypeObject *object1_2 = qobject_cast<MyTypeObject*>(component1.create());
+ QScopedPointer<MyTypeObject> object1_2(qobject_cast<MyTypeObject*>(component1.create()));
QVERIFY(object1_2 != nullptr);
QVERIFY(object1->scriptProperty() != object1_2->scriptProperty());
}
@@ -2310,7 +2329,7 @@ void tst_qqmllanguage::defaultPropertyListOrder()
QQmlComponent component(&engine, testFileUrl("defaultPropertyListOrder.qml"));
VERIFY_ERRORS(0);
- MyContainer *container = qobject_cast<MyContainer *>(component.create());
+ QScopedPointer<MyContainer> container(qobject_cast<MyContainer *>(component.create()));
QVERIFY(container != nullptr);
QCOMPARE(container->getChildren()->count(), 6);
@@ -2331,15 +2350,13 @@ void tst_qqmllanguage::declaredPropertyValues()
void tst_qqmllanguage::dontDoubleCallClassBegin()
{
QQmlComponent component(&engine, testFileUrl("dontDoubleCallClassBegin.qml"));
- QObject *o = component.create();
+ QScopedPointer<QObject> o(component.create());
QVERIFY(o);
MyParserStatus *o2 = qobject_cast<MyParserStatus *>(qvariant_cast<QObject *>(o->property("object")));
QVERIFY(o2);
QCOMPARE(o2->classBeginCount(), 1);
QCOMPARE(o2->componentCompleteCount(), 1);
-
- delete o;
}
void tst_qqmllanguage::reservedWords_data()
@@ -2439,10 +2456,9 @@ void tst_qqmllanguage::testType(const QString& qml, const QString& type, const Q
QCOMPARE(actualerror.left(partialMatch ? expectederror.length(): -1),expectederror);
} else {
VERIFY_ERRORS(0);
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
QCOMPARE(QString(object->metaObject()->className()), type);
- delete object;
}
engine.setImportPathList(defaultImportPathList);
@@ -2453,10 +2469,9 @@ void tst_qqmllanguage::inlineAssignmentsOverrideBindings()
{
QQmlComponent component(&engine, testFileUrl("inlineAssignmentsOverrideBindings.qml"));
- QObject *o = component.create();
+ QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
QCOMPARE(o->property("test").toInt(), 11);
- delete o;
}
// QTBUG-19354
@@ -2887,10 +2902,9 @@ void tst_qqmllanguage::importsPath()
QTRY_VERIFY(component.isReady());
VERIFY_ERRORS(0);
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
QCOMPARE(object->property("test").toString(), value);
- delete object;
engine.setImportPathList(defaultImportPathList);
}
@@ -3098,10 +3112,9 @@ void tst_qqmllanguage::importJs()
}
if (performTest) {
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
QCOMPARE(object->property("test").toBool(),true);
- delete object;
}
engine.setImportPathList(defaultImportPathList);
@@ -3150,21 +3163,21 @@ void tst_qqmllanguage::qmlAttachedPropertiesObjectMethod()
{
QQmlComponent component(&engine, testFileUrl("qmlAttachedPropertiesObjectMethod.1.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
- QCOMPARE(qmlAttachedPropertiesObject<MyQmlObject>(object, false), (QObject *)nullptr);
- QVERIFY(qmlAttachedPropertiesObject<MyQmlObject>(object, true) != nullptr);
+ QCOMPARE(qmlAttachedPropertiesObject<MyQmlObject>(object.data(), false), (QObject *)nullptr);
+ QVERIFY(qmlAttachedPropertiesObject<MyQmlObject>(object.data(), true) != nullptr);
}
{
QQmlComponent component(&engine, testFileUrl("qmlAttachedPropertiesObjectMethod.2.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
- QVERIFY(qmlAttachedPropertiesObject<MyQmlObject>(object, false) != nullptr);
- QVERIFY(qmlAttachedPropertiesObject<MyQmlObject>(object, true) != nullptr);
+ QVERIFY(qmlAttachedPropertiesObject<MyQmlObject>(object.data(), false) != nullptr);
+ QVERIFY(qmlAttachedPropertiesObject<MyQmlObject>(object.data(), true) != nullptr);
}
}
@@ -3185,12 +3198,10 @@ void tst_qqmllanguage::customOnProperty()
QQmlComponent component(&engine, testFileUrl("customOnProperty.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
QCOMPARE(object->property("on").toInt(), 10);
-
- delete object;
}
// QTBUG-12601
@@ -3199,12 +3210,10 @@ void tst_qqmllanguage::variantNotify()
QQmlComponent component(&engine, testFileUrl("variantNotify.qml"));
VERIFY_ERRORS(0);
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
QCOMPARE(object->property("notifyCount").toInt(), 1);
-
- delete object;
}
void tst_qqmllanguage::revisions()
@@ -3213,38 +3222,32 @@ void tst_qqmllanguage::revisions()
QQmlComponent component(&engine, testFileUrl("revisions11.qml"));
VERIFY_ERRORS(0);
- MyRevisionedClass *object = qobject_cast<MyRevisionedClass*>(component.create());
+ QScopedPointer<MyRevisionedClass> object(qobject_cast<MyRevisionedClass*>(component.create()));
QVERIFY(object != nullptr);
QCOMPARE(object->prop2(), 10.0);
-
- delete object;
}
{
QQmlEngine myEngine;
QQmlComponent component(&myEngine, testFileUrl("revisionssub11.qml"));
VERIFY_ERRORS(0);
- MyRevisionedSubclass *object = qobject_cast<MyRevisionedSubclass*>(component.create());
+ QScopedPointer<MyRevisionedSubclass> object(qobject_cast<MyRevisionedSubclass*>(component.create()));
QVERIFY(object != nullptr);
QCOMPARE(object->prop1(), 10.0);
QCOMPARE(object->prop2(), 10.0);
QCOMPARE(object->prop3(), 10.0);
QCOMPARE(object->prop4(), 10.0);
-
- delete object;
}
{
QQmlComponent component(&engine, testFileUrl("versionedbase.qml"));
VERIFY_ERRORS(0);
- MySubclass *object = qobject_cast<MySubclass*>(component.create());
+ QScopedPointer<MySubclass> object(qobject_cast<MySubclass*>(component.create()));
QVERIFY(object != nullptr);
QCOMPARE(object->prop1(), 10.0);
QCOMPARE(object->prop2(), 10.0);
-
- delete object;
}
}
@@ -3290,8 +3293,8 @@ void tst_qqmllanguage::subclassedUncreateableRevision()
QQmlComponent c(&engine);
QTest::ignoreMessage(QtWarningMsg, "QQmlComponent: Component is not ready");
c.setData(qml.toUtf8(), QUrl::fromLocalFile(QDir::currentPath()));
- QObject *obj = c.create();
- QCOMPARE(obj, static_cast<QObject*>(nullptr));
+ QScopedPointer<QObject> obj(c.create());
+ QCOMPARE(obj.data(), static_cast<QObject*>(nullptr));
QCOMPARE(c.errors().count(), 1);
QCOMPARE(c.errors().first().description(), QString("Cannot create MyUncreateableBaseClass"));
}
@@ -3302,17 +3305,16 @@ void tst_qqmllanguage::subclassedUncreateableRevision()
if (!shouldWork)
QTest::ignoreMessage(QtWarningMsg, "QQmlComponent: Component is not ready");
c.setData(qml.toUtf8(), QUrl::fromLocalFile(QDir::currentPath()));
- QObject *obj = c.create();
+ QScopedPointer<QObject> obj(c.create());
if (!shouldWork) {
- QCOMPARE(obj, static_cast<QObject*>(nullptr));
+ QCOMPARE(obj.data(), static_cast<QObject*>(nullptr));
return;
}
QVERIFY(obj);
- MyUncreateableBaseClass *base = qobject_cast<MyUncreateableBaseClass*>(obj);
+ MyUncreateableBaseClass *base = qobject_cast<MyUncreateableBaseClass*>(obj.data());
QVERIFY(base);
QCOMPARE(base->property(prop.toLatin1()).toBool(), true);
- delete obj;
}
void tst_qqmllanguage::subclassedExtendedUncreateableRevision_data()
@@ -3346,8 +3348,8 @@ void tst_qqmllanguage::subclassedExtendedUncreateableRevision()
QQmlComponent c(&engine);
QTest::ignoreMessage(QtWarningMsg, "QQmlComponent: Component is not ready");
c.setData(qml.toUtf8(), QUrl::fromLocalFile(QDir::currentPath()));
- QObject *obj = c.create();
- QCOMPARE(obj, static_cast<QObject*>(nullptr));
+ QScopedPointer<QObject> obj(c.create());
+ QCOMPARE(obj.data(), static_cast<QObject*>(nullptr));
QCOMPARE(c.errors().count(), 1);
QCOMPARE(c.errors().first().description(), QString("Cannot create MyExtendedUncreateableBaseClass"));
}
@@ -3358,17 +3360,16 @@ void tst_qqmllanguage::subclassedExtendedUncreateableRevision()
if (!shouldWork)
QTest::ignoreMessage(QtWarningMsg, "QQmlComponent: Component is not ready");
c.setData(qml.toUtf8(), QUrl::fromLocalFile(QDir::currentPath()));
- QObject *obj = c.create();
+ QScopedPointer<QObject> obj(c.create());
if (!shouldWork) {
- QCOMPARE(obj, static_cast<QObject*>(nullptr));
+ QCOMPARE(obj.data(), static_cast<QObject*>(nullptr));
return;
}
QVERIFY(obj);
- MyExtendedUncreateableBaseClass *base = qobject_cast<MyExtendedUncreateableBaseClass*>(obj);
+ MyExtendedUncreateableBaseClass *base = qobject_cast<MyExtendedUncreateableBaseClass*>(obj.data());
QVERIFY(base);
QCOMPARE(base->property(prop.toLatin1()).toBool(), true);
- delete obj;
}
void tst_qqmllanguage::uncreatableTypesAsProperties()
@@ -3429,12 +3430,10 @@ void tst_qqmllanguage::aliasPropertyChangeSignals()
QQmlComponent component(&engine, testFileUrl("aliasPropertyChangeSignals.qml"));
VERIFY_ERRORS(0);
- QObject *o = component.create();
+ QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
QCOMPARE(o->property("test").toBool(), true);
-
- delete o;
}
// QTCREATORBUG-2769
@@ -3442,12 +3441,10 @@ void tst_qqmllanguage::aliasPropertyChangeSignals()
QQmlComponent component(&engine, testFileUrl("aliasPropertyChangeSignals.2.qml"));
VERIFY_ERRORS(0);
- QObject *o = component.create();
+ QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
QCOMPARE(o->property("test").toBool(), true);
-
- delete o;
}
}
@@ -3458,24 +3455,20 @@ void tst_qqmllanguage::propertyInit()
QQmlComponent component(&engine, testFileUrl("propertyInit.1.qml"));
VERIFY_ERRORS(0);
- QObject *o = component.create();
+ QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
QCOMPARE(o->property("test").toInt(), 1);
-
- delete o;
}
{
QQmlComponent component(&engine, testFileUrl("propertyInit.2.qml"));
VERIFY_ERRORS(0);
- QObject *o = component.create();
+ QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
QCOMPARE(o->property("test").toInt(), 123);
-
- delete o;
}
}
@@ -3485,17 +3478,16 @@ void tst_qqmllanguage::registrationOrder()
{
QQmlComponent component(&engine, testFileUrl("registrationOrder.qml"));
- QObject *o = component.create();
+ QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
QCOMPARE(o->metaObject(), &MyVersion2Class::staticMetaObject);
- delete o;
}
void tst_qqmllanguage::readonly()
{
QQmlComponent component(&engine, testFileUrl("readonly.qml"));
- QObject *o = component.create();
+ QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
QCOMPARE(o->property("test1").toInt(), 10);
@@ -3521,8 +3513,6 @@ void tst_qqmllanguage::readonly()
QCOMPARE(o->property("test1").toInt(), 10);
QCOMPARE(o->property("test2").toInt(), 22);
QCOMPARE(o->property("test3").toInt(), 2);
-
- delete o;
}
void tst_qqmllanguage::readonlyObjectProperties()
@@ -3547,7 +3537,7 @@ void tst_qqmllanguage::receivers()
{
QQmlComponent component(&engine, testFileUrl("receivers.qml"));
- MyReceiversTestObject *o = qobject_cast<MyReceiversTestObject*>(component.create());
+ QScopedPointer<MyReceiversTestObject> o(qobject_cast<MyReceiversTestObject*>(component.create()));
QVERIFY(o != nullptr);
QCOMPARE(o->mySignalCount(), 1);
QCOMPARE(o->propChangedCount(), 2);
@@ -3556,8 +3546,6 @@ void tst_qqmllanguage::receivers()
QVERIFY(o->isSignalConnected(QMetaMethod::fromSignal(&MyReceiversTestObject::mySignal)));
QVERIFY(o->isSignalConnected(QMetaMethod::fromSignal(&MyReceiversTestObject::propChanged)));
QVERIFY(!o->isSignalConnected(QMetaMethod::fromSignal(&MyReceiversTestObject::myUnconnectedSignal)));
-
- delete o;
}
void tst_qqmllanguage::registeredCompositeType()
@@ -3565,10 +3553,8 @@ void tst_qqmllanguage::registeredCompositeType()
QQmlComponent component(&engine, testFileUrl("registeredCompositeType.qml"));
VERIFY_ERRORS(0);
- QObject *o = component.create();
+ QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
-
- delete o;
}
// QTBUG-43582
@@ -3577,14 +3563,12 @@ void tst_qqmllanguage::registeredCompositeTypeWithEnum()
QQmlComponent component(&engine, testFileUrl("registeredCompositeTypeWithEnum.qml"));
VERIFY_ERRORS(0);
- QObject *o = component.create();
+ QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
QCOMPARE(o->property("enumValue0").toInt(), static_cast<int>(MyCompositeBaseType::EnumValue0));
QCOMPARE(o->property("enumValue42").toInt(), static_cast<int>(MyCompositeBaseType::EnumValue42));
QCOMPARE(o->property("enumValue15").toInt(), static_cast<int>(MyCompositeBaseType::ScopedCompositeEnum::EnumValue15));
-
- delete o;
}
// QTBUG-43581
@@ -3593,12 +3577,10 @@ void tst_qqmllanguage::registeredCompositeTypeWithAttachedProperty()
QQmlComponent component(&engine, testFileUrl("registeredCompositeTypeWithAttachedProperty.qml"));
VERIFY_ERRORS(0);
- QObject *o = component.create();
+ QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
QCOMPARE(o->property("attachedProperty").toString(), QStringLiteral("test"));
-
- delete o;
}
// QTBUG-18268
@@ -3611,15 +3593,14 @@ void tst_qqmllanguage::remoteLoadCrash()
while (component.isLoading())
QCoreApplication::processEvents( QEventLoop::ExcludeUserInputEvents | QEventLoop::WaitForMoreEvents, 50);
- QObject *o = component.create();
- delete o;
+ QScopedPointer<QObject> o(component.create());
}
void tst_qqmllanguage::signalWithDefaultArg()
{
QQmlComponent component(&engine, testFileUrl("signalWithDefaultArg.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
QVERIFY(object != nullptr);
QCOMPARE(object->property("signalCount").toInt(), 0);
@@ -3634,15 +3615,13 @@ void tst_qqmllanguage::signalWithDefaultArg()
QCOMPARE(object->property("signalArg").toInt(), 15);
- QMetaObject::invokeMethod(object, "emitNoArgSignal");
+ QMetaObject::invokeMethod(object.data(), "emitNoArgSignal");
QCOMPARE(object->property("signalCount").toInt(), 3);
QCOMPARE(object->property("signalArg").toInt(), 5);
- QMetaObject::invokeMethod(object, "emitArgSignal");
+ QMetaObject::invokeMethod(object.data(), "emitArgSignal");
QCOMPARE(object->property("signalCount").toInt(), 4);
QCOMPARE(object->property("signalArg").toInt(), 22);
-
- delete object;
}
void tst_qqmllanguage::signalParameterTypes()
@@ -3650,19 +3629,17 @@ void tst_qqmllanguage::signalParameterTypes()
// bound signal handlers
{
QQmlComponent component(&engine, testFileUrl("signalParameterTypes.1.qml"));
- QObject *obj = component.create();
+ QScopedPointer<QObject> obj(component.create());
QVERIFY(obj != nullptr);
QVERIFY(obj->property("success").toBool());
- delete obj;
}
// dynamic signal connections
{
QQmlComponent component(&engine, testFileUrl("signalParameterTypes.2.qml"));
- QObject *obj = component.create();
+ QScopedPointer<QObject> obj(component.create());
QVERIFY(obj != nullptr);
QVERIFY(obj->property("success").toBool());
- delete obj;
}
}
@@ -3675,7 +3652,7 @@ void tst_qqmllanguage::globalEnums()
QQmlComponent component(&engine, testFileUrl("globalEnums.qml"));
- QObject *o = component.create();
+ QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
MyEnum1Class *enum1Class = o->findChild<MyEnum1Class *>(QString::fromLatin1("enum1Class"));
@@ -3701,7 +3678,7 @@ void tst_qqmllanguage::globalEnums()
QSignalSpy signalA(enum2Class, SIGNAL(valueAChanged(MyEnum1Class::EnumA)));
QSignalSpy signalB(enum2Class, SIGNAL(valueBChanged(MyEnum2Class::EnumB)));
- QMetaObject::invokeMethod(o, "setEnumValues");
+ QMetaObject::invokeMethod(o.data(), "setEnumValues");
QVERIFY(enum1Class->getValue() == MyEnum1Class::A_13);
QVERIFY(enum2Class->getValueA() == MyEnum1Class::A_11);
@@ -3720,8 +3697,6 @@ void tst_qqmllanguage::globalEnums()
QVERIFY(enum2Class->property("dValue") == 2);
QVERIFY(enum2Class->property("eValue") == 14);
QVERIFY(enum2Class->property("e2Value") == 76);
-
- delete o;
}
void tst_qqmllanguage::lowercaseEnumRuntime_data()
@@ -3767,7 +3742,7 @@ void tst_qqmllanguage::scopedEnum()
{
QQmlComponent component(&engine, testFileUrl("scopedEnum.qml"));
- MyTypeObject *o = qobject_cast<MyTypeObject *>(component.create());
+ QScopedPointer<MyTypeObject> o(qobject_cast<MyTypeObject *>(component.create()));
QVERIFY(o != nullptr);
QCOMPARE(o->scopedEnum(), MyTypeObject::MyScopedEnum::ScopedVal1);
@@ -3775,16 +3750,19 @@ void tst_qqmllanguage::scopedEnum()
QCOMPARE(o->property("listValue").toInt(), (int)MyTypeObject::MyScopedEnum::ScopedVal3);
QCOMPARE(o->property("noScope").toInt(), (int)MyTypeObject::MyScopedEnum::ScopedVal1);
- QMetaObject::invokeMethod(o, "assignNewValue");
+ QMetaObject::invokeMethod(o.data(), "assignNewValue");
QCOMPARE(o->scopedEnum(), MyTypeObject::MyScopedEnum::ScopedVal2);
QCOMPARE(o->property("noScope").toInt(), (int)MyTypeObject::MyScopedEnum::ScopedVal2);
}
void tst_qqmllanguage::qmlEnums()
{
+ QQmlEngine engine;
+ engine.setImportPathList(QStringList(defaultImportPathList) << testFile("lib"));
+
{
QQmlComponent component(&engine, testFileUrl("TypeWithEnum.qml"));
- QObject *o = component.create();
+ QScopedPointer<QObject> o(component.create());
QVERIFY(o);
QCOMPARE(o->property("enumValue").toInt(), 1);
QCOMPARE(o->property("enumValue2").toInt(), 2);
@@ -3799,11 +3777,12 @@ void tst_qqmllanguage::qmlEnums()
{
QQmlComponent component(&engine, testFileUrl("usingTypeWithEnum.qml"));
- QObject *o = component.create();
+ QScopedPointer<QObject> o(component.create());
QVERIFY(o);
QCOMPARE(o->property("enumValue").toInt(), 1);
QCOMPARE(o->property("enumValue2").toInt(), 0);
QCOMPARE(o->property("scopedEnumValue").toInt(), 2);
+ QCOMPARE(o->property("enumValueFromSingleton").toInt(), 42);
}
}
@@ -3844,10 +3823,9 @@ void tst_qqmllanguage::literals()
QQmlComponent component(&engine, testFile("literals.qml"));
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
QCOMPARE(object->property(property.toLatin1()), value);
- delete object;
}
void tst_qqmllanguage::objectDeletionNotify_data()
@@ -3866,19 +3844,17 @@ void tst_qqmllanguage::objectDeletionNotify()
QQmlComponent component(&engine, testFile(file));
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
QCOMPARE(object->property("success").toBool(), true);
- QMetaObject::invokeMethod(object, "destroyObject");
+ QMetaObject::invokeMethod(object.data(), "destroyObject");
// Process the deletion event
QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
QCoreApplication::processEvents();
QCOMPARE(object->property("success").toBool(), true);
-
- delete object;
}
void tst_qqmllanguage::scopedProperties()
@@ -3912,7 +3888,7 @@ void tst_qqmllanguage::implicitImportsLast()
QQmlComponent component(&engine, testFile("localOrderTest.qml"));
VERIFY_ERRORS(0);
- QObject *object = qobject_cast<QObject *>(component.create());
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
QVERIFY(QString(object->metaObject()->className()).startsWith(QLatin1String("QQuickMouseArea")));
QObject* object2 = object->property("item").value<QObject*>();
@@ -3932,10 +3908,10 @@ void tst_qqmllanguage::getSingletonInstance(QQmlEngine& engine, const char* file
QQmlComponent component(&engine, testFile(fileName));
VERIFY_ERRORS(0);
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
- getSingletonInstance(object, propertyName, result);
+ getSingletonInstance(object.data(), propertyName, result);
}
void tst_qqmllanguage::getSingletonInstance(QObject* o, const char* propertyName, QObject** result /* out */)
@@ -3972,10 +3948,10 @@ void tst_qqmllanguage::compositeSingletonProperties()
{
QQmlComponent component(&engine, testFile("singletonTest1.qml"));
VERIFY_ERRORS(0);
- QObject *o = component.create();
+ QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
- verifyCompositeSingletonPropertyValues(o, "value1", 125, "value2", -55);
+ verifyCompositeSingletonPropertyValues(o.data(), "value1", 125, "value2", -55);
}
// Checks that the addresses of the composite singletons used in the same
@@ -4026,15 +4002,15 @@ void tst_qqmllanguage::compositeSingletonQualifiedNamespace()
{
QQmlComponent component(&engine, testFile("singletonTest5.qml"));
VERIFY_ERRORS(0);
- QObject *o = component.create();
+ QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
- verifyCompositeSingletonPropertyValues(o, "value1", 125, "value2", -55);
+ verifyCompositeSingletonPropertyValues(o.data(), "value1", 125, "value2", -55);
// lets verify that the singleton instance we are using is the same
// when loaded through another file (without namespace!)
QObject *s1 = nullptr;
- getSingletonInstance(o, "singletonInstance", &s1);
+ getSingletonInstance(o.data(), "singletonInstance", &s1);
QVERIFY(s1 != nullptr);
QObject* s2 = nullptr;
@@ -4051,16 +4027,16 @@ void tst_qqmllanguage::compositeSingletonModule()
QQmlComponent component(&engine, testFile("singletonTest6.qml"));
VERIFY_ERRORS(0);
- QObject *o = component.create();
+ QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
- verifyCompositeSingletonPropertyValues(o, "value1", 125, "value2", -55);
- verifyCompositeSingletonPropertyValues(o, "value3", 125, "value4", -55);
+ verifyCompositeSingletonPropertyValues(o.data(), "value1", 125, "value2", -55);
+ verifyCompositeSingletonPropertyValues(o.data(), "value3", 125, "value4", -55);
// lets verify that the singleton instance we are using is the same
// when loaded through another file
QObject *s1 = nullptr;
- getSingletonInstance(o, "singletonInstance", &s1);
+ getSingletonInstance(o.data(), "singletonInstance", &s1);
QVERIFY(s1 != nullptr);
QObject* s2 = nullptr;
@@ -4077,16 +4053,16 @@ void tst_qqmllanguage::compositeSingletonModuleVersioned()
QQmlComponent component(&engine, testFile("singletonTest7.qml"));
VERIFY_ERRORS(0);
- QObject *o = component.create();
+ QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
- verifyCompositeSingletonPropertyValues(o, "value1", 225, "value2", 55);
- verifyCompositeSingletonPropertyValues(o, "value3", 225, "value4", 55);
+ verifyCompositeSingletonPropertyValues(o.data(), "value1", 225, "value2", 55);
+ verifyCompositeSingletonPropertyValues(o.data(), "value3", 225, "value4", 55);
// lets verify that the singleton instance we are using is the same
// when loaded through another file
QObject *s1 = nullptr;
- getSingletonInstance(o, "singletonInstance", &s1);
+ getSingletonInstance(o.data(), "singletonInstance", &s1);
QVERIFY(s1 != nullptr);
QObject* s2 = nullptr;
@@ -4103,16 +4079,16 @@ void tst_qqmllanguage::compositeSingletonModuleQualified()
QQmlComponent component(&engine, testFile("singletonTest8.qml"));
VERIFY_ERRORS(0);
- QObject *o = component.create();
+ QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
- verifyCompositeSingletonPropertyValues(o, "value1", 225, "value2", 55);
- verifyCompositeSingletonPropertyValues(o, "value3", 225, "value4", 55);
+ verifyCompositeSingletonPropertyValues(o.data(), "value1", 225, "value2", 55);
+ verifyCompositeSingletonPropertyValues(o.data(), "value3", 225, "value4", 55);
// lets verify that the singleton instance we are using is the same
// when loaded through another file
QObject *s1 = nullptr;
- getSingletonInstance(o, "singletonInstance", &s1);
+ getSingletonInstance(o.data(), "singletonInstance", &s1);
QVERIFY(s1 != nullptr);
QObject* s2 = nullptr;
@@ -4142,10 +4118,10 @@ void tst_qqmllanguage::compositeSingletonDynamicSignal()
{
QQmlComponent component(&engine, testFile("singletonTest11.qml"));
VERIFY_ERRORS(0);
- QObject *o = component.create();
+ QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
- verifyCompositeSingletonPropertyValues(o, "value1", 99, "value2", -55);
+ verifyCompositeSingletonPropertyValues(o.data(), "value1", 99, "value2", -55);
}
// Use qmlRegisterType to register a qml composite type with pragma Singleton defined in it.
@@ -4191,10 +4167,10 @@ void tst_qqmllanguage::compositeSingletonRemote()
QCoreApplication::processEvents( QEventLoop::ExcludeUserInputEvents | QEventLoop::WaitForMoreEvents, 50);
VERIFY_ERRORS(0);
- QObject *o = component.create();
+ QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
- verifyCompositeSingletonPropertyValues(o, "value1", 525, "value2", 355);
+ verifyCompositeSingletonPropertyValues(o.data(), "value1", 525, "value2", 355);
}
// Load a composite singleton type and a javascript file that has .pragma library
@@ -4204,14 +4180,14 @@ void tst_qqmllanguage::compositeSingletonJavaScriptPragma()
{
QQmlComponent component(&engine, testFile("singletonTest16.qml"));
VERIFY_ERRORS(0);
- QObject *o = component.create();
+ QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
// The value1 that is read from the SingletonType was changed from 125 to 99
// in compositeSingletonDynamicSignal() above. As the type is a singleton and
// the engine has not been destroyed, we just retrieve the old instance and
// the value is still 99.
- verifyCompositeSingletonPropertyValues(o, "value1", 99, "value2", 333);
+ verifyCompositeSingletonPropertyValues(o.data(), "value1", 99, "value2", 333);
}
// Reads values from a Singleton accessed through selectors.
@@ -4222,10 +4198,10 @@ void tst_qqmllanguage::compositeSingletonSelectors()
qmlSelector.setExtraSelectors(QStringList() << "basicSelector");
QQmlComponent component(&e2, testFile("singletonTest1.qml"));
VERIFY_ERRORS(0);
- QObject *o = component.create();
+ QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
- verifyCompositeSingletonPropertyValues(o, "value1", 625, "value2", 455);
+ verifyCompositeSingletonPropertyValues(o.data(), "value1", 625, "value2", 455);
}
// Reads values from a Singleton that was registered through the C++ API:
@@ -4234,10 +4210,10 @@ void tst_qqmllanguage::compositeSingletonRegistered()
{
QQmlComponent component(&engine, testFile("singletonTest17.qml"));
VERIFY_ERRORS(0);
- QObject *o = component.create();
+ QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
- verifyCompositeSingletonPropertyValues(o, "value1", 925, "value2", 755);
+ verifyCompositeSingletonPropertyValues(o.data(), "value1", 925, "value2", 755);
}
void tst_qqmllanguage::compositeSingletonCircular()
@@ -4247,7 +4223,7 @@ void tst_qqmllanguage::compositeSingletonCircular()
QQmlTestMessageHandler messageHandler;
- QObject *o = component.create();
+ QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
// ensure we aren't hitting the recursion warning
@@ -4602,7 +4578,7 @@ void tst_qqmllanguage::noChildEvents()
QQmlComponent component(&engine);
component.setData("import QtQml 2.0; import Test 1.0; MyQmlObject { property QtObject child: QtObject {} }", QUrl());
VERIFY_ERRORS(0);
- MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
+ QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject*>(component.create()));
QVERIFY(object != nullptr);
QCOMPARE(object->childAddedEventCount(), 0);
}
@@ -4622,10 +4598,10 @@ void tst_qqmllanguage::deleteSingletons()
QQmlEngine tmpEngine;
QQmlComponent component(&tmpEngine, testFile("singletonTest5.qml"));
VERIFY_ERRORS(0);
- QObject *o = component.create();
+ QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
QObject *s1 = nullptr;
- getSingletonInstance(o, "singletonInstance", &s1);
+ getSingletonInstance(o.data(), "singletonInstance", &s1);
QVERIFY(s1 != nullptr);
singleton = s1;
QVERIFY(singleton.data() != nullptr);
@@ -4649,7 +4625,7 @@ void tst_qqmllanguage::arrayBuffer()
QFETCH(QString, file);
QQmlComponent component(&engine, testFile(file));
VERIFY_ERRORS(0);
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
QCOMPARE(object->property("ok").toBool(), true);
}
diff --git a/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp b/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp
index 4618ea4071..9fdc54f067 100644
--- a/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp
+++ b/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp
@@ -125,6 +125,7 @@ private slots:
void bindingsOnGetResult();
void stringifyModelEntry();
void qobjectTrackerForDynamicModelObjects();
+ void crash_append_empty_array();
};
bool tst_qqmllistmodel::compareVariantList(const QVariantList &testList, QVariant object)
@@ -1534,6 +1535,27 @@ void tst_qqmllistmodel::qobjectTrackerForDynamicModelObjects()
QVERIFY(!ddata->jsWrapper.isNullOrUndefined());
}
+void tst_qqmllistmodel::crash_append_empty_array()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.setData(
+ "import QtQuick 2.0\n"
+ "Item {\n"
+ " ListModel {\n"
+ " id: testModel\n"
+ " objectName: \"testModel\""
+ " }\n"
+ "}\n", QUrl());
+ QScopedPointer<QObject> scene(component.create());
+ QQmlListModel *model = scene->findChild<QQmlListModel*>("testModel");
+ QSignalSpy spy(model, &QQmlListModel::rowsAboutToBeInserted);
+ QQmlExpression expr(engine.rootContext(), model, "append(new Array())");
+ expr.evaluate();
+ QVERIFY2(!expr.hasError(), QTest::toString(expr.error().toString()));
+ QCOMPARE(spy.count(), 0);
+}
+
QTEST_MAIN(tst_qqmllistmodel)
#include "tst_qqmllistmodel.moc"
diff --git a/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp b/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp
index c252bba001..a456facd2f 100644
--- a/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp
+++ b/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp
@@ -89,6 +89,7 @@ private slots:
void customValueType();
void customValueTypeInQml();
void gadgetInheritance();
+ void gadgetTemplateInheritance();
void toStringConversion();
void enumerableProperties();
void enumProperties();
@@ -1613,6 +1614,19 @@ public:
Q_INVOKABLE void functionInDerivedGadget(int value) { m_derivedProperty = value; }
};
+// QTBUG-66744: we want a Q_GADGET giving us generic type safety in C++ and property access in Qml
+template <typename T>
+struct DerivedTypedGadget : public BaseGadget
+{
+ // cannot use Q_GADGET here
+public:
+ DerivedTypedGadget() {}
+};
+
+class DerivedTypedGadgetDummyType {};
+
+Q_DECLARE_METATYPE(DerivedTypedGadget<DerivedTypedGadgetDummyType>)
+
class TypeWithCustomValueType : public QObject
{
Q_OBJECT
@@ -1657,6 +1671,21 @@ void tst_qqmlvaluetypes::gadgetInheritance()
QCOMPARE(value.property("baseProperty").toInt(), 42);
}
+void tst_qqmlvaluetypes::gadgetTemplateInheritance()
+{
+ QJSEngine engine;
+
+ QJSValue value = engine.toScriptValue(DerivedTypedGadget<DerivedTypedGadgetDummyType>());
+
+ QCOMPARE(value.property("baseProperty").toInt(), 0);
+ value.setProperty("baseProperty", 10);
+ QCOMPARE(value.property("baseProperty").toInt(), 10);
+
+ QJSValue method = value.property("functionInBaseGadget");
+ method.call(QJSValueList() << QJSValue(42));
+ QCOMPARE(value.property("baseProperty").toInt(), 42);
+}
+
struct StringLessGadget {
Q_GADGET
};
diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/noqmlcontext.js b/tests/auto/qml/qqmlxmlhttprequest/data/noqmlcontext.js
new file mode 100644
index 0000000000..adb7269310
--- /dev/null
+++ b/tests/auto/qml/qqmlxmlhttprequest/data/noqmlcontext.js
@@ -0,0 +1,11 @@
+(function(url, resultCollector) {
+ var x = new XMLHttpRequest;
+ x.open("GET", url);
+ x.setRequestHeader("Accept-Language","en-US");
+ x.onreadystatechange = function() {
+ if (x.readyState == XMLHttpRequest.DONE) {
+ resultCollector.responseText = x.responseText
+ }
+ }
+ x.send()
+})
diff --git a/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp b/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp
index 59716acc0d..ecce6515ed 100644
--- a/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp
+++ b/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp
@@ -108,6 +108,8 @@ private slots:
void text();
void cdata();
+ void noQmlContext();
+
// Crashes
// void outstanding_request_at_shutdown();
@@ -1243,6 +1245,30 @@ void tst_qqmlxmlhttprequest::cdata()
QCOMPARE(object->property("status").toInt(), 200);
}
+void tst_qqmlxmlhttprequest::noQmlContext()
+{
+ TestHTTPServer server;
+ QVERIFY2(server.listen(), qPrintable(server.errorString()));
+ QVERIFY(server.wait(testFileUrl("open_network.expect"),
+ testFileUrl("open_network.reply"),
+ testFileUrl("testdocument.html")));
+ QUrl url = server.urlString(QStringLiteral("/testdocument.html"));
+
+ QQmlEngine engine;
+
+ QFile f(testFile("noqmlcontext.js"));
+ QVERIFY(f.open(QIODevice::ReadOnly));
+ QString script = QString::fromUtf8(f.readAll());
+ QJSValue testFunction = engine.evaluate(script);
+ QVERIFY(testFunction.isCallable());
+
+ QJSValue resultCollector = engine.newObject();
+
+ testFunction.call(QJSValueList() << url.toString() << resultCollector);
+
+ QTRY_COMPARE(resultCollector.property("responseText").toString(), "QML Rocks!\n");
+ }
+
void tst_qqmlxmlhttprequest::stateChangeCallingContext()
{
#ifdef Q_OS_WIN
diff --git a/tests/auto/qml/qv4assembler/qv4assembler.pro b/tests/auto/qml/qv4assembler/qv4assembler.pro
new file mode 100644
index 0000000000..afd7586ac7
--- /dev/null
+++ b/tests/auto/qml/qv4assembler/qv4assembler.pro
@@ -0,0 +1,7 @@
+CONFIG += testcase
+TARGET = tst_qv4assembler
+macos:CONFIG -= app_bundle
+
+SOURCES += tst_qv4assembler.cpp
+
+QT += qml-private testlib
diff --git a/tests/auto/qml/qv4assembler/tst_qv4assembler.cpp b/tests/auto/qml/qv4assembler/tst_qv4assembler.cpp
new file mode 100644
index 0000000000..9bd1afa256
--- /dev/null
+++ b/tests/auto/qml/qv4assembler/tst_qv4assembler.cpp
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include <QtCore/qprocess.h>
+#include <QtCore/qtemporaryfile.h>
+
+class tst_QV4Assembler : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void perfMapFile();
+};
+
+void tst_QV4Assembler::perfMapFile()
+{
+#if !defined(Q_OS_LINUX)
+ QSKIP("perf map files are only generated on linux");
+#else
+ const QString qmljs = QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmljs";
+ QProcess process;
+
+ QTemporaryFile infile;
+ QVERIFY(infile.open());
+ infile.write("'use strict'; function foo() { return 42 }; foo();");
+ infile.close();
+
+ QProcessEnvironment environment = QProcessEnvironment::systemEnvironment();
+ environment.insert("QV4_PROFILE_WRITE_PERF_MAP", "1");
+ environment.insert("QV4_JIT_CALL_THRESHOLD", "0");
+
+ process.setProcessEnvironment(environment);
+ process.start(qmljs, QStringList({infile.fileName()}));
+ QVERIFY(process.waitForStarted());
+ const qint64 pid = process.processId();
+ QVERIFY(pid != 0);
+ QVERIFY(process.waitForFinished());
+ QCOMPARE(process.exitCode(), 0);
+
+ QFile file(QString::fromLatin1("/tmp/perf-%1.map").arg(pid));
+ QVERIFY(file.exists());
+ QVERIFY(file.open(QIODevice::ReadOnly));
+ QList<QByteArray> functions;
+ while (!file.atEnd()) {
+ const QByteArray contents = file.readLine();
+ QVERIFY(contents.endsWith('\n'));
+ QList<QByteArray> fields = contents.split(' ');
+ QCOMPARE(fields.length(), 3);
+ bool ok = false;
+ const qulonglong address = fields[0].toULongLong(&ok, 16);
+ QVERIFY(ok);
+ QVERIFY(address > 0);
+ const ulong size = fields[1].toULong(&ok, 16);
+ QVERIFY(ok);
+ QVERIFY(size > 0);
+ functions.append(fields[2]);
+ }
+ QVERIFY(functions.contains("foo\n"));
+#endif
+}
+
+QTEST_MAIN(tst_QV4Assembler)
+
+#include "tst_qv4assembler.moc"
+
diff --git a/tests/auto/qmltest/statemachine/tst_triggeredArguments2.qml b/tests/auto/qmltest/statemachine/tst_triggeredArguments2.qml
index 73bc653404..f23cc14152 100644
--- a/tests/auto/qmltest/statemachine/tst_triggeredArguments2.qml
+++ b/tests/auto/qmltest/statemachine/tst_triggeredArguments2.qml
@@ -67,7 +67,6 @@ TestCase {
// Emit the signalTrans.signal
testCase.mysignal("test1", true, 2)
- expectFail("", "QTBUG-50328")
compare(testCase.mystr, "test1")
compare(testCase.mybool, true)
compare(testCase.myint, 2)
diff --git a/tests/auto/quick/examples/tst_examples.cpp b/tests/auto/quick/examples/tst_examples.cpp
index 716651ec0c..eee8dfcf26 100644
--- a/tests/auto/quick/examples/tst_examples.cpp
+++ b/tests/auto/quick/examples/tst_examples.cpp
@@ -86,6 +86,7 @@ tst_examples::tst_examples()
excludedDirs << "snippets/qml/visualdatamodel_rootindex";
excludedDirs << "snippets/qml/qtbinding";
excludedDirs << "snippets/qml/imports";
+ excludedFiles << "snippets/qml/image-ext.qml";
excludedFiles << "examples/quick/shapes/content/main.qml"; // relies on resources
excludedFiles << "examples/quick/shapes/content/interactive.qml"; // relies on resources
diff --git a/tests/auto/quick/qquickimage/tst_qquickimage.cpp b/tests/auto/quick/qquickimage/tst_qquickimage.cpp
index 3613ba6d87..d1f46a3912 100644
--- a/tests/auto/quick/qquickimage/tst_qquickimage.cpp
+++ b/tests/auto/quick/qquickimage/tst_qquickimage.cpp
@@ -445,6 +445,12 @@ void tst_qquickimage::svg()
// Due to aspect ratio calculations we can't get a precise
// check for all setups, so we allow a small margin of error
QVERIFY(qAbs(obj->height() - 141) < 1);
+
+ // Setting it to a size bigger than the actual file, SVG formats
+ // can scale up although other image formats cannot
+ obj->setSourceSize(QSize(800,0));
+ QCOMPARE(obj->width(), 800.0);
+ QVERIFY(qAbs(obj->height() - 1131) < 1);
delete obj;
}
diff --git a/tests/auto/quick/qquickitem/BLACKLIST b/tests/auto/quick/qquickitem/BLACKLIST
index f00b061356..d94a3ef102 100644
--- a/tests/auto/quick/qquickitem/BLACKLIST
+++ b/tests/auto/quick/qquickitem/BLACKLIST
@@ -1,4 +1,2 @@
[contains:hollow square: testing points inside]
xcb
-[ignoreButtonPressNotInAcceptedMouseButtons]
-*
diff --git a/tests/auto/quick/qquickloader/data/rootContext.qml b/tests/auto/quick/qquickloader/data/rootContext.qml
new file mode 100644
index 0000000000..277db43d57
--- /dev/null
+++ b/tests/auto/quick/qquickloader/data/rootContext.qml
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the manual tests of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Rectangle {
+ width: 360
+ height: 360
+
+ property alias loader: loader
+
+ Loader {
+ id: loader
+ }
+
+ property Component component: Item {
+ property bool trigger: false
+ onTriggerChanged: {
+ objectInRootContext.doIt() // make sure we can resolve objectInRootContext
+ loader.active = false
+ objectInRootContext.doIt() // make sure we can STILL resolve objectInRootContext
+ anotherProperty = true // see if we can trigger subsequent signal handlers (we shouldn't)
+ }
+ property bool anotherProperty: false
+ onAnotherPropertyChanged: {
+ // this should never be executed
+ objectInRootContext.doIt()
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickloader/tst_qquickloader.cpp b/tests/auto/quick/qquickloader/tst_qquickloader.cpp
index 30fc52f95a..7a176661e8 100644
--- a/tests/auto/quick/qquickloader/tst_qquickloader.cpp
+++ b/tests/auto/quick/qquickloader/tst_qquickloader.cpp
@@ -29,6 +29,7 @@
#include <QSignalSpy>
+#include <QtQml/QQmlContext>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcomponent.h>
#include <QtQml/qqmlincubator.h>
@@ -123,6 +124,8 @@ private slots:
void bindings();
void parentErrors();
+
+ void rootContext();
};
Q_DECLARE_METATYPE(QList<QQmlError>)
@@ -1327,6 +1330,64 @@ void tst_QQuickLoader::parentErrors()
QVERIFY2(warningsSpy.isEmpty(), qPrintable(failureMessage));
}
+class ObjectInRootContext: public QObject
+{
+ Q_OBJECT
+
+public:
+ int didIt = 0;
+
+public slots:
+ void doIt() {
+ didIt += 1;
+ }
+};
+
+void tst_QQuickLoader::rootContext()
+{
+ QQmlEngine engine;
+ ObjectInRootContext objectInRootContext;
+ engine.rootContext()->setContextProperty("objectInRootContext", &objectInRootContext);
+
+ QQmlComponent component(&engine, testFileUrl("rootContext.qml"));
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
+
+ QQuickLoader *loader = object->property("loader").value<QQuickLoader*>();
+ QVERIFY(loader);
+
+ QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QQmlError>)));
+
+ // Give the loader a component
+ loader->setSourceComponent(object->property("component").value<QQmlComponent*>());
+ QTRY_VERIFY(loader->active());
+ QTRY_VERIFY(loader->item());
+
+ QString failureMessage;
+ if (!warningsSpy.isEmpty()) {
+ QDebug stream(&failureMessage);
+ stream << warningsSpy.first().first().value<QList<QQmlError>>();
+ }
+ QVERIFY2(warningsSpy.isEmpty(), qPrintable(failureMessage));
+ QCOMPARE(objectInRootContext.didIt, 0);
+
+ // Deactivate the loader, which deletes the item.
+ // Check that a) there are no errors, and b) the objectInRootContext can still be resolved even
+ // after deactivating the loader. If it cannot, a ReferenceError for objectInRootContext is
+ // generated (and the 'doIt' counter in objectInRootContext will be 1 for the call before
+ // the deactivation).
+ loader->item()->setProperty("trigger", true);
+ QTRY_VERIFY(!loader->active());
+ QTRY_VERIFY(!loader->item());
+
+ if (!warningsSpy.isEmpty()) {
+ QDebug stream(&failureMessage);
+ stream << warningsSpy.first().first().value<QList<QQmlError>>();
+ }
+ QVERIFY2(warningsSpy.isEmpty(), qPrintable(failureMessage));
+ QCOMPARE(objectInRootContext.didIt, 2);
+}
+
QTEST_MAIN(tst_QQuickLoader)
#include "tst_qquickloader.moc"
diff --git a/tests/auto/quick/qquicktext/data/elideParentChanged.qml b/tests/auto/quick/qquicktext/data/elideParentChanged.qml
new file mode 100644
index 0000000000..f605cf58f1
--- /dev/null
+++ b/tests/auto/quick/qquicktext/data/elideParentChanged.qml
@@ -0,0 +1,13 @@
+import QtQuick 2.0
+
+Item {
+ width: 100
+ height: 30
+
+ Text {
+ width: parent ? parent.width : 0
+ height: parent ? parent.height : 0
+ elide: Text.ElideRight
+ text: "wot"
+ }
+}
diff --git a/tests/auto/quick/qquicktext/tst_qquicktext.cpp b/tests/auto/quick/qquicktext/tst_qquicktext.cpp
index 609a84ce82..89d2590c03 100644
--- a/tests/auto/quick/qquicktext/tst_qquicktext.cpp
+++ b/tests/auto/quick/qquicktext/tst_qquicktext.cpp
@@ -38,6 +38,7 @@
#include <QFontMetrics>
#include <qmath.h>
#include <QtQuick/QQuickView>
+#include <QtQuick/qquickitemgrabresult.h>
#include <private/qguiapplication_p.h>
#include <limits.h>
#include <QtGui/QMouseEvent>
@@ -64,6 +65,7 @@ private slots:
void width();
void wrap();
void elide();
+ void elideParentChanged();
void multilineElide_data();
void multilineElide();
void implicitElide_data();
@@ -554,6 +556,45 @@ void tst_qquicktext::elide()
}
}
+// QTBUG-60328
+// Tests that text with elide set is rendered after
+// having its parent cleared and then set again.
+void tst_qquicktext::elideParentChanged()
+{
+ QQuickView window;
+ window.setSource(testFileUrl("elideParentChanged.qml"));
+ QTRY_COMPARE(window.status(), QQuickView::Ready);
+
+ window.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&window));
+
+ QQuickItem *root = window.rootObject();
+ QVERIFY(root);
+ QCOMPARE(root->childItems().size(), 1);
+
+ // Store a snapshot of the scene so that we can compare it later.
+ QSharedPointer<QQuickItemGrabResult> grabResult = root->grabToImage();
+ QTRY_VERIFY(!grabResult->image().isNull());
+ const QImage expectedItemImageGrab(grabResult->image());
+
+ // Clear the text's parent. It shouldn't render anything.
+ QQuickItem *text = root->childItems().first();
+ text->setParentItem(nullptr);
+ QCOMPARE(text->width(), 0.0);
+ QCOMPARE(text->height(), 0.0);
+
+ // Set the parent back to what it was. The text should
+ // be rendered identically to how it was before.
+ text->setParentItem(root);
+ QCOMPARE(text->width(), 100.0);
+ QCOMPARE(text->height(), 30.0);
+
+ grabResult = root->grabToImage();
+ QTRY_VERIFY(!grabResult->image().isNull());
+ const QImage actualItemImageGrab(grabResult->image());
+ QCOMPARE(actualItemImageGrab, expectedItemImageGrab);
+}
+
void tst_qquicktext::multilineElide_data()
{
QTest::addColumn<QQuickText::TextFormat>("format");
diff --git a/tests/auto/quickwidgets/qquickwidget/data/activeFocusOnTab.qml b/tests/auto/quickwidgets/qquickwidget/data/activeFocusOnTab.qml
new file mode 100644
index 0000000000..9ad1cafed9
--- /dev/null
+++ b/tests/auto/quickwidgets/qquickwidget/data/activeFocusOnTab.qml
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.1
+
+Item {
+ Rectangle {
+ objectName: "topRect"
+ x: 0
+ width: 50
+ height: 50
+ activeFocusOnTab: true
+ focus: true
+ color: activeFocus ? "green" : "red"
+ }
+ Rectangle {
+ objectName: "middleRect"
+ x: 50
+ width: 50
+ height: 50
+ focus: true
+ activeFocusOnTab: true
+ color: activeFocus ? "green" : "red"
+ }
+ Rectangle {
+ objectName: "bottomRect"
+ x: 100
+ width: 50
+ height: 50
+ focus: true
+ activeFocusOnTab: true
+ color: activeFocus ? "green" : "red"
+ }
+}
+
diff --git a/tests/auto/quickwidgets/qquickwidget/data/noActiveFocusOnTab.qml b/tests/auto/quickwidgets/qquickwidget/data/noActiveFocusOnTab.qml
new file mode 100644
index 0000000000..6d86ce45bb
--- /dev/null
+++ b/tests/auto/quickwidgets/qquickwidget/data/noActiveFocusOnTab.qml
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.1
+
+Item {
+ Rectangle {
+ objectName: "topRect2"
+ x: 0
+ width: 50
+ height: 50
+ focus: true
+ color: activeFocus ? "green" : "red"
+ }
+ Rectangle {
+ objectName: "middleRect2"
+ x: 50
+ width: 50
+ height: 50
+ focus: true
+ color: activeFocus ? "green" : "red"
+ }
+ Rectangle {
+ objectName: "bottomRect3"
+ x: 100
+ width: 50
+ height: 50
+ focus: true
+ color: activeFocus ? "green" : "red"
+ }
+}
+
diff --git a/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp b/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp
index a97e3c0538..af358925fe 100644
--- a/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp
+++ b/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp
@@ -40,7 +40,7 @@
#include <QtQml/qqmlengine.h>
#include <QtCore/QLoggingCategory>
-
+#include <QtGui/qstylehints.h>
#include <QtWidgets/QBoxLayout>
#include <QtWidgets/QLabel>
@@ -140,6 +140,7 @@ private slots:
void mouseEventWindowPos();
void synthMouseFromTouch_data();
void synthMouseFromTouch();
+ void tabKey();
private:
QTouchDevice *device = QTest::createTouchDevice();
@@ -620,6 +621,43 @@ void tst_qquickwidget::synthMouseFromTouch()
QCOMPARE(ev.source(), Qt::MouseEventSynthesizedByQt);
}
+void tst_qquickwidget::tabKey()
+{
+ if (QGuiApplication::styleHints()->tabFocusBehavior() != Qt::TabFocusAllControls)
+ QSKIP("This function doesn't support NOT iterating all.");
+ QWidget window1;
+ QQuickWidget *qqw = new QQuickWidget(&window1);
+ qqw->setSource(testFileUrl("activeFocusOnTab.qml"));
+ QQuickWidget *qqw2 = new QQuickWidget(&window1);
+ qqw2->setSource(testFileUrl("noActiveFocusOnTab.qml"));
+ qqw2->move(100, 0);
+ window1.show();
+ qqw->setFocus();
+ QVERIFY(QTest::qWaitForWindowExposed(&window1, 5000));
+ QVERIFY(qqw->hasFocus());
+ QQuickItem *item = qobject_cast<QQuickItem *>(qqw->rootObject());
+ QQuickItem *topItem = item->findChild<QQuickItem *>("topRect");
+ QQuickItem *middleItem = item->findChild<QQuickItem *>("middleRect");
+ QQuickItem *bottomItem = item->findChild<QQuickItem *>("bottomRect");
+ topItem->forceActiveFocus();
+ QVERIFY(topItem->property("activeFocus").toBool());
+ QTest::keyClick(qqw, Qt::Key_Tab);
+ QTRY_VERIFY(middleItem->property("activeFocus").toBool());
+ QTest::keyClick(qqw, Qt::Key_Tab);
+ QTRY_VERIFY(bottomItem->property("activeFocus").toBool());
+ QTest::keyClick(qqw, Qt::Key_Backtab);
+ QTRY_VERIFY(middleItem->property("activeFocus").toBool());
+
+ qqw2->setFocus();
+ QQuickItem *item2 = qobject_cast<QQuickItem *>(qqw2->rootObject());
+ QQuickItem *topItem2 = item2->findChild<QQuickItem *>("topRect2");
+ QTRY_VERIFY(qqw2->hasFocus());
+ QVERIFY(topItem2->property("activeFocus").toBool());
+ QTest::keyClick(qqw2, Qt::Key_Tab);
+ QTRY_VERIFY(qqw->hasFocus());
+ QVERIFY(middleItem->property("activeFocus").toBool());
+}
+
QTEST_MAIN(tst_qquickwidget)
#include "tst_qquickwidget.moc"
diff --git a/tests/manual/imagehandler/embeddedimage.svg b/tests/manual/imagehandler/embeddedimage.svg
new file mode 100644
index 0000000000..f952640822
--- /dev/null
+++ b/tests/manual/imagehandler/embeddedimage.svg
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
+ version="1.2" baseProfile="tiny">
+
+ <desc>This document has a reference to an external image</desc>
+
+ <image x="200" y="200" width="100" height="100" xlink:href="heart.png">
+ <title>External image</title>
+ </image>
+</svg>
diff --git a/tests/manual/imagehandler/heart.png b/tests/manual/imagehandler/heart.png
new file mode 100644
index 0000000000..deaec18274
--- /dev/null
+++ b/tests/manual/imagehandler/heart.png
Binary files differ
diff --git a/tests/manual/imagehandler/main.qml b/tests/manual/imagehandler/main.qml
index 55e5b89cae..ec474e62ce 100644
--- a/tests/manual/imagehandler/main.qml
+++ b/tests/manual/imagehandler/main.qml
@@ -41,6 +41,10 @@ Window {
width: parent.width
sourceSize.height: height
sourceSize.width: width
+ MouseArea {
+ anchors.fill: parent
+ onClicked: svgImage.source = "embeddedimage.svg"
+ }
}
ListModel {
id: imageFillModeModel
@@ -57,7 +61,7 @@ Window {
height: 75
anchors.bottom: parent.bottom
Text {
- text: "Click the options below to change the fill mode"
+ text: "Click the options below to change the fill mode.<br>Click the image to change the used image."
font.pointSize: 16
}
diff --git a/tools/qmlcachegen/Qt5QuickCompilerConfig.cmake b/tools/qmlcachegen/Qt5QuickCompilerConfig.cmake
index 6fe1662995..56cb3fb55e 100644
--- a/tools/qmlcachegen/Qt5QuickCompilerConfig.cmake
+++ b/tools/qmlcachegen/Qt5QuickCompilerConfig.cmake
@@ -44,7 +44,7 @@ function(QTQUICK_COMPILER_ADD_RESOURCES outfiles)
set(rcc_file_with_compilation_units)
- exec_program(${rcc_path} ARGS -list ${input_resource} OUTPUT_VARIABLE rcc_contents)
+ exec_program(${rcc_path} ARGS -list \"${input_resource}\" OUTPUT_VARIABLE rcc_contents)
string(REGEX REPLACE "[\r\n]+" ";" rcc_contents ${rcc_contents})
foreach(it ${rcc_contents})
get_filename_component(extension ${it} EXT)
diff --git a/tools/qmlcachegen/generateloader.cpp b/tools/qmlcachegen/generateloader.cpp
index 1a0b987c64..96528a9477 100644
--- a/tools/qmlcachegen/generateloader.cpp
+++ b/tools/qmlcachegen/generateloader.cpp
@@ -51,6 +51,7 @@ QString symbolNamespaceForPath(const QString &relativePath)
symbol.replace(QLatin1Char('.'), QLatin1Char('_'));
symbol.replace(QLatin1Char('+'), QLatin1Char('_'));
symbol.replace(QLatin1Char('-'), QLatin1Char('_'));
+ symbol.replace(QLatin1Char(' '), QLatin1Char('_'));
return symbol;
}
@@ -358,15 +359,23 @@ bool generateLoader(const QStringList &compiledFiles, const QString &outputFileN
originalResourceFile.truncate(mappingSplit);
}
- const QString function = QLatin1String("qInitResources_") + qtResourceNameForFile(originalResourceFile);
+ const QString suffix = qtResourceNameForFile(originalResourceFile);
+ const QString initFunction = QLatin1String("qInitResources_") + suffix;
- stream << QStringLiteral("int QT_MANGLE_NAMESPACE(%1)() {\n").arg(function);
+ stream << QStringLiteral("int QT_MANGLE_NAMESPACE(%1)() {\n").arg(initFunction);
stream << " ::unitRegistry();\n";
if (!newResourceFile.isEmpty())
stream << " Q_INIT_RESOURCE(" << qtResourceNameForFile(newResourceFile) << ");\n";
stream << " return 1;\n";
stream << "}\n";
- stream << "Q_CONSTRUCTOR_FUNCTION(QT_MANGLE_NAMESPACE(" << function << "));\n";
+ stream << "Q_CONSTRUCTOR_FUNCTION(QT_MANGLE_NAMESPACE(" << initFunction << "));\n";
+
+ const QString cleanupFunction = QLatin1String("qCleanupResources_") + suffix;
+ stream << QStringLiteral("int QT_MANGLE_NAMESPACE(%1)() {\n").arg(cleanupFunction);
+ if (!newResourceFile.isEmpty())
+ stream << " Q_CLEANUP_RESOURCE(" << qtResourceNameForFile(newResourceFile) << ");\n";
+ stream << " return 1;\n";
+ stream << "}\n";
}
}
diff --git a/tools/qmlcachegen/qtquickcompiler.prf b/tools/qmlcachegen/qtquickcompiler.prf
index 75e474ba70..9fa982ca0f 100644
--- a/tools/qmlcachegen/qtquickcompiler.prf
+++ b/tools/qmlcachegen/qtquickcompiler.prf
@@ -2,7 +2,7 @@
qtPrepareTool(QML_CACHEGEN, qmlcachegen, _FILTER)
qtPrepareTool(QMAKE_RCC, rcc, _DEP)
-QMLCACHE_DIR = .qmlcache
+isEmpty(QMLCACHE_DIR): QMLCACHE_DIR = .
defineReplace(qmlCacheResourceFileOutputName) {
name = $$relative_path($$1, $$_PRO_FILE_PWD_)
@@ -22,21 +22,21 @@ QMLCACHE_RESOURCE_FILES =
for(res, RESOURCES) {
absRes = $$absolute_path($$res, $$_PRO_FILE_PWD_)
- rccContents = $$system($$QMAKE_RCC_DEP -list $$absRes,lines)
+ rccContents = $$system($$QMAKE_RCC_DEP -list $$system_quote($$absRes),lines)
contains(rccContents,.*\\.js$)|contains(rccContents,.*\\.qml$) {
new_resource = $$qmlCacheResourceFileOutputName($$res)
mkpath($$dirname(new_resource))
- remaining_files = $$system($$QML_CACHEGEN_FILTER -filter-resource-file -o $$new_resource $$absRes,lines)
+ remaining_files = $$system($$QML_CACHEGEN_FILTER -filter-resource-file -o $$system_quote($$new_resource) $$system_quote($$absRes),lines)
!isEmpty(remaining_files) {
NEWRESOURCES += $$new_resource
- QMLCACHE_LOADER_FLAGS += --resource-file-mapping=$$absRes=$$new_resource
+ QMLCACHE_LOADER_FLAGS += --resource-file-mapping=$$shell_quote($$absRes=$$new_resource)
} else {
- QMLCACHE_LOADER_FLAGS += --resource-file-mapping=$$absRes
+ QMLCACHE_LOADER_FLAGS += --resource-file-mapping=$$shell_quote($$absRes)
}
QMLCACHE_RESOURCE_FILES += $$absRes
- for(candidate, $$list($$rccContents)) {
+ for(candidate, rccContents) {
contains(candidate,.*\\.js$)|contains(candidate,.*\\.qml$) {
QMLCACHE_FILES += $$candidate
}
@@ -50,7 +50,7 @@ RESOURCES = $$NEWRESOURCES
QMLCACHE_RESOURCE_FLAGS =
for(res, QMLCACHE_RESOURCE_FILES) {
- QMLCACHE_RESOURCE_FLAGS += --resource=$$res
+ QMLCACHE_RESOURCE_FLAGS += --resource=$$shell_quote($$res)
}
defineReplace(qmlCacheOutputName) {